From 4a6921e10e6134212867df96a8035576759e9d4b Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 13 Oct 2016 10:17:25 -0500 Subject: [PATCH 001/177] rustdoc: add line breaks to where clauses a la rustfmt --- src/librustdoc/html/format.rs | 34 ++++++++++++++++++++++----------- src/test/rustdoc/line-breaks.rs | 19 ++++++++++++++++++ 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 625acce27bd6..092e1548446e 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -161,48 +161,60 @@ impl<'a> fmt::Display for WhereClause<'a> { if gens.where_predicates.is_empty() { return Ok(()); } + let mut clause = String::new(); if f.alternate() { - f.write_str(" ")?; + clause.push_str(" where "); } else { - f.write_str(" where ")?; + clause.push_str(" where "); } for (i, pred) in gens.where_predicates.iter().enumerate() { if i > 0 { - f.write_str(", ")?; + if f.alternate() { + clause.push_str(", "); + } else { + clause.push_str(",
"); + } } match pred { &clean::WherePredicate::BoundPredicate { ref ty, ref bounds } => { let bounds = bounds; if f.alternate() { - write!(f, "{:#}: {:#}", ty, TyParamBounds(bounds))?; + clause.push_str(&format!("{:#}: {:#}", ty, TyParamBounds(bounds))); } else { - write!(f, "{}: {}", ty, TyParamBounds(bounds))?; + clause.push_str(&format!("{}: {}", ty, TyParamBounds(bounds))); } } &clean::WherePredicate::RegionPredicate { ref lifetime, ref bounds } => { - write!(f, "{}: ", lifetime)?; + clause.push_str(&format!("{}: ", lifetime)); for (i, lifetime) in bounds.iter().enumerate() { if i > 0 { - f.write_str(" + ")?; + clause.push_str(" + "); } - write!(f, "{}", lifetime)?; + clause.push_str(&format!("{}", lifetime)); } } &clean::WherePredicate::EqPredicate { ref lhs, ref rhs } => { if f.alternate() { - write!(f, "{:#} == {:#}", lhs, rhs)?; + clause.push_str(&format!("{:#} == {:#}", lhs, rhs)); } else { - write!(f, "{} == {}", lhs, rhs)?; + clause.push_str(&format!("{} == {}", lhs, rhs)); } } } } if !f.alternate() { f.write_str("
")?; + let plain = format!("{:#}", self); + if plain.len() > 80 { + let padding = repeat(" ").take(8).collect::(); + clause = clause.replace("
", &format!("
{}", padding)); + } else { + clause = clause.replace("
", " "); + } } - Ok(()) + write!(f, "{}", clause) } } diff --git a/src/test/rustdoc/line-breaks.rs b/src/test/rustdoc/line-breaks.rs index cc608a244757..a1eabb515a5c 100644 --- a/src/test/rustdoc/line-breaks.rs +++ b/src/test/rustdoc/line-breaks.rs @@ -10,6 +10,9 @@ #![crate_name = "foo"] +use std::ops::Add; +use std::fmt::Display; + //@count foo/fn.function_with_a_really_long_name.html //pre/br 2 pub fn function_with_a_really_long_name(parameter_one: i32, parameter_two: i32) @@ -19,3 +22,19 @@ pub fn function_with_a_really_long_name(parameter_one: i32, //@count foo/fn.short_name.html //pre/br 0 pub fn short_name(param: i32) -> i32 { param + 1 } + +//@count foo/fn.where_clause.html //pre/br 4 +pub fn where_clause(param_one: T, + param_two: U) + where T: Add + Display + Copy, + U: Add + Display + Copy, + T::Output: Display + Add + Copy, + >::Output: Display, + U::Output: Display + Copy +{ + let x = param_one + param_two; + println!("{} + {} = {}", param_one, param_two, x); + let y = param_two + param_one; + println!("{} + {} = {}", param_two, param_one, y); + println!("{} + {} = {}", x, y, x + y); +} From c6ab68528a468aab1c501f9572926ca64dbdaced Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 13 Oct 2016 13:58:04 -0500 Subject: [PATCH 002/177] fix spurious
appearing before the opening tag --- src/librustdoc/html/format.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 092e1548446e..6d96b172a2e6 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -205,7 +205,7 @@ impl<'a> fmt::Display for WhereClause<'a> { } } if !f.alternate() { - f.write_str("")?; + clause.push_str(""); let plain = format!("{:#}", self); if plain.len() > 80 { let padding = repeat(" ").take(8).collect::(); From 42f28d31bf68abc03141d62054625c50d002c872 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Sat, 15 Oct 2016 09:46:43 -0500 Subject: [PATCH 003/177] rustdoc: apply proper indent when where clauses aren't on their own line --- src/librustdoc/html/format.rs | 34 ++++++++++--- src/librustdoc/html/render.rs | 92 ++++++++++++++++++++++++++--------- 2 files changed, 96 insertions(+), 30 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 6d96b172a2e6..3b2f2430993a 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -50,7 +50,7 @@ pub struct MutableSpace(pub clean::Mutability); #[derive(Copy, Clone)] pub struct RawMutableSpace(pub clean::Mutability); /// Wrapper struct for emitting a where clause from Generics. -pub struct WhereClause<'a>(pub &'a clean::Generics); +pub struct WhereClause<'a>(pub &'a clean::Generics, pub String); /// Wrapper struct for emitting type parameter bounds. pub struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]); /// Wrapper struct for emitting a comma-separated list of items @@ -157,7 +157,7 @@ impl fmt::Display for clean::Generics { impl<'a> fmt::Display for WhereClause<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let &WhereClause(gens) = self; + let &WhereClause(gens, ref pad) = self; if gens.where_predicates.is_empty() { return Ok(()); } @@ -207,8 +207,8 @@ impl<'a> fmt::Display for WhereClause<'a> { if !f.alternate() { clause.push_str(""); let plain = format!("{:#}", self); - if plain.len() > 80 { - let padding = repeat(" ").take(8).collect::(); + if plain.len() + pad.len() > 80 { + let padding = repeat(" ").take(pad.len() + 6).collect::(); clause = clause.replace("
", &format!("
{}", padding)); } else { clause = clause.replace("
", " "); @@ -730,30 +730,44 @@ impl fmt::Display for clean::Type { } fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::Result { + let mut plain = String::new(); + if f.alternate() { write!(f, "impl{:#} ", i.generics)?; } else { write!(f, "impl{} ", i.generics)?; } + plain.push_str(&format!("impl{:#} ", i.generics)); + if let Some(ref ty) = i.trait_ { - write!(f, "{}", - if i.polarity == Some(clean::ImplPolarity::Negative) { "!" } else { "" })?; + if i.polarity == Some(clean::ImplPolarity::Negative) { + write!(f, "!")?; + plain.push_str("!"); + } + if link_trait { fmt::Display::fmt(ty, f)?; + plain.push_str(&format!("{:#}", ty)); } else { match *ty { clean::ResolvedPath{ typarams: None, ref path, is_generic: false, .. } => { let last = path.segments.last().unwrap(); fmt::Display::fmt(&last.name, f)?; fmt::Display::fmt(&last.params, f)?; + plain.push_str(&format!("{:#}{:#}", last.name, last.params)); } _ => unreachable!(), } } write!(f, " for ")?; + plain.push_str(" for "); } + fmt::Display::fmt(&i.for_, f)?; - fmt::Display::fmt(&WhereClause(&i.generics), f)?; + plain.push_str(&format!("{:#}", i.for_)); + + let pad = repeat(" ").take(plain.len() + 1).collect::(); + fmt::Display::fmt(&WhereClause(&i.generics, pad), f)?; Ok(()) } @@ -899,7 +913,11 @@ impl<'a> fmt::Display for Method<'a> { } else { output = output.replace("
", ""); } - write!(f, "{}", output) + if f.alternate() { + write!(f, "{}", output.replace("
", "\n")) + } else { + write!(f, "{}", output) + } } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d8dba00e7d57..067cffc87793 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1983,7 +1983,7 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, abi = AbiSpace(f.abi), name = it.name.as_ref().unwrap(), generics = f.generics, - where_clause = WhereClause(&f.generics), + where_clause = WhereClause(&f.generics, " ".to_string()), decl = Method(&f.decl, &indent))?; document(w, cx, it) } @@ -1991,17 +1991,27 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, t: &clean::Trait) -> fmt::Result { let mut bounds = String::new(); + let mut bounds_plain = String::new(); if !t.bounds.is_empty() { if !bounds.is_empty() { bounds.push(' '); + bounds_plain.push(' '); } bounds.push_str(": "); + bounds_plain.push_str(": "); for (i, p) in t.bounds.iter().enumerate() { - if i > 0 { bounds.push_str(" + "); } + if i > 0 { + bounds.push_str(" + "); + bounds_plain.push_str(" + "); + } bounds.push_str(&format!("{}", *p)); + bounds_plain.push_str(&format!("{:#}", *p)); } } + // Where clauses in traits are indented nine spaces, per rustdoc.css + let indent = " ".to_string(); + // Output the trait definition write!(w, "
{}{}trait {}{}{}{} ",
            VisSpace(&it.visibility),
@@ -2009,7 +2019,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
            it.name.as_ref().unwrap(),
            t.generics,
            bounds,
-           WhereClause(&t.generics))?;
+           WhereClause(&t.generics, indent))?;
 
     let types = t.items.iter().filter(|m| m.is_associated_type()).collect::>();
     let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::>();
@@ -2023,7 +2033,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
         write!(w, "{{\n")?;
         for t in &types {
             write!(w, "    ")?;
-            render_assoc_item(w, t, AssocItemLink::Anchor(None))?;
+            render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait)?;
             write!(w, ";\n")?;
         }
         if !types.is_empty() && !consts.is_empty() {
@@ -2031,7 +2041,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
         }
         for t in &consts {
             write!(w, "    ")?;
-            render_assoc_item(w, t, AssocItemLink::Anchor(None))?;
+            render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait)?;
             write!(w, ";\n")?;
         }
         if !consts.is_empty() && !required.is_empty() {
@@ -2039,7 +2049,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
         }
         for m in &required {
             write!(w, "    ")?;
-            render_assoc_item(w, m, AssocItemLink::Anchor(None))?;
+            render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?;
             write!(w, ";\n")?;
         }
         if !required.is_empty() && !provided.is_empty() {
@@ -2047,7 +2057,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
         }
         for m in &provided {
             write!(w, "    ")?;
-            render_assoc_item(w, m, AssocItemLink::Anchor(None))?;
+            render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?;
             write!(w, " {{ ... }}\n")?;
         }
         write!(w, "}}")?;
@@ -2068,7 +2078,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
                id = id,
                stab = m.stability_class(),
                ns_id = ns_id)?;
-        render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)))?;
+        render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl)?;
         write!(w, "")?;
         render_stability_since(w, m, t)?;
         write!(w, "")?;
@@ -2222,7 +2232,8 @@ fn render_stability_since(w: &mut fmt::Formatter,
 
 fn render_assoc_item(w: &mut fmt::Formatter,
                      item: &clean::Item,
-                     link: AssocItemLink) -> fmt::Result {
+                     link: AssocItemLink,
+                     parent: ItemType) -> fmt::Result {
     fn method(w: &mut fmt::Formatter,
               meth: &clean::Item,
               unsafety: hir::Unsafety,
@@ -2230,7 +2241,8 @@ fn render_assoc_item(w: &mut fmt::Formatter,
               abi: abi::Abi,
               g: &clean::Generics,
               d: &clean::FnDecl,
-              link: AssocItemLink)
+              link: AssocItemLink,
+              parent: ItemType)
               -> fmt::Result {
         let name = meth.name.as_ref().unwrap();
         let anchor = format!("#{}.{}", meth.type_(), name);
@@ -2260,7 +2272,17 @@ fn render_assoc_item(w: &mut fmt::Formatter,
                              AbiSpace(abi),
                              name,
                              *g);
-        let indent = repeat(" ").take(prefix.len()).collect::();
+        let mut indent = repeat(" ").take(prefix.len()).collect::();
+        let where_indent = if parent == ItemType::Trait {
+            indent += "    ";
+            "        ".to_string()
+        } else if parent == ItemType::Impl {
+            "  ".to_string()
+        } else {
+            let prefix = prefix + &format!("{:#}", Method(d, &indent));
+            let prefix = prefix.lines().last().unwrap();
+            repeat(" ").take(prefix.len() + 1).collect::()
+        };
         write!(w, "{}{}{}fn {name}\
                    {generics}{decl}{where_clause}",
                ConstnessSpace(vis_constness),
@@ -2270,18 +2292,17 @@ fn render_assoc_item(w: &mut fmt::Formatter,
                name = name,
                generics = *g,
                decl = Method(d, &indent),
-               where_clause = WhereClause(g))
+               where_clause = WhereClause(g, where_indent))
     }
     match item.inner {
         clean::StrippedItem(..) => Ok(()),
         clean::TyMethodItem(ref m) => {
             method(w, item, m.unsafety, hir::Constness::NotConst,
-                   m.abi, &m.generics, &m.decl, link)
+                   m.abi, &m.generics, &m.decl, link, parent)
         }
         clean::MethodItem(ref m) => {
             method(w, item, m.unsafety, m.constness,
-                   m.abi, &m.generics, &m.decl,
-                   link)
+                   m.abi, &m.generics, &m.decl, link, parent)
         }
         clean::AssociatedConstItem(ref ty, ref default) => {
             assoc_const(w, item, ty, default.as_ref(), link)
@@ -2378,11 +2399,15 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
              e: &clean::Enum) -> fmt::Result {
     write!(w, "
")?;
     render_attributes(w, it)?;
+    let padding = format!("{}enum {}{:#} ",
+                          VisSpace(&it.visibility),
+                          it.name.as_ref().unwrap(),
+                          e.generics);
     write!(w, "{}enum {}{}{}",
            VisSpace(&it.visibility),
            it.name.as_ref().unwrap(),
            e.generics,
-           WhereClause(&e.generics))?;
+           WhereClause(&e.generics, padding))?;
     if e.variants.is_empty() && !e.variants_stripped {
         write!(w, " {{}}")?;
     } else {
@@ -2517,17 +2542,24 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
                  fields: &[clean::Item],
                  tab: &str,
                  structhead: bool) -> fmt::Result {
+    let mut plain = String::new();
     write!(w, "{}{}{}",
            VisSpace(&it.visibility),
            if structhead {"struct "} else {""},
            it.name.as_ref().unwrap())?;
+    plain.push_str(&format!("{}{}{}",
+                            VisSpace(&it.visibility),
+                            if structhead {"struct "} else {""},
+                            it.name.as_ref().unwrap()));
     if let Some(g) = g {
+        plain.push_str(&format!("{:#}", g));
         write!(w, "{}", g)?
     }
     match ty {
         doctree::Plain => {
             if let Some(g) = g {
-                write!(w, "{}", WhereClause(g))?
+                let pad = repeat(" ").take(plain.len() + 1).collect::();
+                write!(w, "{}", WhereClause(g, pad))?
             }
             let mut has_visible_fields = false;
             write!(w, " {{")?;
@@ -2556,30 +2588,37 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
         }
         doctree::Tuple => {
             write!(w, "(")?;
+            plain.push_str("(");
             for (i, field) in fields.iter().enumerate() {
                 if i > 0 {
                     write!(w, ", ")?;
+                    plain.push_str(", ");
                 }
                 match field.inner {
                     clean::StrippedItem(box clean::StructFieldItem(..)) => {
+                        plain.push_str("_");
                         write!(w, "_")?
                     }
                     clean::StructFieldItem(ref ty) => {
+                        plain.push_str(&format!("{}{:#}", VisSpace(&field.visibility), *ty));
                         write!(w, "{}{}", VisSpace(&field.visibility), *ty)?
                     }
                     _ => unreachable!()
                 }
             }
             write!(w, ")")?;
+            plain.push_str(")");
             if let Some(g) = g {
-                write!(w, "{}", WhereClause(g))?
+                let pad = repeat(" ").take(plain.len() + 1).collect::();
+                write!(w, "{}", WhereClause(g, pad))?
             }
             write!(w, ";")?;
         }
         doctree::Unit => {
             // Needed for PhantomData.
             if let Some(g) = g {
-                write!(w, "{}", WhereClause(g))?
+                let pad = repeat(" ").take(plain.len() + 1).collect::();
+                write!(w, "{}", WhereClause(g, pad))?
             }
             write!(w, ";")?;
         }
@@ -2592,13 +2631,20 @@ fn render_union(w: &mut fmt::Formatter, it: &clean::Item,
                 fields: &[clean::Item],
                 tab: &str,
                 structhead: bool) -> fmt::Result {
+    let mut plain = String::new();
     write!(w, "{}{}{}",
            VisSpace(&it.visibility),
            if structhead {"union "} else {""},
            it.name.as_ref().unwrap())?;
+    plain.push_str(&format!("{}{}{}",
+                            VisSpace(&it.visibility),
+                            if structhead {"union "} else {""},
+                            it.name.as_ref().unwrap()));
     if let Some(g) = g {
         write!(w, "{}", g)?;
-        write!(w, "{}", WhereClause(g))?;
+        plain.push_str(&format!("{:#}", g));
+        let pad = repeat(" ").take(plain.len() + 1).collect::();
+        write!(w, "{}", WhereClause(g, pad))?;
     }
 
     write!(w, " {{\n{}", tab)?;
@@ -2789,7 +2835,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
                     write!(w, "

", id, item_type)?; write!(w, "

\n")?; @@ -2899,10 +2945,12 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi fn item_typedef(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, t: &clean::Typedef) -> fmt::Result { + let indent = format!("type {}{:#} ", it.name.as_ref().unwrap(), t.generics); + let indent = repeat(" ").take(indent.len()).collect::(); write!(w, "
type {}{}{where_clause} = {type_};
", it.name.as_ref().unwrap(), t.generics, - where_clause = WhereClause(&t.generics), + where_clause = WhereClause(&t.generics, indent), type_ = t.type_)?; document(w, cx, it) From 07b27bb34c4ce32152369d202cac7a4e0c9878af Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Sat, 15 Oct 2016 10:29:47 -0500 Subject: [PATCH 004/177] rustdoc: break where clauses onto their own line if they don't have enough room --- src/librustdoc/html/format.rs | 7 ++++++- src/librustdoc/html/static/rustdoc.css | 12 ++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 3b2f2430993a..5fb99a2031fb 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -208,7 +208,12 @@ impl<'a> fmt::Display for WhereClause<'a> { clause.push_str(""); let plain = format!("{:#}", self); if plain.len() + pad.len() > 80 { - let padding = repeat(" ").take(pad.len() + 6).collect::(); + let padding = if pad.len() + 25 > 80 { + clause = clause.replace("class='where'", "class='where fmt-newline'"); + repeat(" ").take(8).collect::() + } else { + repeat(" ").take(pad.len() + 6).collect::() + }; clause = clause.replace("
", &format!("
{}", padding)); } else { clause = clause.replace("
", " "); diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index f8133ea49ceb..3b6ffa4a462f 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -361,9 +361,17 @@ h4 > code, h3 > code, .invisible > code { position: relative; } /* Shift "where ..." part of method or fn definition down a line */ -.content .method .where, .content .fn .where { display: block; } +.content .method .where, +.content .fn .where, +.content .where.fmt-newline { + display: block; +} /* Bit of whitespace to indent it */ -.content .method .where::before, .content .fn .where::before { content: ' '; } +.content .method .where::before, +.content .fn .where::before, +.content .where.fmt-newline::before { + content: ' '; +} .content .methods > div { margin-left: 40px; } From 43abad45837a15c62828b700aff7efd8eee76cfd Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Sat, 15 Oct 2016 21:52:18 -0500 Subject: [PATCH 005/177] rustdoc: if a where clause gets any lines, it gets its own line --- src/librustdoc/html/format.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 5fb99a2031fb..c4a4817195b6 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -208,7 +208,9 @@ impl<'a> fmt::Display for WhereClause<'a> { clause.push_str(""); let plain = format!("{:#}", self); if plain.len() + pad.len() > 80 { - let padding = if pad.len() + 25 > 80 { + //break it onto its own line regardless, but make sure method impls and trait + //blocks keep their fixed padding (2 and 9, respectively) + let padding = if pad.len() > 10 { clause = clause.replace("class='where'", "class='where fmt-newline'"); repeat(" ").take(8).collect::() } else { From 61cc8700dfcecde9e7de132356f3c32eb01b147e Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Mon, 17 Oct 2016 09:55:18 -0500 Subject: [PATCH 006/177] rustdoc: make Method/WhereClause wrappers use usize for indents --- src/librustdoc/html/format.rs | 25 ++++++++++--------- src/librustdoc/html/render.rs | 47 ++++++++++++++--------------------- 2 files changed, 32 insertions(+), 40 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index c4a4817195b6..eef530081abe 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -42,7 +42,7 @@ pub struct UnsafetySpace(pub hir::Unsafety); #[derive(Copy, Clone)] pub struct ConstnessSpace(pub hir::Constness); /// Wrapper struct for properly emitting a method declaration. -pub struct Method<'a>(pub &'a clean::FnDecl, pub &'a str); +pub struct Method<'a>(pub &'a clean::FnDecl, pub usize); /// Similar to VisSpace, but used for mutability #[derive(Copy, Clone)] pub struct MutableSpace(pub clean::Mutability); @@ -50,7 +50,7 @@ pub struct MutableSpace(pub clean::Mutability); #[derive(Copy, Clone)] pub struct RawMutableSpace(pub clean::Mutability); /// Wrapper struct for emitting a where clause from Generics. -pub struct WhereClause<'a>(pub &'a clean::Generics, pub String); +pub struct WhereClause<'a>(pub &'a clean::Generics, pub usize); /// Wrapper struct for emitting type parameter bounds. pub struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]); /// Wrapper struct for emitting a comma-separated list of items @@ -157,7 +157,7 @@ impl fmt::Display for clean::Generics { impl<'a> fmt::Display for WhereClause<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let &WhereClause(gens, ref pad) = self; + let &WhereClause(gens, pad) = self; if gens.where_predicates.is_empty() { return Ok(()); } @@ -207,14 +207,14 @@ impl<'a> fmt::Display for WhereClause<'a> { if !f.alternate() { clause.push_str(""); let plain = format!("{:#}", self); - if plain.len() + pad.len() > 80 { + if plain.len() > 80 { //break it onto its own line regardless, but make sure method impls and trait //blocks keep their fixed padding (2 and 9, respectively) - let padding = if pad.len() > 10 { + let padding = if pad > 10 { clause = clause.replace("class='where'", "class='where fmt-newline'"); repeat(" ").take(8).collect::() } else { - repeat(" ").take(pad.len() + 6).collect::() + repeat(" ").take(pad + 6).collect::() }; clause = clause.replace("
", &format!("
{}", padding)); } else { @@ -773,8 +773,7 @@ fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::R fmt::Display::fmt(&i.for_, f)?; plain.push_str(&format!("{:#}", i.for_)); - let pad = repeat(" ").take(plain.len() + 1).collect::(); - fmt::Display::fmt(&WhereClause(&i.generics, pad), f)?; + fmt::Display::fmt(&WhereClause(&i.generics, plain.len() + 1), f)?; Ok(()) } @@ -903,19 +902,21 @@ impl<'a> fmt::Display for Method<'a> { let mut output: String; let plain: String; + let pad = repeat(" ").take(indent).collect::(); if arrow.is_empty() { output = format!("({})", args); - plain = format!("{}({})", indent.replace(" ", " "), args_plain); + plain = format!("{}({})", pad, args_plain); } else { output = format!("({args})
{arrow}", args = args, arrow = arrow); - plain = format!("{indent}({args}){arrow}", - indent = indent.replace(" ", " "), + plain = format!("{pad}({args}){arrow}", + pad = pad, args = args_plain, arrow = arrow_plain); } if plain.len() > 80 { - let pad = format!("
{}", indent); + let pad = repeat(" ").take(indent).collect::(); + let pad = format!("
{}", pad); output = output.replace("
", &pad); } else { output = output.replace("
", ""); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 067cffc87793..c0a1abd4aec3 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1967,14 +1967,13 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, UnstableFeatures::Allow => f.constness, _ => hir::Constness::NotConst }; - let prefix = format!("{}{}{}{:#}fn {}{:#}", + let indent = format!("{}{}{}{:#}fn {}{:#}", VisSpace(&it.visibility), ConstnessSpace(vis_constness), UnsafetySpace(f.unsafety), AbiSpace(f.abi), it.name.as_ref().unwrap(), - f.generics); - let indent = repeat(" ").take(prefix.len()).collect::(); + f.generics).len(); write!(w, "
{vis}{constness}{unsafety}{abi}fn \
                {name}{generics}{decl}{where_clause}
", vis = VisSpace(&it.visibility), @@ -1983,8 +1982,8 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, abi = AbiSpace(f.abi), name = it.name.as_ref().unwrap(), generics = f.generics, - where_clause = WhereClause(&f.generics, " ".to_string()), - decl = Method(&f.decl, &indent))?; + where_clause = WhereClause(&f.generics, 2), + decl = Method(&f.decl, indent))?; document(w, cx, it) } @@ -2009,9 +2008,6 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } } - // Where clauses in traits are indented nine spaces, per rustdoc.css - let indent = " ".to_string(); - // Output the trait definition write!(w, "
{}{}trait {}{}{}{} ",
            VisSpace(&it.visibility),
@@ -2019,7 +2015,8 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
            it.name.as_ref().unwrap(),
            t.generics,
            bounds,
-           WhereClause(&t.generics, indent))?;
+           // Where clauses in traits are indented nine spaces, per rustdoc.css
+           WhereClause(&t.generics, 9))?;
 
     let types = t.items.iter().filter(|m| m.is_associated_type()).collect::>();
     let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::>();
@@ -2272,16 +2269,15 @@ fn render_assoc_item(w: &mut fmt::Formatter,
                              AbiSpace(abi),
                              name,
                              *g);
-        let mut indent = repeat(" ").take(prefix.len()).collect::();
+        let mut indent = prefix.len();
         let where_indent = if parent == ItemType::Trait {
-            indent += "    ";
-            "        ".to_string()
+            indent += 4;
+            8
         } else if parent == ItemType::Impl {
-            "  ".to_string()
+            2
         } else {
-            let prefix = prefix + &format!("{:#}", Method(d, &indent));
-            let prefix = prefix.lines().last().unwrap();
-            repeat(" ").take(prefix.len() + 1).collect::()
+            let prefix = prefix + &format!("{:#}", Method(d, indent));
+            prefix.lines().last().unwrap().len() + 1
         };
         write!(w, "{}{}{}fn {name}\
                    {generics}{decl}{where_clause}",
@@ -2291,7 +2287,7 @@ fn render_assoc_item(w: &mut fmt::Formatter,
                href = href,
                name = name,
                generics = *g,
-               decl = Method(d, &indent),
+               decl = Method(d, indent),
                where_clause = WhereClause(g, where_indent))
     }
     match item.inner {
@@ -2402,7 +2398,7 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
     let padding = format!("{}enum {}{:#} ",
                           VisSpace(&it.visibility),
                           it.name.as_ref().unwrap(),
-                          e.generics);
+                          e.generics).len();
     write!(w, "{}enum {}{}{}",
            VisSpace(&it.visibility),
            it.name.as_ref().unwrap(),
@@ -2558,8 +2554,7 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
     match ty {
         doctree::Plain => {
             if let Some(g) = g {
-                let pad = repeat(" ").take(plain.len() + 1).collect::();
-                write!(w, "{}", WhereClause(g, pad))?
+                write!(w, "{}", WhereClause(g, plain.len() + 1))?
             }
             let mut has_visible_fields = false;
             write!(w, " {{")?;
@@ -2609,16 +2604,14 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
             write!(w, ")")?;
             plain.push_str(")");
             if let Some(g) = g {
-                let pad = repeat(" ").take(plain.len() + 1).collect::();
-                write!(w, "{}", WhereClause(g, pad))?
+                write!(w, "{}", WhereClause(g, plain.len() + 1))?
             }
             write!(w, ";")?;
         }
         doctree::Unit => {
             // Needed for PhantomData.
             if let Some(g) = g {
-                let pad = repeat(" ").take(plain.len() + 1).collect::();
-                write!(w, "{}", WhereClause(g, pad))?
+                write!(w, "{}", WhereClause(g, plain.len() + 1))?
             }
             write!(w, ";")?;
         }
@@ -2643,8 +2636,7 @@ fn render_union(w: &mut fmt::Formatter, it: &clean::Item,
     if let Some(g) = g {
         write!(w, "{}", g)?;
         plain.push_str(&format!("{:#}", g));
-        let pad = repeat(" ").take(plain.len() + 1).collect::();
-        write!(w, "{}", WhereClause(g, pad))?;
+        write!(w, "{}", WhereClause(g, plain.len() + 1))?;
     }
 
     write!(w, " {{\n{}", tab)?;
@@ -2945,8 +2937,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
 
 fn item_typedef(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
                 t: &clean::Typedef) -> fmt::Result {
-    let indent = format!("type {}{:#} ", it.name.as_ref().unwrap(), t.generics);
-    let indent = repeat(" ").take(indent.len()).collect::();
+    let indent = format!("type {}{:#} ", it.name.as_ref().unwrap(), t.generics).len();
     write!(w, "
type {}{}{where_clause} = {type_};
", it.name.as_ref().unwrap(), t.generics, From eed86fac91c12707b8ef6693a5cf2106ca6652c0 Mon Sep 17 00:00:00 2001 From: Geoffry Song Date: Mon, 17 Oct 2016 21:01:36 -0700 Subject: [PATCH 007/177] Don't spin expanding stmt macros. If we can't make progress when parsing a macro expansion as a statement then we should just bail. This alleviates the symptoms shown in e.g. #37113 but it doesn't fix the problem that parsing invalid enum bodies (and others) leaves the parser in a crappy state. --- src/libsyntax/ext/expand.rs | 4 +++- src/test/parse-fail/issue-37234.rs | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 src/test/parse-fail/issue-37234.rs diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index e84a9208029a..6592dff4fb8e 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -536,7 +536,9 @@ impl<'a> Parser<'a> { } ExpansionKind::Stmts => { let mut stmts = SmallVector::zero(); - while self.token != token::Eof { + while self.token != token::Eof && + // won't make progress on a `}` + self.token != token::CloseDelim(token::Brace) { if let Some(stmt) = self.parse_full_stmt(macro_legacy_warnings)? { stmts.push(stmt); } diff --git a/src/test/parse-fail/issue-37234.rs b/src/test/parse-fail/issue-37234.rs new file mode 100644 index 000000000000..651e11d9d21b --- /dev/null +++ b/src/test/parse-fail/issue-37234.rs @@ -0,0 +1,19 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! failed { + () => {{ + let x = 5 ""; //~ ERROR found `""` + }} //~ ERROR macro expansion ignores token `}` +} + +fn main() { + failed!(); +} From 1b39c0a602ad316b8eebd2dd50ae14e45d47dd13 Mon Sep 17 00:00:00 2001 From: nwin Date: Mon, 31 Oct 2016 19:43:50 +0100 Subject: [PATCH 008/177] Remove remark about poor code style The current wording [seems to be confusing](https://www.reddit.com/r/rust/comments/5aat03/why_is_implementing_traits_on_primitive_types/). As an explanation when and why this could be considered as poor style would go beyond of the scope of this chapter I suggest to remove this remark. --- src/doc/book/traits.md | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/src/doc/book/traits.md b/src/doc/book/traits.md index b0d954adf677..18e7f07f722e 100644 --- a/src/doc/book/traits.md +++ b/src/doc/book/traits.md @@ -243,27 +243,7 @@ to know more about [operator traits][operators-and-overloading]. # Rules for implementing traits So far, we’ve only added trait implementations to structs, but you can -implement a trait for any type. So technically, we _could_ implement `HasArea` -for `i32`: - -```rust -trait HasArea { - fn area(&self) -> f64; -} - -impl HasArea for i32 { - fn area(&self) -> f64 { - println!("this is silly"); - - *self as f64 - } -} - -5.area(); -``` - -It is considered poor style to implement methods on such primitive types, even -though it is possible. +implement a trait for any type such as `i32`. This may seem like the Wild West, but there are two restrictions around implementing traits that prevent this from getting out of hand. The first is From 3d1ecc50ed7e83bb63116bc53f97eee409c7922d Mon Sep 17 00:00:00 2001 From: Havvy Date: Tue, 1 Nov 2016 20:32:02 -0700 Subject: [PATCH 009/177] Normalize generic bounds in graph iterators Use where clasues and only where clauses for bounds in the iterators for Graph. The rest of the code uses bounds on the generic declarations for Debug, and we may want to change those to for consistency. I did not do that here because I don't know whether or not that's a good idea. But for the iterators, they were inconsistent causing confusion, at least for me. --- src/librustc_data_structures/graph/mod.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs index fdb629ca5a57..111f3a2cd87e 100644 --- a/src/librustc_data_structures/graph/mod.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -336,7 +336,7 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> { } } -pub struct AdjacentTargets<'g, N: 'g, E: 'g> +pub struct AdjacentTargets<'g, N, E> where N: 'g, E: 'g { @@ -351,7 +351,7 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentTargets<'g, N, E> { } } -pub struct AdjacentSources<'g, N: 'g, E: 'g> +pub struct AdjacentSources<'g, N, E> where N: 'g, E: 'g { @@ -366,7 +366,10 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentSources<'g, N, E> { } } -pub struct DepthFirstTraversal<'g, N: 'g, E: 'g> { +pub struct DepthFirstTraversal<'g, N, E> + where N: 'g, + E: 'g +{ graph: &'g Graph, stack: Vec, visited: BitVector, From fcf02623ee59bb21b948aea63b41b62609a7e663 Mon Sep 17 00:00:00 2001 From: Havvy Date: Wed, 2 Nov 2016 01:35:44 -0700 Subject: [PATCH 010/177] Added general iterators for graph nodes and edges Also used those general iterators in other methods. --- src/librustc_data_structures/graph/mod.rs | 48 +++++++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs index 111f3a2cd87e..a47374feecda 100644 --- a/src/librustc_data_structures/graph/mod.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -231,18 +231,30 @@ impl Graph { // # Iterating over nodes, edges + pub fn all_nodes_enumerated(&self) -> Nodes { + Nodes { + iter: self.nodes.iter().enumerate() + } + } + + pub fn all_edges_enumerated(&self) -> Edges { + Edges { + iter: self.edges.iter().enumerate() + } + } + pub fn each_node<'a, F>(&'a self, mut f: F) -> bool where F: FnMut(NodeIndex, &'a Node) -> bool { //! Iterates over all edges defined in the graph. - self.nodes.iter().enumerate().all(|(i, node)| f(NodeIndex(i), node)) + self.all_nodes_enumerated().all(|(node_idx, node)| f(node_idx, node)) } pub fn each_edge<'a, F>(&'a self, mut f: F) -> bool where F: FnMut(EdgeIndex, &'a Edge) -> bool { //! Iterates over all edges defined in the graph - self.edges.iter().enumerate().all(|(i, edge)| f(EdgeIndex(i), edge)) + self.all_edges_enumerated().all(|(edge_idx, edge)| f(edge_idx, edge)) } pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges { @@ -286,8 +298,8 @@ impl Graph { while changed { changed = false; iteration += 1; - for (i, edge) in self.edges.iter().enumerate() { - changed |= op(iteration, EdgeIndex(i), edge); + for (edge_index, edge) in self.all_edges_enumerated() { + changed |= op(iteration, edge_index, edge); } } } @@ -302,6 +314,34 @@ impl Graph { // # Iterators +pub struct Nodes<'g, N> + where N: 'g, +{ + iter: ::std::iter::Enumerate<::std::slice::Iter<'g, Node>> +} + +impl<'g, N: Debug> Iterator for Nodes<'g, N> { + type Item = (NodeIndex, &'g Node); + + fn next(&mut self) -> Option<(NodeIndex, &'g Node)> { + self.iter.next().map(|(idx, n)| (NodeIndex(idx), n)) + } +} + +pub struct Edges<'g, E> + where E: 'g, +{ + iter: ::std::iter::Enumerate<::std::slice::Iter<'g, Edge>> +} + +impl<'g, E: Debug> Iterator for Edges<'g, E> { + type Item = (EdgeIndex, &'g Edge); + + fn next(&mut self) -> Option<(EdgeIndex, &'g Edge)> { + self.iter.next().map(|(idx, e)| (EdgeIndex(idx), e)) + } +} + pub struct AdjacentEdges<'g, N, E> where N: 'g, E: 'g From 7d91581cca025fbf308ed3402d04a55ea0bb0267 Mon Sep 17 00:00:00 2001 From: Havvy Date: Wed, 2 Nov 2016 01:45:12 -0700 Subject: [PATCH 011/177] Change Make comment into doc comment on Graph::iterate_until_fixed_point --- src/librustc_data_structures/graph/mod.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs index a47374feecda..6b4083789976 100644 --- a/src/librustc_data_structures/graph/mod.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -282,14 +282,11 @@ impl Graph { self.incoming_edges(target).sources() } - // # Fixed-point iteration - // - // A common use for graphs in our compiler is to perform - // fixed-point iteration. In this case, each edge represents a - // constraint, and the nodes themselves are associated with - // variables or other bitsets. This method facilitates such a - // computation. - + /// A common use for graphs in our compiler is to perform + /// fixed-point iteration. In this case, each edge represents a + /// constraint, and the nodes themselves are associated with + /// variables or other bitsets. This method facilitates such a + /// computation. pub fn iterate_until_fixed_point<'a, F>(&'a self, mut op: F) where F: FnMut(usize, EdgeIndex, &'a Edge) -> bool { From 2af61112d4cbe1b0a7ae4afd99ef387002b7a7de Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Tue, 1 Nov 2016 19:06:51 -0600 Subject: [PATCH 012/177] Add Error implementation for std::sync::mpsc::RecvTimeoutError. --- src/libstd/sync/mpsc/mod.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index fce640e7c7a2..2773629c7d7d 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -1267,6 +1267,38 @@ impl error::Error for TryRecvError { } } +#[stable(feature = "mpsc_recv_timeout_error", since = "1.14.0")] +impl fmt::Display for RecvTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + RecvTimeoutError::Timeout => { + "timed out waiting on channel".fmt(f) + } + RecvTimeoutError::Disconnected => { + "channel is empty and sending half is closed".fmt(f) + } + } + } +} + +#[stable(feature = "mpsc_recv_timeout_error", since = "1.14.0")] +impl error::Error for RecvTimeoutError { + fn description(&self) -> &str { + match *self { + RecvTimeoutError::Timeout => { + "timed out waiting on channel" + } + RecvTimeoutError::Disconnected => { + "channel is empty and sending half is closed" + } + } + } + + fn cause(&self) -> Option<&error::Error> { + None + } +} + #[cfg(all(test, not(target_os = "emscripten")))] mod tests { use env; From 5ad235c8c0416ebab0b80e4750b84c061ef6cc6b Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 3 Nov 2016 01:00:55 +0000 Subject: [PATCH 013/177] Bump the bootstrap cargo to match the one paired with 1.13 --- src/stage0.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stage0.txt b/src/stage0.txt index ac2050a6fc8f..4f37a1d1e128 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -13,4 +13,4 @@ # released on `$date` rustc: beta-2016-09-28 -cargo: nightly-2016-09-26 +cargo: nightly-2016-11-02 From 9ddbb9133c86df9aab7b98a0e6b641b847c800ec Mon Sep 17 00:00:00 2001 From: Havvy Date: Wed, 2 Nov 2016 02:38:36 -0700 Subject: [PATCH 014/177] Added Graph::is_cyclicic_node algorithm --- src/librustc_data_structures/graph/mod.rs | 51 ++++++++++++++++----- src/librustc_data_structures/graph/tests.rs | 46 +++++++++++++++++-- 2 files changed, 82 insertions(+), 15 deletions(-) diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs index 6b4083789976..f94ed6b72094 100644 --- a/src/librustc_data_structures/graph/mod.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -231,14 +231,14 @@ impl Graph { // # Iterating over nodes, edges - pub fn all_nodes_enumerated(&self) -> Nodes { - Nodes { + pub fn enumerated_nodes(&self) -> EnumeratedNodes { + EnumeratedNodes { iter: self.nodes.iter().enumerate() } } - pub fn all_edges_enumerated(&self) -> Edges { - Edges { + pub fn enumerated_edges(&self) -> EnumeratedEdges { + EnumeratedEdges { iter: self.edges.iter().enumerate() } } @@ -247,14 +247,14 @@ impl Graph { where F: FnMut(NodeIndex, &'a Node) -> bool { //! Iterates over all edges defined in the graph. - self.all_nodes_enumerated().all(|(node_idx, node)| f(node_idx, node)) + self.enumerated_nodes().all(|(node_idx, node)| f(node_idx, node)) } pub fn each_edge<'a, F>(&'a self, mut f: F) -> bool where F: FnMut(EdgeIndex, &'a Edge) -> bool { //! Iterates over all edges defined in the graph - self.all_edges_enumerated().all(|(edge_idx, edge)| f(edge_idx, edge)) + self.enumerated_edges().all(|(edge_idx, edge)| f(edge_idx, edge)) } pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges { @@ -295,7 +295,7 @@ impl Graph { while changed { changed = false; iteration += 1; - for (edge_index, edge) in self.all_edges_enumerated() { + for (edge_index, edge) in self.enumerated_edges() { changed |= op(iteration, edge_index, edge); } } @@ -307,17 +307,46 @@ impl Graph { -> DepthFirstTraversal<'a, N, E> { DepthFirstTraversal::with_start_node(self, start, direction) } + + /// Whether or not a node can be reached from itself. + pub fn is_node_cyclic(&self, starting_node_index: NodeIndex) -> bool { + // This is similar to depth traversal below, but we + // can't use that, because depth traversal doesn't show + // the starting node a second time. + let mut visited = BitVector::new(self.len_nodes()); + let mut stack = vec![starting_node_index]; + + while let Some(current_node_index) = stack.pop() { + visited.insert(current_node_index.0); + + // Directionality doesn't change the answer, + // so just use outgoing edges. + for (_, edge) in self.outgoing_edges(current_node_index) { + let target_node_index = edge.target(); + + if target_node_index == starting_node_index { + return true; + } + + if !visited.contains(target_node_index.0) { + stack.push(target_node_index); + } + } + } + + false + } } // # Iterators -pub struct Nodes<'g, N> +pub struct EnumeratedNodes<'g, N> where N: 'g, { iter: ::std::iter::Enumerate<::std::slice::Iter<'g, Node>> } -impl<'g, N: Debug> Iterator for Nodes<'g, N> { +impl<'g, N: Debug> Iterator for EnumeratedNodes<'g, N> { type Item = (NodeIndex, &'g Node); fn next(&mut self) -> Option<(NodeIndex, &'g Node)> { @@ -325,13 +354,13 @@ impl<'g, N: Debug> Iterator for Nodes<'g, N> { } } -pub struct Edges<'g, E> +pub struct EnumeratedEdges<'g, E> where E: 'g, { iter: ::std::iter::Enumerate<::std::slice::Iter<'g, Edge>> } -impl<'g, E: Debug> Iterator for Edges<'g, E> { +impl<'g, E: Debug> Iterator for EnumeratedEdges<'g, E> { type Item = (EdgeIndex, &'g Edge); fn next(&mut self) -> Option<(EdgeIndex, &'g Edge)> { diff --git a/src/librustc_data_structures/graph/tests.rs b/src/librustc_data_structures/graph/tests.rs index be7f48d27e04..a87410e6e1c8 100644 --- a/src/librustc_data_structures/graph/tests.rs +++ b/src/librustc_data_structures/graph/tests.rs @@ -20,10 +20,13 @@ fn create_graph() -> TestGraph { // Create a simple graph // - // A -+> B --> C - // | | ^ - // | v | - // F D --> E + // F + // | + // V + // A --> B --> C + // | ^ + // v | + // D --> E let a = graph.add_node("A"); let b = graph.add_node("B"); @@ -42,6 +45,29 @@ fn create_graph() -> TestGraph { return graph; } +fn create_graph_with_cycle() -> TestGraph { + let mut graph = Graph::new(); + + // Create a graph with a cycle. + // + // A --> B <-- + + // | | + // v | + // C --> D + + let a = graph.add_node("A"); + let b = graph.add_node("B"); + let c = graph.add_node("C"); + let d = graph.add_node("D"); + + graph.add_edge(a, b, "AB"); + graph.add_edge(b, c, "BC"); + graph.add_edge(c, d, "CD"); + graph.add_edge(d, b, "DB"); + + return graph; +} + #[test] fn each_node() { let graph = create_graph(); @@ -139,3 +165,15 @@ fn each_adjacent_from_d() { let graph = create_graph(); test_adjacent_edges(&graph, NodeIndex(3), "D", &[("BD", "B")], &[("DE", "E")]); } + +#[test] +fn is_node_cyclic_a() { + let graph = create_graph_with_cycle(); + assert!(!graph.is_node_cyclic(NodeIndex(0))); +} + +#[test] +fn is_node_cyclic_b() { + let graph = create_graph_with_cycle(); + assert!(graph.is_node_cyclic(NodeIndex(1))); +} From 1a5456b766aa427b3bea4e792c0ec21a9ee1bf5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 1 Nov 2016 23:15:02 -0700 Subject: [PATCH 015/177] Fix invalid "ref mut mut" sugestion --- src/librustc_borrowck/borrowck/mod.rs | 23 +++++++++++------ .../did_you_mean}/issue-31424.rs | 3 --- src/test/ui/did_you_mean/issue-31424.stderr | 17 +++++++++++++ src/test/ui/did_you_mean/issue-34126.rs | 23 +++++++++++++++++ src/test/ui/did_you_mean/issue-34126.stderr | 11 ++++++++ src/test/ui/did_you_mean/issue-34337.rs | 17 +++++++++++++ src/test/ui/did_you_mean/issue-34337.stderr | 11 ++++++++ src/test/ui/did_you_mean/issue-37139.rs | 25 +++++++++++++++++++ src/test/ui/did_you_mean/issue-37139.stderr | 11 ++++++++ 9 files changed, 130 insertions(+), 11 deletions(-) rename src/test/{compile-fail => ui/did_you_mean}/issue-31424.rs (79%) create mode 100644 src/test/ui/did_you_mean/issue-31424.stderr create mode 100644 src/test/ui/did_you_mean/issue-34126.rs create mode 100644 src/test/ui/did_you_mean/issue-34126.stderr create mode 100644 src/test/ui/did_you_mean/issue-34337.rs create mode 100644 src/test/ui/did_you_mean/issue-34337.stderr create mode 100644 src/test/ui/did_you_mean/issue-37139.rs create mode 100644 src/test/ui/did_you_mean/issue-37139.stderr diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index ef6936b6e7db..ae360559a5f3 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -997,16 +997,23 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { if let Categorization::Local(local_id) = err.cmt.cat { let span = self.tcx.map.span(local_id); if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) { - if snippet.starts_with("ref ") { - db.span_label(span, - &format!("use `{}` here to make mutable", - snippet.replace("ref ", "ref mut "))); - } else if snippet != "self" { - db.span_label(span, - &format!("use `mut {}` here to make mutable", snippet)); + if snippet.starts_with("ref mut ") || snippet.starts_with("&mut ") { + db.span_label(error_span, &format!("cannot reborrow mutably")); + db.span_label(error_span, &format!("try removing `&mut` here")); + } else { + if snippet.starts_with("ref ") { + db.span_label(span, + &format!("use `{}` here to make mutable", + snippet.replace("ref ", "ref mut "))); + } else if snippet != "self" { + db.span_label(span, + &format!("use `mut {}` here to make mutable", snippet)); + } + db.span_label(error_span, &format!("cannot borrow mutably")); } + } else { + db.span_label(error_span, &format!("cannot borrow mutably")); } - db.span_label(error_span, &format!("cannot borrow mutably")); } } } diff --git a/src/test/compile-fail/issue-31424.rs b/src/test/ui/did_you_mean/issue-31424.rs similarity index 79% rename from src/test/compile-fail/issue-31424.rs rename to src/test/ui/did_you_mean/issue-31424.rs index 262efab22a29..374d06bb71d2 100644 --- a/src/test/compile-fail/issue-31424.rs +++ b/src/test/ui/did_you_mean/issue-31424.rs @@ -15,15 +15,12 @@ struct Struct; impl Struct { fn foo(&mut self) { (&mut self).bar(); - //~^ ERROR cannot borrow immutable argument `self` as mutable - // ... and no SUGGESTION that suggests `&mut mut self` } // In this case we could keep the suggestion, but to distinguish the // two cases is pretty hard. It's an obscure case anyway. fn bar(self: &mut Self) { (&mut self).bar(); - //~^ ERROR cannot borrow immutable argument `self` as mutable } } diff --git a/src/test/ui/did_you_mean/issue-31424.stderr b/src/test/ui/did_you_mean/issue-31424.stderr new file mode 100644 index 000000000000..4873acf551eb --- /dev/null +++ b/src/test/ui/did_you_mean/issue-31424.stderr @@ -0,0 +1,17 @@ +error: cannot borrow immutable argument `self` as mutable + --> $DIR/issue-31424.rs:17:15 + | +17 | (&mut self).bar(); + | ^^^^ + | | + | try removing `&mut` here + | cannot reborrow mutably + +error: cannot borrow immutable argument `self` as mutable + --> $DIR/issue-31424.rs:23:15 + | +23 | (&mut self).bar(); + | ^^^^ cannot borrow mutably + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/did_you_mean/issue-34126.rs b/src/test/ui/did_you_mean/issue-34126.rs new file mode 100644 index 000000000000..9523e6bbf383 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-34126.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Z { } + +impl Z { + fn run(&self, z: &mut Z) { } + fn start(&mut self) { + self.run(&mut self); + } +} + +fn main() { + let mut z = Z {}; + z.start(); +} diff --git a/src/test/ui/did_you_mean/issue-34126.stderr b/src/test/ui/did_you_mean/issue-34126.stderr new file mode 100644 index 000000000000..8011298c80cd --- /dev/null +++ b/src/test/ui/did_you_mean/issue-34126.stderr @@ -0,0 +1,11 @@ +error: cannot borrow immutable argument `self` as mutable + --> $DIR/issue-34126.rs:16:23 + | +16 | self.run(&mut self); + | ^^^^ + | | + | try removing `&mut` here + | cannot reborrow mutably + +error: aborting due to previous error + diff --git a/src/test/ui/did_you_mean/issue-34337.rs b/src/test/ui/did_you_mean/issue-34337.rs new file mode 100644 index 000000000000..42853a5d83db --- /dev/null +++ b/src/test/ui/did_you_mean/issue-34337.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn get(key: &mut String) { } + +fn main() { + let mut v: Vec = Vec::new(); + let ref mut key = v[0]; + get(&mut key); +} diff --git a/src/test/ui/did_you_mean/issue-34337.stderr b/src/test/ui/did_you_mean/issue-34337.stderr new file mode 100644 index 000000000000..d658912835b9 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-34337.stderr @@ -0,0 +1,11 @@ +error: cannot borrow immutable local variable `key` as mutable + --> $DIR/issue-34337.rs:16:14 + | +16 | get(&mut key); + | ^^^ + | | + | try removing `&mut` here + | cannot reborrow mutably + +error: aborting due to previous error + diff --git a/src/test/ui/did_you_mean/issue-37139.rs b/src/test/ui/did_you_mean/issue-37139.rs new file mode 100644 index 000000000000..65181768053c --- /dev/null +++ b/src/test/ui/did_you_mean/issue-37139.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum TestEnum { + Item(i32), +} + +fn test(_: &mut i32) { +} + +fn main() { + let mut x = TestEnum::Item(10); + match x { + TestEnum::Item(ref mut x) => { + test(&mut x); + } + } +} diff --git a/src/test/ui/did_you_mean/issue-37139.stderr b/src/test/ui/did_you_mean/issue-37139.stderr new file mode 100644 index 000000000000..b1a8231fdb6c --- /dev/null +++ b/src/test/ui/did_you_mean/issue-37139.stderr @@ -0,0 +1,11 @@ +error: cannot borrow immutable local variable `x` as mutable + --> $DIR/issue-37139.rs:22:23 + | +22 | test(&mut x); + | ^ + | | + | try removing `&mut` here + | cannot reborrow mutably + +error: aborting due to previous error + From 1a819a2298d046be5b201b02684550e421c69ac0 Mon Sep 17 00:00:00 2001 From: sinkuu Date: Tue, 20 Sep 2016 22:01:58 +0900 Subject: [PATCH 016/177] Make E0243/0244 message consistent with E0107 --- src/librustc_typeck/astconv.rs | 27 +++++++++++-------- src/test/compile-fail/E0243.rs | 4 +-- src/test/compile-fail/E0244.rs | 4 +-- .../generic-type-less-params-with-defaults.rs | 4 +-- .../generic-type-more-params-with-defaults.rs | 4 +-- src/test/compile-fail/issue-14092.rs | 4 +-- src/test/compile-fail/issue-23024.rs | 2 +- .../typeck-builtin-bound-type-parameters.rs | 16 +++++------ .../typeck_type_placeholder_lifetime_1.rs | 4 +-- .../typeck_type_placeholder_lifetime_2.rs | 4 +-- .../unboxed-closure-sugar-wrong-trait.rs | 4 +-- 11 files changed, 41 insertions(+), 36 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index c93f1c6c8e61..560d83fdd586 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -2245,27 +2245,32 @@ fn check_type_argument_count(tcx: TyCtxt, span: Span, supplied: usize, "expected" }; let arguments_plural = if required == 1 { "" } else { "s" }; - struct_span_err!(tcx.sess, span, E0243, "wrong number of type arguments") - .span_label( - span, - &format!("{} {} type argument{}, found {}", - expected, required, arguments_plural, supplied) - ) + + struct_span_err!(tcx.sess, span, E0243, + "wrong number of type arguments: {} {}, found {}", + expected, required, supplied) + .span_label(span, + &format!("{} {} type argument{}", + expected, + required, + arguments_plural)) .emit(); } else if supplied > accepted { - let expected = if required == 0 { - "expected no".to_string() - } else if required < accepted { + let expected = if required < accepted { format!("expected at most {}", accepted) } else { format!("expected {}", accepted) }; let arguments_plural = if accepted == 1 { "" } else { "s" }; - struct_span_err!(tcx.sess, span, E0244, "wrong number of type arguments") + struct_span_err!(tcx.sess, span, E0244, + "wrong number of type arguments: {}, found {}", + expected, supplied) .span_label( span, - &format!("{} type argument{}, found {}", expected, arguments_plural, supplied) + &format!("{} type argument{}", + if accepted == 0 { "expected no" } else { &expected }, + arguments_plural) ) .emit(); } diff --git a/src/test/compile-fail/E0243.rs b/src/test/compile-fail/E0243.rs index 4434723e12f8..d20435a37ff5 100644 --- a/src/test/compile-fail/E0243.rs +++ b/src/test/compile-fail/E0243.rs @@ -10,8 +10,8 @@ struct Foo { x: T } struct Bar { x: Foo } - //~^ ERROR E0243 - //~| NOTE expected 1 type argument, found 0 + //~^ ERROR wrong number of type arguments: expected 1, found 0 [E0243] + //~| NOTE expected 1 type argument fn main() { } diff --git a/src/test/compile-fail/E0244.rs b/src/test/compile-fail/E0244.rs index 5678a7fd450d..02d4b337894b 100644 --- a/src/test/compile-fail/E0244.rs +++ b/src/test/compile-fail/E0244.rs @@ -10,8 +10,8 @@ struct Foo { x: bool } struct Bar { x: Foo } - //~^ ERROR E0244 - //~| NOTE expected no type arguments, found 2 + //~^ ERROR wrong number of type arguments: expected 0, found 2 [E0244] + //~| NOTE expected no type arguments fn main() { diff --git a/src/test/compile-fail/generic-type-less-params-with-defaults.rs b/src/test/compile-fail/generic-type-less-params-with-defaults.rs index 9b1f3e51647c..9b19e09eeae7 100644 --- a/src/test/compile-fail/generic-type-less-params-with-defaults.rs +++ b/src/test/compile-fail/generic-type-less-params-with-defaults.rs @@ -17,6 +17,6 @@ struct Vec( fn main() { let _: Vec; - //~^ ERROR E0243 - //~| NOTE expected at least 1 type argument, found 0 + //~^ ERROR wrong number of type arguments: expected at least 1, found 0 [E0243] + //~| NOTE expected at least 1 type argument } diff --git a/src/test/compile-fail/generic-type-more-params-with-defaults.rs b/src/test/compile-fail/generic-type-more-params-with-defaults.rs index 8f733ddfce18..b5764ef89ab5 100644 --- a/src/test/compile-fail/generic-type-more-params-with-defaults.rs +++ b/src/test/compile-fail/generic-type-more-params-with-defaults.rs @@ -17,6 +17,6 @@ struct Vec( fn main() { let _: Vec; - //~^ ERROR E0244 - //~| NOTE expected at most 2 type arguments, found 3 + //~^ ERROR wrong number of type arguments: expected at most 2, found 3 [E0244] + //~| NOTE expected at most 2 type arguments } diff --git a/src/test/compile-fail/issue-14092.rs b/src/test/compile-fail/issue-14092.rs index df8707ab823e..85dd88e614fd 100644 --- a/src/test/compile-fail/issue-14092.rs +++ b/src/test/compile-fail/issue-14092.rs @@ -9,7 +9,7 @@ // except according to those terms. fn fn1(0: Box) {} - //~^ ERROR E0243 - //~| NOTE expected 1 type argument, found 0 + //~^ ERROR wrong number of type arguments: expected 1, found 0 [E0243] + //~| NOTE expected 1 type argument fn main() {} diff --git a/src/test/compile-fail/issue-23024.rs b/src/test/compile-fail/issue-23024.rs index e266f004317e..5d9b49f486c6 100644 --- a/src/test/compile-fail/issue-23024.rs +++ b/src/test/compile-fail/issue-23024.rs @@ -18,6 +18,6 @@ fn main() vfnfer.push(box h); println!("{:?}",(vfnfer[0] as Fn)(3)); //~^ ERROR the precise format of `Fn`-family traits' - //~| ERROR E0243 + //~| ERROR wrong number of type arguments: expected 1, found 0 [E0243] //~| ERROR the value of the associated type `Output` (from the trait `std::ops::FnOnce`) } diff --git a/src/test/compile-fail/typeck-builtin-bound-type-parameters.rs b/src/test/compile-fail/typeck-builtin-bound-type-parameters.rs index 41242a44f58b..0d98e044ab04 100644 --- a/src/test/compile-fail/typeck-builtin-bound-type-parameters.rs +++ b/src/test/compile-fail/typeck-builtin-bound-type-parameters.rs @@ -9,16 +9,16 @@ // except according to those terms. fn foo1, U>(x: T) {} -//~^ ERROR E0244 -//~| NOTE expected no type arguments, found 1 +//~^ ERROR wrong number of type arguments: expected 0, found 1 [E0244] +//~| NOTE expected no type arguments trait Trait: Copy {} -//~^ ERROR E0244 -//~| NOTE expected no type arguments, found 1 +//~^ ERROR wrong number of type arguments: expected 0, found 1 [E0244] +//~| NOTE expected no type arguments struct MyStruct1>; -//~^ ERROR E0244 -//~| NOTE expected no type arguments, found 1 +//~^ ERROR wrong number of type arguments: expected 0, found 1 [E0244] +//~| NOTE expected no type arguments struct MyStruct2<'a, T: Copy<'a>>; //~^ ERROR: wrong number of lifetime parameters: expected 0, found 1 @@ -26,8 +26,8 @@ struct MyStruct2<'a, T: Copy<'a>>; fn foo2<'a, T:Copy<'a, U>, U>(x: T) {} -//~^ ERROR E0244 -//~| NOTE expected no type arguments, found 1 +//~^ ERROR wrong number of type arguments: expected 0, found 1 [E0244] +//~| NOTE expected no type arguments //~| ERROR: wrong number of lifetime parameters: expected 0, found 1 //~| NOTE unexpected lifetime parameter diff --git a/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs b/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs index f40445a030e0..ad57752b6f75 100644 --- a/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs +++ b/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs @@ -17,6 +17,6 @@ struct Foo<'a, T:'a> { pub fn main() { let c: Foo<_, _> = Foo { r: &5 }; - //~^ ERROR E0244 - //~| NOTE expected 1 type argument, found 2 + //~^ ERROR wrong number of type arguments: expected 1, found 2 [E0244] + //~| NOTE expected 1 type argument } diff --git a/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs b/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs index 47898690fcce..f1ecad0056e9 100644 --- a/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs +++ b/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs @@ -17,6 +17,6 @@ struct Foo<'a, T:'a> { pub fn main() { let c: Foo<_, usize> = Foo { r: &5 }; - //~^ ERROR E0244 - //~| NOTE expected 1 type argument, found 2 + //~^ ERROR wrong number of type arguments: expected 1, found 2 [E0244] + //~| NOTE expected 1 type argument } diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs index 50f4f3b98b33..95d78c075017 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs @@ -13,8 +13,8 @@ trait Trait {} fn f isize>(x: F) {} -//~^ ERROR E0244 -//~| NOTE expected no type arguments, found 1 +//~^ ERROR wrong number of type arguments: expected 0, found 1 [E0244] +//~| NOTE expected no type arguments //~| ERROR E0220 //~| NOTE associated type `Output` not found From 12f0b6f2fb5ab0bdad539fc28b12d6161901103f Mon Sep 17 00:00:00 2001 From: sinkuu Date: Sun, 6 Nov 2016 20:54:00 +0900 Subject: [PATCH 017/177] Fix typo --- src/librustc_typeck/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index be012d8976f6..f5432c6e0fcd 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1355,7 +1355,7 @@ extern "rust-intrinsic" { } ``` -Please check that you provided the right number of lifetime parameters +Please check that you provided the right number of type parameters and verify with the function declaration in the Rust source code. Example: From 8016dc39aa7fa1b796cf8e3dd7cd93c65c53d7a8 Mon Sep 17 00:00:00 2001 From: Juan Gomez Date: Sun, 6 Nov 2016 13:06:01 +0100 Subject: [PATCH 018/177] Add support for ARMv5TE architecture --- mk/cfg/armv5te-unknown-linux-gnueabi.mk | 26 +++++++++++++++ .../target/armv5te_unknown_linux_gnueabi.rs | 33 +++++++++++++++++++ src/librustc_back/target/mod.rs | 1 + 3 files changed, 60 insertions(+) create mode 100644 mk/cfg/armv5te-unknown-linux-gnueabi.mk create mode 100644 src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs diff --git a/mk/cfg/armv5te-unknown-linux-gnueabi.mk b/mk/cfg/armv5te-unknown-linux-gnueabi.mk new file mode 100644 index 000000000000..98567a03c28a --- /dev/null +++ b/mk/cfg/armv5te-unknown-linux-gnueabi.mk @@ -0,0 +1,26 @@ +# armv5-unknown-linux-gnueabi configuration +CROSS_PREFIX_armv5te-unknown-linux-gnueabi=arm-linux-gnueabi- +CC_armv5te-unknown-linux-gnueabi=gcc +CXX_armv5te-unknown-linux-gnueabi=g++ +CPP_armv5te-unknown-linux-gnueabi=gcc -E +AR_armv5te-unknown-linux-gnueabi=ar +CFG_LIB_NAME_armv5te-unknown-linux-gnueabi=lib$(1).so +CFG_STATIC_LIB_NAME_armv5te-unknown-linux-gnueabi=lib$(1).a +CFG_LIB_GLOB_armv5te-unknown-linux-gnueabi=lib$(1)-*.so +CFG_LIB_DSYM_GLOB_armv5te-unknown-linux-gnueabi=lib$(1)-*.dylib.dSYM +CFG_JEMALLOC_CFLAGS_armv5te-unknown-linux-gnueabi := -D__arm__ -mfloat-abi=soft $(CFLAGS) -march=armv5te -marm +CFG_GCCISH_CFLAGS_armv5te-unknown-linux-gnueabi := -Wall -g -fPIC -D__arm__ -mfloat-abi=soft $(CFLAGS) -march=armv5te -marm +CFG_GCCISH_CXXFLAGS_armv5te-unknown-linux-gnueabi := -fno-rtti $(CXXFLAGS) +CFG_GCCISH_LINK_FLAGS_armv5te-unknown-linux-gnueabi := -shared -fPIC -g +CFG_GCCISH_DEF_FLAG_armv5te-unknown-linux-gnueabi := -Wl,--export-dynamic,--dynamic-list= +CFG_LLC_FLAGS_armv5te-unknown-linux-gnueabi := +CFG_INSTALL_NAME_ar,-unknown-linux-gnueabi = +CFG_EXE_SUFFIX_armv5te-unknown-linux-gnueabi := +CFG_WINDOWSY_armv5te-unknown-linux-gnueabi := +CFG_UNIXY_armv5te-unknown-linux-gnueabi := 1 +CFG_LDPATH_armv5te-unknown-linux-gnueabi := +CFG_RUN_armv5te-unknown-linux-gnueabi=$(2) +CFG_RUN_TARG_armv5te-unknown-linux-gnueabi=$(call CFG_RUN_armv5te-unknown-linux-gnueabi,,$(2)) +RUSTC_FLAGS_armv5te-unknown-linux-gnueabi := +RUSTC_CROSS_FLAGS_armv5te-unknown-linux-gnueabi := +CFG_GNU_TRIPLE_armv5te-unknown-linux-gnueabi := armv5te-unknown-linux-gnueabi diff --git a/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs b/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs new file mode 100644 index 000000000000..b9e25c3d9e53 --- /dev/null +++ b/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs @@ -0,0 +1,33 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::{Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + let base = super::linux_base::opts(); + Ok(Target { + llvm_target: "armv5te-unknown-linux-gnueabi".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + target_os: "linux".to_string(), + target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), + + options: TargetOptions { + features: "+soft-float".to_string(), + max_atomic_width: Some(64), + abi_blacklist: super::arm_base::abi_blacklist(), + .. base + } + }) +} + diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 4d9315a1a3bd..14fe02269d14 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -145,6 +145,7 @@ supported_targets! { ("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf), ("arm-unknown-linux-musleabi", arm_unknown_linux_musleabi), ("arm-unknown-linux-musleabihf", arm_unknown_linux_musleabihf), + ("armv5te-unknown-linux-gnueabi", armv5te_unknown_linux_gnueabi), ("armv7-unknown-linux-gnueabihf", armv7_unknown_linux_gnueabihf), ("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf), ("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu), From f9cc16652746285a765eea5db14d1a6ead04bab6 Mon Sep 17 00:00:00 2001 From: meh Date: Sat, 29 Oct 2016 22:25:33 +0200 Subject: [PATCH 019/177] Fix terminfo database search path --- src/libterm/terminfo/searcher.rs | 56 +++++++++++++++----------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/src/libterm/terminfo/searcher.rs b/src/libterm/terminfo/searcher.rs index 4b1df7d170db..011d06b1c0f2 100644 --- a/src/libterm/terminfo/searcher.rs +++ b/src/libterm/terminfo/searcher.rs @@ -26,38 +26,34 @@ pub fn get_dbpath_for_term(term: &str) -> Option { }; // Find search directory - match env::var_os("TERMINFO") { - Some(dir) => dirs_to_search.push(PathBuf::from(dir)), - None => { - if let Some(mut homedir) = env::home_dir() { - // ncurses compatibility; - homedir.push(".terminfo"); - dirs_to_search.push(homedir) - } - match env::var("TERMINFO_DIRS") { - Ok(dirs) => { - for i in dirs.split(':') { - if i == "" { - dirs_to_search.push(PathBuf::from("/usr/share/terminfo")); - } else { - dirs_to_search.push(PathBuf::from(i)); - } - } - } - // Found nothing in TERMINFO_DIRS, use the default paths: - // According to /etc/terminfo/README, after looking at - // ~/.terminfo, ncurses will search /etc/terminfo, then - // /lib/terminfo, and eventually /usr/share/terminfo. - // On Haiku the database can be found at /boot/system/data/terminfo - Err(..) => { - dirs_to_search.push(PathBuf::from("/etc/terminfo")); - dirs_to_search.push(PathBuf::from("/lib/terminfo")); - dirs_to_search.push(PathBuf::from("/usr/share/terminfo")); - dirs_to_search.push(PathBuf::from("/boot/system/data/terminfo")); - } + if let Some(dir) = env::var_os("TERMINFO") { + dirs_to_search.push(PathBuf::from(dir)); + } + + if let Ok(dirs) = env::var("TERMINFO_DIRS") { + for i in dirs.split(':') { + if i == "" { + dirs_to_search.push(PathBuf::from("/usr/share/terminfo")); + } else { + dirs_to_search.push(PathBuf::from(i)); } } - }; + } else { + // Found nothing in TERMINFO_DIRS, use the default paths: + // According to /etc/terminfo/README, after looking at + // ~/.terminfo, ncurses will search /etc/terminfo, then + // /lib/terminfo, and eventually /usr/share/terminfo. + // On Haiku the database can be found at /boot/system/data/terminfo + if let Some(mut homedir) = env::home_dir() { + homedir.push(".terminfo"); + dirs_to_search.push(homedir) + } + + dirs_to_search.push(PathBuf::from("/etc/terminfo")); + dirs_to_search.push(PathBuf::from("/lib/terminfo")); + dirs_to_search.push(PathBuf::from("/usr/share/terminfo")); + dirs_to_search.push(PathBuf::from("/boot/system/data/terminfo")); + } // Look for the terminal in all of the search directories for mut p in dirs_to_search { From 0f817a0dd9b4715ee5df2ae5146a2527ab4f45fc Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 4 Nov 2016 15:59:30 -0700 Subject: [PATCH 020/177] Add release notes for 1.13.0 --- RELEASES.md | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 222ad3aa112a..e468a86e7acc 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,260 @@ +Version 1.13.0 (2016-11-10) +=========================== + +Language +-------- + +* [Stabilize the `?` operator][36995]. `?` is a simple way to propagate + errors, like the `try!` macro, described in [RFC 0243]. +* [Stabilize macros in type position][36014]. Described in [RFC 873]. +* [Stabilize attributes on statements][36995]. Described in [RFC 0016]. +* [Fix `#[derive]` for empty tuple structs/variants][35728] +* [Fix lifetime rules for 'if' conditions][36029] +* [Avoid loading and parsing unconfigured non-inline modules][36482] + +Compiler +-------- + +* [Add the `-C link-arg` argument][36574] +* [Remove the old AST-based backend from rustc_trans][35764] +* [Don't enable NEON by default on armv7 Linux][35814] +* [Fix debug line number info for macro expansions][35238] +* [Do not emit "class method" debuginfo for types that are not + DICompositeType][36008] +* [Warn about multiple conflicting #[repr] hints][34623] +* [When sizing DST, don't double-count nested struct prefixes][36351] +* [Default RUST_MIN_STACK to 16MiB for now][36505] +* [Improve rlib metadata format][36551]. Reduces rlib size significantly. +* [Reject macros with empty repetitions to avoid infinite loop][36721] +* [Expand macros without recursing to avoid stack overflows][36214] + +Diagnostics +----------- + +* [Replace macro backtraces with labeled local uses][35702] +* [Improve error message for missplaced doc comments][33922] +* [Buffer unix and lock windows to prevent message interleaving][35975] +* [Update lifetime errors to specifically note temporaries][36171] +* [Special case a few colors for Windows][36178] +* [Suggest `use self` when such an import resolves][36289] +* [Be more specific when type parameter shadows primitive type][36338] +* Many minor improvements + +Compile-time Optimizations +-------------------------- + +* [Compute and cache HIR hashes at beginning][35854] +* [Don't hash types in loan paths][36004] +* [Cache projections in trans][35761] +* [Optimize the parser's last token handling][36527] +* [Only instantiate #[inline] functions in codegen units referencing + them][36524]. This leads to big improvements in cases where crates export + define many inline functions without using them directly. +* [Lazily allocate TypedArena's first chunk][36592] +* [Don't allocate during default HashSet creation][36734] + +Stabilized APIs +--------------- + +* [`checked_abs`] +* [`wrapping_abs`] +* [`overflowing_abs`] +* [`RefCell::try_borrow`] +* [`RefCell::try_borrow_mut`] + +Libraries +--------- + +* [Add `assert_ne!` and `debug_assert_ne!`][35074] +* [Make `vec_deque::Drain`, `hash_map::Drain`, and `hash_set::Drain` + covariant][35354] +* [Implement `AsRef<[T]>` for `std::slice::Iter`][35559] +* [Implement `Debug` for `std::vec::IntoIter`][35707] +* [`CString`: avoid excessive growth just to 0-terminate][35871] +* [Implement `CoerceUnsized` for `{Cell, RefCell, UnsafeCell}`][35627] +* [Use arc4rand on FreeBSD][35884] +* [memrchr: Correct aligned offset computation][35969] +* [Improve Demangling of Rust Symbols][36059] +* [Use monotonic time in condition variables][35048] +* [Implement `Debug` for `std::path::{Components,Iter}`][36101] +* [Implement conversion traits for `char`][35755] +* [Fix illegal instruction caused by overflow in channel cloning][36104] +* [Zero first byte of CString on drop][36264] +* [Inherit overflow checks for sum and product][36372] +* [Add missing Eq implementations][36423] +* [Implement `Debug` for `DirEntry`][36631] +* [When `getaddrinfo` returns `EAI_SYSTEM` retrieve actual error from + `errno`][36754] +* [`SipHasher`] is deprecated. Use [`DefaultHasher`]. +* [Implement more traits for `std::io::ErrorKind`][35911] +* [Optimize BinaryHeap bounds checking][36072] +* [Work around pointer aliasing issue in `Vec::extend_from_slice`, + `extend_with_element`][36355] +* [Fix overflow checking in unsigned pow()][34942] + +Cargo +----- + +* This release includes security fixes to both curl and OpenSSL. +* [Fix transitive doctests when panic=abort][cargo/3021] +* [Add --all-features flag to cargo][cargo/3038] +* [Reject path-based dependencies in `cargo package`][cargo/3060] +* [Don't parse the home directory more than once][cargo/3078] +* [Don't try to generate Cargo.lock on empty workspaces][cargo/3092] +* [Update OpenSSL to 1.0.2j][cargo/3121] +* [Add license and license_file to cargo metadata output][cargo/3110] +* [Make crates-io registry URL optional in config; ignore all changes to + source.crates-io][cargo/3089] +* [Don't download dependencies from other platforms][cargo/3123] +* [Build transitive dev-dependencies when needed][cargo/3125] +* [Add support for per-target rustflags in .cargo/config][cargo/3157] +* [Avoid updating registry when adding existing deps][cargo/3144] +* [Warn about path overrides that won't work][cargo/3136] +* [Use workspaces during `cargo install`][cargo/3146] +* [Leak mspdbsrv.exe processes on Windows][cargo/3162] +* [Add --message-format flag][cargo/3000] +* [Pass target environment for rustdoc][cargo/3205] +* [Use `CommandExt::exec` for `cargo run` on Unix][cargo/2818] +* [Update curl and curl-sys][cargo/3241] +* [Call rustdoc test with the correct cfg flags of a package][cargo/3242] + +Tooling +------- + +* [rustdoc: Add the `--sysroot` argument][36586] +* [rustdoc: Fix a couple of issues with the search results][35655] +* [rustdoc: remove the `!` from macro URLs and titles][35234] +* [gdb: Fix pretty-printing special-cased Rust types][35585] +* [rustdoc: Filter more incorrect methods inherited through Deref][36266] + +Misc +---- + +* [Remove unmaintained style guide][35124] +* [Add s390x support][36369] +* [Initial work at Haiku OS support][36727] +* [Add mips-uclibc targets][35734] +* [Crate-ify compiler-rt into compiler-builtins][35021] +* [Add rustc version info (git hash + date) to dist tarball][36213] +* Many documentation improvements + +Compatibility Notes +------------------- + +* [`SipHasher`] is deprecated. Use [`DefaultHasher`]. +* [Deny (by default) transmuting from fn item types to pointer-sized + types][34923]. Continuing the long transition to zero-sized fn items, + per [RFC 401]. +* [Fix `#[derive]` for empty tuple structs/variants][35728]. + Part of [RFC 1506]. +* [Issue deprecation warnings for safe accesses to extern statics][36173] +* [Fix lifetime rules for 'if' conditions][36029]. +* [Inherit overflow checks for sum and product][36372]. +* [Forbid user-defined macros named "macro_rules"][36730]. + +[33922]: https://github.com/rust-lang/rust/pull/33922 +[34623]: https://github.com/rust-lang/rust/pull/34623 +[34923]: https://github.com/rust-lang/rust/pull/34923 +[34942]: https://github.com/rust-lang/rust/pull/34942 +[34982]: https://github.com/rust-lang/rust/pull/34982 +[35021]: https://github.com/rust-lang/rust/pull/35021 +[35048]: https://github.com/rust-lang/rust/pull/35048 +[35074]: https://github.com/rust-lang/rust/pull/35074 +[35124]: https://github.com/rust-lang/rust/pull/35124 +[35234]: https://github.com/rust-lang/rust/pull/35234 +[35238]: https://github.com/rust-lang/rust/pull/35238 +[35354]: https://github.com/rust-lang/rust/pull/35354 +[35559]: https://github.com/rust-lang/rust/pull/35559 +[35585]: https://github.com/rust-lang/rust/pull/35585 +[35627]: https://github.com/rust-lang/rust/pull/35627 +[35655]: https://github.com/rust-lang/rust/pull/35655 +[35702]: https://github.com/rust-lang/rust/pull/35702 +[35707]: https://github.com/rust-lang/rust/pull/35707 +[35728]: https://github.com/rust-lang/rust/pull/35728 +[35734]: https://github.com/rust-lang/rust/pull/35734 +[35755]: https://github.com/rust-lang/rust/pull/35755 +[35761]: https://github.com/rust-lang/rust/pull/35761 +[35764]: https://github.com/rust-lang/rust/pull/35764 +[35814]: https://github.com/rust-lang/rust/pull/35814 +[35854]: https://github.com/rust-lang/rust/pull/35854 +[35871]: https://github.com/rust-lang/rust/pull/35871 +[35884]: https://github.com/rust-lang/rust/pull/35884 +[35911]: https://github.com/rust-lang/rust/pull/35911 +[35969]: https://github.com/rust-lang/rust/pull/35969 +[35975]: https://github.com/rust-lang/rust/pull/35975 +[36004]: https://github.com/rust-lang/rust/pull/36004 +[36008]: https://github.com/rust-lang/rust/pull/36008 +[36014]: https://github.com/rust-lang/rust/pull/36014 +[36029]: https://github.com/rust-lang/rust/pull/36029 +[36059]: https://github.com/rust-lang/rust/pull/36059 +[36072]: https://github.com/rust-lang/rust/pull/36072 +[36101]: https://github.com/rust-lang/rust/pull/36101 +[36104]: https://github.com/rust-lang/rust/pull/36104 +[36171]: https://github.com/rust-lang/rust/pull/36171 +[36173]: https://github.com/rust-lang/rust/pull/36173 +[36178]: https://github.com/rust-lang/rust/pull/36178 +[36213]: https://github.com/rust-lang/rust/pull/36213 +[36214]: https://github.com/rust-lang/rust/pull/36214 +[36264]: https://github.com/rust-lang/rust/pull/36264 +[36266]: https://github.com/rust-lang/rust/pull/36266 +[36289]: https://github.com/rust-lang/rust/pull/36289 +[36338]: https://github.com/rust-lang/rust/pull/36338 +[36351]: https://github.com/rust-lang/rust/pull/36351 +[36355]: https://github.com/rust-lang/rust/pull/36355 +[36369]: https://github.com/rust-lang/rust/pull/36369 +[36372]: https://github.com/rust-lang/rust/pull/36372 +[36423]: https://github.com/rust-lang/rust/pull/36423 +[36482]: https://github.com/rust-lang/rust/pull/36482 +[36505]: https://github.com/rust-lang/rust/pull/36505 +[36524]: https://github.com/rust-lang/rust/pull/36524 +[36527]: https://github.com/rust-lang/rust/pull/36527 +[36551]: https://github.com/rust-lang/rust/pull/36551 +[36574]: https://github.com/rust-lang/rust/pull/36574 +[36586]: https://github.com/rust-lang/rust/pull/36586 +[36592]: https://github.com/rust-lang/rust/pull/36592 +[36631]: https://github.com/rust-lang/rust/pull/36631 +[36639]: https://github.com/rust-lang/rust/pull/36639 +[36721]: https://github.com/rust-lang/rust/pull/36721 +[36727]: https://github.com/rust-lang/rust/pull/36727 +[36730]: https://github.com/rust-lang/rust/pull/36730 +[36734]: https://github.com/rust-lang/rust/pull/36734 +[36754]: https://github.com/rust-lang/rust/pull/36754 +[36995]: https://github.com/rust-lang/rust/pull/36995 +[RFC 0016]: https://github.com/rust-lang/rfcs/blob/master/text/0016-more-attributes.md +[RFC 0243]: https://github.com/rust-lang/rfcs/blob/master/text/0243-trait-based-exception-handling.md +[RFC 1506]: https://github.com/rust-lang/rfcs/blob/master/text/1506-adt-kinds.md +[RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md +[RFC 873]: https://github.com/rust-lang/rfcs/blob/master/text/0873-type-macros.md +[cargo/2818]: https://github.com/rust-lang/cargo/pull/2818 +[cargo/3000]: https://github.com/rust-lang/cargo/pull/3000 +[cargo/3021]: https://github.com/rust-lang/cargo/pull/3021 +[cargo/3038]: https://github.com/rust-lang/cargo/pull/3038 +[cargo/3060]: https://github.com/rust-lang/cargo/pull/3060 +[cargo/3078]: https://github.com/rust-lang/cargo/pull/3078 +[cargo/3089]: https://github.com/rust-lang/cargo/pull/3089 +[cargo/3092]: https://github.com/rust-lang/cargo/pull/3092 +[cargo/3110]: https://github.com/rust-lang/cargo/pull/3110 +[cargo/3121]: https://github.com/rust-lang/cargo/pull/3121 +[cargo/3123]: https://github.com/rust-lang/cargo/pull/3123 +[cargo/3125]: https://github.com/rust-lang/cargo/pull/3125 +[cargo/3136]: https://github.com/rust-lang/cargo/pull/3136 +[cargo/3144]: https://github.com/rust-lang/cargo/pull/3144 +[cargo/3146]: https://github.com/rust-lang/cargo/pull/3146 +[cargo/3157]: https://github.com/rust-lang/cargo/pull/3157 +[cargo/3162]: https://github.com/rust-lang/cargo/pull/3162 +[cargo/3205]: https://github.com/rust-lang/cargo/pull/3205 +[cargo/3241]: https://github.com/rust-lang/cargo/pull/3241 +[cargo/3242]: https://github.com/rust-lang/cargo/pull/3242 +[rustup]: https://www.rustup.rs +[`checked_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.checked_abs +[`wrapping_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.wrapping_abs +[`overflowing_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.overflowing_abs +[`RefCell::try_borrow`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.try_borrow +[`RefCell::try_borrow_mut`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.try_borrow_mut +[`SipHasher`]: https://doc.rust-lang.org/std/hash/struct.SipHasher.html +[`DefaultHasher`]: https://doc.rust-lang.org/std/collections/hash_map/struct.DefaultHasher.html + + Version 1.12.1 (2016-10-20) =========================== From b1d0c5bb38913658f26254a5e9aff3550b8cf607 Mon Sep 17 00:00:00 2001 From: Trotter Cashion Date: Sun, 23 Oct 2016 15:14:53 -0700 Subject: [PATCH 021/177] Update testing.md to reflect changes to cargo new `cargo new` now creates a `src/lib.rs` with a `tests` module by default. I've updated the earlier examples in this doc to reflect this. However, I don't know how we want to approach the "introduction" to idiomatic testing that follows in "the tests module" section. I _think_ it should be broken apart, with the module concept being introduced early on, and the `super` concept being addressed when we hit the `add_two` example. I'd like to get agreement on that being the right approach before I do it though. I _also_ removed the `#fn main() {}` hidden at the beginning of each example, as these cause Rust Playground to not treat the file as a set of tests that it can run. Removing it _should_ cause Rust Playground to display a "Test >" button in the top left when a user runs the code, which will allow them to see the test runner output. --- src/doc/book/testing.md | 126 ++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 50 deletions(-) diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index 0e6cdb8f09dd..1ae093afafe8 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -38,8 +38,9 @@ currently has no body. That's good enough to pass! We can run the tests with ```bash $ cargo test - Compiling adder v0.1.0 (file:///home/you/projects/adder) - Running target/debug/deps/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///private/tmp/adder) + Finished debug [unoptimized + debuginfo] target(s) in 0.15 secs + Running target/debug/deps/adder-941f01916ca4a642 running 1 test test tests::it_works ... ok @@ -61,11 +62,11 @@ those later. For now, see this line: test tests::it_works ... ok ``` -Note the `it_works`. This comes from the name of our function: +Note the `tests::it_works`. This comes from the name of our module and function: ```rust fn it_works() { -# } +} ``` We also get a summary line: @@ -78,10 +79,12 @@ So why does our do-nothing test pass? Any test which doesn't `panic!` passes, and any test that does `panic!` fails. Let's make our test fail: ```rust -# fn main() {} -#[test] -fn it_works() { - assert!(false); +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert!(false); + } } ``` @@ -91,16 +94,18 @@ run our tests again: ```bash $ cargo test - Compiling adder v0.1.0 (file:///home/you/projects/adder) - Running target/debug/deps/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///private/tmp/adder) + Finished debug [unoptimized + debuginfo] target(s) in 0.17 secs + Running target/debug/deps/adder-941f01916ca4a642 running 1 test test tests::it_works ... FAILED failures: ----- test::it_works stdout ---- +---- tests::it_works stdout ---- thread 'tests::it_works' panicked at 'assertion failed: false', src/lib.rs:5 +note: Run with `RUST_BACKTRACE=1` for a backtrace. failures: @@ -148,20 +153,24 @@ This is useful if you want to integrate `cargo test` into other tooling. We can invert our test's failure with another attribute: `should_panic`: ```rust -# fn main() {} -#[test] -#[should_panic] -fn it_works() { - assert!(false); +#[cfg(test)] +mod tests { + #[test] + #[should_panic] + fn it_works() { + assert!(false); + } } + ``` This test will now succeed if we `panic!` and fail if we complete. Let's try it: ```bash $ cargo test - Compiling adder v0.1.0 (file:///home/you/projects/adder) - Running target/debug/deps/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///private/tmp/adder) + Finished debug [unoptimized + debuginfo] target(s) in 0.17 secs + Running target/debug/deps/adder-941f01916ca4a642 running 1 test test tests::it_works ... ok @@ -179,11 +188,13 @@ Rust provides another macro, `assert_eq!`, that compares two arguments for equality: ```rust -# fn main() {} -#[test] -#[should_panic] -fn it_works() { - assert_eq!("Hello", "world"); +#[cfg(test)] +mod tests { + #[test] + #[should_panic] + fn it_works() { + assert_eq!("Hello", "world"); + } } ``` @@ -192,8 +203,9 @@ passes: ```bash $ cargo test - Compiling adder v0.1.0 (file:///home/you/projects/adder) - Running target/debug/deps/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///private/tmp/adder) + Finished debug [unoptimized + debuginfo] target(s) in 0.21 secs + Running target/debug/deps/adder-941f01916ca4a642 running 1 test test tests::it_works ... ok @@ -214,25 +226,31 @@ make sure that the failure message contains the provided text. A safer version of the example above would be: ```rust -# fn main() {} -#[test] -#[should_panic(expected = "assertion failed")] -fn it_works() { - assert_eq!("Hello", "world"); +#[cfg(test)] +mod tests { + #[test] + #[should_panic(expected = "assertion failed")] + fn it_works() { + assert_eq!("Hello", "world"); + } } ``` That's all there is to the basics! Let's write one 'real' test: ```rust,ignore -# fn main() {} pub fn add_two(a: i32) -> i32 { a + 2 } -#[test] -fn it_works() { - assert_eq!(4, add_two(2)); +#[cfg(test)] +mod tests { + use super::add_two; + + #[test] + fn it_works() { + assert_eq!(4, add_two(2)); + } } ``` @@ -245,16 +263,24 @@ Sometimes a few specific tests can be very time-consuming to execute. These can be disabled by default by using the `ignore` attribute: ```rust -# fn main() {} -#[test] -fn it_works() { - assert_eq!(4, add_two(2)); +pub fn add_two(a: i32) -> i32 { + a + 2 } -#[test] -#[ignore] -fn expensive_test() { - // code that takes an hour to run +#[cfg(test)] +mod tests { + use super::add_two; + + #[test] + fn it_works() { + assert_eq!(4, add_two(2)); + } + + #[test] + #[ignore] + fn expensive_test() { + // code that takes an hour to run + } } ``` @@ -263,12 +289,13 @@ not: ```bash $ cargo test - Compiling adder v0.1.0 (file:///home/you/projects/adder) - Running target/debug/deps/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///private/tmp/adder) + Finished debug [unoptimized + debuginfo] target(s) in 0.20 secs + Running target/debug/deps/adder-941f01916ca4a642 running 2 tests -test expensive_test ... ignored -test it_works ... ok +test tests::expensive_test ... ignored +test tests::it_works ... ok test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured @@ -283,10 +310,11 @@ The expensive tests can be run explicitly using `cargo test -- --ignored`: ```bash $ cargo test -- --ignored - Running target/debug/deps/adder-91b3e234d4ed382a + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs + Running target/debug/deps/adder-941f01916ca4a642 running 1 test -test expensive_test ... ok +test tests::expensive_test ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured @@ -310,7 +338,6 @@ was missing from our last example. Let's explain what this does. The idiomatic way of writing our example looks like this: ```rust,ignore -# fn main() {} pub fn add_two(a: i32) -> i32 { a + 2 } @@ -339,7 +366,6 @@ a large module, and so this is a common use of globs. Let's change our `src/lib.rs` to make use of it: ```rust,ignore -# fn main() {} pub fn add_two(a: i32) -> i32 { a + 2 } From cfdf7633f08ee77e303f1bf88b613a35f9946e75 Mon Sep 17 00:00:00 2001 From: Mikhail Modin Date: Thu, 3 Nov 2016 09:58:01 +0300 Subject: [PATCH 022/177] Improve "Doesn't live long enough" error case with temporary variable --- src/librustc_borrowck/borrowck/mod.rs | 25 +++++++++---------- .../lifetimes/borrowck-let-suggestion.stderr | 4 +-- .../borrowck-let-suggestion-suffixes.stderr | 12 ++++----- .../{compile-fail => ui/span}/issue-15480.rs | 1 - src/test/ui/span/issue-15480.stderr | 15 +++++++++++ .../regions-close-over-borrowed-ref-in-obj.rs | 2 +- ...ions-close-over-borrowed-ref-in-obj.stderr | 13 ++++++++++ .../{compile-fail => ui/span}/slice-borrow.rs | 2 +- src/test/ui/span/slice-borrow.stderr | 13 ++++++++++ 9 files changed, 63 insertions(+), 24 deletions(-) rename src/test/{compile-fail => ui/span}/issue-15480.rs (91%) create mode 100644 src/test/ui/span/issue-15480.stderr rename src/test/{compile-fail => ui/span}/regions-close-over-borrowed-ref-in-obj.rs (88%) create mode 100644 src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr rename src/test/{compile-fail => ui/span}/slice-borrow.rs (86%) create mode 100644 src/test/ui/span/slice-borrow.stderr diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 0d084d9b930d..a0e1e4f3c939 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -1013,11 +1013,11 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } err_out_of_scope(super_scope, sub_scope, cause) => { - let (value_kind, value_msg, is_temporary) = match err.cmt.cat { + let (value_kind, value_msg) = match err.cmt.cat { mc::Categorization::Rvalue(_) => - ("temporary value", "temporary value created here", true), + ("temporary value", "temporary value created here"), _ => - ("borrowed value", "does not live long enough", false) + ("borrowed value", "borrow occurs here") }; let is_closure = match cause { @@ -1030,14 +1030,14 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { Some(primary) => { db.span = MultiSpan::from_span(s); db.span_label(primary, &format!("capture occurs here")); - db.span_label(s, &value_msg); + db.span_label(s, &"does not live long enough"); true } None => false } } _ => { - db.span_label(error_span, &value_msg); + db.span_label(error_span, &"does not live long enough"); false } }; @@ -1047,11 +1047,11 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { match (sub_span, super_span) { (Some(s1), Some(s2)) if s1 == s2 => { - if !is_temporary && !is_closure { + if !is_closure { db.span = MultiSpan::from_span(s1); - db.span_label(error_span, &format!("borrow occurs here")); + db.span_label(error_span, &value_msg); let msg = match opt_loan_path(&err.cmt) { - None => "borrowed value".to_string(), + None => value_kind.to_string(), Some(lp) => { format!("`{}`", self.loan_path_to_string(&lp)) } @@ -1064,17 +1064,16 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { db.note("values in a scope are dropped in the opposite order \ they are created"); } - (Some(s1), Some(s2)) if !is_temporary && !is_closure => { + (Some(s1), Some(s2)) if !is_closure => { db.span = MultiSpan::from_span(s2); - db.span_label(error_span, &format!("borrow occurs here")); + db.span_label(error_span, &value_msg); let msg = match opt_loan_path(&err.cmt) { - None => "borrowed value".to_string(), + None => value_kind.to_string(), Some(lp) => { format!("`{}`", self.loan_path_to_string(&lp)) } }; - db.span_label(s2, - &format!("{} dropped here while still borrowed", msg)); + db.span_label(s2, &format!("{} dropped here while still borrowed", msg)); db.span_label(s1, &format!("{} needs to live until here", value_kind)); } _ => { diff --git a/src/test/ui/lifetimes/borrowck-let-suggestion.stderr b/src/test/ui/lifetimes/borrowck-let-suggestion.stderr index 91600340019c..d85483f43c9e 100644 --- a/src/test/ui/lifetimes/borrowck-let-suggestion.stderr +++ b/src/test/ui/lifetimes/borrowck-let-suggestion.stderr @@ -1,8 +1,8 @@ error: borrowed value does not live long enough - --> $DIR/borrowck-let-suggestion.rs:12:13 + --> $DIR/borrowck-let-suggestion.rs:12:23 | 12 | let x = [1].iter(); - | ^^^ - temporary value only lives until here + | --- ^ temporary value dropped here while still borrowed | | | temporary value created here 13 | } diff --git a/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr b/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr index 0bba986e437b..5bb656878b3f 100644 --- a/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr +++ b/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr @@ -10,10 +10,10 @@ error: `young[..]` does not live long enough = note: values in a scope are dropped in the opposite order they are created error: borrowed value does not live long enough - --> $DIR/borrowck-let-suggestion-suffixes.rs:24:14 + --> $DIR/borrowck-let-suggestion-suffixes.rs:24:18 | 24 | v3.push(&'x'); // statement 6 - | ^^^ - temporary value only lives until here + | --- ^ temporary value dropped here while still borrowed | | | temporary value created here ... @@ -23,10 +23,10 @@ error: borrowed value does not live long enough = note: consider using a `let` binding to increase its lifetime error: borrowed value does not live long enough - --> $DIR/borrowck-let-suggestion-suffixes.rs:34:18 + --> $DIR/borrowck-let-suggestion-suffixes.rs:34:22 | 34 | v4.push(&'y'); - | ^^^ - temporary value only lives until here + | --- ^ temporary value dropped here while still borrowed | | | temporary value created here ... @@ -36,10 +36,10 @@ error: borrowed value does not live long enough = note: consider using a `let` binding to increase its lifetime error: borrowed value does not live long enough - --> $DIR/borrowck-let-suggestion-suffixes.rs:45:14 + --> $DIR/borrowck-let-suggestion-suffixes.rs:45:18 | 45 | v5.push(&'z'); - | ^^^ - temporary value only lives until here + | --- ^ temporary value dropped here while still borrowed | | | temporary value created here ... diff --git a/src/test/compile-fail/issue-15480.rs b/src/test/ui/span/issue-15480.rs similarity index 91% rename from src/test/compile-fail/issue-15480.rs rename to src/test/ui/span/issue-15480.rs index 30f58f909a08..ea5f4d3fe60e 100644 --- a/src/test/compile-fail/issue-15480.rs +++ b/src/test/ui/span/issue-15480.rs @@ -11,7 +11,6 @@ fn main() { let v = vec![ &3 -//~^ ERROR borrowed value does not live long enough ]; for &&x in &v { diff --git a/src/test/ui/span/issue-15480.stderr b/src/test/ui/span/issue-15480.stderr new file mode 100644 index 000000000000..85f6c41c3664 --- /dev/null +++ b/src/test/ui/span/issue-15480.stderr @@ -0,0 +1,15 @@ +error: borrowed value does not live long enough + --> $DIR/issue-15480.rs:14:6 + | +13 | &3 + | - temporary value created here +14 | ]; + | ^ temporary value dropped here while still borrowed +... +19 | } + | - temporary value needs to live until here + | + = note: consider using a `let` binding to increase its lifetime + +error: aborting due to previous error + diff --git a/src/test/compile-fail/regions-close-over-borrowed-ref-in-obj.rs b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.rs similarity index 88% rename from src/test/compile-fail/regions-close-over-borrowed-ref-in-obj.rs rename to src/test/ui/span/regions-close-over-borrowed-ref-in-obj.rs index 25b8137d29ca..a524562f2d95 100644 --- a/src/test/compile-fail/regions-close-over-borrowed-ref-in-obj.rs +++ b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.rs @@ -17,7 +17,7 @@ impl<'a> Foo for &'a isize { } fn main() { let blah; { - let ss: &isize = &1; //~ ERROR borrowed value does not live long enough + let ss: &isize = &1; blah = box ss as Box; } } diff --git a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr new file mode 100644 index 000000000000..205734c25e0e --- /dev/null +++ b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr @@ -0,0 +1,13 @@ +error: borrowed value does not live long enough + --> $DIR/regions-close-over-borrowed-ref-in-obj.rs:22:5 + | +20 | let ss: &isize = &1; + | - temporary value created here +21 | blah = box ss as Box; +22 | } + | ^ temporary value dropped here while still borrowed +23 | } + | - temporary value needs to live until here + +error: aborting due to previous error + diff --git a/src/test/compile-fail/slice-borrow.rs b/src/test/ui/span/slice-borrow.rs similarity index 86% rename from src/test/compile-fail/slice-borrow.rs rename to src/test/ui/span/slice-borrow.rs index 0062f66ae220..4ca0ccaa731d 100644 --- a/src/test/compile-fail/slice-borrow.rs +++ b/src/test/ui/span/slice-borrow.rs @@ -13,7 +13,7 @@ fn main() { let y; { - let x: &[isize] = &[1, 2, 3, 4, 5]; //~ ERROR borrowed value does not live long enough + let x: &[isize] = &[1, 2, 3, 4, 5]; y = &x[1..]; } } diff --git a/src/test/ui/span/slice-borrow.stderr b/src/test/ui/span/slice-borrow.stderr new file mode 100644 index 000000000000..efe81fd00bf4 --- /dev/null +++ b/src/test/ui/span/slice-borrow.stderr @@ -0,0 +1,13 @@ +error: borrowed value does not live long enough + --> $DIR/slice-borrow.rs:18:5 + | +16 | let x: &[isize] = &[1, 2, 3, 4, 5]; + | --------------- temporary value created here +17 | y = &x[1..]; +18 | } + | ^ temporary value dropped here while still borrowed +19 | } + | - temporary value needs to live until here + +error: aborting due to previous error + From c4285359a4b94541a887dcbef659a4fdea4da91a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 8 Nov 2016 16:18:44 -0500 Subject: [PATCH 023/177] introduce a `fudge_regions_if_ok` to address false region edges Fixes #37655. --- src/librustc/infer/fudge.rs | 137 ++++++++++++++++++++++++++ src/librustc/infer/mod.rs | 44 +-------- src/librustc/infer/type_variable.rs | 4 + src/librustc_typeck/check/mod.rs | 5 +- src/librustc_typeck/check/regionck.rs | 2 +- src/test/run-pass/issue-37655.rs | 46 +++++++++ 6 files changed, 192 insertions(+), 46 deletions(-) create mode 100644 src/librustc/infer/fudge.rs create mode 100644 src/test/run-pass/issue-37655.rs diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs new file mode 100644 index 000000000000..806b94486615 --- /dev/null +++ b/src/librustc/infer/fudge.rs @@ -0,0 +1,137 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ty::{self, TyCtxt}; +use ty::fold::{TypeFoldable, TypeFolder}; + +use super::InferCtxt; +use super::RegionVariableOrigin; + +impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { + /// This rather funky routine is used while processing expected + /// types. What happens here is that we want to propagate a + /// coercion through the return type of a fn to its + /// argument. Consider the type of `Option::Some`, which is + /// basically `for fn(T) -> Option`. So if we have an + /// expression `Some(&[1, 2, 3])`, and that has the expected type + /// `Option<&[u32]>`, we would like to type check `&[1, 2, 3]` + /// with the expectation of `&[u32]`. This will cause us to coerce + /// from `&[u32; 3]` to `&[u32]` and make the users life more + /// pleasant. + /// + /// The way we do this is using `fudge_regions_if_ok`. What the + /// routine actually does is to start a snapshot and execute the + /// closure `f`. In our example above, what this closure will do + /// is to unify the expectation (`Option<&[u32]>`) with the actual + /// return type (`Option`, where `?T` represents the variable + /// instantiated for `T`). This will cause `?T` to be unified + /// with `&?a [u32]`, where `?a` is a fresh lifetime variable. The + /// input type (`?T`) is then returned by `f()`. + /// + /// At this point, `fudge_regions_if_ok` will normalize all type + /// variables, converting `?T` to `&?a [u32]` and end the + /// snapshot. The problem is that we can't just return this type + /// out, because it references the region variable `?a`, and that + /// region variable was popped when we popped the snapshot. + /// + /// So what we do is to keep a list (`region_vars`, in the code below) + /// of region variables created during the snapshot (here, `?a`). We + /// fold the return value and replace any such regions with a *new* + /// region variable (e.g., `?b`) and return the result (`&?b [u32]`). + /// This can then be used as the expectation for the fn argument. + /// + /// The important point here is that, for soundness purposes, the + /// regions in question are not particularly important. We will + /// use the expected types to guide coercions, but we will still + /// type-check the resulting types from those coercions against + /// the actual types (`?T`, `Option(&self, + origin: &RegionVariableOrigin, + f: F) -> Result where + F: FnOnce() -> Result, + T: TypeFoldable<'tcx>, + { + let (region_vars, value) = self.probe(|snapshot| { + let vars_at_start = self.type_variables.borrow().num_vars(); + + match f() { + Ok(value) => { + let value = self.resolve_type_vars_if_possible(&value); + + // At this point, `value` could in principle refer + // to regions that have been created during the + // snapshot (we assert below that `f()` does not + // create any new type variables, so there + // shouldn't be any of those). Once we exit + // `probe()`, those are going to be popped, so we + // will have to eliminate any references to them. + + assert_eq!(self.type_variables.borrow().num_vars(), vars_at_start, + "type variables were created during fudge_regions_if_ok"); + let region_vars = + self.region_vars.vars_created_since_snapshot( + &snapshot.region_vars_snapshot); + + Ok((region_vars, value)) + } + Err(e) => Err(e), + } + })?; + + // At this point, we need to replace any of the now-popped + // region variables that appear in `value` with a fresh region + // variable. We can't do this during the probe because they + // would just get popped then too. =) + + // Micro-optimization: if no variables have been created, then + // `value` can't refer to any of them. =) So we can just return it. + if region_vars.is_empty() { + return Ok(value); + } + + let mut fudger = RegionFudger { + infcx: self, + region_vars: ®ion_vars, + origin: origin + }; + + Ok(value.fold_with(&mut fudger)) + } +} + +pub struct RegionFudger<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + region_vars: &'a Vec, + origin: &'a RegionVariableOrigin, +} + +impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { + self.infcx.tcx + } + + fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { + match *r { + ty::ReVar(v) if self.region_vars.contains(&v) => { + self.infcx.next_region_var(self.origin.clone()) + } + _ => { + r + } + } + } +} diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 21820ca07192..8aac950b778b 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -50,6 +50,7 @@ mod bivariate; mod combine; mod equate; pub mod error_reporting; +mod fudge; mod glb; mod higher_ranked; pub mod lattice; @@ -986,49 +987,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { r } - /// Execute `f` and commit only the region bindings if successful. - /// The function f must be very careful not to leak any non-region - /// variables that get created. - pub fn commit_regions_if_ok(&self, f: F) -> Result where - F: FnOnce() -> Result - { - debug!("commit_regions_if_ok()"); - let CombinedSnapshot { projection_cache_snapshot, - type_snapshot, - int_snapshot, - float_snapshot, - region_vars_snapshot, - obligations_in_snapshot } = self.start_snapshot(); - - let r = self.commit_if_ok(|_| f()); - - debug!("commit_regions_if_ok: rolling back everything but regions"); - - assert!(!self.obligations_in_snapshot.get()); - self.obligations_in_snapshot.set(obligations_in_snapshot); - - // Roll back any non-region bindings - they should be resolved - // inside `f`, with, e.g. `resolve_type_vars_if_possible`. - self.projection_cache - .borrow_mut() - .rollback_to(projection_cache_snapshot); - self.type_variables - .borrow_mut() - .rollback_to(type_snapshot); - self.int_unification_table - .borrow_mut() - .rollback_to(int_snapshot); - self.float_unification_table - .borrow_mut() - .rollback_to(float_snapshot); - - // Commit region vars that may escape through resolved types. - self.region_vars - .commit(region_vars_snapshot); - - r - } - /// Execute `f` then unroll any bindings it creates pub fn probe(&self, f: F) -> R where F: FnOnce(&CombinedSnapshot) -> R, diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 3856ea420b0f..804765ec8811 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -184,6 +184,10 @@ impl<'tcx> TypeVariableTable<'tcx> { v } + pub fn num_vars(&self) -> usize { + self.values.len() + } + pub fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { self.eq_relations.find(vid) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d8314bd6c2ae..26778c83c3a0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -86,7 +86,8 @@ use fmt_macros::{Parser, Piece, Position}; use hir::def::{Def, CtorKind, PathResolution}; use hir::def_id::{DefId, LOCAL_CRATE}; use hir::pat_util; -use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin, TypeTrace, type_variable}; +use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin, + TypeOrigin, TypeTrace, type_variable}; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits::{self, Reveal}; use rustc::ty::{ParamTy, ParameterEnvironment}; @@ -2752,7 +2753,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { formal_args: &[Ty<'tcx>]) -> Vec> { let expected_args = expected_ret.only_has_type(self).and_then(|ret_ty| { - self.commit_regions_if_ok(|| { + self.fudge_regions_if_ok(&RegionVariableOrigin::Coercion(call_span), || { // Attempt to apply a subtyping relationship between the formal // return type (likely containing type variables if the function // is polymorphic) and the expected return type. diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 6f6538254c46..3d2277134bb9 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1149,7 +1149,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { autoderefs: usize, autoref: &adjustment::AutoBorrow<'tcx>) { - debug!("link_autoref(autoref={:?})", autoref); + debug!("link_autoref(autoderefs={}, autoref={:?})", autoderefs, autoref); let mc = mc::MemCategorizationContext::new(self); let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs)); debug!("expr_cmt={:?}", expr_cmt); diff --git a/src/test/run-pass/issue-37655.rs b/src/test/run-pass/issue-37655.rs new file mode 100644 index 000000000000..d229bcacc501 --- /dev/null +++ b/src/test/run-pass/issue-37655.rs @@ -0,0 +1,46 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for #37655. The problem was a false edge created by +// coercion that wound up requiring that `'a` (in `split()`) outlive +// `'b`, which shouldn't be necessary. + +#![allow(warnings)] + +trait SliceExt { + type Item; + + fn get_me(&self, index: I) -> &I::Output + where I: SliceIndex; +} + +impl SliceExt for [T] { + type Item = T; + + fn get_me(&self, index: I) -> &I::Output + where I: SliceIndex + { + panic!() + } +} + +pub trait SliceIndex { + type Output: ?Sized; +} + +impl SliceIndex for usize { + type Output = T; +} + +fn foo<'a, 'b>(split: &'b [&'a [u8]]) -> &'a [u8] { + split.get_me(0) +} + +fn main() { } From a820d99eb28fcc144c97fc3d152b272d85f6e280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 25 Oct 2016 23:24:09 -0700 Subject: [PATCH 024/177] Group unused import warnings per path list Given a file ```rust use std::collections::{BinaryHeap, BTreeMap, BTreeSet}; fn main() {} ``` Show a single warning, instead of three for each unused import: ```nocode warning: unused imports, #[warn(unused_imports)] on by default --> foo.rs:1:24 | 1 | use std::collections::{BinaryHeap, BTreeMap, BTreeSet}; | ^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^ ``` Include support for lints pointing at `MultilineSpan`s, instead of just `Span`s. --- src/librustc/lint/context.rs | 11 ++-- src/librustc/session/mod.rs | 11 ++-- src/librustc_resolve/check_unused.rs | 54 ++++++++++++++----- src/libsyntax_pos/lib.rs | 6 +-- src/test/compile-fail/lint-unused-imports.rs | 5 +- src/test/ui/span/multispan-import-lint.rs | 15 ++++++ src/test/ui/span/multispan-import-lint.stderr | 6 +++ 7 files changed, 82 insertions(+), 26 deletions(-) create mode 100644 src/test/ui/span/multispan-import-lint.rs create mode 100644 src/test/ui/span/multispan-import-lint.stderr diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index f08aa2eb49f7..35c0dcf2c565 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -106,7 +106,7 @@ pub trait IntoEarlyLint { fn into_early_lint(self, id: LintId) -> EarlyLint; } -impl<'a> IntoEarlyLint for (Span, &'a str) { +impl<'a, S: Into> IntoEarlyLint for (S, &'a str) { fn into_early_lint(self, id: LintId) -> EarlyLint { let (span, msg) = self; let mut diagnostic = Diagnostic::new(errors::Level::Warning, msg); @@ -530,7 +530,10 @@ pub trait LintContext: Sized { }) } - fn lookup_and_emit(&self, lint: &'static Lint, span: Option, msg: &str) { + fn lookup_and_emit>(&self, + lint: &'static Lint, + span: Option, + msg: &str) { let (level, src) = match self.level_src(lint) { None => return, Some(pair) => pair, @@ -553,7 +556,7 @@ pub trait LintContext: Sized { } /// Emit a lint at the appropriate level, for a particular span. - fn span_lint(&self, lint: &'static Lint, span: Span, msg: &str) { + fn span_lint>(&self, lint: &'static Lint, span: S, msg: &str) { self.lookup_and_emit(lint, Some(span), msg); } @@ -601,7 +604,7 @@ pub trait LintContext: Sized { /// Emit a lint at the appropriate level, with no associated span. fn lint(&self, lint: &'static Lint, msg: &str) { - self.lookup_and_emit(lint, None, msg); + self.lookup_and_emit(lint, None as Option, msg); } /// Merge the lints specified by any lint attributes into the diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index b4dadbf7961f..f258b4c51820 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -258,14 +258,15 @@ impl Session { pub fn unimpl(&self, msg: &str) -> ! { self.diagnostic().unimpl(msg) } - pub fn add_lint(&self, - lint: &'static lint::Lint, - id: ast::NodeId, - sp: Span, - msg: String) + pub fn add_lint>(&self, + lint: &'static lint::Lint, + id: ast::NodeId, + sp: S, + msg: String) { self.add_lint_diagnostic(lint, id, (sp, &msg[..])) } + pub fn add_lint_diagnostic(&self, lint: &'static lint::Lint, id: ast::NodeId, diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index e1ea40809da0..36e05a433414 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -25,13 +25,16 @@ use Resolver; use Namespace::{TypeNS, ValueNS}; use rustc::lint; +use rustc::util::nodemap::NodeMap; use syntax::ast::{self, ViewPathGlob, ViewPathList, ViewPathSimple}; use syntax::visit::{self, Visitor}; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::{Span, MultiSpan, DUMMY_SP}; struct UnusedImportCheckVisitor<'a, 'b: 'a> { resolver: &'a mut Resolver<'b>, + /// All the (so far) unused imports, grouped path list + unused_imports: NodeMap>, } // Deref and DerefMut impls allow treating UnusedImportCheckVisitor as Resolver. @@ -52,23 +55,21 @@ impl<'a, 'b> DerefMut for UnusedImportCheckVisitor<'a, 'b> { impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> { // We have information about whether `use` (import) directives are actually // used now. If an import is not used at all, we signal a lint error. - fn check_import(&mut self, id: ast::NodeId, span: Span) { + fn check_import(&mut self, item_id: ast::NodeId, id: ast::NodeId, span: Span) { if !self.used_imports.contains(&(id, TypeNS)) && !self.used_imports.contains(&(id, ValueNS)) { if self.maybe_unused_trait_imports.contains(&id) { // Check later. return; } - let msg = if let Ok(snippet) = self.session.codemap().span_to_snippet(span) { - format!("unused import: `{}`", snippet) - } else { - "unused import".to_string() - }; - self.session.add_lint(lint::builtin::UNUSED_IMPORTS, id, span, msg); + self.unused_imports.entry(item_id).or_insert_with(NodeMap).insert(id, span); } else { // This trait import is definitely used, in a way other than // method resolution. self.maybe_unused_trait_imports.remove(&id); + if let Some(i) = self.unused_imports.get_mut(&item_id) { + i.remove(&id); + } } } } @@ -98,16 +99,16 @@ impl<'a, 'b> Visitor for UnusedImportCheckVisitor<'a, 'b> { ast::ItemKind::Use(ref p) => { match p.node { ViewPathSimple(..) => { - self.check_import(item.id, p.span) + self.check_import(item.id, item.id, p.span) } ViewPathList(_, ref list) => { for i in list { - self.check_import(i.node.id, i.span); + self.check_import(item.id, i.node.id, i.span); } } ViewPathGlob(_) => { - self.check_import(item.id, p.span) + self.check_import(item.id, item.id, p.span); } } } @@ -117,6 +118,35 @@ impl<'a, 'b> Visitor for UnusedImportCheckVisitor<'a, 'b> { } pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) { - let mut visitor = UnusedImportCheckVisitor { resolver: resolver }; + let mut visitor = UnusedImportCheckVisitor { + resolver: resolver, + unused_imports: NodeMap(), + }; visit::walk_crate(&mut visitor, krate); + + for (id, spans) in &visitor.unused_imports { + let len = spans.len(); + let mut spans = spans.values().map(|s| *s).collect::>(); + spans.sort(); + let ms = MultiSpan::from_spans(spans.clone()); + let mut span_snippets = spans.iter() + .filter_map(|s| { + match visitor.session.codemap().span_to_snippet(*s) { + Ok(s) => Some(format!("`{}`", s)), + _ => None, + } + }).collect::>(); + span_snippets.sort(); + let msg = format!("unused import{}{}", + if len > 1 { "s" } else { "" }, + if span_snippets.len() > 0 { + format!(": {}", span_snippets.join(", ")) + } else { + String::new() + }); + visitor.session.add_lint(lint::builtin::UNUSED_IMPORTS, + *id, + ms, + msg); + } } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index d99850332c36..d6e45aa0b9f0 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -52,7 +52,7 @@ pub type FileName = String; /// able to use many of the functions on spans in codemap and you cannot assume /// that the length of the span = hi - lo; there may be space in the BytePos /// range between files. -#[derive(Clone, Copy, Hash, PartialEq, Eq)] +#[derive(Clone, Copy, Hash, PartialEq, Eq, Ord, PartialOrd)] pub struct Span { pub lo: BytePos, pub hi: BytePos, @@ -67,7 +67,7 @@ pub struct Span { /// the error, and would be rendered with `^^^`. /// - they can have a *label*. In this case, the label is written next /// to the mark in the snippet when we render. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct MultiSpan { primary_spans: Vec, span_labels: Vec<(Span, String)>, @@ -254,7 +254,7 @@ impl From for MultiSpan { } } -#[derive(PartialEq, Eq, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Copy)] +#[derive(PartialEq, Eq, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Copy, Ord, PartialOrd)] pub struct ExpnId(pub u32); pub const NO_EXPANSION: ExpnId = ExpnId(!0); diff --git a/src/test/compile-fail/lint-unused-imports.rs b/src/test/compile-fail/lint-unused-imports.rs index 3f91c3e1e5c7..5b1c04946a40 100644 --- a/src/test/compile-fail/lint-unused-imports.rs +++ b/src/test/compile-fail/lint-unused-imports.rs @@ -17,8 +17,9 @@ use std::mem::*; // shouldn't get errors for not using // everything imported // Should get errors for both 'Some' and 'None' -use std::option::Option::{Some, None}; //~ ERROR unused import: `Some` - //~^ ERROR unused import: `None` +use std::option::Option::{Some, None}; +//~^ ERROR unused imports: `None`, `Some` +//~| ERROR unused imports: `None`, `Some` use test::A; //~ ERROR unused import: `test::A` // Be sure that if we just bring some methods into scope that they're also diff --git a/src/test/ui/span/multispan-import-lint.rs b/src/test/ui/span/multispan-import-lint.rs new file mode 100644 index 000000000000..43b6cd8f85f8 --- /dev/null +++ b/src/test/ui/span/multispan-import-lint.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cmp::{Eq, Ord, min, PartialEq, PartialOrd}; + +fn main() { + let _ = min(1, 2); +} diff --git a/src/test/ui/span/multispan-import-lint.stderr b/src/test/ui/span/multispan-import-lint.stderr new file mode 100644 index 000000000000..b581584eee7e --- /dev/null +++ b/src/test/ui/span/multispan-import-lint.stderr @@ -0,0 +1,6 @@ +warning: unused imports: `Eq`, `Ord`, `PartialEq`, `PartialOrd`, #[warn(unused_imports)] on by default + --> $DIR/multispan-import-lint.rs:11:16 + | +11 | use std::cmp::{Eq, Ord, min, PartialEq, PartialOrd}; + | ^^ ^^^ ^^^^^^^^^ ^^^^^^^^^^ + From bc4fc6567c892b4bf468175445388dd3e2faf480 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sat, 5 Nov 2016 19:26:57 -0400 Subject: [PATCH 025/177] Add documentation for many of the atomic_* intrinsics Part of #34338 --- src/libcore/intrinsics.rs | 396 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 396 insertions(+) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index e844a158484a..ea5544221c9b 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -51,76 +51,472 @@ extern "rust-intrinsic" { // NB: These intrinsics take raw pointers because they mutate aliased // memory, which is not valid for either `&` or `&mut`. + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as both the `success` and `failure` parameters. For example, + /// [`AtomicBool::compare_exchange`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). pub fn atomic_cxchg(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as both the `success` and `failure` parameters. For example, + /// [`AtomicBool::compare_exchange`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). pub fn atomic_cxchg_acq(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange` method by passing + /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). pub fn atomic_cxchg_rel(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). pub fn atomic_cxchg_acqrel(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as both the `success` and `failure` parameters. For example, + /// [`AtomicBool::compare_exchange`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). pub fn atomic_cxchg_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). pub fn atomic_cxchg_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). pub fn atomic_cxchg_failacq(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). pub fn atomic_cxchg_acq_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). pub fn atomic_cxchg_acqrel_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as both the `success` and `failure` parameters. For example, + /// [`AtomicBool::compare_exchange_weak`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). pub fn atomic_cxchgweak(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as both the `success` and `failure` parameters. For example, + /// [`AtomicBool::compare_exchange_weak`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). pub fn atomic_cxchgweak_acq(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing + /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange_weak`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). pub fn atomic_cxchgweak_rel(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange_weak`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). pub fn atomic_cxchgweak_acqrel(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as both the `success` and `failure` parameters. For example, + /// [`AtomicBool::compare_exchange_weak`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). pub fn atomic_cxchgweak_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange_weak`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). pub fn atomic_cxchgweak_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange_weak`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). pub fn atomic_cxchgweak_failacq(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange_weak`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). pub fn atomic_cxchgweak_acq_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange_weak`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). pub fn atomic_cxchgweak_acqrel_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); + /// Loads the current value of the pointer. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `load` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::load`](../../std/sync/atomic/struct.AtomicBool.html#method.load). pub fn atomic_load(src: *const T) -> T; + /// Loads the current value of the pointer. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `load` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::load`](../../std/sync/atomic/struct.AtomicBool.html#method.load). pub fn atomic_load_acq(src: *const T) -> T; + /// Loads the current value of the pointer. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `load` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::load`](../../std/sync/atomic/struct.AtomicBool.html#method.load). pub fn atomic_load_relaxed(src: *const T) -> T; pub fn atomic_load_unordered(src: *const T) -> T; + /// Stores the value at the specified memory location. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `store` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::store`](../../std/sync/atomic/struct.AtomicBool.html#method.store). pub fn atomic_store(dst: *mut T, val: T); + /// Stores the value at the specified memory location. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `store` method by passing + /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::store`](../../std/sync/atomic/struct.AtomicBool.html#method.store). pub fn atomic_store_rel(dst: *mut T, val: T); + /// Stores the value at the specified memory location. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `store` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::store`](../../std/sync/atomic/struct.AtomicBool.html#method.store). pub fn atomic_store_relaxed(dst: *mut T, val: T); pub fn atomic_store_unordered(dst: *mut T, val: T); + /// Stores the value at the specified memory location, returning the old value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `swap` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::swap`](../../std/sync/atomic/struct.AtomicBool.html#method.swap). pub fn atomic_xchg(dst: *mut T, src: T) -> T; + /// Stores the value at the specified memory location, returning the old value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `swap` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::swap`](../../std/sync/atomic/struct.AtomicBool.html#method.swap). pub fn atomic_xchg_acq(dst: *mut T, src: T) -> T; + /// Stores the value at the specified memory location, returning the old value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `swap` method by passing + /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::swap`](../../std/sync/atomic/struct.AtomicBool.html#method.swap). pub fn atomic_xchg_rel(dst: *mut T, src: T) -> T; + /// Stores the value at the specified memory location, returning the old value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `swap` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::swap`](../../std/sync/atomic/struct.AtomicBool.html#method.swap). pub fn atomic_xchg_acqrel(dst: *mut T, src: T) -> T; + /// Stores the value at the specified memory location, returning the old value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `swap` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::swap`](../../std/sync/atomic/struct.AtomicBool.html#method.swap). pub fn atomic_xchg_relaxed(dst: *mut T, src: T) -> T; + /// Add to the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_add` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicIsize::fetch_add`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_add). pub fn atomic_xadd(dst: *mut T, src: T) -> T; + /// Add to the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_add` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicIsize::fetch_add`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_add). pub fn atomic_xadd_acq(dst: *mut T, src: T) -> T; + /// Add to the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_add` method by passing + /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicIsize::fetch_add`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_add). pub fn atomic_xadd_rel(dst: *mut T, src: T) -> T; + /// Add to the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_add` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicIsize::fetch_add`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_add). pub fn atomic_xadd_acqrel(dst: *mut T, src: T) -> T; + /// Add to the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_add` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicIsize::fetch_add`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_add). pub fn atomic_xadd_relaxed(dst: *mut T, src: T) -> T; + /// Subtract from the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_sub` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicIsize::fetch_sub`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_sub). pub fn atomic_xsub(dst: *mut T, src: T) -> T; + /// Subtract from the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_sub` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicIsize::fetch_sub`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_sub). pub fn atomic_xsub_acq(dst: *mut T, src: T) -> T; + /// Subtract from the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_sub` method by passing + /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicIsize::fetch_sub`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_sub). pub fn atomic_xsub_rel(dst: *mut T, src: T) -> T; + /// Subtract from the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_sub` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicIsize::fetch_sub`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_sub). pub fn atomic_xsub_acqrel(dst: *mut T, src: T) -> T; + /// Subtract from the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_sub` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicIsize::fetch_sub`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_sub). pub fn atomic_xsub_relaxed(dst: *mut T, src: T) -> T; + /// Bitwise and with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_and` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_and`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_and). pub fn atomic_and(dst: *mut T, src: T) -> T; + /// Bitwise and with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_and` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_and`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_and). pub fn atomic_and_acq(dst: *mut T, src: T) -> T; + /// Bitwise and with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_and` method by passing + /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_and`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_and). pub fn atomic_and_rel(dst: *mut T, src: T) -> T; + /// Bitwise and with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_and` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_and`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_and). pub fn atomic_and_acqrel(dst: *mut T, src: T) -> T; + /// Bitwise and with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_and` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_and`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_and). pub fn atomic_and_relaxed(dst: *mut T, src: T) -> T; + /// Bitwise nand with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic::AtomicBool` type via the `fetch_nand` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_nand`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_nand). pub fn atomic_nand(dst: *mut T, src: T) -> T; + /// Bitwise nand with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic::AtomicBool` type via the `fetch_nand` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_nand`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_nand). pub fn atomic_nand_acq(dst: *mut T, src: T) -> T; + /// Bitwise nand with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic::AtomicBool` type via the `fetch_nand` method by passing + /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_nand`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_nand). pub fn atomic_nand_rel(dst: *mut T, src: T) -> T; + /// Bitwise nand with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic::AtomicBool` type via the `fetch_nand` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_nand`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_nand). pub fn atomic_nand_acqrel(dst: *mut T, src: T) -> T; + /// Bitwise nand with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic::AtomicBool` type via the `fetch_nand` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_nand`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_nand). pub fn atomic_nand_relaxed(dst: *mut T, src: T) -> T; + /// Bitwise or with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_or` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_or`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_or). pub fn atomic_or(dst: *mut T, src: T) -> T; + /// Bitwise or with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_or` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_or`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_or). pub fn atomic_or_acq(dst: *mut T, src: T) -> T; + /// Bitwise or with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_or` method by passing + /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_or`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_or). pub fn atomic_or_rel(dst: *mut T, src: T) -> T; + /// Bitwise or with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_or` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_or`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_or). pub fn atomic_or_acqrel(dst: *mut T, src: T) -> T; + /// Bitwise or with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_or` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_or`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_or). pub fn atomic_or_relaxed(dst: *mut T, src: T) -> T; + /// Bitwise xor with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_xor` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_xor`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_xor). pub fn atomic_xor(dst: *mut T, src: T) -> T; + /// Bitwise xor with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_xor` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_xor`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_xor). pub fn atomic_xor_acq(dst: *mut T, src: T) -> T; + /// Bitwise xor with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_xor` method by passing + /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_xor`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_xor). pub fn atomic_xor_rel(dst: *mut T, src: T) -> T; + /// Bitwise xor with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_xor` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_xor`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_xor). pub fn atomic_xor_acqrel(dst: *mut T, src: T) -> T; + /// Bitwise xor with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_xor` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_xor`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_xor). pub fn atomic_xor_relaxed(dst: *mut T, src: T) -> T; pub fn atomic_max(dst: *mut T, src: T) -> T; From a3f75fb07222c3c6d7efe0c4252f413deb489246 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sat, 5 Nov 2016 19:30:56 -0400 Subject: [PATCH 026/177] Add documentation for the `volatile_read` and `volatile_write` intrinsics Part of #34338 --- src/libcore/intrinsics.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index ea5544221c9b..7f37b744148d 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1027,8 +1027,12 @@ extern "rust-intrinsic" { pub fn volatile_set_memory(dst: *mut T, val: u8, count: usize); /// Perform a volatile load from the `src` pointer. + /// The stabilized version of this intrinsic is + /// [`std::ptr::read_volatile`](../../std/ptr/fn.read_volatile.html). pub fn volatile_load(src: *const T) -> T; /// Perform a volatile store to the `dst` pointer. + /// The stabilized version of this intrinsic is + /// [`std::ptr::write_volatile`](../../std/ptr/fn.write_volatile.html). pub fn volatile_store(dst: *mut T, val: T); /// Returns the square root of an `f32` From a62a67cc6a8bb3e69b81eebf1265fb1c19103c32 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Tue, 8 Nov 2016 20:22:09 -0500 Subject: [PATCH 027/177] Add documentation for some of the add/sub/mul intrinsics Part of #34338 --- src/libcore/intrinsics.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 7f37b744148d..3726eee9a93c 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1166,12 +1166,21 @@ extern "rust-intrinsic" { pub fn bswap(x: T) -> T; /// Performs checked integer addition. + /// The stabilized versions of this intrinsic are available on the integer + /// primitives via the `overflowing_add` method. For example, + /// [`std::u32::overflowing_add`](../../std/primitive.u32.html#method.overflowing_add) pub fn add_with_overflow(x: T, y: T) -> (T, bool); /// Performs checked integer subtraction + /// The stabilized versions of this intrinsic are available on the integer + /// primitives via the `overflowing_sub` method. For example, + /// [`std::u32::overflowing_sub`](../../std/primitive.u32.html#method.overflowing_sub) pub fn sub_with_overflow(x: T, y: T) -> (T, bool); /// Performs checked integer multiplication + /// The stabilized versions of this intrinsic are available on the integer + /// primitives via the `overflowing_mul` method. For example, + /// [`std::u32::overflowing_mul`](../../std/primitive.u32.html#method.overflowing_mul) pub fn mul_with_overflow(x: T, y: T) -> (T, bool); /// Performs an unchecked division, resulting in undefined behavior @@ -1182,10 +1191,19 @@ extern "rust-intrinsic" { pub fn unchecked_rem(x: T, y: T) -> T; /// Returns (a + b) mod 2^N, where N is the width of T in bits. + /// The stabilized versions of this intrinsic are available on the integer + /// primitives via the `wrapping_add` method. For example, + /// [`std::u32::wrapping_add`](../../std/primitive.u32.html#method.wrapping_add) pub fn overflowing_add(a: T, b: T) -> T; /// Returns (a - b) mod 2^N, where N is the width of T in bits. + /// The stabilized versions of this intrinsic are available on the integer + /// primitives via the `wrapping_sub` method. For example, + /// [`std::u32::wrapping_sub`](../../std/primitive.u32.html#method.wrapping_sub) pub fn overflowing_sub(a: T, b: T) -> T; /// Returns (a * b) mod 2^N, where N is the width of T in bits. + /// The stabilized versions of this intrinsic are available on the integer + /// primitives via the `wrapping_mul` method. For example, + /// [`std::u32::wrapping_mul`](../../std/primitive.u32.html#method.wrapping_mul) pub fn overflowing_mul(a: T, b: T) -> T; /// Returns the value of the discriminant for the variant in 'v', From 43aed325aacfbe592fef2acffcf4f888155fb9bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 28 Oct 2016 00:30:23 -0700 Subject: [PATCH 028/177] Show one error for duplicated type definitions For the following code: ```rustc struct Bar; struct Bar; fn main () { } ``` show ```nocode error[E0428]: a type named `Bar` has already been defined in this module --> src/test/compile-fail/E0428.rs:12:1 | 11 | struct Bar; | ----------- previous definition of `Bar` here 12 | struct Bar; | ^^^^^^^^^^^ error: aborting due to previous error ``` instead of ```nocode error[E0428]: a type named `Bar` has already been defined in this module --> src/test/compile-fail/E0428.rs:12:1 | 11 | struct Bar; | ----------- previous definition of `Bar` here 12 | struct Bar; | ^^^^^^^^^^^ error[E0428]: a value named `Bar` has already been defined in this module --> src/test/compile-fail/E0428.rs:12:1 | 11 | struct Bar; | ----------- previous definition of `Bar` here 12 | struct Bar; | ^^^^^^^^^^^ error: aborting due to 2 previous errors ``` --- src/librustc_resolve/lib.rs | 14 +++++++++++++- src/test/compile-fail/E0428.rs | 3 --- .../compile-fail/blind-item-block-item-shadow.rs | 3 +-- src/test/compile-fail/double-type-import.rs | 1 - src/test/compile-fail/variant-namespacing.rs | 6 ------ 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0c7c1a55a618..fce6d1c5c28d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1081,6 +1081,9 @@ pub struct Resolver<'a> { // Maps the `Mark` of an expansion to its containing module or block. invocations: FxHashMap>, + + // Avoid duplicated errors for "name already defined". + name_already_seen: FxHashMap, } pub struct ResolverArenas<'a> { @@ -1270,6 +1273,7 @@ impl<'a> Resolver<'a> { builtin_macros: FxHashMap(), lexical_macro_resolutions: Vec::new(), invocations: invocations, + name_already_seen: FxHashMap(), } } @@ -3396,7 +3400,7 @@ impl<'a> Resolver<'a> { } } - fn report_conflict(&self, + fn report_conflict(&mut self, parent: Module, name: Name, ns: Namespace, @@ -3420,6 +3424,13 @@ impl<'a> Resolver<'a> { }; let span = binding.span; + + if let Some(s) = self.name_already_seen.get(&name) { + if s == &span { + return; + } + } + let msg = { let kind = match (ns, old_binding.module()) { (ValueNS, _) => "a value", @@ -3471,6 +3482,7 @@ impl<'a> Resolver<'a> { err.span_label(old_binding.span, &format!("previous {} of `{}` here", noun, name)); } err.emit(); + self.name_already_seen.insert(name, span); } } diff --git a/src/test/compile-fail/E0428.rs b/src/test/compile-fail/E0428.rs index 63b4efb73f0c..f8502140c440 100644 --- a/src/test/compile-fail/E0428.rs +++ b/src/test/compile-fail/E0428.rs @@ -9,11 +9,8 @@ // except according to those terms. struct Bar; //~ previous definition of `Bar` here - //~| previous definition of `Bar` here struct Bar; //~ ERROR E0428 //~| NOTE already defined - //~| ERROR E0428 - //~| NOTE already defined fn main () { } diff --git a/src/test/compile-fail/blind-item-block-item-shadow.rs b/src/test/compile-fail/blind-item-block-item-shadow.rs index 03af0d51ec29..a26b9e3c7aa2 100644 --- a/src/test/compile-fail/blind-item-block-item-shadow.rs +++ b/src/test/compile-fail/blind-item-block-item-shadow.rs @@ -14,7 +14,6 @@ fn main() { { struct Bar; use foo::Bar; - //~^ ERROR a type named `Bar` has already been defined in this block - //~^^ ERROR a value named `Bar` has already been defined in this block + //~^ ERROR a value named `Bar` has already been defined in this block } } diff --git a/src/test/compile-fail/double-type-import.rs b/src/test/compile-fail/double-type-import.rs index 923f95e69d12..e51ef5e32e81 100644 --- a/src/test/compile-fail/double-type-import.rs +++ b/src/test/compile-fail/double-type-import.rs @@ -12,7 +12,6 @@ mod foo { pub use self::bar::X; use self::bar::X; //~^ ERROR a value named `X` has already been imported in this module - //~| ERROR a type named `X` has already been imported in this module mod bar { pub struct X; diff --git a/src/test/compile-fail/variant-namespacing.rs b/src/test/compile-fail/variant-namespacing.rs index a8bb94b78fcc..3d8e2daaa15b 100644 --- a/src/test/compile-fail/variant-namespacing.rs +++ b/src/test/compile-fail/variant-namespacing.rs @@ -33,17 +33,11 @@ const XUnit: u8 = 0; extern crate variant_namespacing; pub use variant_namespacing::XE::*; //~^ ERROR `XStruct` has already been defined -//~| ERROR `XStruct` has already been defined //~| ERROR `XTuple` has already been defined -//~| ERROR `XTuple` has already been defined -//~| ERROR `XUnit` has already been defined //~| ERROR `XUnit` has already been defined pub use E::*; //~^ ERROR `Struct` has already been defined -//~| ERROR `Struct` has already been defined //~| ERROR `Tuple` has already been defined -//~| ERROR `Tuple` has already been defined -//~| ERROR `Unit` has already been defined //~| ERROR `Unit` has already been defined fn main() {} From 0d6323f44d3cd2a132a073e7a92893e777ca11fc Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 9 Nov 2016 22:18:02 -0800 Subject: [PATCH 029/177] rustbuild: enable an initial local cargo This allows the initial build of src/bootstrap itself to use a local cargo taken from `configure --local-rust-root`. It was already finding rustc this way, but was always downloading cargo since it didn't know where to find it. It now matches the same logic that `config.rs` will use for stage0, where both rustc and cargo are taken from `CFG_LOCAL_RUST_ROOT`. --- src/bootstrap/bootstrap.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 08a8ca5a6313..a3fabbb3e809 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -226,13 +226,16 @@ class RustBuild(object): config = self.get_toml('cargo') if config: return config + config = self.get_mk('CFG_LOCAL_RUST_ROOT') + if config: + return config + '/bin/cargo' + self.exe_suffix() return os.path.join(self.bin_root(), "bin/cargo" + self.exe_suffix()) def rustc(self): config = self.get_toml('rustc') if config: return config - config = self.get_mk('CFG_LOCAL_RUST') + config = self.get_mk('CFG_LOCAL_RUST_ROOT') if config: return config + '/bin/rustc' + self.exe_suffix() return os.path.join(self.bin_root(), "bin/rustc" + self.exe_suffix()) From 365ea800bdb95ed91ac92697e5820ef4a5d7104f Mon Sep 17 00:00:00 2001 From: Juan Gomez Date: Wed, 9 Nov 2016 13:50:37 +0100 Subject: [PATCH 030/177] Set max_atomic_width to 0 because there's no atomic instructions on ARMv5 --- src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs b/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs index b9e25c3d9e53..37216e20762d 100644 --- a/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs +++ b/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs @@ -24,7 +24,8 @@ pub fn target() -> TargetResult { options: TargetOptions { features: "+soft-float".to_string(), - max_atomic_width: Some(64), + // No atomic instructions on ARMv5 + max_atomic_width: Some(0), abi_blacklist: super::arm_base::abi_blacklist(), .. base } From 3f9eba1c7c31edd58b65d22bfad07c5e269e3af6 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 10 Nov 2016 16:49:53 +0200 Subject: [PATCH 031/177] rustc: clean up lookup_item_type and remove TypeScheme. --- src/librustc/dep_graph/dep_tracking_map.rs | 8 +- src/librustc/infer/error_reporting.rs | 2 +- src/librustc/middle/dead.rs | 2 +- src/librustc/middle/intrinsicck.rs | 2 +- src/librustc/middle/liveness.rs | 26 +-- src/librustc/mir/tcx.rs | 4 +- src/librustc/traits/fulfill.rs | 8 +- src/librustc/traits/mod.rs | 2 +- src/librustc/traits/object_safety.rs | 8 +- src/librustc/traits/project.rs | 6 +- src/librustc/traits/select.rs | 4 +- src/librustc/traits/util.rs | 6 +- src/librustc/ty/context.rs | 8 +- src/librustc/ty/item_path.rs | 2 +- src/librustc/ty/maps.rs | 2 +- src/librustc/ty/mod.rs | 86 ++------- src/librustc/ty/sty.rs | 4 +- src/librustc/ty/subst.rs | 8 +- src/librustc/ty/trait_def.rs | 2 +- src/librustc/ty/wf.rs | 2 +- src/librustc/util/ppaux.rs | 8 +- .../borrowck/mir/elaborate_drops.rs | 2 +- src/librustc_lint/builtin.rs | 23 ++- src/librustc_lint/types.rs | 14 +- src/librustc_metadata/astencode.rs | 7 +- src/librustc_metadata/decoder.rs | 2 +- src/librustc_metadata/encoder.rs | 10 +- src/librustc_mir/build/mod.rs | 10 +- src/librustc_mir/build/scope.rs | 2 +- src/librustc_mir/hair/cx/mod.rs | 4 +- src/librustc_mir/mir_map.rs | 10 +- src/librustc_mir/transform/type_check.rs | 2 +- src/librustc_save_analysis/lib.rs | 3 +- src/librustc_trans/back/symbol_names.rs | 4 +- src/librustc_trans/base.rs | 8 +- src/librustc_trans/callee.rs | 4 +- src/librustc_trans/collector.rs | 15 +- src/librustc_trans/consts.rs | 4 +- src/librustc_trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/debuginfo/mod.rs | 6 +- src/librustc_trans/partitioning.rs | 2 +- src/librustc_trans/trans_item.rs | 4 +- src/librustc_typeck/astconv.rs | 22 +-- src/librustc_typeck/check/compare_method.rs | 24 +-- src/librustc_typeck/check/dropck.rs | 20 +- src/librustc_typeck/check/intrinsic.rs | 12 +- src/librustc_typeck/check/method/confirm.rs | 6 +- src/librustc_typeck/check/method/mod.rs | 4 +- src/librustc_typeck/check/method/probe.rs | 14 +- src/librustc_typeck/check/mod.rs | 73 ++++---- src/librustc_typeck/check/regionck.rs | 2 +- src/librustc_typeck/check/wfcheck.rs | 38 ++-- src/librustc_typeck/check/writeback.rs | 33 ++-- src/librustc_typeck/coherence/mod.rs | 16 +- src/librustc_typeck/coherence/orphan.rs | 2 +- src/librustc_typeck/collect.rs | 175 +++++++++--------- src/librustc_typeck/lib.rs | 33 +--- src/librustc_typeck/variance/constraints.rs | 12 +- src/librustdoc/clean/inline.rs | 48 +++-- src/librustdoc/clean/mod.rs | 16 +- src/librustdoc/clean/simplify.rs | 2 +- 61 files changed, 399 insertions(+), 491 deletions(-) diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs index 50a478fcc2fd..50dfe9d22f12 100644 --- a/src/librustc/dep_graph/dep_tracking_map.rs +++ b/src/librustc/dep_graph/dep_tracking_map.rs @@ -112,15 +112,15 @@ impl MemoizationMap for RefCell> { /// switched to `Map(key)`. Therefore, if `op` makes use of any /// HIR nodes or shared state accessed through its closure /// environment, it must explicitly register a read of that - /// state. As an example, see `type_scheme_of_item` in `collect`, + /// state. As an example, see `type_of_item` in `collect`, /// which looks something like this: /// /// ``` - /// fn type_scheme_of_item(..., item: &hir::Item) -> ty::TypeScheme<'tcx> { + /// fn type_of_item(..., item: &hir::Item) -> Ty<'tcx> { /// let item_def_id = ccx.tcx.map.local_def_id(it.id); - /// ccx.tcx.tcache.memoized(item_def_id, || { + /// ccx.tcx.item_types.memoized(item_def_id, || { /// ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id)); // (*) - /// compute_type_scheme_of_item(ccx, item) + /// compute_type_of_item(ccx, item) /// }); /// } /// ``` diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 47c0bc5fd60c..2ef296aacc56 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -1436,7 +1436,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { match self.tcx.expect_def(cur_ty.id) { Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => { - let generics = self.tcx.lookup_generics(did); + let generics = self.tcx.item_generics(did); let expected = generics.regions.len() as u32; diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 23fc5911259d..94667b398b08 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -433,7 +433,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { } fn should_warn_about_field(&mut self, field: &hir::StructField) -> bool { - let field_type = self.tcx.tables().node_id_to_type(field.id); + let field_type = self.tcx.item_type(self.tcx.map.local_def_id(field.id)); let is_marker_field = match field_type.ty_to_def_id() { Some(def_id) => self.tcx.lang_items.items().iter().any(|item| *item == Some(def_id)), _ => false diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 7dbf9aa74144..0f9748a16f46 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -51,7 +51,7 @@ struct ExprVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> { fn def_id_is_transmute(&self, def_id: DefId) -> bool { - let intrinsic = match self.infcx.tcx.lookup_item_type(def_id).ty.sty { + let intrinsic = match self.infcx.tcx.item_type(def_id).sty { ty::TyFnDef(.., ref bfty) => bfty.abi == RustIntrinsic, _ => return false }; diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index a654d65bc679..f472205b732d 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -112,7 +112,7 @@ use self::VarKind::*; use dep_graph::DepNode; use hir::def::*; use hir::pat_util; -use ty::{self, Ty, TyCtxt, ParameterEnvironment}; +use ty::{self, TyCtxt, ParameterEnvironment}; use traits::{self, Reveal}; use ty::subst::Subst; use lint; @@ -1440,28 +1440,30 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { } impl<'a, 'tcx> Liveness<'a, 'tcx> { - fn fn_ret(&self, id: NodeId) -> ty::Binder> { - let fn_ty = self.ir.tcx.tables().node_id_to_type(id); - match fn_ty.sty { - ty::TyClosure(closure_def_id, substs) => - self.ir.tcx.closure_type(closure_def_id, substs).sig.output(), - _ => fn_ty.fn_ret() - } - } - fn check_ret(&self, id: NodeId, sp: Span, - _fk: FnKind, + fk: FnKind, entry_ln: LiveNode, body: &hir::Expr) { + let fn_ty = if let FnKind::Closure(_) = fk { + self.ir.tcx.tables().node_id_to_type(id) + } else { + self.ir.tcx.item_type(self.ir.tcx.map.local_def_id(id)) + }; + let fn_ret = match fn_ty.sty { + ty::TyClosure(closure_def_id, substs) => + self.ir.tcx.closure_type(closure_def_id, substs).sig.output(), + _ => fn_ty.fn_ret() + }; + // within the fn body, late-bound regions are liberated // and must outlive the *call-site* of the function. let fn_ret = self.ir.tcx.liberate_late_bound_regions( self.ir.tcx.region_maps.call_site_extent(id, body.id), - &self.fn_ret(id)); + &fn_ret); if !fn_ret.is_never() && self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() { let param_env = ParameterEnvironment::for_item(self.ir.tcx, id); diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index f9afbaf104a6..73ea84e94aec 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -125,7 +125,7 @@ impl<'tcx> Lvalue<'tcx> { Lvalue::Local(index) => LvalueTy::Ty { ty: mir.local_decls[index].ty }, Lvalue::Static(def_id) => - LvalueTy::Ty { ty: tcx.lookup_item_type(def_id).ty }, + LvalueTy::Ty { ty: tcx.item_type(def_id) }, Lvalue::Projection(ref proj) => proj.base.ty(mir, tcx).projection_ty(tcx, &proj.elem), } @@ -188,7 +188,7 @@ impl<'tcx> Rvalue<'tcx> { )) } AggregateKind::Adt(def, _, substs, _) => { - Some(tcx.lookup_item_type(def.did).ty.subst(tcx, substs)) + Some(tcx.item_type(def.did).subst(tcx, substs)) } AggregateKind::Closure(did, substs) => { Some(tcx.mk_closure_from_closure_substs(did, substs)) diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 6de93adce3f8..b4592a03bcd1 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -154,9 +154,13 @@ impl<'a, 'gcx, 'tcx> DeferredObligation<'tcx> { pub fn try_select(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option>> { if let ty::TyAnon(def_id, substs) = self.predicate.skip_binder().self_ty().sty { + let ty = if def_id.is_local() { + tcx.item_types.borrow().get(&def_id).cloned() + } else { + Some(tcx.item_type(def_id)) + }; // We can resolve the `impl Trait` to its concrete type. - if let Some(ty_scheme) = tcx.opt_lookup_item_type(def_id) { - let concrete_ty = ty_scheme.ty.subst(tcx, substs); + if let Some(concrete_ty) = ty.subst(tcx, substs) { let predicate = ty::TraitRef { def_id: self.predicate.def_id(), substs: tcx.mk_substs_trait(concrete_ty, &[]) diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 36405df6325a..eba24bfd2c9e 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -603,7 +603,7 @@ pub fn get_vtable_methods<'a, 'tcx>( // do not hold for this particular set of type parameters. // Note that this method could then never be called, so we // do not want to try and trans it, in that case (see #23435). - let predicates = tcx.lookup_predicates(def_id).instantiate_own(tcx, substs); + let predicates = tcx.item_predicates(def_id).instantiate_own(tcx, substs); if !normalize_and_test_predicates(tcx, predicates.predicates) { debug!("get_vtable_methods: predicates do not hold"); return None; diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index c783bd561bb1..0681be129b67 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -129,7 +129,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let trait_def = self.lookup_trait_def(trait_def_id); let trait_ref = trait_def.trait_ref.clone(); let trait_ref = trait_ref.to_poly_trait_ref(); - let predicates = self.lookup_super_predicates(trait_def_id); + let predicates = self.item_super_predicates(trait_def_id); predicates .predicates .into_iter() @@ -166,7 +166,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // Search for a predicate like `Self : Sized` amongst the trait bounds. let free_substs = self.construct_free_substs(def_id, self.region_maps.node_extent(ast::DUMMY_NODE_ID)); - let predicates = self.lookup_predicates(def_id); + let predicates = self.item_predicates(def_id); let predicates = predicates.instantiate(self, free_substs).predicates; elaborate_predicates(self, predicates) .any(|predicate| { @@ -238,7 +238,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // The `Self` type is erased, so it should not appear in list of // arguments or return type apart from the receiver. - let ref sig = self.lookup_item_type(method.def_id).ty.fn_sig(); + let ref sig = self.item_type(method.def_id).fn_sig(); for &input_ty in &sig.0.inputs[1..] { if self.contains_illegal_self_type_reference(trait_def_id, input_ty) { return Some(MethodViolationCode::ReferencesSelf); @@ -249,7 +249,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } // We can't monomorphize things like `fn foo(...)`. - if !self.lookup_generics(method.def_id).types.is_empty() { + if !self.item_generics(method.def_id).types.is_empty() { return Some(MethodViolationCode::Generic); } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index b1ab61b09757..f1b69feb545e 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -311,7 +311,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, ty::TyAnon(def_id, substs) if !substs.has_escaping_regions() => { // (*) // Only normalize `impl Trait` after type-checking, usually in trans. if self.selcx.projection_mode() == Reveal::All { - let generic_ty = self.tcx().lookup_item_type(def_id).ty; + let generic_ty = self.tcx().item_type(def_id); let concrete_ty = generic_ty.subst(self.tcx(), substs); self.fold_ty(concrete_ty) } else { @@ -809,7 +809,7 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>( }; // If so, extract what we know from the trait and try to come up with a good answer. - let trait_predicates = selcx.tcx().lookup_predicates(def_id); + let trait_predicates = selcx.tcx().item_predicates(def_id); let bounds = trait_predicates.instantiate(selcx.tcx(), substs); let bounds = elaborate_predicates(selcx.tcx(), bounds.predicates); assemble_candidates_from_predicates(selcx, @@ -1313,7 +1313,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( obligation.predicate.trait_ref); tcx.types.err } else { - tcx.lookup_item_type(node_item.item.def_id).ty + tcx.item_type(node_item.item.def_id) }; let substs = translate_substs(selcx.infcx(), impl_def_id, substs, node_item.node); Progress { diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 5e3f78b1208d..3944c7e09c0b 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1200,7 +1200,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { def_id={:?}, substs={:?}", def_id, substs); - let item_predicates = self.tcx().lookup_predicates(def_id); + let item_predicates = self.tcx().item_predicates(def_id); let bounds = item_predicates.instantiate(self.tcx(), substs); debug!("match_projection_obligation_against_definition_bounds: \ bounds={:?}", @@ -2884,7 +2884,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // obligation will normalize to `<$0 as Iterator>::Item = $1` and // `$1: Copy`, so we must ensure the obligations are emitted in // that order. - let predicates = tcx.lookup_predicates(def_id); + let predicates = tcx.item_predicates(def_id); assert_eq!(predicates.parent, None); let predicates = predicates.predicates.iter().flat_map(|predicate| { let predicate = normalize_with_depth(self, cause.clone(), recursion_depth, diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 9346bbd30f9c..b94597d47592 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -128,7 +128,7 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> { match *predicate { ty::Predicate::Trait(ref data) => { // Predicates declared on the trait. - let predicates = tcx.lookup_super_predicates(data.def_id()); + let predicates = tcx.item_super_predicates(data.def_id()); let mut predicates: Vec<_> = predicates.predicates @@ -295,7 +295,7 @@ impl<'cx, 'gcx, 'tcx> Iterator for SupertraitDefIds<'cx, 'gcx, 'tcx> { None => { return None; } }; - let predicates = self.tcx.lookup_super_predicates(def_id); + let predicates = self.tcx.item_super_predicates(def_id); let visited = &mut self.visited; self.stack.extend( predicates.predicates @@ -362,7 +362,7 @@ pub fn impl_trait_ref_and_oblig<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } = super::normalize(selcx, ObligationCause::dummy(), &impl_trait_ref); - let predicates = selcx.tcx().lookup_predicates(impl_def_id); + let predicates = selcx.tcx().item_predicates(impl_def_id); let predicates = predicates.instantiate(selcx.tcx(), impl_substs); let Normalized { value: predicates, obligations: normalization_obligations2 } = super::normalize(selcx, ObligationCause::dummy(), &predicates); diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 60a48ba580a0..ac1c4fc6a191 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -444,7 +444,7 @@ pub struct GlobalCtxt<'tcx> { pub maybe_unused_trait_imports: NodeSet, // Records the type of every item. - pub tcache: RefCell>>, + pub item_types: RefCell>>, // Internal cache for metadata decoding. No need to track deps on this. pub rcache: RefCell>>, @@ -665,10 +665,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.ty_param_defs.borrow().get(&node_id).unwrap().clone() } - pub fn node_type_insert(self, id: NodeId, ty: Ty<'gcx>) { - self.tables.borrow_mut().node_types.insert(id, ty); - } - pub fn alloc_generics(self, generics: ty::Generics<'gcx>) -> &'gcx ty::Generics<'gcx> { self.global_interners.arenas.generics.alloc(generics) @@ -815,7 +811,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { mir_map: RefCell::new(DepTrackingMap::new(dep_graph.clone())), freevars: RefCell::new(freevars), maybe_unused_trait_imports: maybe_unused_trait_imports, - tcache: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + item_types: RefCell::new(DepTrackingMap::new(dep_graph.clone())), rcache: RefCell::new(FxHashMap()), tc_cache: RefCell::new(FxHashMap()), associated_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())), diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index fdf5185eb69e..8222583d9a7d 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -218,7 +218,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // users may find it useful. Currently, we omit the parent if // the impl is either in the same module as the self-type or // as the trait. - let self_ty = self.lookup_item_type(impl_def_id).ty; + let self_ty = self.item_type(impl_def_id); let in_self_mod = match characteristic_def_id_of_type(self_ty) { None => false, Some(ty_def_id) => self.parent_def_id(ty_def_id) == Some(parent_def_id), diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 43abb61e7fcd..bf0445858794 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -33,7 +33,7 @@ macro_rules! dep_map_ty { } dep_map_ty! { AssociatedItems: AssociatedItems(DefId) -> ty::AssociatedItem } -dep_map_ty! { Tcache: ItemSignature(DefId) -> Ty<'tcx> } +dep_map_ty! { Types: ItemSignature(DefId) -> Ty<'tcx> } dep_map_ty! { Generics: ItemSignature(DefId) -> &'tcx ty::Generics<'tcx> } dep_map_ty! { Predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> } dep_map_ty! { SuperPredicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 1d260fd65fef..3db705140411 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -169,9 +169,9 @@ impl<'a, 'gcx, 'tcx> ImplHeader<'tcx> { let header = ImplHeader { impl_def_id: impl_def_id, - self_ty: tcx.lookup_item_type(impl_def_id).ty, + self_ty: tcx.item_type(impl_def_id), trait_ref: tcx.impl_trait_ref(impl_def_id), - predicates: tcx.lookup_predicates(impl_def_id).predicates + predicates: tcx.item_predicates(impl_def_id).predicates }.subst(tcx, impl_substs); let traits::Normalized { value: mut header, obligations } = @@ -708,7 +708,7 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> { instantiated: &mut InstantiatedPredicates<'tcx>, substs: &Substs<'tcx>) { if let Some(def_id) = self.parent { - tcx.lookup_predicates(def_id).instantiate_into(tcx, instantiated, substs); + tcx.item_predicates(def_id).instantiate_into(tcx, instantiated, substs); } instantiated.predicates.extend(self.predicates.iter().map(|p| p.subst(tcx, substs))) } @@ -1301,31 +1301,6 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { } } -/// A "type scheme", in ML terminology, is a type combined with some -/// set of generic types that the type is, well, generic over. In Rust -/// terms, it is the "type" of a fn item or struct -- this type will -/// include various generic parameters that must be substituted when -/// the item/struct is referenced. That is called converting the type -/// scheme to a monotype. -/// -/// - `generics`: the set of type parameters and their bounds -/// - `ty`: the base types, which may reference the parameters defined -/// in `generics` -/// -/// Note that TypeSchemes are also sometimes called "polytypes" (and -/// in fact this struct used to carry that name, so you may find some -/// stray references in a comment or something). We try to reserve the -/// "poly" prefix to refer to higher-ranked things, as in -/// `PolyTraitRef`. -/// -/// Note that each item also comes with predicates, see -/// `lookup_predicates`. -#[derive(Clone, Debug)] -pub struct TypeScheme<'tcx> { - pub generics: &'tcx Generics<'tcx>, - pub ty: Ty<'tcx>, -} - bitflags! { flags AdtFlags: u32 { const NO_ADT_FLAGS = 0, @@ -1359,8 +1334,6 @@ pub struct VariantDefData<'tcx, 'container: 'tcx> { } pub struct FieldDefData<'tcx, 'container: 'tcx> { - /// The field's DefId. NOTE: the fields of tuple-like enum variants - /// are not real items, and don't have entries in tcache etc. pub did: DefId, pub name: Name, pub vis: Visibility, @@ -1541,14 +1514,9 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { &self.variants[0] } - #[inline] - pub fn type_scheme(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> TypeScheme<'gcx> { - tcx.lookup_item_type(self.did) - } - #[inline] pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> GenericPredicates<'gcx> { - tcx.lookup_predicates(self.did) + tcx.item_predicates(self.did) } /// Returns an iterator over all fields contained @@ -1784,7 +1752,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> { def_id: sized_trait, substs: tcx.mk_substs_trait(ty, &[]) }).to_predicate(); - let predicates = tcx.lookup_predicates(self.did).predicates; + let predicates = tcx.item_predicates(self.did).predicates; if predicates.into_iter().any(|p| p == sized_predicate) { vec![] } else { @@ -1963,7 +1931,7 @@ impl LvaluePreference { } /// Helper for looking things up in the various maps that are populated during -/// typeck::collect (e.g., `tcx.associated_items`, `tcx.tcache`, etc). All of +/// typeck::collect (e.g., `tcx.associated_items`, `tcx.types`, etc). All of /// these share the pattern that if the id is local, it should have been loaded /// into the map by the `typeck::collect` phase. If the def-id is external, /// then we have to go consult the crate loading code (and cache the result for @@ -2351,38 +2319,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - // Register a given item type - pub fn register_item_type(self, did: DefId, scheme: TypeScheme<'gcx>) { - self.tcache.borrow_mut().insert(did, scheme.ty); - self.generics.borrow_mut().insert(did, scheme.generics); - } - // If the given item is in an external crate, looks up its type and adds it to // the type cache. Returns the type parameters and type. - pub fn lookup_item_type(self, did: DefId) -> TypeScheme<'gcx> { - let ty = lookup_locally_or_in_crate_store( - "tcache", did, &self.tcache, - || self.sess.cstore.item_type(self.global_tcx(), did)); - - TypeScheme { - ty: ty, - generics: self.lookup_generics(did) - } - } - - pub fn opt_lookup_item_type(self, did: DefId) -> Option> { - if did.krate != LOCAL_CRATE { - return Some(self.lookup_item_type(did)); - } - - if let Some(ty) = self.tcache.borrow().get(&did).cloned() { - Some(TypeScheme { - ty: ty, - generics: self.lookup_generics(did) - }) - } else { - None - } + pub fn item_type(self, did: DefId) -> Ty<'gcx> { + lookup_locally_or_in_crate_store( + "item_types", did, &self.item_types, + || self.sess.cstore.item_type(self.global_tcx(), did)) } /// Given the did of a trait, returns its canonical trait ref. @@ -2411,21 +2353,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } /// Given the did of an item, returns its generics. - pub fn lookup_generics(self, did: DefId) -> &'gcx Generics<'gcx> { + pub fn item_generics(self, did: DefId) -> &'gcx Generics<'gcx> { lookup_locally_or_in_crate_store( "generics", did, &self.generics, || self.alloc_generics(self.sess.cstore.item_generics(self.global_tcx(), did))) } /// Given the did of an item, returns its full set of predicates. - pub fn lookup_predicates(self, did: DefId) -> GenericPredicates<'gcx> { + pub fn item_predicates(self, did: DefId) -> GenericPredicates<'gcx> { lookup_locally_or_in_crate_store( "predicates", did, &self.predicates, || self.sess.cstore.item_predicates(self.global_tcx(), did)) } /// Given the did of a trait, returns its superpredicates. - pub fn lookup_super_predicates(self, did: DefId) -> GenericPredicates<'gcx> { + pub fn item_super_predicates(self, did: DefId) -> GenericPredicates<'gcx> { lookup_locally_or_in_crate_store( "super_predicates", did, &self.super_predicates, || self.sess.cstore.item_super_predicates(self.global_tcx(), did)) @@ -2718,7 +2660,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // let tcx = self.global_tcx(); - let generic_predicates = tcx.lookup_predicates(def_id); + let generic_predicates = tcx.item_predicates(def_id); let bounds = generic_predicates.instantiate(tcx, free_substs); let bounds = tcx.liberate_late_bound_regions(free_id_outlive, &ty::Binder(bounds)); let predicates = bounds.predicates; diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 92dfb883ef30..7d209093ec77 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -164,7 +164,7 @@ pub enum TypeVariants<'tcx> { /// Anonymized (`impl Trait`) type found in a return type. /// The DefId comes from the `impl Trait` ast::Ty node, and the /// substitutions are for the generics of the function in question. - /// After typeck, the concrete type can be found in the `tcache` map. + /// After typeck, the concrete type can be found in the `types` map. TyAnon(DefId, &'tcx Substs<'tcx>), /// A type parameter; for example, `T` in `fn f(x: T) {} @@ -556,7 +556,7 @@ pub struct DebruijnIndex { /// /// These are regions that are stored behind a binder and must be substituted /// with some concrete region before being used. There are 2 kind of -/// bound regions: early-bound, which are bound in a TypeScheme/TraitDef, +/// bound regions: early-bound, which are bound in an item's Generics, /// and are substituted by a Substs, and late-bound, which are part of /// higher-ranked types (e.g. `for<'a> fn(&'a ())`) and are substituted by /// the likes of `liberate_late_bound_regions`. The distinction exists diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index a4ceecd8c9d7..15f4437ed0aa 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -177,7 +177,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { -> &'tcx Substs<'tcx> where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region, FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> { - let defs = tcx.lookup_generics(def_id); + let defs = tcx.item_generics(def_id); let mut substs = Vec::with_capacity(defs.count()); Substs::fill_item(&mut substs, tcx, defs, &mut mk_region, &mut mk_type); tcx.intern_substs(&substs) @@ -192,7 +192,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> { if let Some(def_id) = defs.parent { - let parent_defs = tcx.lookup_generics(def_id); + let parent_defs = tcx.item_generics(def_id); Substs::fill_item(substs, tcx, parent_defs, mk_region, mk_type); } @@ -271,7 +271,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { source_ancestor: DefId, target_substs: &Substs<'tcx>) -> &'tcx Substs<'tcx> { - let defs = tcx.lookup_generics(source_ancestor); + let defs = tcx.item_generics(source_ancestor); tcx.mk_substs(target_substs.iter().chain(&self[defs.own_count()..]).cloned()) } } @@ -519,7 +519,7 @@ impl<'a, 'gcx, 'tcx> ty::TraitRef<'tcx> { trait_id: DefId, substs: &Substs<'tcx>) -> ty::TraitRef<'tcx> { - let defs = tcx.lookup_generics(trait_id); + let defs = tcx.item_generics(trait_id); ty::TraitRef { def_id: trait_id, diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index fc3202994838..fd81065e61d4 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -18,7 +18,7 @@ use std::cell::{Cell, RefCell}; use hir; use util::nodemap::FxHashMap; -/// As `TypeScheme` but for a trait ref. +/// A trait's definition with type information. pub struct TraitDef<'tcx> { pub unsafety: hir::Unsafety, diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 155fa4989ea3..74c6d7d334c3 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -446,7 +446,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { -> Vec> { let predicates = - self.infcx.tcx.lookup_predicates(def_id) + self.infcx.tcx.item_predicates(def_id) .instantiate(self.infcx.tcx, substs); let cause = self.cause(traits::ItemObligation(def_id)); predicates.predicates diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 01b44ced8e08..3ed4580336aa 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -105,7 +105,7 @@ pub fn parameterized(f: &mut fmt::Formatter, } } } - let mut generics = tcx.lookup_generics(item_def_id); + let mut generics = tcx.item_generics(item_def_id); let mut path_def_id = did; verbose = tcx.sess.verbose(); has_self = generics.has_self; @@ -115,7 +115,7 @@ pub fn parameterized(f: &mut fmt::Formatter, // Methods. assert!(is_value_path); child_types = generics.types.len(); - generics = tcx.lookup_generics(def_id); + generics = tcx.item_generics(def_id); num_regions = generics.regions.len(); num_types = generics.types.len(); @@ -865,7 +865,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { TyAdt(def, substs) => { ty::tls::with(|tcx| { if def.did.is_local() && - !tcx.tcache.borrow().contains_key(&def.did) { + !tcx.item_types.borrow().contains_key(&def.did) { write!(f, "{}<..>", tcx.item_path_str(def.did)) } else { parameterized(f, substs, def.did, &[]) @@ -878,7 +878,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { ty::tls::with(|tcx| { // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the projections associated with the def_id. - let item_predicates = tcx.lookup_predicates(def_id); + let item_predicates = tcx.item_predicates(def_id); let substs = tcx.lift(&substs).unwrap_or_else(|| { tcx.intern_substs(&[]) }); diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index be85069db313..eced5d1eb1b8 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -858,7 +858,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem) .unwrap_or_else(|e| tcx.sess.fatal(&e)); let substs = tcx.mk_substs(iter::once(Kind::from(ty))); - let fty = tcx.lookup_item_type(free_func).ty.subst(tcx, substs); + let fty = tcx.item_type(free_func).subst(tcx, substs); self.patch.new_block(BasicBlockData { statements: statements, diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index c19b3c40f65c..f6b6c89b7cc2 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -118,9 +118,10 @@ impl LateLintPass for BoxPointers { hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => { - self.check_heap_type(cx, it.span, cx.tcx.tables().node_id_to_type(it.id)) + let def_id = cx.tcx.map.local_def_id(it.id); + self.check_heap_type(cx, it.span, cx.tcx.item_type(def_id)) } - _ => (), + _ => () } // If it's a struct, we also have to check the fields' types @@ -128,9 +129,9 @@ impl LateLintPass for BoxPointers { hir::ItemStruct(ref struct_def, _) | hir::ItemUnion(ref struct_def, _) => { for struct_field in struct_def.fields() { - self.check_heap_type(cx, - struct_field.span, - cx.tcx.tables().node_id_to_type(struct_field.id)); + let def_id = cx.tcx.map.local_def_id(struct_field.id); + self.check_heap_type(cx, struct_field.span, + cx.tcx.item_type(def_id)); } } _ => (), @@ -585,11 +586,9 @@ impl LateLintPass for MissingDebugImplementations { let debug_def = cx.tcx.lookup_trait_def(debug); let mut impls = NodeSet(); debug_def.for_each_impl(cx.tcx, |d| { - if let Some(n) = cx.tcx.map.as_local_node_id(d) { - if let Some(ty_def) = cx.tcx.tables().node_id_to_type(n).ty_to_def_id() { - if let Some(node_id) = cx.tcx.map.as_local_node_id(ty_def) { - impls.insert(node_id); - } + if let Some(ty_def) = cx.tcx.item_type(d).ty_to_def_id() { + if let Some(node_id) = cx.tcx.map.as_local_node_id(ty_def) { + impls.insert(node_id); } } }); @@ -1225,7 +1224,7 @@ impl LateLintPass for MutableTransmutes { } fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool { - match cx.tcx.lookup_item_type(def_id).ty.sty { + match cx.tcx.item_type(def_id).sty { ty::TyFnDef(.., ref bfty) if bfty.abi == RustIntrinsic => (), _ => return false, } @@ -1282,7 +1281,7 @@ impl LateLintPass for UnionsWithDropFields { if let hir::ItemUnion(ref vdata, _) = item.node { let param_env = &ty::ParameterEnvironment::for_item(ctx.tcx, item.id); for field in vdata.fields() { - let field_ty = ctx.tcx.tables().node_id_to_type(field.id); + let field_ty = ctx.tcx.item_type(ctx.tcx.map.local_def_id(field.id)); if ctx.tcx.type_needs_drop_given_env(field_ty, param_env) { ctx.span_lint(UNIONS_WITH_DROP_FIELDS, field.span, diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 48471282672a..4155d3e67a26 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -675,8 +675,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { fn check_foreign_fn(&mut self, id: ast::NodeId, decl: &hir::FnDecl) { let def_id = self.cx.tcx.map.local_def_id(id); - let scheme = self.cx.tcx.lookup_item_type(def_id); - let sig = scheme.ty.fn_sig(); + let sig = self.cx.tcx.item_type(def_id).fn_sig(); let sig = self.cx.tcx.erase_late_bound_regions(&sig); for (&input_ty, input_hir) in sig.inputs.iter().zip(&decl.inputs) { @@ -693,8 +692,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { fn check_foreign_static(&mut self, id: ast::NodeId, span: Span) { let def_id = self.cx.tcx.map.local_def_id(id); - let scheme = self.cx.tcx.lookup_item_type(def_id); - self.check_type_for_ffi_and_report_errors(span, scheme.ty); + let ty = self.cx.tcx.item_type(def_id); + self.check_type_for_ffi_and_report_errors(span, ty); } } @@ -740,11 +739,12 @@ impl LateLintPass for VariantSizeDifferences { if let hir::ItemEnum(ref enum_definition, ref gens) = it.node { if gens.ty_params.is_empty() { // sizes only make sense for non-generic types - let t = cx.tcx.tables().node_id_to_type(it.id); + let t = cx.tcx.item_type(cx.tcx.map.local_def_id(it.id)); let layout = cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { let ty = cx.tcx.erase_regions(&t); - ty.layout(&infcx) - .unwrap_or_else(|e| bug!("failed to get layout for `{}`: {}", t, e)) + ty.layout(&infcx).unwrap_or_else(|e| { + bug!("failed to get layout for `{}`: {}", t, e) + }) }); if let Layout::General { ref variants, ref size, discr, .. } = *layout { diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index e009955b92ee..e2fa535bb44a 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -133,7 +133,10 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata, &InlinedItem::ImplItem(_, ref ii) => ii.id, }; let inlined_did = tcx.map.local_def_id(item_node_id); - tcx.register_item_type(inlined_did, tcx.lookup_item_type(orig_did)); + let ty = tcx.item_type(orig_did); + let generics = tcx.item_generics(orig_did); + tcx.item_types.borrow_mut().insert(inlined_did, ty); + tcx.generics.borrow_mut().insert(inlined_did, generics); for (id, entry) in ast.side_tables.decode((cdata, tcx, id_ranges)) { match entry { @@ -141,7 +144,7 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata, tcx.def_map.borrow_mut().insert(id, def::PathResolution::new(def)); } TableEntry::NodeType(ty) => { - tcx.node_type_insert(id, ty); + tcx.tables.borrow_mut().node_types.insert(id, ty); } TableEntry::ItemSubsts(item_substs) => { tcx.tables.borrow_mut().item_substs.insert(id, item_substs); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 7973cd880fe3..818fb4e86f92 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -526,7 +526,7 @@ impl<'a, 'tcx> CrateMetadata { ty::TraitDef::new(data.unsafety, data.paren_sugar, - tcx.lookup_generics(self.local_def_id(item_id)), + tcx.item_generics(self.local_def_id(item_id)), data.trait_ref.decode((self, tcx)), self.def_path(item_id).unwrap().deterministic_hash(tcx)) } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 2379e744c49e..2abfff4ceaae 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -246,7 +246,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_item_type(&mut self, def_id: DefId) -> Lazy> { let tcx = self.tcx; - self.lazy(&tcx.lookup_item_type(def_id).ty) + self.lazy(&tcx.item_type(def_id)) } /// Encode data for the given variant of the given ADT. The @@ -444,12 +444,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_generics(&mut self, def_id: DefId) -> Lazy> { let tcx = self.tcx; - self.lazy(tcx.lookup_generics(def_id)) + self.lazy(tcx.item_generics(def_id)) } fn encode_predicates(&mut self, def_id: DefId) -> Lazy> { let tcx = self.tcx; - self.lazy(&tcx.lookup_predicates(def_id)) + self.lazy(&tcx.item_predicates(def_id)) } fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> { @@ -556,7 +556,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let (ast, mir) = if impl_item.kind == ty::AssociatedKind::Const { (true, true) } else if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node { - let generics = self.tcx.lookup_generics(def_id); + let generics = self.tcx.item_generics(def_id); let types = generics.parent_types as usize + generics.types.len(); let needs_inline = types > 0 || attr::requests_inline(&ast_item.attrs); let is_const_fn = sig.constness == hir::Constness::Const; @@ -717,7 +717,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { paren_sugar: trait_def.paren_sugar, has_default_impl: tcx.trait_has_default_impl(def_id), trait_ref: self.lazy(&trait_def.trait_ref), - super_predicates: self.lazy(&tcx.lookup_super_predicates(def_id)), + super_predicates: self.lazy(&tcx.item_super_predicates(def_id)), }; EntryKind::Trait(self.lazy(&data)) diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 902798ec9800..f43181d8a610 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -155,6 +155,7 @@ macro_rules! unpack { pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, fn_id: ast::NodeId, arguments: A, + abi: Abi, return_ty: Ty<'gcx>, ast_body: &'gcx hir::Expr) -> (Mir<'tcx>, ScopeAuxiliaryVec) @@ -191,12 +192,9 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, assert_eq!(block, builder.return_block()); let mut spread_arg = None; - match tcx.tables().node_id_to_type(fn_id).sty { - ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => { - // RustCall pseudo-ABI untuples the last argument. - spread_arg = Some(Local::new(arguments.len())); - } - _ => {} + if abi == Abi::RustCall { + // RustCall pseudo-ABI untuples the last argument. + spread_arg = Some(Local::new(arguments.len())); } // Gather the upvars of a closure, if any. diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index b5343975a9cd..4af87381c704 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -806,7 +806,7 @@ fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, TerminatorKind::Call { func: Operand::Constant(Constant { span: data.span, - ty: tcx.lookup_item_type(free_func).ty.subst(tcx, substs), + ty: tcx.item_type(free_func).subst(tcx, substs), literal: Literal::Item { def_id: free_func, substs: substs diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index ecc2d8fe050a..038300068fce 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -149,8 +149,8 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { let substs = self.tcx.mk_substs_trait(self_ty, params); for item in self.tcx.associated_items(trait_def_id) { if item.kind == ty::AssociatedKind::Method && item.name == method_name { - let method_ty = self.tcx.lookup_item_type(item.def_id); - let method_ty = method_ty.ty.subst(self.tcx, substs); + let method_ty = self.tcx.item_type(item.def_id); + let method_ty = method_ty.subst(self.tcx, substs); return (method_ty, Literal::Item { def_id: item.def_id, substs: substs, diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index af2f9adfc9a8..f22a2a7ac9c7 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -31,6 +31,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; use rustc::hir; use rustc::hir::intravisit::{self, FnKind, Visitor}; +use syntax::abi::Abi; use syntax::ast; use syntax_pos::Span; @@ -221,10 +222,11 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> { } }; - let implicit_argument = if let FnKind::Closure(..) = fk { - Some((closure_self_ty(self.tcx, id, body.id), None)) + let (abi, implicit_argument) = if let FnKind::Closure(..) = fk { + (Abi::Rust, Some((closure_self_ty(self.tcx, id, body.id), None))) } else { - None + let def_id = self.tcx.map.local_def_id(id); + (self.tcx.item_type(def_id).fn_abi(), None) }; let explicit_arguments = @@ -237,7 +239,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> { let arguments = implicit_argument.into_iter().chain(explicit_arguments); self.cx(MirSource::Fn(id)).build(|cx| { - build::construct_fn(cx, id, arguments, fn_sig.output, body) + build::construct_fn(cx, id, arguments, abi, fn_sig.output, body) }); intravisit::walk_fn(self, fk, decl, body, span, id); diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 9d3afe541cca..ad525d210694 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -127,7 +127,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { match *lvalue { Lvalue::Local(index) => LvalueTy::Ty { ty: self.mir.local_decls[index].ty }, Lvalue::Static(def_id) => - LvalueTy::Ty { ty: self.tcx().lookup_item_type(def_id).ty }, + LvalueTy::Ty { ty: self.tcx().item_type(def_id) }, Lvalue::Projection(ref proj) => { let base_ty = self.sanitize_lvalue(&proj.base, location); if let LvalueTy::Ty { ty } = base_ty { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index fded34d2c856..e6b015b8e173 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -286,7 +286,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: NodeId) -> Option { if let Some(ident) = field.ident { let qualname = format!("::{}::{}", self.tcx.node_path_str(scope), ident); - let typ = self.tcx.tables().node_types.get(&field.id).unwrap().to_string(); + let def_id = self.tcx.map.local_def_id(field.id); + let typ = self.tcx.item_type(def_id).to_string(); let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon); filter!(self.span_utils, sub_span, field.span, None); Some(VariableData { diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index bf2a5d76c10d..0ad663f05b48 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -231,7 +231,7 @@ impl<'a, 'tcx> Instance<'tcx> { match key.disambiguated_data.data { DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => { - instance_ty = scx.tcx().lookup_item_type(ty_def_id); + instance_ty = scx.tcx().item_type(ty_def_id); break; } _ => { @@ -248,7 +248,7 @@ impl<'a, 'tcx> Instance<'tcx> { // Erase regions because they may not be deterministic when hashed // and should not matter anyhow. - let instance_ty = scx.tcx().erase_regions(&instance_ty.ty); + let instance_ty = scx.tcx().erase_regions(&instance_ty); let hash = get_symbol_hash(scx, &def_path, instance_ty, Some(substs)); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index d50669272f72..a990a7c507fd 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1045,7 +1045,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance debug!("trans_instance(instance={:?})", instance); let _icx = push_ctxt("trans_instance"); - let fn_ty = ccx.tcx().lookup_item_type(instance.def).ty; + let fn_ty = ccx.tcx().item_type(instance.def); let fn_ty = ccx.tcx().erase_regions(&fn_ty); let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty); @@ -1068,7 +1068,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, attributes::inline(llfndecl, attributes::InlineAttr::Hint); attributes::set_frame_pointer_elimination(ccx, llfndecl); - let ctor_ty = ccx.tcx().lookup_item_type(def_id).ty; + let ctor_ty = ccx.tcx().item_type(def_id); let ctor_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &ctor_ty); let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&ctor_ty.fn_sig()); @@ -1514,7 +1514,7 @@ pub fn filter_reachable_ids(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { hir_map::NodeImplItem(&hir::ImplItem { node: hir::ImplItemKind::Method(..), .. }) => { let def_id = tcx.map.local_def_id(id); - let generics = tcx.lookup_generics(def_id); + let generics = tcx.item_generics(def_id); let attributes = tcx.get_attrs(def_id); (generics.parent_types == 0 && generics.types.is_empty()) && // Functions marked with #[inline] are only ever translated @@ -1719,7 +1719,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let applicable = match sess.cstore.describe_def(def_id) { Some(Def::Static(..)) => true, Some(Def::Fn(_)) => { - shared_ccx.tcx().lookup_generics(def_id).types.is_empty() + shared_ccx.tcx().item_generics(def_id).types.is_empty() } _ => false }; diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index ffb13a833a58..f49d63b83764 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -246,7 +246,7 @@ fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - let ty = shared.tcx().lookup_item_type(def_id).ty; + let ty = shared.tcx().item_type(def_id); monomorphize::apply_param_substs(shared, substs, &ty) } @@ -400,7 +400,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let substs = tcx.normalize_associated_type(&substs); let instance = Instance::new(def_id, substs); - let item_ty = ccx.tcx().lookup_item_type(def_id).ty; + let item_ty = ccx.tcx().item_type(def_id); let fn_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &item_ty); if let Some(&llfn) = ccx.instances().borrow().get(&instance) { diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 2c0ba36f3b41..41071057274f 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -337,7 +337,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, } TransItem::Static(node_id) => { let def_id = scx.tcx().map.local_def_id(node_id); - let ty = scx.tcx().lookup_item_type(def_id).ty; + let ty = scx.tcx().item_type(def_id); let ty = glue::get_drop_glue_type(scx.tcx(), ty); neighbors.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); @@ -618,7 +618,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { fn can_result_in_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { - match tcx.lookup_item_type(def_id).ty.sty { + match tcx.item_type(def_id).sty { ty::TyFnDef(def_id, _, f) => { // Some constructors also have type TyFnDef but they are // always instantiated inline and don't result in @@ -1077,13 +1077,12 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemStruct(_, ref generics) | hir::ItemUnion(_, ref generics) => { if !generics.is_parameterized() { - let ty = self.scx.tcx().tables().node_types[&item.id]; - if self.mode == TransItemCollectionMode::Eager { + let def_id = self.scx.tcx().map.local_def_id(item.id); debug!("RootCollector: ADT drop-glue for {}", - def_id_to_string(self.scx.tcx(), - self.scx.tcx().map.local_def_id(item.id))); + def_id_to_string(self.scx.tcx(), def_id)); + let ty = self.scx.tcx().item_type(def_id); let ty = glue::get_drop_glue_type(self.scx.tcx(), ty); self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); } @@ -1182,7 +1181,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' continue; } - if !tcx.lookup_generics(method.def_id).types.is_empty() { + if !tcx.item_generics(method.def_id).types.is_empty() { continue; } @@ -1201,7 +1200,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' callee_substs, &impl_data); - let predicates = tcx.lookup_predicates(def_id).predicates + let predicates = tcx.item_predicates(def_id).predicates .subst(tcx, substs); if !traits::normalize_and_test_predicates(tcx, predicates) { continue; diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 0dc10aa7759e..670a84565faf 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -84,7 +84,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { return g; } - let ty = ccx.tcx().lookup_item_type(def_id).ty; + let ty = ccx.tcx().item_type(def_id); let g = if let Some(id) = ccx.tcx().map.as_local_node_id(def_id) { let llty = type_of::type_of(ccx, ty); @@ -226,7 +226,7 @@ pub fn trans_static(ccx: &CrateContext, v }; - let ty = ccx.tcx().lookup_item_type(def_id).ty; + let ty = ccx.tcx().item_type(def_id); let llty = type_of::type_of(ccx, ty); let g = if val_llty == llty { g diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index e81461b66217..679e308c3454 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1765,7 +1765,7 @@ pub fn create_global_var_metadata(cx: &CrateContext, }; let is_local_to_unit = is_node_local_to_unit(cx, node_id); - let variable_type = tcx.erase_regions(&tcx.tables().node_id_to_type(node_id)); + let variable_type = tcx.erase_regions(&tcx.item_type(node_def_id)); let type_metadata = type_metadata(cx, variable_type, span); let var_name = tcx.item_name(node_def_id).to_string(); let linkage_name = mangled_name_of_item(cx, node_def_id, ""); diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 62fb40cc389c..45b8ec1dc80b 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -259,7 +259,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Get_template_parameters() will append a `<...>` clause to the function // name if necessary. - let generics = cx.tcx().lookup_generics(fn_def_id); + let generics = cx.tcx().item_generics(fn_def_id); let template_parameters = get_template_parameters(cx, &generics, instance.substs, @@ -397,7 +397,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, generics: &ty::Generics<'tcx>) -> Vec { let mut names = generics.parent.map_or(vec![], |def_id| { - get_type_parameter_names(cx, cx.tcx().lookup_generics(def_id)) + get_type_parameter_names(cx, cx.tcx().item_generics(def_id)) }); names.extend(generics.types.iter().map(|param| param.name)); names @@ -412,7 +412,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let self_type = cx.tcx().impl_of_method(instance.def).and_then(|impl_def_id| { // If the method does *not* belong to a trait, proceed if cx.tcx().trait_id_of_impl(impl_def_id).is_none() { - let impl_self_ty = cx.tcx().lookup_item_type(impl_def_id).ty; + let impl_self_ty = cx.tcx().item_type(impl_def_id); let impl_self_ty = cx.tcx().erase_regions(&impl_self_ty); let impl_self_ty = monomorphize::apply_param_substs(cx.shared(), instance.substs, diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index c9c12fb6d453..09a1cbd319ac 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -495,7 +495,7 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 't if let Some(impl_def_id) = tcx.impl_of_method(instance.def) { // This is a method within an inherent impl, find out what the // self-type is: - let impl_self_ty = tcx.lookup_item_type(impl_def_id).ty; + let impl_self_ty = tcx.item_type(impl_def_id); let impl_self_ty = tcx.erase_regions(&impl_self_ty); let impl_self_ty = monomorphize::apply_param_substs(scx, instance.substs, diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 8930387c046e..93790cc27bca 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -131,7 +131,7 @@ impl<'a, 'tcx> TransItem<'tcx> { linkage: llvm::Linkage, symbol_name: &str) { let def_id = ccx.tcx().map.local_def_id(node_id); - let ty = ccx.tcx().lookup_item_type(def_id).ty; + let ty = ccx.tcx().item_type(def_id); let llty = type_of::type_of(ccx, ty); let g = declare::define_global(ccx, symbol_name, llty).unwrap_or_else(|| { @@ -153,7 +153,7 @@ impl<'a, 'tcx> TransItem<'tcx> { assert!(!instance.substs.needs_infer() && !instance.substs.has_param_types()); - let item_ty = ccx.tcx().lookup_item_type(instance.def).ty; + let item_ty = ccx.tcx().item_type(instance.def); let item_ty = ccx.tcx().erase_regions(&item_ty); let mono_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &item_ty); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 513b4860d5e8..fae0f932798d 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -16,12 +16,12 @@ //! somewhat differently during the collect and check phases, //! particularly with respect to looking up the types of top-level //! items. In the collect phase, the crate context is used as the -//! `AstConv` instance; in this phase, the `get_item_type_scheme()` -//! function triggers a recursive call to `type_scheme_of_item()` +//! `AstConv` instance; in this phase, the `get_item_type()` +//! function triggers a recursive call to `type_of_item()` //! (note that `ast_ty_to_ty()` will detect recursive types and report //! an error). In the check phase, when the FnCtxt is used as the -//! `AstConv`, `get_item_type_scheme()` just looks up the item type in -//! `tcx.tcache` (using `ty::lookup_item_type`). +//! `AstConv`, `get_item_type()` just looks up the item type in +//! `tcx.types` (using `TyCtxt::item_type`). //! //! The `RegionScope` trait controls what happens when the user does //! not specify a region in some location where a region is required @@ -85,11 +85,8 @@ pub trait AstConv<'gcx, 'tcx> { fn get_generics(&self, span: Span, id: DefId) -> Result<&'tcx ty::Generics<'tcx>, ErrorReported>; - /// Identify the type scheme for an item with a type, like a type - /// alias, fn, or struct. This allows you to figure out the set of - /// type parameters defined on the item. - fn get_item_type_scheme(&self, span: Span, id: DefId) - -> Result, ErrorReported>; + /// Identify the type for an item, like a type alias, fn, or struct. + fn get_item_type(&self, span: Span, id: DefId) -> Result, ErrorReported>; /// Returns the `TraitDef` for a given trait. This allows you to /// figure out the set of type parameters defined on the trait. @@ -938,8 +935,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { -> Ty<'tcx> { let tcx = self.tcx(); - let decl_ty = match self.get_item_type_scheme(span, did) { - Ok(type_scheme) => type_scheme.ty, + let decl_ty = match self.get_item_type(span, did) { + Ok(ty) => ty, Err(ErrorReported) => { return tcx.types.err; } @@ -1521,8 +1518,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // Self in impl (we know the concrete type). tcx.prohibit_type_params(base_segments); - let impl_id = tcx.map.as_local_node_id(def_id).unwrap(); - let ty = tcx.tables().node_id_to_type(impl_id); + let ty = tcx.item_type(def_id); if let Some(free_substs) = self.get_free_substs() { ty.subst(tcx, free_substs) } else { diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index ffde940b3f48..54a0ef071ce4 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -174,10 +174,10 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("compare_impl_method: trait_to_skol_substs={:?}", trait_to_skol_substs); - let impl_m_generics = tcx.lookup_generics(impl_m.def_id); - let trait_m_generics = tcx.lookup_generics(trait_m.def_id); - let impl_m_predicates = tcx.lookup_predicates(impl_m.def_id); - let trait_m_predicates = tcx.lookup_predicates(trait_m.def_id); + let impl_m_generics = tcx.item_generics(impl_m.def_id); + let trait_m_generics = tcx.item_generics(trait_m.def_id); + let impl_m_predicates = tcx.item_predicates(impl_m.def_id); + let trait_m_predicates = tcx.item_predicates(trait_m.def_id); // Check region bounds. check_region_bounds_on_impl_method(ccx, @@ -193,7 +193,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // environment. We can't just use `impl_env.caller_bounds`, // however, because we want to replace all late-bound regions with // region variables. - let impl_predicates = tcx.lookup_predicates(impl_m_predicates.parent.unwrap()); + let impl_predicates = tcx.item_predicates(impl_m_predicates.parent.unwrap()); let mut hybrid_preds = impl_predicates.instantiate(tcx, impl_to_skol_substs); debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds); @@ -269,7 +269,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let origin = TypeOrigin::MethodCompatCheck(impl_m_span); let m_fty = |method: &ty::AssociatedItem| { - match tcx.lookup_item_type(method.def_id).ty.sty { + match tcx.item_type(method.def_id).sty { ty::TyFnDef(_, _, f) => f, _ => bug!() } @@ -542,7 +542,7 @@ fn compare_self_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty::ImplContainer(_) => impl_trait_ref.self_ty(), ty::TraitContainer(_) => tcx.mk_self_type() }; - let method_ty = tcx.lookup_item_type(method.def_id).ty; + let method_ty = tcx.item_type(method.def_id); let self_arg_ty = *method_ty.fn_sig().input(0).skip_binder(); match ExplicitSelf::determine(untransformed_self_ty, self_arg_ty) { ExplicitSelf::ByValue => "self".to_string(), @@ -601,8 +601,8 @@ fn compare_number_of_generics<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_item_span: Option) -> Result<(), ErrorReported> { let tcx = ccx.tcx; - let impl_m_generics = tcx.lookup_generics(impl_m.def_id); - let trait_m_generics = tcx.lookup_generics(trait_m.def_id); + let impl_m_generics = tcx.item_generics(impl_m.def_id); + let trait_m_generics = tcx.item_generics(trait_m.def_id); let num_impl_m_type_params = impl_m_generics.types.len(); let num_trait_m_type_params = trait_m_generics.types.len(); if num_impl_m_type_params != num_trait_m_type_params { @@ -672,7 +672,7 @@ fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, -> Result<(), ErrorReported> { let tcx = ccx.tcx; let m_fty = |method: &ty::AssociatedItem| { - match tcx.lookup_item_type(method.def_id).ty.sty { + match tcx.item_type(method.def_id).sty { ty::TyFnDef(_, _, f) => f, _ => bug!() } @@ -785,8 +785,8 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_to_skol_substs); // Compute skolemized form of impl and trait const tys. - let impl_ty = tcx.lookup_item_type(impl_c.def_id).ty.subst(tcx, impl_to_skol_substs); - let trait_ty = tcx.lookup_item_type(trait_c.def_id).ty.subst(tcx, trait_to_skol_substs); + let impl_ty = tcx.item_type(impl_c.def_id).subst(tcx, impl_to_skol_substs); + let trait_ty = tcx.item_type(trait_c.def_id).subst(tcx, trait_to_skol_substs); let mut origin = TypeOrigin::Misc(impl_c_span); let err = infcx.commit_if_ok(|_| { diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index a06b3e70881a..8657b30bf8ee 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -41,8 +41,8 @@ use syntax_pos::{self, Span}; /// cannot do `struct S; impl Drop for S { ... }`). /// pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()> { - let dtor_self_type = ccx.tcx.lookup_item_type(drop_impl_did).ty; - let dtor_predicates = ccx.tcx.lookup_predicates(drop_impl_did); + let dtor_self_type = ccx.tcx.item_type(drop_impl_did); + let dtor_predicates = ccx.tcx.item_predicates(drop_impl_did); match dtor_self_type.sty { ty::TyAdt(adt_def, self_to_impl_substs) => { ensure_drop_params_and_item_params_correspond(ccx, @@ -85,7 +85,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( let tcx = infcx.tcx; let mut fulfillment_cx = traits::FulfillmentContext::new(); - let named_type = tcx.lookup_item_type(self_type_did).ty; + let named_type = tcx.item_type(self_type_did); let named_type = named_type.subst(tcx, &infcx.parameter_environment.free_substs); let drop_impl_span = tcx.map.def_id_span(drop_impl_did, syntax_pos::DUMMY_SP); @@ -177,7 +177,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>( // We can assume the predicates attached to struct/enum definition // hold. - let generic_assumptions = tcx.lookup_predicates(self_type_did); + let generic_assumptions = tcx.item_predicates(self_type_did); let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs); let assumptions_in_impl_context = assumptions_in_impl_context.predicates; @@ -570,30 +570,30 @@ fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // Constructs new Ty just like the type defined by `adt_def` coupled // with `substs`, except each type and lifetime parameter marked as -// `#[may_dangle]` in the Drop impl (identified by `impl_id`) is +// `#[may_dangle]` in the Drop impl (identified by `impl_def_id`) is // respectively mapped to `()` or `'static`. // // For example: If the `adt_def` maps to: // // enum Foo<'a, X, Y> { ... } // -// and the `impl_id` maps to: +// and the `impl_def_id` maps to: // // impl<#[may_dangle] 'a, X, #[may_dangle] Y> Drop for Foo<'a, X, Y> { ... } // // then revises input: `Foo<'r,i64,&'r i64>` to: `Foo<'static,i64,()>` fn revise_self_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, adt_def: ty::AdtDef<'tcx>, - impl_id: DefId, + impl_def_id: DefId, substs: &Substs<'tcx>) -> Ty<'tcx> { // Get generics for `impl Drop` to query for `#[may_dangle]` attr. - let impl_bindings = tcx.lookup_generics(impl_id); + let impl_bindings = tcx.item_generics(impl_def_id); // Get Substs attached to Self on `impl Drop`; process in parallel // with `substs`, replacing dangling entries as appropriate. let self_substs = { - let impl_self_ty: Ty<'tcx> = tcx.lookup_item_type(impl_id).ty; + let impl_self_ty: Ty<'tcx> = tcx.item_type(impl_def_id); if let ty::TyAdt(self_adt_def, self_substs) = impl_self_ty.sty { assert_eq!(adt_def, self_adt_def); self_substs @@ -648,5 +648,5 @@ fn revise_self_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, t }); - return tcx.mk_adt(adt_def, &substs); + tcx.mk_adt(adt_def, &substs) } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 95d2b2211f5b..ac6343cae1c8 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -34,7 +34,6 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, output: Ty<'tcx>) { let tcx = ccx.tcx; let def_id = tcx.map.local_def_id(it.id); - let i_ty = tcx.lookup_item_type(def_id); let substs = Substs::for_item(tcx, def_id, |_, _| tcx.mk_region(ty::ReErased), @@ -49,7 +48,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, variadic: false, }), })); - let i_n_tps = i_ty.generics.types.len(); + let i_n_tps = tcx.item_generics(def_id).types.len(); if i_n_tps != n_tps { let span = match it.node { hir::ForeignItemFn(_, ref generics) => generics.span, @@ -65,7 +64,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } else { require_same_types(ccx, TypeOrigin::IntrinsicType(it.span), - i_ty.ty, + tcx.item_type(def_id), fty); } } @@ -330,8 +329,8 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt, }; let tcx = ccx.tcx; - let i_ty = tcx.lookup_item_type(tcx.map.local_def_id(it.id)); - let i_n_tps = i_ty.generics.types.len(); + let def_id = tcx.map.local_def_id(it.id); + let i_n_tps = tcx.item_generics(def_id).types.len(); let name = it.name.as_str(); let (n_tps, inputs, output) = match &*name { @@ -374,7 +373,8 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt, let mut structural_to_nomimal = FxHashMap(); - let sig = tcx.no_late_bound_regions(i_ty.ty.fn_sig()).unwrap(); + let sig = tcx.item_type(def_id).fn_sig(); + let sig = tcx.no_late_bound_regions(sig).unwrap(); if intr.inputs.len() != sig.inputs.len() { span_err!(tcx.sess, it.span, E0444, "platform-specific intrinsic has invalid number of \ diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 3894a7a2097e..0b6f7794e9fe 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -276,7 +276,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // If they were not explicitly supplied, just construct fresh // variables. let num_supplied_types = supplied_method_types.len(); - let method_generics = self.tcx.lookup_generics(pick.item.def_id); + let method_generics = self.tcx.item_generics(pick.item.def_id); let num_method_types = method_generics.types.len(); if num_supplied_types > 0 && num_supplied_types != num_method_types { @@ -359,14 +359,14 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // type/early-bound-regions substitutions performed. There can // be no late-bound regions appearing here. let def_id = pick.item.def_id; - let method_predicates = self.tcx.lookup_predicates(def_id) + let method_predicates = self.tcx.item_predicates(def_id) .instantiate(self.tcx, all_substs); let method_predicates = self.normalize_associated_types_in(self.span, &method_predicates); debug!("method_predicates after subst = {:?}", method_predicates); - let fty = match self.tcx.lookup_item_type(def_id).ty.sty { + let fty = match self.tcx.item_type(def_id).sty { ty::TyFnDef(_, _, f) => f, _ => bug!() }; diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 579a54fb5318..66a532fd76ac 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -230,7 +230,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let tcx = self.tcx; let method_item = self.associated_item(trait_def_id, m_name).unwrap(); let def_id = method_item.def_id; - let generics = tcx.lookup_generics(def_id); + let generics = tcx.item_generics(def_id); assert_eq!(generics.types.len(), 0); assert_eq!(generics.regions.len(), 0); @@ -242,7 +242,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // NB: Instantiate late-bound regions first so that // `instantiate_type_scheme` can normalize associated types that // may reference those regions. - let original_method_ty = tcx.lookup_item_type(def_id).ty; + let original_method_ty = tcx.item_type(def_id); let fty = match original_method_ty.sty { ty::TyFnDef(_, _, f) => f, _ => bug!() diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 7068b2dea726..481923c25978 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -672,9 +672,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } }; - let impl_type = self.tcx.lookup_item_type(impl_def_id); + let impl_type = self.tcx.item_type(impl_def_id); let impl_simplified_type = - match ty::fast_reject::simplify_type(self.tcx, impl_type.ty, false) { + match ty::fast_reject::simplify_type(self.tcx, impl_type, false) { Some(simplified_type) => simplified_type, None => { return true; @@ -771,7 +771,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { def_id, substs); - let trait_predicates = self.tcx.lookup_predicates(def_id); + let trait_predicates = self.tcx.item_predicates(def_id); let bounds = trait_predicates.instantiate(self.tcx, substs); let predicates = bounds.predicates; debug!("assemble_projection_candidates: predicates={:?}", @@ -1070,7 +1070,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let cause = traits::ObligationCause::misc(self.span, self.body_id); // Check whether the impl imposes obligations we have to worry about. - let impl_bounds = self.tcx.lookup_predicates(impl_def_id); + let impl_bounds = self.tcx.item_predicates(impl_def_id); let impl_bounds = impl_bounds.instantiate(self.tcx, substs); let traits::Normalized { value: impl_bounds, obligations: norm_obligations } = traits::normalize(selcx, cause.clone(), &impl_bounds); @@ -1171,7 +1171,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { impl_ty: Ty<'tcx>, substs: &Substs<'tcx>) -> Ty<'tcx> { - let self_ty = self.tcx.lookup_item_type(method).ty.fn_sig().input(0); + let self_ty = self.tcx.item_type(method).fn_sig().input(0); debug!("xform_self_ty(impl_ty={:?}, self_ty={:?}, substs={:?})", impl_ty, self_ty, @@ -1184,7 +1184,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // are given do not include type/lifetime parameters for the // method yet. So create fresh variables here for those too, // if there are any. - let generics = self.tcx.lookup_generics(method); + let generics = self.tcx.item_generics(method); assert_eq!(substs.types().count(), generics.parent_types as usize); assert_eq!(substs.regions().count(), generics.parent_regions as usize); @@ -1218,7 +1218,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { /// Get the type of an impl and generate substitutions with placeholders. fn impl_ty_and_substs(&self, impl_def_id: DefId) -> (Ty<'tcx>, &'tcx Substs<'tcx>) { - let impl_ty = self.tcx.lookup_item_type(impl_def_id).ty; + let impl_ty = self.tcx.item_type(impl_def_id); let substs = Substs::for_item(self.tcx, impl_def_id, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 08242cff112c..e0a429ea5aa1 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -597,7 +597,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, body: &'tcx hir::Expr, fn_id: ast::NodeId, span: Span) { - let raw_fty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(fn_id)).ty; + let raw_fty = ccx.tcx.item_type(ccx.tcx.map.local_def_id(fn_id)); let fn_ty = match raw_fty.sty { ty::TyFnDef(.., f) => f, _ => span_bug!(body.span, "check_bare_fn: function type expected") @@ -780,15 +780,16 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, } fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) { - check_representable(ccx.tcx, span, id); + let def_id = ccx.tcx.map.local_def_id(id); + check_representable(ccx.tcx, span, def_id); - if ccx.tcx.lookup_simd(ccx.tcx.map.local_def_id(id)) { - check_simd(ccx.tcx, span, id); + if ccx.tcx.lookup_simd(def_id) { + check_simd(ccx.tcx, span, def_id); } } fn check_union(ccx: &CrateCtxt, id: ast::NodeId, span: Span) { - check_representable(ccx.tcx, span, id); + check_representable(ccx.tcx, span, ccx.tcx.map.local_def_id(id)); } pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { @@ -831,7 +832,8 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { check_union(ccx, it.id, it.span); } hir::ItemTy(_, ref generics) => { - let pty_ty = ccx.tcx.tables().node_id_to_type(it.id); + let def_id = ccx.tcx.map.local_def_id(it.id); + let pty_ty = ccx.tcx.item_type(def_id); check_bounds_are_used(ccx, generics, pty_ty); } hir::ItemForeignMod(ref m) => { @@ -847,8 +849,8 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { } } else { for item in &m.items { - let pty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(item.id)); - if !pty.generics.types.is_empty() { + let generics = ccx.tcx.item_generics(ccx.tcx.map.local_def_id(item.id)); + if !generics.types.is_empty() { let mut err = struct_span_err!(ccx.tcx.sess, item.span, E0044, "foreign items may not have type parameters"); span_help!(&mut err, item.span, @@ -917,7 +919,7 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, def_id: DefId, item: &hir::Item) { - let generics = ccx.tcx.lookup_generics(def_id); + let generics = ccx.tcx.item_generics(def_id); if let Some(ref attr) = item.attrs.iter().find(|a| { a.check_name("rustc_on_unimplemented") }) { @@ -1143,12 +1145,11 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let signature = |item: &ty::AssociatedItem| { match item.kind { ty::AssociatedKind::Method => { - format!("{}", tcx.lookup_item_type(item.def_id).ty.fn_sig().0) + format!("{}", tcx.item_type(item.def_id).fn_sig().0) } ty::AssociatedKind::Type => format!("type {};", item.name.to_string()), ty::AssociatedKind::Const => { - format!("const {}: {:?};", item.name.to_string(), - tcx.lookup_item_type(item.def_id).ty) + format!("const {}: {:?};", item.name.to_string(), tcx.item_type(item.def_id)) } } }; @@ -1218,7 +1219,7 @@ fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, fn check_const<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>, expr: &'tcx hir::Expr, id: ast::NodeId) { - let decl_ty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(id)).ty; + let decl_ty = ccx.tcx.item_type(ccx.tcx.map.local_def_id(id)); check_const_with_type(ccx, expr, decl_ty, id); } @@ -1227,9 +1228,9 @@ fn check_const<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>, /// pointer, which would mean their size is unbounded. fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, - item_id: ast::NodeId) + item_def_id: DefId) -> bool { - let rty = tcx.tables().node_id_to_type(item_id); + let rty = tcx.item_type(item_def_id); // Check that it is possible to represent this type. This call identifies // (1) types that contain themselves and (2) types that contain a different @@ -1238,7 +1239,6 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // caught by case 1. match rty.is_representable(tcx, sp) { Representability::SelfRecursive => { - let item_def_id = tcx.map.local_def_id(item_id); tcx.recursive_type_with_infinite_size_error(item_def_id).emit(); return false } @@ -1247,8 +1247,8 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return true } -pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, id: ast::NodeId) { - let t = tcx.tables().node_id_to_type(id); +pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId) { + let t = tcx.item_type(def_id); match t.sty { ty::TyAdt(def, substs) if def.is_struct() => { let fields = &def.struct_variant().fields; @@ -1328,7 +1328,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, disr_vals.push(current_disr_val); } - check_representable(ccx.tcx, sp, id); + check_representable(ccx.tcx, sp, def_id); } impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { @@ -1341,13 +1341,12 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { fn get_generics(&self, _: Span, id: DefId) -> Result<&'tcx ty::Generics<'tcx>, ErrorReported> { - Ok(self.tcx().lookup_generics(id)) + Ok(self.tcx().item_generics(id)) } - fn get_item_type_scheme(&self, _: Span, id: DefId) - -> Result, ErrorReported> + fn get_item_type(&self, _: Span, id: DefId) -> Result, ErrorReported> { - Ok(self.tcx().lookup_item_type(id)) + Ok(self.tcx().item_type(id)) } fn get_trait_def(&self, _: Span, id: DefId) @@ -1662,7 +1661,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// generic type scheme. fn instantiate_bounds(&self, span: Span, def_id: DefId, substs: &Substs<'tcx>) -> ty::InstantiatedPredicates<'tcx> { - let bounds = self.tcx.lookup_predicates(def_id); + let bounds = self.tcx.item_predicates(def_id); let result = bounds.instantiate(self.tcx, substs); let result = self.normalize_associated_types_in(span, &result.predicates); debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}", @@ -1687,7 +1686,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ty_var = self.next_ty_var(); self.anon_types.borrow_mut().insert(def_id, ty_var); - let item_predicates = self.tcx.lookup_predicates(def_id); + let item_predicates = self.tcx.item_predicates(def_id); let bounds = item_predicates.instantiate(self.tcx, substs); let span = self.tcx.map.def_id_span(def_id, codemap::DUMMY_SP); @@ -2742,11 +2741,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { span: Span, // (potential) receiver for this impl did: DefId) -> TypeAndSubsts<'tcx> { - let ity = self.tcx.lookup_item_type(did); + let ity = self.tcx.item_type(did); debug!("impl_self_ty: ity={:?}", ity); let substs = self.fresh_substs_for_item(span, did); - let substd_ty = self.instantiate_type_scheme(span, &substs, &ity.ty); + let substd_ty = self.instantiate_type_scheme(span, &substs, &ity); TypeAndSubsts { substs: substs, ty: substd_ty } } @@ -4184,11 +4183,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Def::VariantCtor(def_id, ..) => { // Everything but the final segment should have no // parameters at all. - let mut generics = self.tcx.lookup_generics(def_id); + let mut generics = self.tcx.item_generics(def_id); if let Some(def_id) = generics.parent { // Variant and struct constructors use the // generics of their parent type definition. - generics = self.tcx.lookup_generics(def_id); + generics = self.tcx.item_generics(def_id); } type_segment = Some((segments.last().unwrap(), generics)); } @@ -4198,7 +4197,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Def::Const(def_id) | Def::Static(def_id, _) => { fn_segment = Some((segments.last().unwrap(), - self.tcx.lookup_generics(def_id))); + self.tcx.item_generics(def_id))); } // Case 3. Reference to a method or associated const. @@ -4212,9 +4211,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty::ImplContainer(_) => {} } - let generics = self.tcx.lookup_generics(def_id); + let generics = self.tcx.item_generics(def_id); if segments.len() >= 2 { - let parent_generics = self.tcx.lookup_generics(generics.parent.unwrap()); + let parent_generics = self.tcx.item_generics(generics.parent.unwrap()); type_segment = Some((&segments[segments.len() - 2], parent_generics)); } else { // `::assoc` will end up here, and so can `T::assoc`. @@ -4344,9 +4343,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // The things we are substituting into the type should not contain // escaping late-bound regions, and nor should the base type scheme. - let scheme = self.tcx.lookup_item_type(def.def_id()); + let ty = self.tcx.item_type(def.def_id()); assert!(!substs.has_escaping_regions()); - assert!(!scheme.ty.has_escaping_regions()); + assert!(!ty.has_escaping_regions()); // Add all the obligations that are required, substituting and // normalized appropriately. @@ -4357,16 +4356,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Substitute the values for the type parameters into the type of // the referenced item. - let ty_substituted = self.instantiate_type_scheme(span, &substs, &scheme.ty); + let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty); if let Some((ty::ImplContainer(impl_def_id), self_ty)) = ufcs_associated { // In the case of `Foo::method` and `>::method`, if `method` // is inherent, there is no `Self` parameter, instead, the impl needs // type parameters, which we can infer by unifying the provided `Self` // with the substituted impl type. - let impl_scheme = self.tcx.lookup_item_type(impl_def_id); + let ty = self.tcx.item_type(impl_def_id); - let impl_ty = self.instantiate_type_scheme(span, &substs, &impl_scheme.ty); + let impl_ty = self.instantiate_type_scheme(span, &substs, &ty); match self.sub_types(false, TypeOrigin::Misc(span), self_ty, impl_ty) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index d4e5e9a5bb35..e39d6ae7083b 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1729,7 +1729,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // ``` // // we can thus deduce that `>::SomeType : 'a`. - let trait_predicates = self.tcx.lookup_predicates(projection_ty.trait_ref.def_id); + let trait_predicates = self.tcx.item_predicates(projection_ty.trait_ref.def_id); assert_eq!(trait_predicates.parent, None); let predicates = trait_predicates.predicates.as_slice().to_vec(); traits::elaborate_predicates(self.tcx, predicates) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 4136f543ccca..066b3d4be088 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -179,18 +179,18 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let (mut implied_bounds, self_ty) = match item.container { ty::TraitContainer(_) => (vec![], fcx.tcx.mk_self_type()), ty::ImplContainer(def_id) => (fcx.impl_implied_bounds(def_id, span), - fcx.tcx.lookup_item_type(def_id).ty) + fcx.tcx.item_type(def_id)) }; match item.kind { ty::AssociatedKind::Const => { - let ty = fcx.tcx.lookup_item_type(item.def_id).ty; + let ty = fcx.tcx.item_type(item.def_id); let ty = fcx.instantiate_type_scheme(span, free_substs, &ty); fcx.register_wf_obligation(ty, span, code.clone()); } ty::AssociatedKind::Method => { reject_shadowing_type_parameters(fcx.tcx, span, item.def_id); - let method_ty = fcx.tcx.lookup_item_type(item.def_id).ty; + let method_ty = fcx.tcx.item_type(item.def_id); let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method_ty); let predicates = fcx.instantiate_bounds(span, item.def_id, free_substs); let fty = match method_ty.sty { @@ -205,7 +205,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } ty::AssociatedKind::Type => { if item.has_value { - let ty = fcx.tcx.lookup_item_type(item.def_id).ty; + let ty = fcx.tcx.item_type(item.def_id); let ty = fcx.instantiate_type_scheme(span, free_substs, &ty); fcx.register_wf_obligation(ty, span, code.clone()); } @@ -276,7 +276,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { // // 3) that the trait definition does not have any type parameters - let predicates = self.tcx().lookup_predicates(trait_def_id); + let predicates = self.tcx().item_predicates(trait_def_id); // We must exclude the Self : Trait predicate contained by all // traits. @@ -353,8 +353,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { self.for_item(item).with_fcx(|fcx, this| { let free_substs = &fcx.parameter_environment.free_substs; let def_id = fcx.tcx.map.local_def_id(item.id); - let type_scheme = fcx.tcx.lookup_item_type(def_id); - let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &type_scheme.ty); + let ty = fcx.tcx.item_type(def_id); + let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &ty); let bare_fn_ty = match item_ty.sty { ty::TyFnDef(.., ref bare_fn_ty) => bare_fn_ty, _ => { @@ -378,11 +378,11 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { debug!("check_item_type: {:?}", item); self.for_item(item).with_fcx(|fcx, this| { - let type_scheme = fcx.tcx.lookup_item_type(fcx.tcx.map.local_def_id(item.id)); + let ty = fcx.tcx.item_type(fcx.tcx.map.local_def_id(item.id)); let item_ty = fcx.instantiate_type_scheme(item.span, &fcx.parameter_environment .free_substs, - &type_scheme.ty); + &ty); fcx.register_wf_obligation(item_ty, item.span, this.code.clone()); @@ -417,7 +417,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } } None => { - let self_ty = fcx.tcx.tables().node_id_to_type(item.id); + let self_ty = fcx.tcx.item_type(item_def_id); let self_ty = fcx.instantiate_type_scheme(item.span, free_substs, &self_ty); fcx.register_wf_obligation(self_ty, ast_self_ty.span, this.code.clone()); } @@ -426,7 +426,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let predicates = fcx.instantiate_bounds(item.span, item_def_id, free_substs); this.check_where_clauses(fcx, item.span, &predicates); - fcx.impl_implied_bounds(fcx.tcx.map.local_def_id(item.id), item.span) + fcx.impl_implied_bounds(item_def_id, item.span) }); } @@ -492,7 +492,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let span = method_sig.decl.inputs[0].pat.span; let free_substs = &fcx.parameter_environment.free_substs; - let method_ty = fcx.tcx.lookup_item_type(method.def_id).ty; + let method_ty = fcx.tcx.item_type(method.def_id); let fty = fcx.instantiate_type_scheme(span, free_substs, &method_ty); let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.fn_sig()); @@ -523,13 +523,13 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { item: &hir::Item, ast_generics: &hir::Generics) { - let ty = self.tcx().tables().node_id_to_type(item.id); + let item_def_id = self.tcx().map.local_def_id(item.id); + let ty = self.tcx().item_type(item_def_id); if self.tcx().has_error_field(ty) { return; } - let item_def_id = self.tcx().map.local_def_id(item.id); - let ty_predicates = self.tcx().lookup_predicates(item_def_id); + let ty_predicates = self.tcx().item_predicates(item_def_id); assert_eq!(ty_predicates.parent, None); let variances = self.tcx().item_variances(item_def_id); @@ -583,8 +583,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } fn reject_shadowing_type_parameters(tcx: TyCtxt, span: Span, def_id: DefId) { - let generics = tcx.lookup_generics(def_id); - let parent = tcx.lookup_generics(generics.parent.unwrap()); + let generics = tcx.item_generics(def_id); + let parent = tcx.item_generics(generics.parent.unwrap()); let impl_params: FxHashMap<_, _> = parent.types .iter() .map(|tp| (tp.name, tp.def_id)) @@ -654,7 +654,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let fields = struct_def.fields().iter() .map(|field| { - let field_ty = self.tcx.tables().node_id_to_type(field.id); + let field_ty = self.tcx.item_type(self.tcx.map.local_def_id(field.id)); let field_ty = self.instantiate_type_scheme(field.span, &self.parameter_environment .free_substs, @@ -683,7 +683,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None => { // Inherent impl: take implied bounds from the self type. - let self_ty = self.tcx.lookup_item_type(impl_def_id).ty; + let self_ty = self.tcx.item_type(impl_def_id); let self_ty = self.instantiate_type_scheme(span, free_substs, &self_ty); vec![self_ty] } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 9f3214a0d813..979ce82ff4ec 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -20,8 +20,6 @@ use rustc::ty::adjustment; use rustc::ty::fold::{TypeFolder,TypeFoldable}; use rustc::infer::{InferCtxt, FixupError}; use rustc::util::nodemap::DefIdMap; -use write_substs_to_tcx; -use write_ty_to_tcx; use std::cell::Cell; @@ -67,7 +65,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { wbcx.visit_closures(); wbcx.visit_liberated_fn_sigs(); wbcx.visit_fru_field_types(); - wbcx.visit_anon_types(item_id); + wbcx.visit_anon_types(); wbcx.visit_deferred_obligations(item_id); } } @@ -133,6 +131,12 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { self.fcx.tcx } + fn write_ty_to_tcx(&self, node_id: ast::NodeId, ty: Ty<'gcx>) { + debug!("write_ty_to_tcx({}, {:?})", node_id, ty); + assert!(!ty.needs_infer()); + self.tcx().tables.borrow_mut().node_types.insert(node_id, ty); + } + // Hacky hack: During type-checking, we treat *all* operators // as potentially overloaded. But then, during writeback, if // we observe that something like `a+b` is (known to be) @@ -241,7 +245,7 @@ impl<'cx, 'gcx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'gcx, 'tcx> { let var_ty = self.fcx.local_ty(l.span, l.id); let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span)); - write_ty_to_tcx(self.fcx.ccx, l.id, var_ty); + self.write_ty_to_tcx(l.id, var_ty); intravisit::walk_local(self, l); } @@ -249,7 +253,7 @@ impl<'cx, 'gcx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'gcx, 'tcx> { match t.node { hir::TyArray(ref ty, ref count_expr) => { self.visit_ty(&ty); - write_ty_to_tcx(self.fcx.ccx, count_expr.id, self.tcx().types.usize); + self.write_ty_to_tcx(count_expr.id, self.tcx().types.usize); } hir::TyBareFn(ref function_declaration) => { intravisit::walk_fn_decl_nopat(self, &function_declaration.decl); @@ -302,13 +306,11 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } - fn visit_anon_types(&self, item_id: ast::NodeId) { + fn visit_anon_types(&self) { if self.fcx.writeback_errors.get() { return } - let item_def_id = self.fcx.tcx.map.local_def_id(item_id); - let gcx = self.tcx().global_tcx(); for (&def_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() { let reason = ResolvingAnonTy(def_id); @@ -349,10 +351,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } }); - gcx.register_item_type(def_id, ty::TypeScheme { - ty: outside_ty, - generics: gcx.lookup_generics(item_def_id) - }); + gcx.item_types.borrow_mut().insert(def_id, outside_ty); } } @@ -363,13 +362,17 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { // Resolve the type of the node with id `id` let n_ty = self.fcx.node_ty(id); let n_ty = self.resolve(&n_ty, reason); - write_ty_to_tcx(self.fcx.ccx, id, n_ty); + self.write_ty_to_tcx(id, n_ty); debug!("Node {} has type {:?}", id, n_ty); // Resolve any substitutions self.fcx.opt_node_ty_substs(id, |item_substs| { - write_substs_to_tcx(self.fcx.ccx, id, - self.resolve(item_substs, reason)); + let item_substs = self.resolve(item_substs, reason); + if !item_substs.is_noop() { + debug!("write_substs_to_tcx({}, {:?})", id, item_substs); + assert!(!item_substs.substs.needs_infer()); + self.tcx().tables.borrow_mut().item_substs.insert(id, item_substs); + } }); } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 90541539c1e2..586330582646 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -106,7 +106,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { fn check_implementation(&self, item: &Item) { let tcx = self.crate_context.tcx; let impl_did = tcx.map.local_def_id(item.id); - let self_type = tcx.lookup_item_type(impl_did); + let self_type = tcx.item_type(impl_did); // If there are no traits, then this implementation must have a // base type. @@ -129,14 +129,14 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { } else { // Skip inherent impls where the self type is an error // type. This occurs with e.g. resolve failures (#30589). - if self_type.ty.references_error() { + if self_type.references_error() { return; } // Add the implementation to the mapping from implementation to base // type def ID, if there is a base type for this implementation and // the implementation does not have any associated traits. - if let Some(base_def_id) = self.get_base_type_def_id(item.span, self_type.ty) { + if let Some(base_def_id) = self.get_base_type_def_id(item.span, self_type) { self.add_inherent_impl(base_def_id, impl_did); } } @@ -175,8 +175,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { } let method_def_id = items[0]; - let self_type = tcx.lookup_item_type(impl_did); - match self_type.ty.sty { + let self_type = tcx.item_type(impl_did); + match self_type.sty { ty::TyAdt(type_def, _) => { type_def.set_destructor(method_def_id); } @@ -232,13 +232,13 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { return; }; - let self_type = tcx.lookup_item_type(impl_did); + let self_type = tcx.item_type(impl_did); debug!("check_implementations_of_copy: self_type={:?} (bound)", self_type); let span = tcx.map.span(impl_node_id); let param_env = ParameterEnvironment::for_item(tcx, impl_node_id); - let self_type = self_type.ty.subst(tcx, ¶m_env.free_substs); + let self_type = self_type.subst(tcx, ¶m_env.free_substs); assert!(!self_type.has_escaping_regions()); debug!("check_implementations_of_copy: self_type={:?} (free)", @@ -326,7 +326,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { return; }; - let source = tcx.lookup_item_type(impl_did).ty; + let source = tcx.item_type(impl_did); let trait_ref = self.crate_context.tcx.impl_trait_ref(impl_did).unwrap(); let target = trait_ref.substs.type_at(1); debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)", diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index bff794364c09..371c182030e2 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -81,7 +81,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { // defined in this crate. debug!("coherence2::orphan check: inherent impl {}", self.tcx.map.node_to_string(item.id)); - let self_ty = self.tcx.lookup_item_type(def_id).ty; + let self_ty = self.tcx.item_type(def_id); match self_ty.sty { ty::TyAdt(def, _) => { self.check_def_id(item, def.did); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d92a98485103..968d5d73e7a8 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -13,7 +13,7 @@ # Collect phase The collect phase of type check has the job of visiting all items, -determining their type, and writing that type into the `tcx.tcache` +determining their type, and writing that type into the `tcx.types` table. Despite its name, this table does not really operate as a *cache*, at least not for the types of items defined within the current crate: we assume that after the collect phase, the types of @@ -22,8 +22,7 @@ all local items will be present in the table. Unlike most of the types that are present in Rust, the types computed for each item are in fact type schemes. This means that they are generic types that may have type parameters. TypeSchemes are -represented by an instance of `ty::TypeScheme`. This combines the -core type along with a list of the bounds for each parameter. Type +represented by a pair of `Generics` and `Ty`. Type parameters themselves are represented as `ty_param()` instances. The phasing of type conversion is somewhat complicated. There is no @@ -51,8 +50,8 @@ There are some shortcomings in this design: - Before walking the set of supertraits for a given trait, you must call `ensure_super_predicates` on that trait def-id. Otherwise, - `lookup_super_predicates` will result in ICEs. -- Because the type scheme includes defaults, cycles through type + `item_super_predicates` will result in ICEs. +- Because the item generics include defaults, cycles through type parameter defaults are illegal even if those defaults are never employed. This is not necessarily a bug. @@ -67,13 +66,13 @@ use rustc_const_eval::EvalHint::UncheckedExprHint; use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err}; use rustc::ty::subst::Substs; use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer}; -use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; +use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::util::IntTypeExt; use rscope::*; use rustc::dep_graph::DepNode; use util::common::{ErrorReported, MemoizationMap}; use util::nodemap::{NodeMap, FxHashMap, FxHashSet}; -use {CrateCtxt, write_ty_to_tcx}; +use CrateCtxt; use rustc_const_math::ConstInt; @@ -132,6 +131,15 @@ struct CollectItemTypesVisitor<'a, 'tcx: 'a> { impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { convert_item(self.ccx, item); + intravisit::walk_item(self, item); + } + + fn visit_ty(&mut self, ty: &hir::Ty) { + if let hir::TyImplTrait(..) = ty.node { + let def_id = self.ccx.tcx.map.local_def_id(ty.id); + generics_of_def_id(self.ccx, def_id); + } + intravisit::walk_ty(self, ty); } } @@ -308,11 +316,9 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { }) } - fn get_item_type_scheme(&self, span: Span, id: DefId) - -> Result, ErrorReported> - { + fn get_item_type(&self, span: Span, id: DefId) -> Result, ErrorReported> { self.ccx.cycle_check(span, AstConvRequest::GetItemTypeScheme(id), || { - Ok(type_scheme_of_def_id(self.ccx, id)) + Ok(type_of_def_id(self.ccx, id)) }) } @@ -447,7 +453,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> { let def = astconv.tcx().type_parameter_def(node_id); let mut results = self.parent.map_or(vec![], |def_id| { - let parent = astconv.tcx().lookup_predicates(def_id); + let parent = astconv.tcx().item_predicates(def_id); parent.get_type_parameter_bounds(astconv, span, node_id) }); @@ -546,16 +552,11 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, { let tt = ccx.icx(struct_predicates).to_ty(&ExplicitRscope, &field.ty); ty_f.fulfill_ty(tt); - write_ty_to_tcx(ccx, field.id, tt); - /* add the field to the tcache */ - ccx.tcx.register_item_type(ccx.tcx.map.local_def_id(field.id), - ty::TypeScheme { - generics: struct_generics, - ty: tt - }); - ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(field.id), - struct_predicates.clone()); + let def_id = ccx.tcx.map.local_def_id(field.id); + ccx.tcx.item_types.borrow_mut().insert(def_id, tt); + ccx.tcx.generics.borrow_mut().insert(def_id, struct_generics); + ccx.tcx.predicates.borrow_mut().insert(def_id, struct_predicates.clone()); } fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, @@ -580,8 +581,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), ccx.tcx.map.span(id), def_id); let fty = ccx.tcx.mk_fn_def(def_id, substs, fty); - ccx.tcx.tcache.borrow_mut().insert(def_id, fty); - write_ty_to_tcx(ccx, id, fty); + ccx.tcx.item_types.borrow_mut().insert(def_id, fty); ccx.tcx.predicates.borrow_mut().insert(def_id, ty_generic_predicates); } @@ -596,9 +596,7 @@ fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }; let def_id = ccx.tcx.map.local_def_id(id); ccx.tcx.predicates.borrow_mut().insert(def_id, predicates); - ccx.tcx.tcache.borrow_mut().insert(def_id, ty); - - write_ty_to_tcx(ccx, id, ty); + ccx.tcx.item_types.borrow_mut().insert(def_id, ty); } fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, @@ -614,8 +612,7 @@ fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ccx.tcx.predicates.borrow_mut().insert(def_id, predicates); if let Some(ty) = ty { - ccx.tcx.tcache.borrow_mut().insert(def_id, ty); - write_ty_to_tcx(ccx, id, ty); + ccx.tcx.item_types.borrow_mut().insert(def_id, ty); } } @@ -662,11 +659,13 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } hir::ItemEnum(ref enum_definition, _) => { let def_id = ccx.tcx.map.local_def_id(it.id); - let scheme = type_scheme_of_def_id(ccx, def_id); + let ty = type_of_def_id(ccx, def_id); + let generics = generics_of_def_id(ccx, def_id); let predicates = predicates_of_item(ccx, it); convert_enum_variant_types(ccx, tcx.lookup_adt_def_master(ccx.tcx.map.local_def_id(it.id)), - scheme, + ty, + generics, predicates, &enum_definition.variants); }, @@ -690,18 +689,15 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { // Create generics from the generics specified in the impl head. debug!("convert: ast_generics={:?}", generics); let def_id = ccx.tcx.map.local_def_id(it.id); - let ty_generics = generics_of_def_id(ccx, def_id); + generics_of_def_id(ccx, def_id); let mut ty_predicates = ty_generic_predicates(ccx, generics, None, vec![], false); debug!("convert: impl_bounds={:?}", ty_predicates); let selfty = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, &selfty); - write_ty_to_tcx(ccx, it.id, selfty); + tcx.item_types.borrow_mut().insert(def_id, selfty); - tcx.register_item_type(def_id, - TypeScheme { generics: ty_generics, - ty: selfty }); let trait_ref = opt_trait_ref.as_ref().map(|ast_trait_ref| { AstConv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates), &ExplicitRscope, @@ -742,14 +738,10 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { if let hir::ImplItemKind::Const(ref ty, _) = impl_item.node { let const_def_id = ccx.tcx.map.local_def_id(impl_item.id); - let ty_generics = generics_of_def_id(ccx, const_def_id); + generics_of_def_id(ccx, const_def_id); let ty = ccx.icx(&ty_predicates) .to_ty(&ExplicitRscope, &ty); - tcx.register_item_type(const_def_id, - TypeScheme { - generics: ty_generics, - ty: ty, - }); + tcx.item_types.borrow_mut().insert(const_def_id, ty); convert_associated_const(ccx, ImplContainer(def_id), impl_item.id, ty); } @@ -788,7 +780,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { let _: Result<(), ErrorReported> = // any error is already reported, can ignore ccx.ensure_super_predicates(it.span, def_id); convert_trait_predicates(ccx, it); - let trait_predicates = tcx.lookup_predicates(def_id); + let trait_predicates = tcx.item_predicates(def_id); debug!("convert: trait_bounds={:?}", trait_predicates); @@ -799,14 +791,10 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { for trait_item in trait_items { if let hir::ConstTraitItem(ref ty, _) = trait_item.node { let const_def_id = ccx.tcx.map.local_def_id(trait_item.id); - let ty_generics = generics_of_def_id(ccx, const_def_id); + generics_of_def_id(ccx, const_def_id); let ty = ccx.icx(&trait_predicates) .to_ty(&ExplicitRscope, ty); - tcx.register_item_type(const_def_id, - TypeScheme { - generics: ty_generics, - ty: ty, - }); + tcx.item_types.borrow_mut().insert(const_def_id, ty); convert_associated_const(ccx, container, trait_item.id, ty) } } @@ -840,28 +828,31 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { hir::ItemStruct(ref struct_def, _) | hir::ItemUnion(ref struct_def, _) => { let def_id = ccx.tcx.map.local_def_id(it.id); - let scheme = type_scheme_of_def_id(ccx, def_id); + let ty = type_of_def_id(ccx, def_id); + let generics = generics_of_def_id(ccx, def_id); let predicates = predicates_of_item(ccx, it); let variant = tcx.lookup_adt_def_master(def_id).struct_variant(); for (f, ty_f) in struct_def.fields().iter().zip(variant.fields.iter()) { - convert_field(ccx, &scheme.generics, &predicates, f, ty_f) + convert_field(ccx, generics, &predicates, f, ty_f) } if !struct_def.is_struct() { - convert_variant_ctor(ccx, struct_def.id(), variant, scheme, predicates); + convert_variant_ctor(ccx, struct_def.id(), variant, ty, predicates); } }, hir::ItemTy(_, ref generics) => { ensure_no_ty_param_bounds(ccx, it.span, generics, "type"); let def_id = ccx.tcx.map.local_def_id(it.id); - type_scheme_of_def_id(ccx, def_id); + type_of_def_id(ccx, def_id); + generics_of_def_id(ccx, def_id); predicates_of_item(ccx, it); }, _ => { let def_id = ccx.tcx.map.local_def_id(it.id); - type_scheme_of_def_id(ccx, def_id); + type_of_def_id(ccx, def_id); + generics_of_def_id(ccx, def_id); predicates_of_item(ccx, it); }, } @@ -870,13 +861,13 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ctor_id: ast::NodeId, variant: ty::VariantDef<'tcx>, - scheme: ty::TypeScheme<'tcx>, + ty: Ty<'tcx>, predicates: ty::GenericPredicates<'tcx>) { let tcx = ccx.tcx; let def_id = tcx.map.local_def_id(ctor_id); generics_of_def_id(ccx, def_id); let ctor_ty = match variant.ctor_kind { - CtorKind::Fictive | CtorKind::Const => scheme.ty, + CtorKind::Fictive | CtorKind::Const => ty, CtorKind::Fn => { let inputs: Vec<_> = variant.fields @@ -890,26 +881,26 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, abi: abi::Abi::Rust, sig: ty::Binder(ty::FnSig { inputs: inputs, - output: scheme.ty, + output: ty, variadic: false }) })) } }; - write_ty_to_tcx(ccx, ctor_id, ctor_ty); - tcx.tcache.borrow_mut().insert(def_id, ctor_ty); + tcx.item_types.borrow_mut().insert(def_id, ctor_ty); tcx.predicates.borrow_mut().insert(tcx.map.local_def_id(ctor_id), predicates); } fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, def: ty::AdtDefMaster<'tcx>, - scheme: ty::TypeScheme<'tcx>, + ty: Ty<'tcx>, + generics: &'tcx ty::Generics<'tcx>, predicates: ty::GenericPredicates<'tcx>, variants: &[hir::Variant]) { // fill the field types for (variant, ty_variant) in variants.iter().zip(def.variants.iter()) { for (f, ty_f) in variant.node.data.fields().iter().zip(ty_variant.fields.iter()) { - convert_field(ccx, &scheme.generics, &predicates, f, ty_f) + convert_field(ccx, generics, &predicates, f, ty_f) } // Convert the ctor, if any. This also registers the variant as @@ -918,7 +909,7 @@ fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ccx, variant.node.data.id(), ty_variant, - scheme.clone(), + ty, predicates.clone() ); } @@ -1216,7 +1207,7 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) } }; - let super_predicates = ccx.tcx.lookup_super_predicates(def_id); + let super_predicates = ccx.tcx.item_super_predicates(def_id); // `ty_generic_predicates` below will consider the bounds on the type // parameters (including `Self`) and the explicit where-clauses, @@ -1283,7 +1274,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let node_id = if let Some(id) = tcx.map.as_local_node_id(def_id) { id } else { - return tcx.lookup_generics(def_id); + return tcx.item_generics(def_id); }; tcx.generics.memoize(def_id, || { use rustc::hir::map::*; @@ -1298,6 +1289,18 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let parent_id = tcx.map.get_parent(node_id); Some(tcx.map.local_def_id(parent_id)) } + NodeTy(&hir::Ty { node: hir::TyImplTrait(..), .. }) => { + let mut parent_id = node_id; + loop { + match tcx.map.get(parent_id) { + NodeItem(_) | NodeImplItem(_) | NodeTraitItem(_) => break, + _ => { + parent_id = tcx.map.get_parent_node(parent_id); + } + } + } + Some(tcx.map.local_def_id(parent_id)) + } _ => None }; @@ -1377,13 +1380,11 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let mut own_start = has_self as u32; let (parent_regions, parent_types) = parent_def_id.map_or((0, 0), |def_id| { let generics = generics_of_def_id(ccx, def_id); - assert_eq!(generics.parent, None); - assert_eq!(generics.parent_regions, 0); - assert_eq!(generics.parent_types, 0); assert_eq!(has_self, false); parent_has_self = generics.has_self; own_start = generics.count() as u32; - (generics.regions.len() as u32, generics.types.len() as u32) + (generics.parent_regions + generics.regions.len() as u32, + generics.parent_types + generics.types.len() as u32) }); let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics); @@ -1436,12 +1437,15 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let node_id = if let Some(id) = ccx.tcx.map.as_local_node_id(def_id) { id } else { - return ccx.tcx.lookup_item_type(def_id).ty; + return ccx.tcx.item_type(def_id); }; - ccx.tcx.tcache.memoize(def_id, || { + ccx.tcx.item_types.memoize(def_id, || { use rustc::hir::map::*; use rustc::hir::*; + // Alway bring in generics, as computing the type needs them. + generics_of_def_id(ccx, def_id); + let ty = match ccx.tcx.map.get(node_id) { NodeItem(item) => { match item.node { @@ -1505,24 +1509,10 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } }; - write_ty_to_tcx(ccx, node_id, ty); ty }) } -fn type_scheme_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>, - def_id: DefId) - -> ty::TypeScheme<'tcx> { - if def_id.is_local() { - ty::TypeScheme { - generics: generics_of_def_id(ccx, def_id), - ty: type_of_def_id(ccx, def_id) - } - } else { - ccx.tcx.lookup_item_type(def_id) - } -} - fn predicates_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) -> ty::GenericPredicates<'tcx> { @@ -1554,7 +1544,8 @@ fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // moral failing, but at the moment it seems like the only // convenient way to extract the ABI. - ndm let def_id = ccx.tcx.map.local_def_id(it.id); - type_scheme_of_def_id(ccx, def_id); + type_of_def_id(ccx, def_id); + generics_of_def_id(ccx, def_id); let no_generics = hir::Generics::empty(); let generics = match it.node { @@ -1648,7 +1639,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let ref base_predicates = match parent { Some(def_id) => { assert_eq!(super_predicates, vec![]); - tcx.lookup_predicates(def_id) + tcx.item_predicates(def_id) } None => { ty::GenericPredicates { @@ -2035,14 +2026,14 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_predicates: &mut ty::GenericPredicates<'tcx>, impl_def_id: DefId) { - let impl_scheme = ccx.tcx.lookup_item_type(impl_def_id); + let impl_ty = ccx.tcx.item_type(impl_def_id); let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id); // The trait reference is an input, so find all type parameters // reachable from there, to start (if this is an inherent impl, // then just examine the self type). let mut input_parameters: FxHashSet<_> = - ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect(); + ctp::parameters_for(&impl_ty, false).into_iter().collect(); if let Some(ref trait_ref) = impl_trait_ref { input_parameters.extend(ctp::parameters_for(trait_ref, false)); } @@ -2066,12 +2057,12 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_items: &[hir::ImplItem]) { // Every lifetime used in an associated type must be constrained. - let impl_scheme = ccx.tcx.lookup_item_type(impl_def_id); - let impl_predicates = ccx.tcx.lookup_predicates(impl_def_id); + let impl_ty = ccx.tcx.item_type(impl_def_id); + let impl_predicates = ccx.tcx.item_predicates(impl_def_id); let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id); let mut input_parameters: FxHashSet<_> = - ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect(); + ctp::parameters_for(&impl_ty, false).into_iter().collect(); if let Some(ref trait_ref) = impl_trait_ref { input_parameters.extend(ctp::parameters_for(trait_ref, false)); } @@ -2085,10 +2076,10 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, item.kind == ty::AssociatedKind::Type && item.has_value }) .flat_map(|def_id| { - ctp::parameters_for(&ccx.tcx.lookup_item_type(def_id).ty, true) + ctp::parameters_for(&ccx.tcx.item_type(def_id), true) }).collect(); - for (ty_lifetime, lifetime) in impl_scheme.generics.regions.iter() + for (ty_lifetime, lifetime) in ccx.tcx.item_generics(impl_def_id).regions.iter() .zip(&ast_generics.lifetimes) { let param = ctp::Parameter::from(ty_lifetime.to_early_bound_region_data()); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index d7573c7a7bd2..2c12959dbdde 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -44,7 +44,7 @@ independently: into the `ty` representation - collect: computes the types of each top-level item and enters them into - the `cx.tcache` table for later use + the `tcx.types` table for later use - coherence: enforces coherence rules, builds some tables @@ -108,7 +108,7 @@ use dep_graph::DepNode; use hir::map as hir_map; use rustc::infer::{InferOk, TypeOrigin}; use rustc::ty::subst::Substs; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::traits::{self, Reveal}; use session::{config, CompileResult}; use util::common::time; @@ -159,27 +159,6 @@ pub struct CrateCtxt<'a, 'tcx: 'a> { pub deferred_obligations: RefCell>>>, } -// Functions that write types into the node type table -fn write_ty_to_tcx<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, node_id: ast::NodeId, ty: Ty<'tcx>) { - debug!("write_ty_to_tcx({}, {:?})", node_id, ty); - assert!(!ty.needs_infer()); - ccx.tcx.node_type_insert(node_id, ty); -} - -fn write_substs_to_tcx<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - node_id: ast::NodeId, - item_substs: ty::ItemSubsts<'tcx>) { - if !item_substs.is_noop() { - debug!("write_substs_to_tcx({}, {:?})", - node_id, - item_substs); - - assert!(!item_substs.substs.needs_infer()); - - ccx.tcx.tables.borrow_mut().item_substs.insert(node_id, item_substs); - } -} - fn require_c_abi_if_variadic(tcx: TyCtxt, decl: &hir::FnDecl, abi: Abi, @@ -216,7 +195,8 @@ fn check_main_fn_ty(ccx: &CrateCtxt, main_id: ast::NodeId, main_span: Span) { let tcx = ccx.tcx; - let main_t = tcx.tables().node_id_to_type(main_id); + let main_def_id = tcx.map.local_def_id(main_id); + let main_t = tcx.item_type(main_def_id); match main_t.sty { ty::TyFnDef(..) => { match tcx.map.find(main_id) { @@ -237,7 +217,6 @@ fn check_main_fn_ty(ccx: &CrateCtxt, } _ => () } - let main_def_id = tcx.map.local_def_id(main_id); let substs = tcx.intern_substs(&[]); let se_ty = tcx.mk_fn_def(main_def_id, substs, tcx.mk_bare_fn(ty::BareFnTy { @@ -268,7 +247,8 @@ fn check_start_fn_ty(ccx: &CrateCtxt, start_id: ast::NodeId, start_span: Span) { let tcx = ccx.tcx; - let start_t = tcx.tables().node_id_to_type(start_id); + let start_def_id = ccx.tcx.map.local_def_id(start_id); + let start_t = tcx.item_type(start_def_id); match start_t.sty { ty::TyFnDef(..) => { match tcx.map.find(start_id) { @@ -289,7 +269,6 @@ fn check_start_fn_ty(ccx: &CrateCtxt, _ => () } - let start_def_id = ccx.tcx.map.local_def_id(start_id); let substs = tcx.intern_substs(&[]); let se_ty = tcx.mk_fn_def(start_def_id, substs, tcx.mk_bare_fn(ty::BareFnTy { diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index c9e93a1a46d6..10fca644ec16 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -82,16 +82,16 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> { hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => { - let scheme = tcx.lookup_item_type(did); + let generics = tcx.item_generics(did); // Not entirely obvious: constraints on structs/enums do not // affect the variance of their type parameters. See discussion // in comment at top of module. // - // self.add_constraints_from_generics(&scheme.generics); + // self.add_constraints_from_generics(generics); for field in tcx.lookup_adt_def(did).all_fields() { - self.add_constraints_from_ty(&scheme.generics, + self.add_constraints_from_ty(generics, field.unsubst_ty(), self.covariant); } @@ -336,7 +336,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::TyAdt(def, substs) => { - let item_type = self.tcx().lookup_item_type(def.did); + let adt_generics = self.tcx().item_generics(def.did); // This edge is actually implied by the call to // `lookup_trait_def`, but I'm trying to be future-proof. See @@ -345,8 +345,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_substs(generics, def.did, - &item_type.generics.types, - &item_type.generics.regions, + &adt_generics.types, + &adt_generics.regions, substs, variance); } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index a2955169cbb8..e8367bca2ef2 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -164,7 +164,7 @@ pub fn build_external_trait<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tc did: DefId) -> clean::Trait { let def = tcx.lookup_trait_def(did); let trait_items = tcx.associated_items(did).map(|item| item.clean(cx)).collect(); - let predicates = tcx.lookup_predicates(did); + let predicates = tcx.item_predicates(did); let generics = (def.generics, &predicates).clean(cx); let generics = filter_non_trait_generics(did, generics); let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); @@ -178,8 +178,8 @@ pub fn build_external_trait<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tc fn build_external_function<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> clean::Function { - let t = tcx.lookup_item_type(did); - let (decl, style, abi) = match t.ty.sty { + let ty = tcx.item_type(did); + let (decl, style, abi) = match ty.sty { ty::TyFnDef(.., ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi), _ => panic!("bad function"), }; @@ -190,10 +190,10 @@ fn build_external_function<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx hir::Constness::NotConst }; - let predicates = tcx.lookup_predicates(did); + let predicates = tcx.item_predicates(did); clean::Function { decl: decl, - generics: (t.generics, &predicates).clean(cx), + generics: (tcx.item_generics(did), &predicates).clean(cx), unsafety: style, constness: constness, abi: abi, @@ -202,11 +202,10 @@ fn build_external_function<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx fn build_enum<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> clean::Enum { - let t = tcx.lookup_item_type(did); - let predicates = tcx.lookup_predicates(did); + let predicates = tcx.item_predicates(did); clean::Enum { - generics: (t.generics, &predicates).clean(cx), + generics: (tcx.item_generics(did), &predicates).clean(cx), variants_stripped: false, variants: tcx.lookup_adt_def(did).variants.clean(cx), } @@ -214,8 +213,7 @@ fn build_enum<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> clean::Struct { - let t = tcx.lookup_item_type(did); - let predicates = tcx.lookup_predicates(did); + let predicates = tcx.item_predicates(did); let variant = tcx.lookup_adt_def(did).struct_variant(); clean::Struct { @@ -224,7 +222,7 @@ fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, CtorKind::Fn => doctree::Tuple, CtorKind::Const => doctree::Unit, }, - generics: (t.generics, &predicates).clean(cx), + generics: (tcx.item_generics(did), &predicates).clean(cx), fields: variant.fields.clean(cx), fields_stripped: false, } @@ -232,13 +230,12 @@ fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, fn build_union<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> clean::Union { - let t = tcx.lookup_item_type(did); - let predicates = tcx.lookup_predicates(did); + let predicates = tcx.item_predicates(did); let variant = tcx.lookup_adt_def(did).struct_variant(); clean::Union { struct_type: doctree::Plain, - generics: (t.generics, &predicates).clean(cx), + generics: (tcx.item_generics(did), &predicates).clean(cx), fields: variant.fields.clean(cx), fields_stripped: false, } @@ -246,12 +243,11 @@ fn build_union<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, fn build_type_alias<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> clean::Typedef { - let t = tcx.lookup_item_type(did); - let predicates = tcx.lookup_predicates(did); + let predicates = tcx.item_predicates(did); clean::Typedef { - type_: t.ty.clean(cx), - generics: (t.generics, &predicates).clean(cx), + type_: tcx.item_type(did).clean(cx), + generics: (tcx.item_generics(did), &predicates).clean(cx), } } @@ -354,8 +350,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, }); } - let ty = tcx.lookup_item_type(did); - let for_ = ty.ty.clean(cx); + let for_ = tcx.item_type(did).clean(cx); // Only inline impl if the implementing type is // reachable in rustdoc generated documentation @@ -365,11 +360,10 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, } } - let predicates = tcx.lookup_predicates(did); + let predicates = tcx.item_predicates(did); let trait_items = tcx.associated_items(did).filter_map(|item| { match item.kind { ty::AssociatedKind::Const => { - let type_scheme = tcx.lookup_item_type(item.def_id); let default = if item.has_value { Some(pprust::expr_to_string( lookup_const_by_id(tcx, item.def_id, None).unwrap().0)) @@ -379,7 +373,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, Some(clean::Item { name: Some(item.name.clean(cx)), inner: clean::AssociatedConstItem( - type_scheme.ty.clean(cx), + tcx.item_type(item.def_id).clean(cx), default, ), source: clean::Span::empty(), @@ -419,7 +413,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, } ty::AssociatedKind::Type => { let typedef = clean::Typedef { - type_: tcx.lookup_item_type(item.def_id).ty.clean(cx), + type_: tcx.item_type(item.def_id).clean(cx), generics: clean::Generics { lifetimes: vec![], type_params: vec![], @@ -463,7 +457,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, provided_trait_methods: provided, trait_: trait_, for_: for_, - generics: (ty.generics, &predicates).clean(cx), + generics: (tcx.item_generics(did), &predicates).clean(cx), items: trait_items, polarity: Some(polarity.clean(cx)), }), @@ -514,7 +508,7 @@ fn build_const<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("got snippet {}", sn); clean::Constant { - type_: ty.map(|t| t.clean(cx)).unwrap_or_else(|| tcx.lookup_item_type(did).ty.clean(cx)), + type_: ty.map(|t| t.clean(cx)).unwrap_or_else(|| tcx.item_type(did).clean(cx)), expr: sn } } @@ -523,7 +517,7 @@ fn build_static<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId, mutable: bool) -> clean::Static { clean::Static { - type_: tcx.lookup_item_type(did).ty.clean(cx), + type_: tcx.item_type(did).clean(cx), mutability: if mutable {clean::Mutable} else {clean::Immutable}, expr: "\n\n\n".to_string(), // trigger the "[definition]" links } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9e29d191946b..f4df28a14763 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1342,13 +1342,13 @@ impl<'tcx> Clean for ty::AssociatedItem { fn clean(&self, cx: &DocContext) -> Item { let inner = match self.kind { ty::AssociatedKind::Const => { - let ty = cx.tcx().lookup_item_type(self.def_id).ty; + let ty = cx.tcx().item_type(self.def_id); AssociatedConstItem(ty.clean(cx), None) } ty::AssociatedKind::Method => { - let generics = (cx.tcx().lookup_generics(self.def_id), - &cx.tcx().lookup_predicates(self.def_id)).clean(cx); - let fty = match cx.tcx().lookup_item_type(self.def_id).ty.sty { + let generics = (cx.tcx().item_generics(self.def_id), + &cx.tcx().item_predicates(self.def_id)).clean(cx); + let fty = match cx.tcx().item_type(self.def_id).sty { ty::TyFnDef(_, _, f) => f, _ => unreachable!() }; @@ -1357,7 +1357,7 @@ impl<'tcx> Clean for ty::AssociatedItem { if self.method_has_self_argument { let self_ty = match self.container { ty::ImplContainer(def_id) => { - cx.tcx().lookup_item_type(def_id).ty + cx.tcx().item_type(def_id) } ty::TraitContainer(_) => cx.tcx().mk_self_type() }; @@ -1405,7 +1405,7 @@ impl<'tcx> Clean for ty::AssociatedItem { // all of the generics from there and then look for bounds that are // applied to this associated type in question. let def = cx.tcx().lookup_trait_def(did); - let predicates = cx.tcx().lookup_predicates(did); + let predicates = cx.tcx().item_predicates(did); let generics = (def.generics, &predicates).clean(cx); generics.where_predicates.iter().filter_map(|pred| { let (name, self_type, trait_, bounds) = match *pred { @@ -1441,7 +1441,7 @@ impl<'tcx> Clean for ty::AssociatedItem { } let ty = if self.has_value { - Some(cx.tcx().lookup_item_type(self.def_id).ty) + Some(cx.tcx().item_type(self.def_id)) } else { None }; @@ -1901,7 +1901,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { ty::TyAnon(def_id, substs) => { // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the projections associated with the def_id. - let item_predicates = cx.tcx().lookup_predicates(def_id); + let item_predicates = cx.tcx().item_predicates(def_id); let substs = cx.tcx().lift(&substs).unwrap(); let bounds = item_predicates.instantiate(cx.tcx(), substs); ImplTrait(bounds.predicates.into_iter().filter_map(|predicate| { diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 15e042f8c080..19e084905aa9 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -153,7 +153,7 @@ fn trait_is_same_or_supertrait(cx: &DocContext, child: DefId, if child == trait_ { return true } - let predicates = cx.tcx().lookup_super_predicates(child).predicates; + let predicates = cx.tcx().item_super_predicates(child).predicates; predicates.iter().filter_map(|pred| { if let ty::Predicate::Trait(ref pred) = *pred { if pred.0.trait_ref.self_ty().is_self() { From d9c60ca06c2400eba893d1efd2407d046a395862 Mon Sep 17 00:00:00 2001 From: Trotter Cashion Date: Thu, 10 Nov 2016 07:30:20 -0800 Subject: [PATCH 032/177] Instruct play.rust-lang.org to treat code as tests Without these changes, play.rust-lang.org (as of today) would wrap our examples in `fn main() {}`. This prevents the user from being able to easily run the tests. --- src/doc/book/testing.md | 48 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index 1ae093afafe8..c36e0c09401b 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -24,6 +24,10 @@ Cargo will automatically generate a simple test when you make a new project. Here's the contents of `src/lib.rs`: ```rust +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# #[cfg(test)] mod tests { #[test] @@ -79,6 +83,10 @@ So why does our do-nothing test pass? Any test which doesn't `panic!` passes, and any test that does `panic!` fails. Let's make our test fail: ```rust +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# #[cfg(test)] mod tests { #[test] @@ -153,6 +161,10 @@ This is useful if you want to integrate `cargo test` into other tooling. We can invert our test's failure with another attribute: `should_panic`: ```rust +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# #[cfg(test)] mod tests { #[test] @@ -188,6 +200,10 @@ Rust provides another macro, `assert_eq!`, that compares two arguments for equality: ```rust +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# #[cfg(test)] mod tests { #[test] @@ -226,6 +242,10 @@ make sure that the failure message contains the provided text. A safer version of the example above would be: ```rust +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# #[cfg(test)] mod tests { #[test] @@ -239,6 +259,10 @@ mod tests { That's all there is to the basics! Let's write one 'real' test: ```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# pub fn add_two(a: i32) -> i32 { a + 2 } @@ -263,6 +287,10 @@ Sometimes a few specific tests can be very time-consuming to execute. These can be disabled by default by using the `ignore` attribute: ```rust +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# pub fn add_two(a: i32) -> i32 { a + 2 } @@ -338,6 +366,10 @@ was missing from our last example. Let's explain what this does. The idiomatic way of writing our example looks like this: ```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# pub fn add_two(a: i32) -> i32 { a + 2 } @@ -366,6 +398,10 @@ a large module, and so this is a common use of globs. Let's change our `src/lib.rs` to make use of it: ```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# pub fn add_two(a: i32) -> i32 { a + 2 } @@ -415,9 +451,14 @@ To write an integration test, let's make a `tests` directory and put a `tests/integration_test.rs` file inside with this as its contents: ```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# +# // Sadly, this code will not work in play.rust-lang.org, because we have no +# // crate adder to import. You'll need to try this part on your own machine. extern crate adder; -# fn main() {} #[test] fn it_works() { assert_eq!(4, adder::add_two(2)); @@ -478,7 +519,10 @@ running examples in your documentation (**note:** this only works in library crates, not binary crates). Here's a fleshed-out `src/lib.rs` with examples: ```rust,ignore -# fn main() {} +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# //! The `adder` crate provides functions that add numbers to other numbers. //! //! # Examples From 35903bb9aae79fd29476fd9fb63971e75bb82b0a Mon Sep 17 00:00:00 2001 From: Trotter Cashion Date: Thu, 10 Nov 2016 07:48:01 -0800 Subject: [PATCH 033/177] Remove `mod tests` from earlier sections The narrative flows better if we follow what @steveklabnik is doing in rust-lang/book#288. Therefore, I completely copied it. --- src/doc/book/testing.md | 113 ++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 62 deletions(-) diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index c36e0c09401b..9cb3e5e48ace 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -36,6 +36,18 @@ mod tests { } ``` +For now, let's remove the `mod` bit, and focus on just the function: + +```rust +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# +#[test] +fn it_works() { +} +``` + Note the `#[test]`. This attribute indicates that this is a test function. It currently has no body. That's good enough to pass! We can run the tests with `cargo test`: @@ -47,7 +59,7 @@ $ cargo test Running target/debug/deps/adder-941f01916ca4a642 running 1 test -test tests::it_works ... ok +test it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured @@ -63,10 +75,10 @@ for the test we wrote, and another for documentation tests. We'll talk about those later. For now, see this line: ```text -test tests::it_works ... ok +test it_works ... ok ``` -Note the `tests::it_works`. This comes from the name of our module and function: +Note the `it_works`. This comes from the name of our module and function: ```rust fn it_works() { @@ -87,12 +99,9 @@ and any test that does `panic!` fails. Let's make our test fail: # // test: # // fn main # -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert!(false); - } +#[test] +fn it_works() { + assert!(false); } ``` @@ -107,17 +116,17 @@ $ cargo test Running target/debug/deps/adder-941f01916ca4a642 running 1 test -test tests::it_works ... FAILED +test it_works ... FAILED failures: ----- tests::it_works stdout ---- - thread 'tests::it_works' panicked at 'assertion failed: false', src/lib.rs:5 +---- it_works stdout ---- + thread 'it_works' panicked at 'assertion failed: false', src/lib.rs:5 note: Run with `RUST_BACKTRACE=1` for a backtrace. failures: - tests::it_works + it_works test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured @@ -127,7 +136,7 @@ error: test failed Rust indicates that our test failed: ```text -test tests::it_works ... FAILED +test it_works ... FAILED ``` And that's reflected in the summary line: @@ -165,15 +174,11 @@ We can invert our test's failure with another attribute: `should_panic`: # // test: # // fn main # -#[cfg(test)] -mod tests { - #[test] - #[should_panic] - fn it_works() { - assert!(false); - } +#[test] +#[should_panic] +fn it_works() { + assert!(false); } - ``` This test will now succeed if we `panic!` and fail if we complete. Let's try it: @@ -185,7 +190,7 @@ $ cargo test Running target/debug/deps/adder-941f01916ca4a642 running 1 test -test tests::it_works ... ok +test it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured @@ -204,13 +209,10 @@ equality: # // test: # // fn main # -#[cfg(test)] -mod tests { - #[test] - #[should_panic] - fn it_works() { - assert_eq!("Hello", "world"); - } +#[test] +#[should_panic] +fn it_works() { + assert_eq!("Hello", "world"); } ``` @@ -224,7 +226,7 @@ $ cargo test Running target/debug/deps/adder-941f01916ca4a642 running 1 test -test tests::it_works ... ok +test it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured @@ -246,13 +248,10 @@ of the example above would be: # // test: # // fn main # -#[cfg(test)] -mod tests { - #[test] - #[should_panic(expected = "assertion failed")] - fn it_works() { - assert_eq!("Hello", "world"); - } +#[test] +#[should_panic(expected = "assertion failed")] +fn it_works() { + assert_eq!("Hello", "world"); } ``` @@ -267,14 +266,9 @@ pub fn add_two(a: i32) -> i32 { a + 2 } -#[cfg(test)] -mod tests { - use super::add_two; - - #[test] - fn it_works() { - assert_eq!(4, add_two(2)); - } +#[test] +fn it_works() { + assert_eq!(4, add_two(2)); } ``` @@ -295,20 +289,15 @@ pub fn add_two(a: i32) -> i32 { a + 2 } -#[cfg(test)] -mod tests { - use super::add_two; - - #[test] - fn it_works() { - assert_eq!(4, add_two(2)); - } +#[test] +fn it_works() { + assert_eq!(4, add_two(2)); +} - #[test] - #[ignore] - fn expensive_test() { - // code that takes an hour to run - } +#[test] +#[ignore] +fn expensive_test() { + // code that takes an hour to run } ``` @@ -322,8 +311,8 @@ $ cargo test Running target/debug/deps/adder-941f01916ca4a642 running 2 tests -test tests::expensive_test ... ignored -test tests::it_works ... ok +test expensive_test ... ignored +test it_works ... ok test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured @@ -342,7 +331,7 @@ $ cargo test -- --ignored Running target/debug/deps/adder-941f01916ca4a642 running 1 test -test tests::expensive_test ... ok +test expensive_test ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured From dd9280920f1f3ccf6a481ecd499434e6054c39d2 Mon Sep 17 00:00:00 2001 From: Trotter Cashion Date: Thu, 10 Nov 2016 07:52:51 -0800 Subject: [PATCH 034/177] Change project path for consistency I had used `/tmp/adder` for my previous commits. Flipped over to `/home/you/projects/adder` for consistency with other parts of testing.md --- src/doc/book/testing.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index 9cb3e5e48ace..95194976c292 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -54,7 +54,7 @@ currently has no body. That's good enough to pass! We can run the tests with ```bash $ cargo test - Compiling adder v0.1.0 (file:///private/tmp/adder) + Compiling adder v0.1.0 (file:///home/you/projects/adder) Finished debug [unoptimized + debuginfo] target(s) in 0.15 secs Running target/debug/deps/adder-941f01916ca4a642 @@ -111,7 +111,7 @@ run our tests again: ```bash $ cargo test - Compiling adder v0.1.0 (file:///private/tmp/adder) + Compiling adder v0.1.0 (file:///home/you/projects/adder) Finished debug [unoptimized + debuginfo] target(s) in 0.17 secs Running target/debug/deps/adder-941f01916ca4a642 @@ -185,7 +185,7 @@ This test will now succeed if we `panic!` and fail if we complete. Let's try it: ```bash $ cargo test - Compiling adder v0.1.0 (file:///private/tmp/adder) + Compiling adder v0.1.0 (file:///home/you/projects/adder) Finished debug [unoptimized + debuginfo] target(s) in 0.17 secs Running target/debug/deps/adder-941f01916ca4a642 @@ -221,7 +221,7 @@ passes: ```bash $ cargo test - Compiling adder v0.1.0 (file:///private/tmp/adder) + Compiling adder v0.1.0 (file:///home/you/projects/adder) Finished debug [unoptimized + debuginfo] target(s) in 0.21 secs Running target/debug/deps/adder-941f01916ca4a642 @@ -306,7 +306,7 @@ not: ```bash $ cargo test - Compiling adder v0.1.0 (file:///private/tmp/adder) + Compiling adder v0.1.0 (file:///home/you/projects/adder) Finished debug [unoptimized + debuginfo] target(s) in 0.20 secs Running target/debug/deps/adder-941f01916ca4a642 From 4cf764470a84b68445db2529f17371a0f6ab2023 Mon Sep 17 00:00:00 2001 From: Trotter Cashion Date: Thu, 10 Nov 2016 07:55:20 -0800 Subject: [PATCH 035/177] Remove extraneous word --- src/doc/book/testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index 95194976c292..4fd73e4854bc 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -78,7 +78,7 @@ those later. For now, see this line: test it_works ... ok ``` -Note the `it_works`. This comes from the name of our module and function: +Note the `it_works`. This comes from the name of our function: ```rust fn it_works() { From 0254f12224032be95dd97441a866e63c8e15a0e3 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Thu, 10 Nov 2016 17:30:06 +0100 Subject: [PATCH 036/177] rustbuild: support RelWithDebInfo for llvm --- src/bootstrap/config.rs | 3 +++ src/bootstrap/config.toml.example | 3 +++ src/bootstrap/native.rs | 9 ++++++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 9a939fee43e8..a630aaf8af48 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -50,6 +50,7 @@ pub struct Config { // llvm codegen options pub llvm_assertions: bool, pub llvm_optimize: bool, + pub llvm_release_debuginfo: bool, pub llvm_version_check: bool, pub llvm_static_stdcpp: bool, @@ -137,6 +138,7 @@ struct Llvm { ninja: Option, assertions: Option, optimize: Option, + release_debuginfo: Option, version_check: Option, static_libstdcpp: Option, } @@ -243,6 +245,7 @@ impl Config { set(&mut config.ninja, llvm.ninja); set(&mut config.llvm_assertions, llvm.assertions); set(&mut config.llvm_optimize, llvm.optimize); + set(&mut config.llvm_release_debuginfo, llvm.release_debuginfo); set(&mut config.llvm_version_check, llvm.version_check); set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp); } diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 306708f9e4b6..1388dab303a4 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -17,6 +17,9 @@ # Indicates whether the LLVM build is a Release or Debug build #optimize = true +# Indicates whether an LLVM Release build should include debug info +#release-debuginfo = false + # Indicates whether the LLVM assertions are enabled or not #assertions = false diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 1b4e86fb30f2..358cfac74277 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -67,10 +67,17 @@ pub fn llvm(build: &Build, target: &str) { if build.config.ninja { cfg.generator("Ninja"); } + + let profile = match (build.config.llvm_optimize, build.config.llvm_release_debuginfo) { + (false, _) => "Debug", + (true, false) => "Release", + (true, true) => "RelWithDebInfo", + }; + cfg.target(target) .host(&build.config.build) .out_dir(&dst) - .profile(if build.config.llvm_optimize {"Release"} else {"Debug"}) + .profile(profile) .define("LLVM_ENABLE_ASSERTIONS", assertions) .define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend") .define("LLVM_INCLUDE_EXAMPLES", "OFF") From 2743128876a997a822f289e816c7efa89666af2c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 10 Nov 2016 09:23:29 -0800 Subject: [PATCH 037/177] std: Update compiler-rt for more ABI fixes This update of compiler-rt includes rust-lang/compiler-rt#26 which provides a targeted fix to the powisf2 intrinsics to keep #37559 fixed but also address the new issue of #37630. I've also [written up my thoughts][1] on why it appears that this is the correct fix for now (hoepfully at least). Closes #37630 [1]: https://github.com/rust-lang/compiler-rt/pull/26#issuecomment-259751998 --- src/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler-rt b/src/compiler-rt index ecd2b1f6d689..3bc0272cab9f 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit ecd2b1f6d689d5afbf5debe8afb3739337323852 +Subproject commit 3bc0272cab9fdcfc2ef4df9625ec3c9d5909db79 From 4ce4900218bd8378e08cd7d1d4c57e370c0949a0 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Thu, 10 Nov 2016 17:54:31 +0000 Subject: [PATCH 038/177] Balance the debug output of Lvalue Subslice --- src/librustc/mir/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 9d82006ac9f9..b3cec6ec8ff3 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -923,7 +923,7 @@ impl<'tcx> Debug for Lvalue<'tcx> { ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => write!(fmt, "{:?}[-{:?} of {:?}]", data.base, offset, min_length), ProjectionElem::Subslice { from, to } if to == 0 => - write!(fmt, "{:?}[{:?}:", data.base, from), + write!(fmt, "{:?}[{:?}:]", data.base, from), ProjectionElem::Subslice { from, to } if from == 0 => write!(fmt, "{:?}[:-{:?}]", data.base, to), ProjectionElem::Subslice { from, to } => From 669102f0f07974f4643242302be5a4a0fafa1034 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 10 Nov 2016 11:55:31 -0500 Subject: [PATCH 039/177] ICH: Add test case for call expressions. --- .../incremental/hashes/call_expressions.rs | 203 ++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 src/test/incremental/hashes/call_expressions.rs diff --git a/src/test/incremental/hashes/call_expressions.rs b/src/test/incremental/hashes/call_expressions.rs new file mode 100644 index 000000000000..d2030d935546 --- /dev/null +++ b/src/test/incremental/hashes/call_expressions.rs @@ -0,0 +1,203 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// This test case tests the incremental compilation hash (ICH) implementation +// for function and method call expressions. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph + + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![crate_type="rlib"] + +fn callee1(_x: u32, _y: i64) {} +fn callee2(_x: u32, _y: i64) {} + + +// Change Callee (Function) ---------------------------------------------------- +#[cfg(cfail1)] +pub fn change_callee_function() { + callee1(1, 2) +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_callee_function() { + callee2(1, 2) +} + + + +// Change Argument (Function) -------------------------------------------------- +#[cfg(cfail1)] +pub fn change_argument_function() { + callee1(1, 2) +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_argument_function() { + callee1(1, 3) +} + + + +// Change Callee Indirectly (Function) ----------------------------------------- +mod change_callee_indirectly_function { + #[cfg(cfail1)] + use super::callee1 as callee; + #[cfg(not(cfail1))] + use super::callee2 as callee; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + pub fn change_callee_indirectly_function() { + callee(1, 2) + } +} + + +struct Struct; +impl Struct { + fn method1(&self, _x: char, _y: bool) {} + fn method2(&self, _x: char, _y: bool) {} +} + +// Change Callee (Method) ------------------------------------------------------ +#[cfg(cfail1)] +pub fn change_callee_method() { + let s = Struct; + s.method1('x', true); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_callee_method() { + let s = Struct; + s.method2('x', true); +} + + + +// Change Argument (Method) ---------------------------------------------------- +#[cfg(cfail1)] +pub fn change_argument_method() { + let s = Struct; + s.method1('x', true); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_argument_method() { + let s = Struct; + s.method1('y', true); +} + + + +// Change Callee (Method, UFCS) ------------------------------------------------ +#[cfg(cfail1)] +pub fn change_ufcs_callee_method() { + let s = Struct; + Struct::method1(&s, 'x', true); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_ufcs_callee_method() { + let s = Struct; + Struct::method2(&s, 'x', true); +} + + + +// Change Argument (Method, UFCS) ---------------------------------------------- +#[cfg(cfail1)] +pub fn change_argument_method_ufcs() { + let s = Struct; + Struct::method1(&s, 'x', true); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_argument_method_ufcs() { + let s = Struct; + Struct::method1(&s, 'x', false); +} + + + +// Change To UFCS -------------------------------------------------------------- +#[cfg(cfail1)] +pub fn change_to_ufcs() { + let s = Struct; + s.method1('x', true); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_to_ufcs() { + let s = Struct; + Struct::method1(&s, 'x', true); +} + + +struct Struct2; +impl Struct2 { + fn method1(&self, _x: char, _y: bool) {} +} + +// Change UFCS Callee Indirectly ----------------------------------------------- +mod change_ufcs_callee_indirectly { + #[cfg(cfail1)] + use super::Struct as Struct; + #[cfg(not(cfail1))] + use super::Struct2 as Struct; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + pub fn change_ufcs_callee_indirectly() { + let s = Struct; + Struct::method1(&s, 'q', false) + } +} From f2b8d7bb3189115b3de4bc5e73b57a67b1dce364 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 10 Nov 2016 15:06:51 -0500 Subject: [PATCH 040/177] ICH: Add test case for if- and if-let-expressions. --- src/test/incremental/hashes/if_expressions.rs | 232 ++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 src/test/incremental/hashes/if_expressions.rs diff --git a/src/test/incremental/hashes/if_expressions.rs b/src/test/incremental/hashes/if_expressions.rs new file mode 100644 index 000000000000..ba6289f754ed --- /dev/null +++ b/src/test/incremental/hashes/if_expressions.rs @@ -0,0 +1,232 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// This test case tests the incremental compilation hash (ICH) implementation +// for if expressions. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph + + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![crate_type="rlib"] + +// Change condition (if) ------------------------------------------------------- +#[cfg(cfail1)] +pub fn change_condition(x: bool) -> u32 { + if x { + return 1 + } + + return 0 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_condition(x: bool) -> u32 { + if !x { + return 1 + } + + return 0 +} + +// Change then branch (if) ----------------------------------------------------- +#[cfg(cfail1)] +pub fn change_then_branch(x: bool) -> u32 { + if x { + return 1 + } + + return 0 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_then_branch(x: bool) -> u32 { + if x { + return 2 + } + + return 0 +} + + + +// Change else branch (if) ----------------------------------------------------- +#[cfg(cfail1)] +pub fn change_else_branch(x: bool) -> u32 { + if x { + 1 + } else { + 2 + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_else_branch(x: bool) -> u32 { + if x { + 1 + } else { + 3 + } +} + + + +// Add else branch (if) -------------------------------------------------------- +#[cfg(cfail1)] +pub fn add_else_branch(x: bool) -> u32 { + let mut ret = 1; + + if x { + ret += 1; + } + + ret +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn add_else_branch(x: bool) -> u32 { + let mut ret = 1; + + if x { + ret += 1; + } else { + } + + ret +} + + + +// Change condition (if let) --------------------------------------------------- +#[cfg(cfail1)] +pub fn change_condition_if_let(x: Option) -> u32 { + if let Some(_x) = x { + return 1 + } + + 0 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_condition_if_let(x: Option) -> u32 { + if let Some(_) = x { + return 1 + } + + 0 +} + + + +// Change then branch (if let) ------------------------------------------------- +#[cfg(cfail1)] +pub fn change_then_branch_if_let(x: Option) -> u32 { + if let Some(x) = x { + return x + } + + 0 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_then_branch_if_let(x: Option) -> u32 { + if let Some(x) = x { + return x + 1 + } + + 0 +} + + + +// Change else branch (if let) ------------------------------------------------- +#[cfg(cfail1)] +pub fn change_else_branch_if_let(x: Option) -> u32 { + if let Some(x) = x { + x + } else { + 1 + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_else_branch_if_let(x: Option) -> u32 { + if let Some(x) = x { + x + } else { + 2 + } +} + + + +// Add else branch (if let) ---------------------------------------------------- +#[cfg(cfail1)] +pub fn add_else_branch_if_let(x: Option) -> u32 { + let mut ret = 1; + + if let Some(x) = x { + ret += x; + } + + ret +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn add_else_branch_if_let(x: Option) -> u32 { + let mut ret = 1; + + if let Some(x) = x { + ret += x; + } else { + } + + ret +} From c96e3524e319e3654a5542a3b078c4f7537e94f6 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Tue, 11 Oct 2016 20:08:26 -0400 Subject: [PATCH 041/177] Don't use self type for cat_index on overloaded indexing. Fixes #20649. --- src/librustc/middle/mem_categorization.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index e3ed13e1e401..fedf8c2ec747 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -945,9 +945,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let ref_ty = self.overloaded_method_return_ty(method_ty); base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty); - // FIXME(#20649) -- why are we using the `self_ty` as the element type...? - let self_ty = method_ty.fn_sig().input(0); - (self.tcx().no_late_bound_regions(&self_ty).unwrap(), + (ref_ty.builtin_deref(false, ty::NoPreference).unwrap().ty, ElementKind::OtherElement) } None => { From 6076fef6bd7af7fc34cb9adf8c2b3fa1a35c50bb Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Tue, 11 Oct 2016 20:42:26 -0400 Subject: [PATCH 042/177] ExprAssignable does not need the original Expr so let's just remove outdated FIXME. --- src/librustc/infer/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index ebafd206e26e..8f4a12e03975 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -184,7 +184,6 @@ pub enum TypeOrigin { MethodCompatCheck(Span), // Checking that this expression can be assigned where it needs to be - // FIXME(eddyb) #11161 is the original Expr required? ExprAssignable(Span), // Relating trait type parameters to those found in impl etc From 34f8e62c6bcf46aba647493bbc9e6da430d8b064 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Tue, 11 Oct 2016 22:10:54 -0400 Subject: [PATCH 043/177] Remove outdated FIXME: #10604 was fixed by #11717. --- src/librustc_trans/adt.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 4d3361c1873f..d028dd7e7b5a 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -245,8 +245,6 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // So we start with the discriminant, pad it up to the alignment with // more of its own type, then use alignment-sized ints to get the rest // of the size. - // - // FIXME #10604: this breaks when vector types are present. let size = size.bytes(); let align = align.abi(); let discr_ty = Type::from_integer(cx, discr); From c2f1e5d16455057f86c1e3051e77009d90b167fc Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Tue, 11 Oct 2016 23:46:22 -0400 Subject: [PATCH 044/177] Get rid of superfluous HashMap in LocalCrateContext. We only need the str slice type. --- src/librustc_trans/common.rs | 2 +- src/librustc_trans/context.rs | 16 ++++++++-------- src/librustc_trans/type_.rs | 25 ------------------------- src/librustc_trans/type_of.rs | 2 +- 4 files changed, 10 insertions(+), 35 deletions(-) diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 464b261b08e0..d238cf7bb458 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -815,7 +815,7 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va pub fn C_str_slice(cx: &CrateContext, s: InternedString) -> ValueRef { let len = s.len(); let cs = consts::ptrcast(C_cstr(cx, s, false), Type::i8p(cx)); - C_named_struct(cx.tn().find_type("str_slice").unwrap(), &[cs, C_uint(cx, len)]) + C_named_struct(cx.str_slice_type(), &[cs, C_uint(cx, len)]) } pub fn C_struct(cx: &CrateContext, elts: &[ValueRef], packed: bool) -> ValueRef { diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 264d4940c17f..3930bcbdd9ae 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -25,7 +25,7 @@ use monomorphize::Instance; use partitioning::CodegenUnit; use trans_item::TransItem; -use type_::{Type, TypeNames}; +use type_::Type; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; use session::config::NoDebugInfo; @@ -87,7 +87,6 @@ pub struct LocalCrateContext<'tcx> { llmod: ModuleRef, llcx: ContextRef, previous_work_product: Option, - tn: TypeNames, // FIXME: This seems to be largely unused. codegen_unit: CodegenUnit<'tcx>, needs_unwind_cleanup_cache: RefCell, bool>>, fn_pointer_shims: RefCell, ValueRef>>, @@ -137,6 +136,7 @@ pub struct LocalCrateContext<'tcx> { type_hashcodes: RefCell, String>>, int_type: Type, opaque_vec_type: Type, + str_slice_type: Type, builder: BuilderRef_res, /// Holds the LLVM values for closure IDs. @@ -611,7 +611,6 @@ impl<'tcx> LocalCrateContext<'tcx> { llcx: llcx, previous_work_product: previous_work_product, codegen_unit: codegen_unit, - tn: TypeNames::new(), needs_unwind_cleanup_cache: RefCell::new(FxHashMap()), fn_pointer_shims: RefCell::new(FxHashMap()), drop_glues: RefCell::new(FxHashMap()), @@ -631,6 +630,7 @@ impl<'tcx> LocalCrateContext<'tcx> { type_hashcodes: RefCell::new(FxHashMap()), int_type: Type::from_ref(ptr::null_mut()), opaque_vec_type: Type::from_ref(ptr::null_mut()), + str_slice_type: Type::from_ref(ptr::null_mut()), builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)), closure_vals: RefCell::new(FxHashMap()), dbg_cx: dbg_cx, @@ -662,7 +662,7 @@ impl<'tcx> LocalCrateContext<'tcx> { local_ccx.int_type = int_type; local_ccx.opaque_vec_type = opaque_vec_type; - local_ccx.tn.associate_type("str_slice", &str_slice_ty); + local_ccx.str_slice_type = str_slice_ty; if shared.tcx.sess.count_llvm_insns() { base::init_insn_ctxt() @@ -778,10 +778,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { unsafe { llvm::LLVMRustGetModuleDataLayout(self.llmod()) } } - pub fn tn<'a>(&'a self) -> &'a TypeNames { - &self.local().tn - } - pub fn export_map<'a>(&'a self) -> &'a ExportMap { &self.shared.export_map } @@ -885,6 +881,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.local().opaque_vec_type } + pub fn str_slice_type(&self) -> Type { + self.local().str_slice_type + } + pub fn closure_vals<'a>(&'a self) -> &'a RefCell, ValueRef>> { &self.local().closure_vals } diff --git a/src/librustc_trans/type_.rs b/src/librustc_trans/type_.rs index 2a6f79d3ed57..2b2776acab86 100644 --- a/src/librustc_trans/type_.rs +++ b/src/librustc_trans/type_.rs @@ -15,7 +15,6 @@ use llvm::{TypeRef, Bool, False, True, TypeKind}; use llvm::{Float, Double, X86_FP80, PPC_FP128, FP128}; use context::CrateContext; -use util::nodemap::FxHashMap; use syntax::ast; use rustc::ty::layout; @@ -24,7 +23,6 @@ use std::ffi::CString; use std::fmt; use std::mem; use std::ptr; -use std::cell::RefCell; use libc::c_uint; @@ -321,26 +319,3 @@ impl Type { } } } - -/* Memory-managed object interface to type handles. */ - -pub struct TypeNames { - named_types: RefCell>, -} - -impl TypeNames { - pub fn new() -> TypeNames { - TypeNames { - named_types: RefCell::new(FxHashMap()) - } - } - - pub fn associate_type(&self, s: &str, t: &Type) { - assert!(self.named_types.borrow_mut().insert(s.to_string(), - t.to_ref()).is_none()); - } - - pub fn find_type(&self, s: &str) -> Option { - self.named_types.borrow().get(s).map(|x| Type::from_ref(*x)) - } -} diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 132b0a910b9c..dc794d5946a6 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -238,7 +238,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> if let ty::TyStr = ty.sty { // This means we get a nicer name in the output (str is always // unsized). - cx.tn().find_type("str_slice").unwrap() + cx.str_slice_type() } else { let ptr_ty = in_memory_type_of(cx, ty).ptr_to(); let info_ty = unsized_info_ty(cx, ty); From dcd80b80ae3fe2f327515e57fdc423a3927e44e6 Mon Sep 17 00:00:00 2001 From: Arthur Silva Date: Thu, 10 Nov 2016 22:02:44 +0100 Subject: [PATCH 045/177] Remove one bounds check from BufReader Otherwise the optimizer can't be sure that pos <= cap. Added a paranoid debug_assert to ensure correctness instead. --- src/libstd/io/buffered.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 44dd4e9874ac..cd7a50d07e26 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -187,7 +187,10 @@ impl BufRead for BufReader { fn fill_buf(&mut self) -> io::Result<&[u8]> { // If we've reached the end of our internal buffer then we need to fetch // some more data from the underlying reader. - if self.pos == self.cap { + // Branch using `>=` instead of the more correct `==` + // to tell the compiler that the pos..cap slice is always valid. + if self.pos >= self.cap { + debug_assert!(self.pos == self.cap); self.cap = self.inner.read(&mut self.buf)?; self.pos = 0; } From c67ff64b6fb57313c81e241f6a16b60783ffbb95 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 9 Nov 2016 19:27:05 +0100 Subject: [PATCH 046/177] Add missing urls for FusedIterator and TrustedLen traits --- src/libcore/iter/traits.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 9d402971d18d..e94582cda7c3 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -666,13 +666,17 @@ float_sum_product! { f32 f64 } /// An iterator that always continues to yield `None` when exhausted. /// /// Calling next on a fused iterator that has returned `None` once is guaranteed -/// to return `None` again. This trait is should be implemented by all iterators +/// to return [`None`] again. This trait is should be implemented by all iterators /// that behave this way because it allows for some significant optimizations. /// /// Note: In general, you should not use `FusedIterator` in generic bounds if -/// you need a fused iterator. Instead, you should just call `Iterator::fused()` -/// on the iterator. If the iterator is already fused, the additional `Fuse` +/// you need a fused iterator. Instead, you should just call [`Iterator::fuse()`] +/// on the iterator. If the iterator is already fused, the additional [`Fuse`] /// wrapper will be a no-op with no performance penalty. +/// +/// [`None`]: ../../std/option/enum.Option.html#variant.None +/// [`Iterator::fuse()`]: ../../std/iter/trait.Iterator.html#method.fuse +/// [`Fuse`]: ../../std/iter/struct.Fuse.html #[unstable(feature = "fused", issue = "35602")] pub trait FusedIterator: Iterator {} @@ -682,16 +686,20 @@ impl<'a, I: FusedIterator + ?Sized> FusedIterator for &'a mut I {} /// An iterator that reports an accurate length using size_hint. /// /// The iterator reports a size hint where it is either exact -/// (lower bound is equal to upper bound), or the upper bound is `None`. -/// The upper bound must only be `None` if the actual iterator length is -/// larger than `usize::MAX`. +/// (lower bound is equal to upper bound), or the upper bound is [`None`]. +/// The upper bound must only be [`None`] if the actual iterator length is +/// larger than [`usize::MAX`]. /// /// The iterator must produce exactly the number of elements it reported. /// /// # Safety /// /// This trait must only be implemented when the contract is upheld. -/// Consumers of this trait must inspect `.size_hint()`’s upper bound. +/// Consumers of this trait must inspect [`.size_hint()`]’s upper bound. +/// +/// [`None`]: ../../std/option/enum.Option.html#variant.None +/// [`usize::MAX`]: ../../std/usize/constant.MAX.html +/// [`.size_hint()`]: ../../std/iter/trait.Iterator.html#method.size_hint #[unstable(feature = "trusted_len", issue = "37572")] pub unsafe trait TrustedLen : Iterator {} From fdf482c398a5efea0c748d840c6b77c71fbe8a7b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 10 Nov 2016 23:13:37 +0100 Subject: [PATCH 047/177] Add missing urls for marker's traits --- src/libcore/marker.rs | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index bdb0dd8e7d1a..9af10966eda4 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -26,15 +26,15 @@ use hash::Hasher; /// appropriate. /// /// An example of a non-`Send` type is the reference-counting pointer -/// [`rc::Rc`][rc]. If two threads attempt to clone `Rc`s that point to the same +/// [`rc::Rc`][`Rc`]. If two threads attempt to clone [`Rc`]s that point to the same /// reference-counted value, they might try to update the reference count at the -/// same time, which is [undefined behavior][ub] because `Rc` doesn't use atomic +/// same time, which is [undefined behavior][ub] because [`Rc`] doesn't use atomic /// operations. Its cousin [`sync::Arc`][arc] does use atomic operations (incurring /// some overhead) and thus is `Send`. /// /// See [the Nomicon](../../nomicon/send-and-sync.html) for more details. /// -/// [rc]: ../../std/rc/struct.Rc.html +/// [`Rc`]: ../../std/rc/struct.Rc.html /// [arc]: ../../std/sync/struct.Arc.html /// [ub]: ../../reference.html#behavior-considered-undefined #[stable(feature = "rust1", since = "1.0.0")] @@ -183,20 +183,17 @@ pub trait Unsize { /// Copies happen implicitly, for example as part of an assignment `y = x`. The behavior of /// `Copy` is not overloadable; it is always a simple bit-wise copy. /// -/// Cloning is an explicit action, `x.clone()`. The implementation of [`Clone`][clone] can +/// Cloning is an explicit action, `x.clone()`. The implementation of [`Clone`] can /// provide any type-specific behavior necessary to duplicate values safely. For example, -/// the implementation of `Clone` for [`String`][string] needs to copy the pointed-to string -/// buffer in the heap. A simple bitwise copy of `String` values would merely copy the -/// pointer, leading to a double free down the line. For this reason, `String` is `Clone` +/// the implementation of [`Clone`] for [`String`] needs to copy the pointed-to string +/// buffer in the heap. A simple bitwise copy of [`String`] values would merely copy the +/// pointer, leading to a double free down the line. For this reason, [`String`] is [`Clone`] /// but not `Copy`. /// -/// `Clone` is a supertrait of `Copy`, so everything which is `Copy` must also implement -/// `Clone`. If a type is `Copy` then its `Clone` implementation need only return `*self` +/// [`Clone`] is a supertrait of `Copy`, so everything which is `Copy` must also implement +/// [`Clone`]. If a type is `Copy` then its [`Clone`] implementation need only return `*self` /// (see the example above). /// -/// [clone]: ../clone/trait.Clone.html -/// [string]: ../../std/string/struct.String.html -/// /// ## When can my type be `Copy`? /// /// A type can implement `Copy` if all of its components implement `Copy`. For example, this @@ -210,7 +207,7 @@ pub trait Unsize { /// } /// ``` /// -/// A struct can be `Copy`, and `i32` is `Copy`, therefore `Point` is eligible to be `Copy`. +/// A struct can be `Copy`, and [`i32`] is `Copy`, therefore `Point` is eligible to be `Copy`. /// By contrast, consider /// /// ``` @@ -231,8 +228,8 @@ pub trait Unsize { /// ## When *can't* my type be `Copy`? /// /// Some types can't be copied safely. For example, copying `&mut T` would create an aliased -/// mutable reference. Copying [`String`] would duplicate responsibility for managing the `String`'s -/// buffer, leading to a double free. +/// mutable reference. Copying [`String`] would duplicate responsibility for managing the +/// [`String`]'s buffer, leading to a double free. /// /// Generalizing the latter case, any type implementing [`Drop`] can't be `Copy`, because it's /// managing some resource besides its own [`size_of::()`] bytes. @@ -255,6 +252,9 @@ pub trait Unsize { /// [`String`]: ../../std/string/struct.String.html /// [`Drop`]: ../../std/ops/trait.Drop.html /// [`size_of::()`]: ../../std/mem/fn.size_of.html +/// [`Clone`]: ../clone/trait.Clone.html +/// [`String`]: ../../std/string/struct.String.html +/// [`i32`]: ../../std/primitive.i32.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "copy"] pub trait Copy : Clone { @@ -290,20 +290,20 @@ pub trait Copy : Clone { /// mutability" in a non-thread-safe form, such as [`cell::Cell`][cell] /// and [`cell::RefCell`][refcell]. These types allow for mutation of /// their contents even through an immutable, shared reference. For -/// example the `set` method on `Cell` takes `&self`, so it requires -/// only a shared reference `&Cell`. The method performs no -/// synchronization, thus `Cell` cannot be `Sync`. +/// example the `set` method on [`Cell`][cell] takes `&self`, so it requires +/// only a shared reference [`&Cell`][cell]. The method performs no +/// synchronization, thus [`Cell`][cell] cannot be `Sync`. /// /// Another example of a non-`Sync` type is the reference-counting -/// pointer [`rc::Rc`][rc]. Given any reference `&Rc`, you can clone -/// a new `Rc`, modifying the reference counts in a non-atomic way. +/// pointer [`rc::Rc`][rc]. Given any reference [`&Rc`][rc], you can clone +/// a new [`Rc`][rc], modifying the reference counts in a non-atomic way. /// /// For cases when one does need thread-safe interior mutability, /// Rust provides [atomic data types], as well as explicit locking via /// [`sync::Mutex`][mutex] and [`sync::RWLock`][rwlock]. These types /// ensure that any mutation cannot cause data races, hence the types /// are `Sync`. Likewise, [`sync::Arc`][arc] provides a thread-safe -/// analogue of `Rc`. +/// analogue of [`Rc`][rc]. /// /// Any types with interior mutability must also use the /// [`cell::UnsafeCell`][unsafecell] wrapper around the value(s) which From 30502b820519ab63c1007f2cb615322301a9ce3d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 10 Nov 2016 16:21:51 -0800 Subject: [PATCH 048/177] std: Derive `Default` for `Duration`. Discussed in #37546 the libs team reached the conclusion that a default zero duration seems like a reasonable implementation of the `Default` trait. Closes #37546 --- src/libstd/time/duration.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 10a0c567e142..41d675b6f88f 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -39,7 +39,7 @@ const MILLIS_PER_SEC: u64 = 1_000; /// let ten_millis = Duration::from_millis(10); /// ``` #[stable(feature = "duration", since = "1.3.0")] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] pub struct Duration { secs: u64, nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC From 87b6d386541c6f7a409775296da1cda2da469c36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 29 Oct 2016 22:57:23 -0700 Subject: [PATCH 049/177] Don't hint to add lifetime on trait impl Don't provide hint to add lifetime on impl items that implement a trait. ```rust use std::str::FromStr; pub struct Foo<'a> { field: &'a str, } impl<'a> FromStr for Foo<'a> { type Err = (); fn from_str(path: &str) -> Result { Ok(Foo { field: path }) } } ``` would give the following hint: ```nocode help: consider using an explicit lifetime parameter as shown: fn from_str(path: &'a str) -> Result --> :9:5 | 9 | fn from_str(path: &str) -> Result { | ^ ``` which is never correct, since then there will be a lifetime mismatch between the impl and the trait. Remove this hint for impl items that implement a trait. --- src/librustc/infer/error_reporting.rs | 35 +++++++++++-------- ...time-inference-give-expl-lifetime-param.rs | 2 -- .../consider-using-explicit-lifetime.rs | 28 +++++++++++++++ .../consider-using-explicit-lifetime.stderr | 22 ++++++++++++ 4 files changed, 71 insertions(+), 16 deletions(-) create mode 100644 src/test/ui/lifetimes/consider-using-explicit-lifetime.rs create mode 100644 src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 47c0bc5fd60c..75334a517fb3 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -1052,21 +1052,28 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { match item.node { hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, _) => { Some((fn_decl, gen, unsafety, constness, item.name, item.span)) - }, - _ => None + } + _ => None, } } ast_map::NodeImplItem(item) => { - match item.node { - hir::ImplItemKind::Method(ref sig, _) => { - Some((&sig.decl, - &sig.generics, - sig.unsafety, - sig.constness, - item.name, - item.span)) + let id = self.tcx.map.get_parent(item.id); + if let Some(ast_map::NodeItem(parent_scope)) = self.tcx.map.find(id) { + if let hir::ItemImpl(_, _, _, None, _, _) = parent_scope.node { + // this impl scope implements a trait, do not recomend + // using explicit lifetimes (#37363) + return; } - _ => None, + } + if let hir::ImplItemKind::Method(ref sig, _) = item.node { + Some((&sig.decl, + &sig.generics, + sig.unsafety, + sig.constness, + item.name, + item.span)) + } else { + None } }, ast_map::NodeTraitItem(item) => { @@ -1079,12 +1086,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { item.name, item.span)) } - _ => None + _ => None, } } - _ => None + _ => None, }, - None => None + None => None, }; let (fn_decl, generics, unsafety, constness, name, span) = node_inner.expect("expect item fn"); diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs index 6da87fca3f35..4323929e2e37 100644 --- a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs +++ b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs @@ -49,8 +49,6 @@ struct Baz<'x> { impl<'a> Baz<'a> { fn baz2<'b>(&self, x: &isize) -> (&'b isize, &'b isize) { - //~^ HELP consider using an explicit lifetime parameter as shown: fn baz2<'b>(&self, x: &' - // FIXME #35038: The above suggestion is different on Linux and Mac. (self.bar, x) //~ ERROR E0312 //~^ ERROR E0312 } diff --git a/src/test/ui/lifetimes/consider-using-explicit-lifetime.rs b/src/test/ui/lifetimes/consider-using-explicit-lifetime.rs new file mode 100644 index 000000000000..603f55af465f --- /dev/null +++ b/src/test/ui/lifetimes/consider-using-explicit-lifetime.rs @@ -0,0 +1,28 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::str::FromStr; + +pub struct Foo<'a> { + field: &'a str, +} + +impl<'a> Foo<'a> { + fn bar(path: &str) -> Result { + Ok(Foo { field: path }) + } +} + +impl<'a> FromStr for Foo<'a> { + type Err = (); + fn from_str(path: &str) -> Result { + Ok(Foo { field: path }) + } +} diff --git a/src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr b/src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr new file mode 100644 index 000000000000..353e251369a1 --- /dev/null +++ b/src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr @@ -0,0 +1,22 @@ +error: main function not found + +error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements + --> $DIR/consider-using-explicit-lifetime.rs:19:12 + | +19 | Ok(Foo { field: path }) + | ^^^ + +error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements + --> $DIR/consider-using-explicit-lifetime.rs:26:12 + | +26 | Ok(Foo { field: path }) + | ^^^ + | +help: consider using an explicit lifetime parameter as shown: fn from_str(path: &'a str) -> Result + --> $DIR/consider-using-explicit-lifetime.rs:25:5 + | +25 | fn from_str(path: &str) -> Result { + | ^ + +error: aborting due to 2 previous errors + From c524c50edf85b3489734beb6b6619082307de116 Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Thu, 10 Nov 2016 16:04:53 -0700 Subject: [PATCH 050/177] compiletest: detect nodejs binary, allow override Allow passing a custom nodejs directory in configure. --- src/bootstrap/config.rs | 2 ++ src/bootstrap/sanity.rs | 13 +++++++------ src/tools/compiletest/src/runtest.rs | 7 +++++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 9a939fee43e8..f88bb04fb107 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -128,6 +128,7 @@ struct Build { submodules: Option, gdb: Option, vendor: Option, + nodejs: Option, } /// TOML representation of how the LLVM build is configured. @@ -232,6 +233,7 @@ impl Config { } config.rustc = build.rustc.map(PathBuf::from); config.cargo = build.cargo.map(PathBuf::from); + config.nodejs = build.nodejs.map(PathBuf::from); config.gdb = build.gdb.map(PathBuf::from); set(&mut config.compiler_docs, build.compiler_docs); set(&mut config.docs, build.docs); diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index cc1b7136d475..a541ba0b2f3f 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -81,15 +81,16 @@ pub fn check(build: &mut Build) { need_cmd("python".as_ref()); - // Look for the nodejs command, needed for emscripten testing - if let Some(node) = have_cmd("node".as_ref()) { - build.config.nodejs = Some(node); - } else if let Some(node) = have_cmd("nodejs".as_ref()) { - build.config.nodejs = Some(node); - } if let Some(ref s) = build.config.nodejs { need_cmd(s.as_ref()); + } else { + // Look for the nodejs command, needed for emscripten testing + if let Some(node) = have_cmd("node".as_ref()) { + build.config.nodejs = Some(node); + } else if let Some(node) = have_cmd("nodejs".as_ref()) { + build.config.nodejs = Some(node); + } } if let Some(ref gdb) = build.config.gdb { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 8cb2e3b1c2de..4c024434e17c 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1456,8 +1456,11 @@ actual:\n\ // If this is emscripten, then run tests under nodejs if self.config.target.contains("emscripten") { - let nodejs = self.config.nodejs.clone().unwrap_or("nodejs".to_string()); - args.push(nodejs); + if let Some(ref p) = self.config.nodejs { + args.push(p.clone()); + } else { + self.fatal("no NodeJS binary found (--nodejs)"); + } } let exe_file = self.make_exe_name(); From 2a832a03c5a3efd6388e4eb5c5b5b4568bcd80f6 Mon Sep 17 00:00:00 2001 From: Trotter Cashion Date: Thu, 10 Nov 2016 19:08:45 -0800 Subject: [PATCH 051/177] Ignore tests failing due to lack of `fn main` While the commit message on this one sounds terrible, it's really not so bad. The issue is that our test runner _expects_ a `fn main() {}` in code blocks that it'll test, but this code really shouldn't have them. If it did, then clicking the "play" link in the docs would result in play.rust-lang.org not treating this code as a test example to be run. --- src/doc/book/testing.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index 4fd73e4854bc..ed916fd798bb 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -23,7 +23,7 @@ $ cd adder Cargo will automatically generate a simple test when you make a new project. Here's the contents of `src/lib.rs`: -```rust +```rust,ignore # // The next line exists to trick play.rust-lang.org into running our code as a # // test: # // fn main @@ -38,7 +38,7 @@ mod tests { For now, let's remove the `mod` bit, and focus on just the function: -```rust +```rust,ignore # // The next line exists to trick play.rust-lang.org into running our code as a # // test: # // fn main @@ -81,8 +81,10 @@ test it_works ... ok Note the `it_works`. This comes from the name of our function: ```rust +# fn main() { fn it_works() { } +# } ``` We also get a summary line: @@ -94,7 +96,7 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured So why does our do-nothing test pass? Any test which doesn't `panic!` passes, and any test that does `panic!` fails. Let's make our test fail: -```rust +```rust,ignore # // The next line exists to trick play.rust-lang.org into running our code as a # // test: # // fn main @@ -169,7 +171,7 @@ This is useful if you want to integrate `cargo test` into other tooling. We can invert our test's failure with another attribute: `should_panic`: -```rust +```rust,ignore # // The next line exists to trick play.rust-lang.org into running our code as a # // test: # // fn main @@ -204,7 +206,7 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured Rust provides another macro, `assert_eq!`, that compares two arguments for equality: -```rust +```rust,ignore # // The next line exists to trick play.rust-lang.org into running our code as a # // test: # // fn main @@ -243,7 +245,7 @@ parameter can be added to the `should_panic` attribute. The test harness will make sure that the failure message contains the provided text. A safer version of the example above would be: -```rust +```rust,ignore # // The next line exists to trick play.rust-lang.org into running our code as a # // test: # // fn main @@ -280,7 +282,7 @@ some known arguments and compare it to the expected output. Sometimes a few specific tests can be very time-consuming to execute. These can be disabled by default by using the `ignore` attribute: -```rust +```rust,ignore # // The next line exists to trick play.rust-lang.org into running our code as a # // test: # // fn main From 455723c638b0e9db34d427a82bc13f95b75a304d Mon Sep 17 00:00:00 2001 From: Daniel Keep Date: Fri, 11 Nov 2016 15:23:15 +1100 Subject: [PATCH 052/177] Add foreign formatting directive detection. This teaches `format_args!` how to interpret format printf- and shell-style format directives. This is used in cases where there are unused formatting arguments, and the reason for that *might* be because the programmer is trying to use the wrong kind of formatting string. This was prompted by an issue encountered by simulacrum on the #rust IRC channel. In short: although `println!` told them that they weren't using all of the conversion arguments, the problem was in using printf-syle directives rather than ones `println!` would undertand. Where possible, `format_args!` will tell the programmer what they should use instead. For example, it will suggest replacing `%05d` with `{:0>5}`, or `%2$.*3$s` with `{1:.3$}`. Even if it cannot suggest a replacement, it will explicitly note that Rust does not support that style of directive, and direct the user to the `std::fmt` documentation. --- src/libsyntax_ext/format.rs | 76 +- src/libsyntax_ext/format_foreign.rs | 1013 ++++++++++++++++++++++ src/libsyntax_ext/lib.rs | 1 + src/test/compile-fail/ifmt-bad-arg.rs | 3 + src/test/ui/macros/format-foreign.rs | 20 + src/test/ui/macros/format-foreign.stderr | 52 ++ 6 files changed, 1163 insertions(+), 2 deletions(-) create mode 100644 src/libsyntax_ext/format_foreign.rs create mode 100644 src/test/ui/macros/format-foreign.rs create mode 100644 src/test/ui/macros/format-foreign.stderr diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index de78f859f0f6..117bb39f8e78 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -22,7 +22,7 @@ use syntax::ptr::P; use syntax_pos::{Span, DUMMY_SP}; use syntax::tokenstream; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::collections::hash_map::Entry; #[derive(PartialEq)] @@ -767,6 +767,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, // Make sure that all arguments were used and all arguments have types. let num_pos_args = cx.args.len() - cx.names.len(); + let mut errs = vec![]; for (i, ty) in cx.arg_types.iter().enumerate() { if ty.len() == 0 { if cx.count_positions.contains_key(&i) { @@ -779,9 +780,80 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, // positional argument "argument never used" }; - cx.ecx.span_err(cx.args[i].span, msg); + errs.push((cx.args[i].span, msg)); } } + if errs.len() > 0 { + let args_used = cx.arg_types.len() - errs.len(); + let args_unused = errs.len(); + + let mut diag = { + if errs.len() == 1 { + let (sp, msg) = errs.into_iter().next().unwrap(); + cx.ecx.struct_span_err(sp, msg) + } else { + let mut diag = cx.ecx.struct_span_err(cx.fmtsp, + "multiple unused formatting arguments"); + for (sp, msg) in errs { + diag.span_note(sp, msg); + } + diag + } + }; + + // Decide if we want to look for foreign formatting directives. + if args_used < args_unused { + use super::format_foreign as foreign; + let fmt_str = &fmt.node.0[..]; + + // The set of foreign substitutions we've explained. This prevents spamming the user + // with `%d should be written as {}` over and over again. + let mut explained = HashSet::new(); + + // Used to ensure we only report translations for *one* kind of foreign format. + let mut found_foreign = false; + + macro_rules! check_foreign { + ($kind:ident) => {{ + let mut show_doc_note = false; + + for sub in foreign::$kind::iter_subs(fmt_str) { + let trn = match sub.translate() { + Some(trn) => trn, + + // If it has no translation, don't call it out specifically. + None => continue, + }; + + let sub = String::from(sub.as_str()); + if explained.contains(&sub) { + continue; + } + explained.insert(sub.clone()); + + if !found_foreign { + found_foreign = true; + show_doc_note = true; + } + + diag.help(&format!("`{}` should be written as `{}`", sub, trn)); + } + + if show_doc_note { + diag.note(concat!(stringify!($kind), " formatting not supported; see \ + the documentation for `std::fmt`")); + } + }}; + } + + check_foreign!(printf); + if !found_foreign { + check_foreign!(shell); + } + } + + diag.emit(); + } cx.into_expr() } diff --git a/src/libsyntax_ext/format_foreign.rs b/src/libsyntax_ext/format_foreign.rs new file mode 100644 index 000000000000..3c802e8334da --- /dev/null +++ b/src/libsyntax_ext/format_foreign.rs @@ -0,0 +1,1013 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! try_opt { + ($e:expr) => { + match $e { + Some(v) => v, + None => return None, + } + }; +} + +pub mod printf { + use super::strcursor::StrCursor as Cur; + + /// Represents a single `printf`-style substitution. + #[derive(Clone, Eq, PartialEq, Debug)] + pub enum Substitution<'a> { + /// A formatted output substitution. + Format(Format<'a>), + /// A literal `%%` escape. + Escape, + } + + impl<'a> Substitution<'a> { + pub fn as_str(&self) -> &str { + match *self { + Substitution::Format(ref fmt) => fmt.span, + Substitution::Escape => "%%", + } + } + + /// Translate this substitution into an equivalent Rust formatting directive. + /// + /// This ignores cases where the substitution does not have an exact equivalent, or where + /// the substitution would be unnecessary. + pub fn translate(&self) -> Option { + match *self { + Substitution::Format(ref fmt) => fmt.translate(), + Substitution::Escape => None, + } + } + } + + #[derive(Clone, Eq, PartialEq, Debug)] + /// A single `printf`-style formatting directive. + pub struct Format<'a> { + /// The entire original formatting directive. + pub span: &'a str, + /// The (1-based) parameter to be converted. + pub parameter: Option, + /// Formatting flags. + pub flags: &'a str, + /// Minimum width of the output. + pub width: Option, + /// Precision of the conversion. + pub precision: Option, + /// Length modifier for the conversion. + pub length: Option<&'a str>, + /// Type of parameter being converted. + pub type_: &'a str, + } + + impl<'a> Format<'a> { + /// Translate this directive into an equivalent Rust formatting directive. + /// + /// Returns `None` in cases where the `printf` directive does not have an exact Rust + /// equivalent, rather than guessing. + pub fn translate(&self) -> Option { + use std::fmt::Write; + + let (c_alt, c_zero, c_left, c_plus) = { + let mut c_alt = false; + let mut c_zero = false; + let mut c_left = false; + let mut c_plus = false; + for c in self.flags.chars() { + match c { + '#' => c_alt = true, + '0' => c_zero = true, + '-' => c_left = true, + '+' => c_plus = true, + _ => return None + } + } + (c_alt, c_zero, c_left, c_plus) + }; + + // Has a special form in Rust for numbers. + let fill = if c_zero { Some("0") } else { None }; + + let align = if c_left { Some("<") } else { None }; + + // Rust doesn't have an equivalent to the `' '` flag. + let sign = if c_plus { Some("+") } else { None }; + + // Not *quite* the same, depending on the type... + let alt = c_alt; + + let width = match self.width { + Some(Num::Next) => { + // NOTE: Rust doesn't support this. + return None; + } + w @ Some(Num::Arg(_)) => w, + w @ Some(Num::Num(_)) => w, + None => None, + }; + + let precision = self.precision; + + // NOTE: although length *can* have an effect, we can't duplicate the effect in Rust, so + // we just ignore it. + + let (type_, use_zero_fill, is_int) = match self.type_ { + "d" | "i" | "u" => (None, true, true), + "f" | "F" => (None, false, false), + "s" | "c" => (None, false, false), + "e" | "E" => (Some(self.type_), true, false), + "x" | "X" | "o" => (Some(self.type_), true, true), + "p" => (Some(self.type_), false, true), + "g" => (Some("e"), true, false), + "G" => (Some("E"), true, false), + _ => return None, + }; + + let (fill, width, precision) = match (is_int, width, precision) { + (true, Some(_), Some(_)) => { + // Rust can't duplicate this insanity. + return None; + }, + (true, None, Some(p)) => (Some("0"), Some(p), None), + (true, w, None) => (fill, w, None), + (false, w, p) => (fill, w, p), + }; + + let align = match (self.type_, width.is_some(), align.is_some()) { + ("s", true, false) => Some(">"), + _ => align, + }; + + let (fill, zero_fill) = match (fill, use_zero_fill) { + (Some("0"), true) => (None, true), + (fill, _) => (fill, false), + }; + + let alt = match type_ { + Some("x") | Some("X") => alt, + _ => false, + }; + + let has_options = fill.is_some() + || align.is_some() + || sign.is_some() + || alt + || zero_fill + || width.is_some() + || precision.is_some() + || type_.is_some() + ; + + // Initialise with a rough guess. + let cap = self.span.len() + if has_options { 2 } else { 0 }; + let mut s = String::with_capacity(cap); + + s.push_str("{"); + + if let Some(arg) = self.parameter { + try_opt!(write!(s, "{}", try_opt!(arg.checked_sub(1))).ok()); + } + + if has_options { + s.push_str(":"); + + let align = if let Some(fill) = fill { + s.push_str(fill); + align.or(Some(">")) + } else { + align + }; + + if let Some(align) = align { + s.push_str(align); + } + + if let Some(sign) = sign { + s.push_str(sign); + } + + if alt { + s.push_str("#"); + } + + if zero_fill { + s.push_str("0"); + } + + if let Some(width) = width { + try_opt!(width.translate(&mut s).ok()); + } + + if let Some(precision) = precision { + s.push_str("."); + try_opt!(precision.translate(&mut s).ok()); + } + + if let Some(type_) = type_ { + s.push_str(type_); + } + } + + s.push_str("}"); + Some(s) + } + } + + /// A general number used in a `printf` formatting directive. + #[derive(Copy, Clone, Eq, PartialEq, Debug)] + pub enum Num { + // The range of these values is technically bounded by `NL_ARGMAX`... but, at least for GNU + // libc, it apparently has no real fixed limit. A `u16` is used here on the basis that it + // is *vanishingly* unlikely that *anyone* is going to try formatting something wider, or + // with more precision, than 32 thousand positions which is so wide it couldn't possibly fit + // on a screen. + + /// A specific, fixed value. + Num(u16), + /// The value is derived from a positional argument. + Arg(u16), + /// The value is derived from the "next" unconverted argument. + Next, + } + + impl Num { + fn from_str(s: &str, arg: Option<&str>) -> Self { + if let Some(arg) = arg { + Num::Arg(arg.parse().expect(&format!("invalid format arg `{:?}`", arg))) + } else if s == "*" { + Num::Next + } else { + Num::Num(s.parse().expect(&format!("invalid format num `{:?}`", s))) + } + } + + fn translate(&self, s: &mut String) -> ::std::fmt::Result { + use std::fmt::Write; + match *self { + Num::Num(n) => write!(s, "{}", n), + Num::Arg(n) => { + let n = try!(n.checked_sub(1).ok_or(::std::fmt::Error)); + write!(s, "{}$", n) + }, + Num::Next => write!(s, "*"), + } + } + } + + /// Returns an iterator over all substitutions in a given string. + pub fn iter_subs(s: &str) -> Substitutions { + Substitutions { + s: s, + } + } + + /// Iterator over substitutions in a string. + pub struct Substitutions<'a> { + s: &'a str, + } + + impl<'a> Iterator for Substitutions<'a> { + type Item = Substitution<'a>; + fn next(&mut self) -> Option { + match parse_next_substitution(self.s) { + Some((sub, tail)) => { + self.s = tail; + Some(sub) + }, + None => None, + } + } + } + + enum State { + Start, + Flags, + Width, + WidthArg, + Prec, + PrecInner, + Length, + Type, + } + + /// Parse the next substitution from the input string. + pub fn parse_next_substitution(s: &str) -> Option<(Substitution, &str)> { + use self::State::*; + + let at = { + let start = try_opt!(s.find('%')); + match s[start+1..].chars().next() { + Some('%') => return Some((Substitution::Escape, &s[start+2..])), + Some(_) => {/* fall-through */}, + None => return None, + } + + Cur::new_at_start(&s[start..]) + }; + + // This is meant to be a translation of the following regex: + // + // ```regex + // (?x) + // ^ % + // (?: (?P \d+) \$ )? + // (?P [-+ 0\#']* ) + // (?P \d+ | \* (?: (?P \d+) \$ )? )? + // (?: \. (?P \d+ | \* (?: (?P \d+) \$ )? ) )? + // (?P + // # Standard + // hh | h | ll | l | L | z | j | t + // + // # Other + // | I32 | I64 | I | q + // )? + // (?P . ) + // ``` + + // Used to establish the full span at the end. + let start = at; + // The current position within the string. + let mut at = try_opt!(at.at_next_cp()); + // `c` is the next codepoint, `next` is a cursor after it. + let (mut c, mut next) = try_opt!(at.next_cp()); + + // Update `at`, `c`, and `next`, exiting if we're out of input. + macro_rules! move_to { + ($cur:expr) => { + { + at = $cur; + let (c_, next_) = try_opt!(at.next_cp()); + c = c_; + next = next_; + } + }; + } + + // Constructs a result when parsing fails. + // + // Note: `move` used to capture copies of the cursors as they are *now*. + let fallback = move || { + return Some(( + Substitution::Format(Format { + span: start.slice_between(next).unwrap(), + parameter: None, + flags: "", + width: None, + precision: None, + length: None, + type_: at.slice_between(next).unwrap(), + }), + next.slice_after() + )); + }; + + // Next parsing state. + let mut state = Start; + + // Sadly, Rust isn't *quite* smart enough to know these *must* be initialised by the end. + let mut parameter: Option = None; + let mut flags: &str = ""; + let mut width: Option = None; + let mut precision: Option = None; + let mut length: Option<&str> = None; + let mut type_: &str = ""; + let end: Cur; + + if let Start = state { + match c { + '1'...'9' => { + let end = at_next_cp_while(next, is_digit); + match end.next_cp() { + // Yes, this *is* the parameter. + Some(('$', end2)) => { + state = Flags; + parameter = Some(at.slice_between(end).unwrap().parse().unwrap()); + move_to!(end2); + }, + // Wait, no, actually, it's the width. + Some(_) => { + state = Prec; + parameter = None; + flags = ""; + width = Some(Num::from_str(at.slice_between(end).unwrap(), None)); + move_to!(end); + }, + // It's invalid, is what it is. + None => return fallback(), + } + }, + _ => { + state = Flags; + parameter = None; + move_to!(at); + } + } + } + + if let Flags = state { + let end = at_next_cp_while(at, is_flag); + state = Width; + flags = at.slice_between(end).unwrap(); + move_to!(end); + } + + if let Width = state { + match c { + '*' => { + state = WidthArg; + move_to!(next); + }, + '1' ... '9' => { + let end = at_next_cp_while(next, is_digit); + state = Prec; + width = Some(Num::from_str(at.slice_between(end).unwrap(), None)); + move_to!(end); + }, + _ => { + state = Prec; + width = None; + move_to!(at); + } + } + } + + if let WidthArg = state { + let end = at_next_cp_while(at, is_digit); + match end.next_cp() { + Some(('$', end2)) => { + state = Prec; + width = Some(Num::from_str("", Some(at.slice_between(end).unwrap()))); + move_to!(end2); + }, + _ => { + state = Prec; + width = Some(Num::Next); + move_to!(end); + } + } + } + + if let Prec = state { + match c { + '.' => { + state = PrecInner; + move_to!(next); + }, + _ => { + state = Length; + precision = None; + move_to!(at); + } + } + } + + if let PrecInner = state { + match c { + '*' => { + let end = at_next_cp_while(next, is_digit); + match end.next_cp() { + Some(('$', end2)) => { + state = Length; + precision = Some(Num::from_str("*", next.slice_between(end))); + move_to!(end2); + }, + _ => { + state = Length; + precision = Some(Num::Next); + move_to!(end); + } + } + }, + '0' ... '9' => { + let end = at_next_cp_while(next, is_digit); + state = Length; + precision = Some(Num::from_str(at.slice_between(end).unwrap(), None)); + move_to!(end); + }, + _ => return fallback(), + } + } + + if let Length = state { + let c1_next1 = next.next_cp(); + match (c, c1_next1) { + ('h', Some(('h', next1))) + | ('l', Some(('l', next1))) + => { + state = Type; + length = Some(at.slice_between(next1).unwrap()); + move_to!(next1); + }, + + ('h', _) | ('l', _) | ('L', _) + | ('z', _) | ('j', _) | ('t', _) + | ('q', _) + => { + state = Type; + length = Some(at.slice_between(next).unwrap()); + move_to!(next); + }, + + ('I', _) => { + let end = next.at_next_cp() + .and_then(|end| end.at_next_cp()) + .map(|end| (next.slice_between(end).unwrap(), end)); + let end = match end { + Some(("32", end)) => end, + Some(("64", end)) => end, + _ => next + }; + state = Type; + length = Some(at.slice_between(end).unwrap()); + move_to!(end); + }, + + _ => { + state = Type; + length = None; + move_to!(at); + } + } + } + + if let Type = state { + drop(c); + type_ = at.slice_between(next).unwrap(); + + // Don't use `move_to!` here, as we *can* be at the end of the input. + at = next; + } + + drop(c); + drop(next); + + end = at; + + let f = Format { + span: start.slice_between(end).unwrap(), + parameter: parameter, + flags: flags, + width: width, + precision: precision, + length: length, + type_: type_, + }; + Some((Substitution::Format(f), end.slice_after())) + } + + fn at_next_cp_while(mut cur: Cur, mut pred: F) -> Cur + where F: FnMut(char) -> bool { + loop { + match cur.next_cp() { + Some((c, next)) => if pred(c) { + cur = next; + } else { + return cur; + }, + None => return cur, + } + } + } + + fn is_digit(c: char) -> bool { + match c { + '0' ... '9' => true, + _ => false + } + } + + fn is_flag(c: char) -> bool { + match c { + '0' | '-' | '+' | ' ' | '#' | '\'' => true, + _ => false + } + } + + #[cfg(test)] + mod tests { + use super::{ + Format as F, + Num as N, + Substitution as S, + iter_subs, + parse_next_substitution as pns, + }; + + macro_rules! assert_eq_pnsat { + ($lhs:expr, $rhs:expr) => { + assert_eq!( + pns($lhs).and_then(|(s, _)| s.translate()), + $rhs.map(>::from) + ) + }; + } + + #[test] + fn test_escape() { + assert_eq!(pns("has no escapes"), None); + assert_eq!(pns("has no escapes, either %"), None); + assert_eq!(pns("*so* has a %% escape"), Some((S::Escape," escape"))); + assert_eq!(pns("%% leading escape"), Some((S::Escape, " leading escape"))); + assert_eq!(pns("trailing escape %%"), Some((S::Escape, ""))); + } + + #[test] + fn test_parse() { + macro_rules! assert_pns_eq_sub { + ($in_:expr, { + $param:expr, $flags:expr, + $width:expr, $prec:expr, $len:expr, $type_:expr, + }) => { + assert_eq!( + pns(concat!($in_, "!")), + Some(( + S::Format(F { + span: $in_, + parameter: $param, + flags: $flags, + width: $width, + precision: $prec, + length: $len, + type_: $type_, + }), + "!" + )) + ) + }; + } + + assert_pns_eq_sub!("%!", + { None, "", None, None, None, "!", }); + assert_pns_eq_sub!("%c", + { None, "", None, None, None, "c", }); + assert_pns_eq_sub!("%s", + { None, "", None, None, None, "s", }); + assert_pns_eq_sub!("%06d", + { None, "0", Some(N::Num(6)), None, None, "d", }); + assert_pns_eq_sub!("%4.2f", + { None, "", Some(N::Num(4)), Some(N::Num(2)), None, "f", }); + assert_pns_eq_sub!("%#x", + { None, "#", None, None, None, "x", }); + assert_pns_eq_sub!("%-10s", + { None, "-", Some(N::Num(10)), None, None, "s", }); + assert_pns_eq_sub!("%*s", + { None, "", Some(N::Next), None, None, "s", }); + assert_pns_eq_sub!("%-10.*s", + { None, "-", Some(N::Num(10)), Some(N::Next), None, "s", }); + assert_pns_eq_sub!("%-*.*s", + { None, "-", Some(N::Next), Some(N::Next), None, "s", }); + assert_pns_eq_sub!("%.6i", + { None, "", None, Some(N::Num(6)), None, "i", }); + assert_pns_eq_sub!("%+i", + { None, "+", None, None, None, "i", }); + assert_pns_eq_sub!("%08X", + { None, "0", Some(N::Num(8)), None, None, "X", }); + assert_pns_eq_sub!("%lu", + { None, "", None, None, Some("l"), "u", }); + assert_pns_eq_sub!("%Iu", + { None, "", None, None, Some("I"), "u", }); + assert_pns_eq_sub!("%I32u", + { None, "", None, None, Some("I32"), "u", }); + assert_pns_eq_sub!("%I64u", + { None, "", None, None, Some("I64"), "u", }); + assert_pns_eq_sub!("%'d", + { None, "'", None, None, None, "d", }); + assert_pns_eq_sub!("%10s", + { None, "", Some(N::Num(10)), None, None, "s", }); + assert_pns_eq_sub!("%-10.10s", + { None, "-", Some(N::Num(10)), Some(N::Num(10)), None, "s", }); + assert_pns_eq_sub!("%1$d", + { Some(1), "", None, None, None, "d", }); + assert_pns_eq_sub!("%2$.*3$d", + { Some(2), "", None, Some(N::Arg(3)), None, "d", }); + assert_pns_eq_sub!("%1$*2$.*3$d", + { Some(1), "", Some(N::Arg(2)), Some(N::Arg(3)), None, "d", }); + assert_pns_eq_sub!("%-8ld", + { None, "-", Some(N::Num(8)), None, Some("l"), "d", }); + } + + #[test] + fn test_iter() { + let s = "The %d'th word %% is: `%.*s` %!\n"; + let subs: Vec<_> = iter_subs(s).map(|sub| sub.translate()).collect(); + assert_eq!( + subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::>(), + vec![Some("{}"), None, Some("{:.*}"), None] + ); + } + + /// Check that the translations are what we expect. + #[test] + fn test_trans() { + assert_eq_pnsat!("%c", Some("{}")); + assert_eq_pnsat!("%d", Some("{}")); + assert_eq_pnsat!("%u", Some("{}")); + assert_eq_pnsat!("%x", Some("{:x}")); + assert_eq_pnsat!("%X", Some("{:X}")); + assert_eq_pnsat!("%e", Some("{:e}")); + assert_eq_pnsat!("%E", Some("{:E}")); + assert_eq_pnsat!("%f", Some("{}")); + assert_eq_pnsat!("%g", Some("{:e}")); + assert_eq_pnsat!("%G", Some("{:E}")); + assert_eq_pnsat!("%s", Some("{}")); + assert_eq_pnsat!("%p", Some("{:p}")); + + assert_eq_pnsat!("%06d", Some("{:06}")); + assert_eq_pnsat!("%4.2f", Some("{:4.2}")); + assert_eq_pnsat!("%#x", Some("{:#x}")); + assert_eq_pnsat!("%-10s", Some("{:<10}")); + assert_eq_pnsat!("%*s", None); + assert_eq_pnsat!("%-10.*s", Some("{:<10.*}")); + assert_eq_pnsat!("%-*.*s", None); + assert_eq_pnsat!("%.6i", Some("{:06}")); + assert_eq_pnsat!("%+i", Some("{:+}")); + assert_eq_pnsat!("%08X", Some("{:08X}")); + assert_eq_pnsat!("%lu", Some("{}")); + assert_eq_pnsat!("%Iu", Some("{}")); + assert_eq_pnsat!("%I32u", Some("{}")); + assert_eq_pnsat!("%I64u", Some("{}")); + assert_eq_pnsat!("%'d", None); + assert_eq_pnsat!("%10s", Some("{:>10}")); + assert_eq_pnsat!("%-10.10s", Some("{:<10.10}")); + assert_eq_pnsat!("%1$d", Some("{0}")); + assert_eq_pnsat!("%2$.*3$d", Some("{1:02$}")); + assert_eq_pnsat!("%1$*2$.*3$s", Some("{0:>1$.2$}")); + assert_eq_pnsat!("%-8ld", Some("{:<8}")); + } + } +} + +pub mod shell { + use super::strcursor::StrCursor as Cur; + + #[derive(Clone, Eq, PartialEq, Debug)] + pub enum Substitution<'a> { + Ordinal(u8), + Name(&'a str), + Escape, + } + + impl<'a> Substitution<'a> { + pub fn as_str(&self) -> String { + match *self { + Substitution::Ordinal(n) => format!("${}", n), + Substitution::Name(n) => format!("${}", n), + Substitution::Escape => "$$".into(), + } + } + + pub fn translate(&self) -> Option { + match *self { + Substitution::Ordinal(n) => Some(format!("{{{}}}", n)), + Substitution::Name(n) => Some(format!("{{{}}}", n)), + Substitution::Escape => None, + } + } + } + + /// Returns an iterator over all substitutions in a given string. + pub fn iter_subs(s: &str) -> Substitutions { + Substitutions { + s: s, + } + } + + /// Iterator over substitutions in a string. + pub struct Substitutions<'a> { + s: &'a str, + } + + impl<'a> Iterator for Substitutions<'a> { + type Item = Substitution<'a>; + fn next(&mut self) -> Option { + match parse_next_substitution(self.s) { + Some((sub, tail)) => { + self.s = tail; + Some(sub) + }, + None => None, + } + } + } + + /// Parse the next substitution from the input string. + pub fn parse_next_substitution(s: &str) -> Option<(Substitution, &str)> { + let at = { + let start = try_opt!(s.find('$')); + match s[start+1..].chars().next() { + Some('$') => return Some((Substitution::Escape, &s[start+2..])), + Some(c @ '0' ... '9') => { + let n = (c as u8) - b'0'; + return Some((Substitution::Ordinal(n), &s[start+2..])); + }, + Some(_) => {/* fall-through */}, + None => return None, + } + + Cur::new_at_start(&s[start..]) + }; + + let at = try_opt!(at.at_next_cp()); + match at.next_cp() { + Some((c, inner)) => { + if !is_ident_head(c) { + None + } else { + let end = at_next_cp_while(inner, is_ident_tail); + Some((Substitution::Name(at.slice_between(end).unwrap()), end.slice_after())) + } + }, + _ => None + } + } + + fn at_next_cp_while(mut cur: Cur, mut pred: F) -> Cur + where F: FnMut(char) -> bool { + loop { + match cur.next_cp() { + Some((c, next)) => if pred(c) { + cur = next; + } else { + return cur; + }, + None => return cur, + } + } + } + + fn is_ident_head(c: char) -> bool { + match c { + 'a' ... 'z' | 'A' ... 'Z' | '_' => true, + _ => false + } + } + + fn is_ident_tail(c: char) -> bool { + match c { + '0' ... '9' => true, + c => is_ident_head(c) + } + } + + #[cfg(test)] + mod tests { + use super::{ + Substitution as S, + parse_next_substitution as pns, + }; + + macro_rules! assert_eq_pnsat { + ($lhs:expr, $rhs:expr) => { + assert_eq!( + pns($lhs).and_then(|(f, _)| f.translate()), + $rhs.map(>::from) + ) + }; + } + + #[test] + fn test_escape() { + assert_eq!(pns("has no escapes"), None); + assert_eq!(pns("has no escapes, either $"), None); + assert_eq!(pns("*so* has a $$ escape"), Some((S::Escape, " escape"))); + assert_eq!(pns("$$ leading escape"), Some((S::Escape, " leading escape"))); + assert_eq!(pns("trailing escape $$"), Some((S::Escape, ""))); + } + + #[test] + fn test_parse() { + macro_rules! assert_pns_eq_sub { + ($in_:expr, $kind:ident($arg:expr)) => { + assert_eq!(pns(concat!($in_, "!")), Some((S::$kind($arg.into()), "!"))) + }; + } + + assert_pns_eq_sub!("$0", Ordinal(0)); + assert_pns_eq_sub!("$1", Ordinal(1)); + assert_pns_eq_sub!("$9", Ordinal(9)); + assert_pns_eq_sub!("$N", Name("N")); + assert_pns_eq_sub!("$NAME", Name("NAME")); + } + + #[test] + fn test_iter() { + use super::iter_subs; + let s = "The $0'th word $$ is: `$WORD` $!\n"; + let subs: Vec<_> = iter_subs(s).map(|sub| sub.translate()).collect(); + assert_eq!( + subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::>(), + vec![Some("{0}"), None, Some("{WORD}")] + ); + } + + #[test] + fn test_trans() { + assert_eq_pnsat!("$0", Some("{0}")); + assert_eq_pnsat!("$9", Some("{9}")); + assert_eq_pnsat!("$1", Some("{1}")); + assert_eq_pnsat!("$10", Some("{1}")); + assert_eq_pnsat!("$stuff", Some("{stuff}")); + assert_eq_pnsat!("$NAME", Some("{NAME}")); + assert_eq_pnsat!("$PREFIX/bin", Some("{PREFIX}")); + } + + } +} + +mod strcursor { + use std; + + pub struct StrCursor<'a> { + s: &'a str, + at: usize, + } + + impl<'a> StrCursor<'a> { + pub fn new_at_start(s: &'a str) -> StrCursor<'a> { + StrCursor { + s: s, + at: 0, + } + } + + pub fn at_next_cp(mut self) -> Option> { + match self.try_seek_right_cp() { + true => Some(self), + false => None + } + } + + pub fn next_cp(mut self) -> Option<(char, StrCursor<'a>)> { + let cp = match self.cp_after() { + Some(cp) => cp, + None => return None, + }; + self.seek_right(cp.len_utf8()); + Some((cp, self)) + } + + fn slice_before(&self) -> &'a str { + &self.s[0..self.at] + } + + pub fn slice_after(&self) -> &'a str { + &self.s[self.at..] + } + + pub fn slice_between(&self, until: StrCursor<'a>) -> Option<&'a str> { + if !str_eq_literal(self.s, until.s) { + None + } else { + use std::cmp::{max, min}; + let beg = min(self.at, until.at); + let end = max(self.at, until.at); + Some(&self.s[beg..end]) + } + } + + fn cp_after(&self) -> Option { + self.slice_after().chars().next() + } + + fn try_seek_right_cp(&mut self) -> bool { + match self.slice_after().chars().next() { + Some(c) => { + self.at += c.len_utf8(); + true + }, + None => false, + } + } + + fn seek_right(&mut self, bytes: usize) { + self.at += bytes; + } + } + + impl<'a> Copy for StrCursor<'a> {} + + impl<'a> Clone for StrCursor<'a> { + fn clone(&self) -> StrCursor<'a> { + *self + } + } + + impl<'a> std::fmt::Debug for StrCursor<'a> { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + write!(fmt, "StrCursor({:?} | {:?})", self.slice_before(), self.slice_after()) + } + } + + fn str_eq_literal(a: &str, b: &str) -> bool { + a.as_bytes().as_ptr() == b.as_bytes().as_ptr() + && a.len() == b.len() + } +} diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index f336b26ae41f..f884bed9b525 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -40,6 +40,7 @@ mod concat; mod concat_idents; mod env; mod format; +mod format_foreign; mod log_syntax; mod trace_macros; diff --git a/src/test/compile-fail/ifmt-bad-arg.rs b/src/test/compile-fail/ifmt-bad-arg.rs index 59c61a42e077..a23b4b077410 100644 --- a/src/test/compile-fail/ifmt-bad-arg.rs +++ b/src/test/compile-fail/ifmt-bad-arg.rs @@ -17,6 +17,7 @@ fn main() { //~^ ERROR: argument never used format!("{foo}"); //~ ERROR: no argument named `foo` + format!("", 1, 2); //~ ERROR: multiple unused formatting arguments format!("{}", 1, 2); //~ ERROR: argument never used format!("{1}", 1, 2); //~ ERROR: argument never used format!("{}", 1, foo=2); //~ ERROR: named argument never used @@ -53,4 +54,6 @@ fn main() { format!("foo } bar"); //~ ERROR: unmatched `}` found format!("foo }"); //~ ERROR: unmatched `}` found + + format!("foo %s baz", "bar"); //~ ERROR: argument never used } diff --git a/src/test/ui/macros/format-foreign.rs b/src/test/ui/macros/format-foreign.rs new file mode 100644 index 000000000000..cca45ca9ecdd --- /dev/null +++ b/src/test/ui/macros/format-foreign.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + println!("%.*3$s %s!\n", "Hello,", "World", 4); + println!("%1$*2$.*3$f", 123.456); + + // This should *not* produce hints, on the basis that there's equally as + // many "correct" format specifiers. It's *probably* just an actual typo. + println!("{} %f", "one", 2.0); + + println!("Hi there, $NAME.", NAME="Tim"); +} diff --git a/src/test/ui/macros/format-foreign.stderr b/src/test/ui/macros/format-foreign.stderr new file mode 100644 index 000000000000..0283052a89f5 --- /dev/null +++ b/src/test/ui/macros/format-foreign.stderr @@ -0,0 +1,52 @@ +error: multiple unused formatting arguments + --> $DIR/format-foreign.rs:12:5 + | +12 | println!("%.*3$s %s!/n", "Hello,", "World", 4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: argument never used + --> $DIR/format-foreign.rs:12:30 + | +12 | println!("%.*3$s %s!/n", "Hello,", "World", 4); + | ^^^^^^^^ +note: argument never used + --> $DIR/format-foreign.rs:12:40 + | +12 | println!("%.*3$s %s!/n", "Hello,", "World", 4); + | ^^^^^^^ +note: argument never used + --> $DIR/format-foreign.rs:12:49 + | +12 | println!("%.*3$s %s!/n", "Hello,", "World", 4); + | ^ + = help: `%.*3$s` should be written as `{:.2$}` + = help: `%s` should be written as `{}` + = note: printf formatting not supported; see the documentation for `std::fmt` + = note: this error originates in a macro outside of the current crate + +error: argument never used + --> $DIR/format-foreign.rs:13:29 + | +13 | println!("%1$*2$.*3$f", 123.456); + | ^^^^^^^ + | + = help: `%1$*2$.*3$f` should be written as `{0:1$.2$}` + = note: printf formatting not supported; see the documentation for `std::fmt` + +error: argument never used + --> $DIR/format-foreign.rs:17:30 + | +17 | println!("{} %f", "one", 2.0); + | ^^^ + +error: named argument never used + --> $DIR/format-foreign.rs:19:39 + | +19 | println!("Hi there, $NAME.", NAME="Tim"); + | ^^^^^ + | + = help: `$NAME` should be written as `{NAME}` + = note: shell formatting not supported; see the documentation for `std::fmt` + +error: aborting due to 4 previous errors + From 11c1126688bab32f76dbe1a973906c7586da143f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 11 Nov 2016 15:56:58 +1100 Subject: [PATCH 053/177] Avoid unnecessary mk_ty calls in Ty::super_fold_with. This speeds up compilation of several rustc-benchmarks by 1--2% and the workload in #36799 by 5%. --- src/librustc/ty/structural_impls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 9ca911837b51..282cb9f80f51 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -482,7 +482,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyAnon(did, substs) => ty::TyAnon(did, substs.fold_with(folder)), ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) | - ty::TyParam(..) | ty::TyNever => self.sty.clone(), + ty::TyParam(..) | ty::TyNever => return self }; folder.tcx().mk_ty(sty) } From 5058e58676bd6c3af63fc4e35a327c07fce2a276 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Fri, 11 Nov 2016 12:54:10 +0100 Subject: [PATCH 054/177] vec: Write the .extend() specialization in cleaner style As far as possible, use regular `default fn` specialization in favour of ad-hoc conditionals. --- src/libcollections/vec.rs | 71 ++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 30 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 71c49ee616cb..53b7ae0703bf 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1586,36 +1586,34 @@ impl<'a, T> IntoIterator for &'a mut Vec { impl Extend for Vec { #[inline] fn extend>(&mut self, iter: I) { - self.extend_desugared(iter.into_iter()) + self.spec_extend(iter.into_iter()) } } -trait IsTrustedLen : Iterator { - fn trusted_len(&self) -> Option { None } +trait SpecExtend { + fn spec_extend(&mut self, iter: I); } -impl IsTrustedLen for I where I: Iterator { } -impl IsTrustedLen for I where I: TrustedLen +impl SpecExtend for Vec + where I: Iterator, { - fn trusted_len(&self) -> Option { - let (low, high) = self.size_hint(); + default fn spec_extend(&mut self, iter: I) { + self.extend_desugared(iter) + } +} + +impl SpecExtend for Vec + where I: TrustedLen, +{ + fn spec_extend(&mut self, iterator: I) { + // This is the case for a TrustedLen iterator. + let (low, high) = iterator.size_hint(); if let Some(high_value) = high { debug_assert_eq!(low, high_value, "TrustedLen iterator's size hint is not exact: {:?}", (low, high)); } - high - } -} - -impl Vec { - fn extend_desugared>(&mut self, mut iterator: I) { - // This function should be the moral equivalent of: - // - // for item in iterator { - // self.push(item); - // } - if let Some(additional) = iterator.trusted_len() { + if let Some(additional) = high { self.reserve(additional); unsafe { let mut ptr = self.as_mut_ptr().offset(self.len() as isize); @@ -1628,17 +1626,30 @@ impl Vec { } } } else { - while let Some(element) = iterator.next() { - let len = self.len(); - if len == self.capacity() { - let (lower, _) = iterator.size_hint(); - self.reserve(lower.saturating_add(1)); - } - unsafe { - ptr::write(self.get_unchecked_mut(len), element); - // NB can't overflow since we would have had to alloc the address space - self.set_len(len + 1); - } + self.extend_desugared(iterator) + } + } +} + +impl Vec { + fn extend_desugared>(&mut self, mut iterator: I) { + // This is the case for a general iterator. + // + // This function should be the moral equivalent of: + // + // for item in iterator { + // self.push(item); + // } + while let Some(element) = iterator.next() { + let len = self.len(); + if len == self.capacity() { + let (lower, _) = iterator.size_hint(); + self.reserve(lower.saturating_add(1)); + } + unsafe { + ptr::write(self.get_unchecked_mut(len), element); + // NB can't overflow since we would have had to alloc the address space + self.set_len(len + 1); } } } From 323c20c8a4747aa96285c90005a00aa43228af8e Mon Sep 17 00:00:00 2001 From: Oliver 'ker' Schneider Date: Fri, 11 Nov 2016 11:55:47 +0100 Subject: [PATCH 055/177] [breaking-change] change the `box_free` item to accept pointers to unsized types --- src/doc/book/lang-items.md | 4 ++-- src/liballoc/heap.rs | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/doc/book/lang-items.md b/src/doc/book/lang-items.md index de7dbab3f12e..9fb130845fb1 100644 --- a/src/doc/book/lang-items.md +++ b/src/doc/book/lang-items.md @@ -46,8 +46,8 @@ unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) { } #[lang = "box_free"] -unsafe fn box_free(ptr: *mut T) { - deallocate(ptr as *mut u8, ::core::mem::size_of::(), ::core::mem::align_of::()); +unsafe fn box_free(ptr: *mut T) { + deallocate(ptr as *mut u8, ::core::mem::size_of_val(&*ptr), ::core::mem::align_of_val(&*ptr)); } #[start] diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index bfed8a8e83a5..12809171b743 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -17,7 +17,7 @@ use core::{isize, usize}; #[cfg(not(test))] -use core::intrinsics::{min_align_of, size_of}; +use core::intrinsics::{min_align_of_val, size_of_val}; #[allow(improper_ctypes)] extern "C" { @@ -152,11 +152,12 @@ unsafe fn exchange_free(ptr: *mut u8, old_size: usize, align: usize) { #[cfg(not(test))] #[lang = "box_free"] #[inline] -unsafe fn box_free(ptr: *mut T) { - let size = size_of::(); +unsafe fn box_free(ptr: *mut T) { + let size = size_of_val(&*ptr); + let align = min_align_of_val(&*ptr); // We do not allocate for Box when T is ZST, so deallocation is also not necessary. if size != 0 { - deallocate(ptr as *mut u8, size, min_align_of::()); + deallocate(ptr as *mut u8, size, align); } } From 7bbebb1f542e4431249faa1138da4cfcb6b9269a Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Wed, 2 Nov 2016 22:33:35 -0600 Subject: [PATCH 056/177] Change implementation of syntax::util::SmallVector to use data_structures::SmallVec. --- mk/crates.mk | 2 +- src/Cargo.lock | 1 + src/librustc/infer/combine.rs | 2 +- .../accumulate_vec.rs | 158 ++++++++++- src/librustc_data_structures/array_vec.rs | 153 +++++++++- src/librustc_data_structures/lib.rs | 1 + src/librustc_data_structures/small_vec.rs | 203 +++++++++++++ src/libsyntax/Cargo.toml | 1 + src/libsyntax/config.rs | 2 +- src/libsyntax/ext/base.rs | 6 +- src/libsyntax/ext/expand.rs | 14 +- src/libsyntax/ext/source_util.rs | 2 +- src/libsyntax/lib.rs | 1 + src/libsyntax/util/move_map.rs | 49 ++++ src/libsyntax/util/small_vector.rs | 268 +----------------- 15 files changed, 575 insertions(+), 288 deletions(-) create mode 100644 src/librustc_data_structures/small_vec.rs diff --git a/mk/crates.mk b/mk/crates.mk index 25192bfd27a4..7ae5846c54b9 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -100,7 +100,7 @@ DEPS_serialize := std log DEPS_term := std DEPS_test := std getopts term native:rust_test_helpers -DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode rustc_errors syntax_pos +DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode rustc_errors syntax_pos rustc_data_structures DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros proc_macro DEPS_syntax_pos := serialize DEPS_proc_macro_tokens := syntax syntax_pos log diff --git a/src/Cargo.lock b/src/Cargo.lock index d3517175d4ce..ee38a043b122 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -621,6 +621,7 @@ version = "0.0.0" dependencies = [ "log 0.0.0", "rustc_bitflags 0.0.0", + "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "serialize 0.0.0", "syntax_pos 0.0.0", diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index fda08eba0213..641273d2b762 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -184,7 +184,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { { // We use SmallVector here instead of Vec because this code is hot and // it's rare that the stack length exceeds 1. - let mut stack = SmallVector::zero(); + let mut stack = SmallVector::new(); stack.push((a_ty, dir, b_vid)); loop { // For each turn of the loop, we extract a tuple diff --git a/src/librustc_data_structures/accumulate_vec.rs b/src/librustc_data_structures/accumulate_vec.rs index 3894db40277a..937cb3f60074 100644 --- a/src/librustc_data_structures/accumulate_vec.rs +++ b/src/librustc_data_structures/accumulate_vec.rs @@ -11,22 +11,68 @@ //! A vector type intended to be used for collecting from iterators onto the stack. //! //! Space for up to N elements is provided on the stack. If more elements are collected, Vec is -//! used to store the values on the heap. This type does not support re-allocating onto the heap, -//! and there is no way to push more elements onto the existing storage. +//! used to store the values on the heap. //! //! The N above is determined by Array's implementor, by way of an associatated constant. -use std::ops::Deref; -use std::iter::{IntoIterator, FromIterator}; +use std::ops::{Deref, DerefMut}; +use std::iter::{self, IntoIterator, FromIterator}; +use std::slice; +use std::vec; -use array_vec::{Array, ArrayVec}; +use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; -#[derive(Debug)] +use array_vec::{self, Array, ArrayVec}; + +#[derive(PartialEq, Eq, Hash, Debug)] pub enum AccumulateVec { Array(ArrayVec), Heap(Vec) } +impl Clone for AccumulateVec + where A: Array, + A::Element: Clone { + fn clone(&self) -> Self { + match *self { + AccumulateVec::Array(ref arr) => AccumulateVec::Array(arr.clone()), + AccumulateVec::Heap(ref vec) => AccumulateVec::Heap(vec.clone()), + } + } +} + +impl AccumulateVec { + pub fn new() -> AccumulateVec { + AccumulateVec::Array(ArrayVec::new()) + } + + pub fn one(el: A::Element) -> Self { + iter::once(el).collect() + } + + pub fn many>(iter: I) -> Self { + iter.into_iter().collect() + } + + pub fn len(&self) -> usize { + match *self { + AccumulateVec::Array(ref arr) => arr.len(), + AccumulateVec::Heap(ref vec) => vec.len(), + } + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + pub fn pop(&mut self) -> Option { + match *self { + AccumulateVec::Array(ref mut arr) => arr.pop(), + AccumulateVec::Heap(ref mut vec) => vec.pop(), + } + } +} + impl Deref for AccumulateVec { type Target = [A::Element]; fn deref(&self) -> &Self::Target { @@ -37,6 +83,15 @@ impl Deref for AccumulateVec { } } +impl DerefMut for AccumulateVec { + fn deref_mut(&mut self) -> &mut [A::Element] { + match *self { + AccumulateVec::Array(ref mut v) => &mut v[..], + AccumulateVec::Heap(ref mut v) => &mut v[..], + } + } +} + impl FromIterator for AccumulateVec { fn from_iter(iter: I) -> AccumulateVec where I: IntoIterator { let iter = iter.into_iter(); @@ -50,3 +105,94 @@ impl FromIterator for AccumulateVec { } } +pub struct IntoIter { + repr: IntoIterRepr, +} + +enum IntoIterRepr { + Array(array_vec::Iter), + Heap(vec::IntoIter), +} + +impl Iterator for IntoIter { + type Item = A::Element; + + fn next(&mut self) -> Option { + match self.repr { + IntoIterRepr::Array(ref mut arr) => arr.next(), + IntoIterRepr::Heap(ref mut iter) => iter.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + match self.repr { + IntoIterRepr::Array(ref iter) => iter.size_hint(), + IntoIterRepr::Heap(ref iter) => iter.size_hint(), + } + } +} + +impl IntoIterator for AccumulateVec { + type Item = A::Element; + type IntoIter = IntoIter; + fn into_iter(self) -> Self::IntoIter { + IntoIter { + repr: match self { + AccumulateVec::Array(arr) => IntoIterRepr::Array(arr.into_iter()), + AccumulateVec::Heap(vec) => IntoIterRepr::Heap(vec.into_iter()), + } + } + } +} + +impl<'a, A: Array> IntoIterator for &'a AccumulateVec { + type Item = &'a A::Element; + type IntoIter = slice::Iter<'a, A::Element>; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, A: Array> IntoIterator for &'a mut AccumulateVec { + type Item = &'a mut A::Element; + type IntoIter = slice::IterMut<'a, A::Element>; + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +impl From> for AccumulateVec { + fn from(v: Vec) -> AccumulateVec { + AccumulateVec::many(v) + } +} + +impl Default for AccumulateVec { + fn default() -> AccumulateVec { + AccumulateVec::new() + } +} + +impl Encodable for AccumulateVec + where A: Array, + A::Element: Encodable { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + try!(s.emit_seq_elt(i, |s| e.encode(s))); + } + Ok(()) + }) + } +} + +impl Decodable for AccumulateVec + where A: Array, + A::Element: Decodable { + fn decode(d: &mut D) -> Result, D::Error> { + d.read_seq(|d, len| { + Ok(try!((0..len).map(|i| d.read_seq_elt(i, |d| Decodable::decode(d))).collect())) + }) + } +} + diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index f87426cee59e..631cf2cfcf6d 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -9,15 +9,15 @@ // except according to those terms. //! A stack-allocated vector, allowing storage of N elements on the stack. -//! -//! Currently, only the N = 8 case is supported (due to Array only being impl-ed for [T; 8]). use std::marker::Unsize; use std::iter::Extend; -use std::ptr::drop_in_place; -use std::ops::{Deref, DerefMut}; +use std::ptr::{self, drop_in_place}; +use std::ops::{Deref, DerefMut, Range}; +use std::hash::{Hash, Hasher}; use std::slice; use std::fmt; +use std::mem; pub unsafe trait Array { type Element; @@ -25,6 +25,12 @@ pub unsafe trait Array { const LEN: usize; } +unsafe impl Array for [T; 1] { + type Element = T; + type PartialStorage = [ManuallyDrop; 1]; + const LEN: usize = 1; +} + unsafe impl Array for [T; 8] { type Element = T; type PartialStorage = [ManuallyDrop; 8]; @@ -36,6 +42,32 @@ pub struct ArrayVec { values: A::PartialStorage } +impl Hash for ArrayVec + where A: Array, + A::Element: Hash { + fn hash(&self, state: &mut H) where H: Hasher { + (&self[..]).hash(state); + } +} + +impl PartialEq for ArrayVec { + fn eq(&self, other: &Self) -> bool { + self == other + } +} + +impl Eq for ArrayVec {} + +impl Clone for ArrayVec + where A: Array, + A::Element: Clone { + fn clone(&self) -> Self { + let mut v = ArrayVec::new(); + v.extend(self.iter().cloned()); + v + } +} + impl ArrayVec { pub fn new() -> Self { ArrayVec { @@ -43,6 +75,41 @@ impl ArrayVec { values: Default::default(), } } + + pub fn len(&self) -> usize { + self.count + } + + pub unsafe fn set_len(&mut self, len: usize) { + self.count = len; + } + + /// Panics when the stack vector is full. + pub fn push(&mut self, el: A::Element) { + let arr = &mut self.values as &mut [ManuallyDrop<_>]; + arr[self.count] = ManuallyDrop { value: el }; + self.count += 1; + } + + pub fn pop(&mut self) -> Option { + if self.count > 0 { + let arr = &mut self.values as &mut [ManuallyDrop<_>]; + self.count -= 1; + unsafe { + let value = ptr::read(&arr[self.count]); + Some(value.value) + } + } else { + None + } + } +} + +impl Default for ArrayVec + where A: Array { + fn default() -> Self { + ArrayVec::new() + } } impl fmt::Debug for ArrayVec @@ -81,15 +148,69 @@ impl Drop for ArrayVec { impl Extend for ArrayVec { fn extend(&mut self, iter: I) where I: IntoIterator { for el in iter { - unsafe { - let arr = &mut self.values as &mut [ManuallyDrop<_>]; - arr[self.count].value = el; - } - self.count += 1; + self.push(el); } } } +pub struct Iter { + indices: Range, + store: A::PartialStorage, +} + +impl Drop for Iter { + fn drop(&mut self) { + for _ in self {} + } +} + +impl Iterator for Iter { + type Item = A::Element; + + fn next(&mut self) -> Option { + let arr = &self.store as &[ManuallyDrop<_>]; + unsafe { + self.indices.next().map(|i| ptr::read(&arr[i]).value) + } + } + + fn size_hint(&self) -> (usize, Option) { + self.indices.size_hint() + } +} + +impl IntoIterator for ArrayVec { + type Item = A::Element; + type IntoIter = Iter; + fn into_iter(self) -> Self::IntoIter { + let store = unsafe { + ptr::read(&self.values) + }; + let indices = 0..self.count; + mem::forget(self); + Iter { + indices: indices, + store: store, + } + } +} + +impl<'a, A: Array> IntoIterator for &'a ArrayVec { + type Item = &'a A::Element; + type IntoIter = slice::Iter<'a, A::Element>; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, A: Array> IntoIterator for &'a mut ArrayVec { + type Item = &'a mut A::Element; + type IntoIter = slice::IterMut<'a, A::Element>; + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + // FIXME: This should use repr(transparent) from rust-lang/rfcs#1758. #[allow(unions_with_drop_fields)] pub union ManuallyDrop { @@ -98,9 +219,17 @@ pub union ManuallyDrop { empty: (), } -impl Default for ManuallyDrop { - fn default() -> Self { - ManuallyDrop { empty: () } +impl ManuallyDrop { + fn new() -> ManuallyDrop { + ManuallyDrop { + empty: () + } + } +} + +impl Default for ManuallyDrop { + fn default() -> Self { + ManuallyDrop::new() } } diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index fdcbec6bac11..2e4206d2ee1e 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -46,6 +46,7 @@ extern crate libc; pub mod array_vec; pub mod accumulate_vec; +pub mod small_vec; pub mod bitslice; pub mod blake2b; pub mod bitvec; diff --git a/src/librustc_data_structures/small_vec.rs b/src/librustc_data_structures/small_vec.rs new file mode 100644 index 000000000000..565a3c443a34 --- /dev/null +++ b/src/librustc_data_structures/small_vec.rs @@ -0,0 +1,203 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A vector type intended to be used for collecting from iterators onto the stack. +//! +//! Space for up to N elements is provided on the stack. If more elements are collected, Vec is +//! used to store the values on the heap. SmallVec is similar to AccumulateVec, but adds +//! the ability to push elements. +//! +//! The N above is determined by Array's implementor, by way of an associatated constant. + +use std::ops::{Deref, DerefMut}; +use std::iter::{IntoIterator, FromIterator}; +use std::fmt::{self, Debug}; +use std::mem; +use std::ptr; + +use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; + +use accumulate_vec::{IntoIter, AccumulateVec}; +use array_vec::Array; + +pub struct SmallVec(AccumulateVec); + +impl Clone for SmallVec + where A: Array, + A::Element: Clone { + fn clone(&self) -> Self { + SmallVec(self.0.clone()) + } +} + +impl Debug for SmallVec + where A: Array + Debug, + A::Element: Debug { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("SmallVec").field(&self.0).finish() + } +} + +impl SmallVec { + pub fn new() -> Self { + SmallVec(AccumulateVec::new()) + } + + pub fn with_capacity(cap: usize) -> Self { + let mut vec = SmallVec::new(); + vec.reserve(cap); + vec + } + + pub fn one(el: A::Element) -> Self { + SmallVec(AccumulateVec::one(el)) + } + + pub fn many>(els: I) -> Self { + SmallVec(AccumulateVec::many(els)) + } + + pub fn expect_one(self, err: &'static str) -> A::Element { + assert!(self.len() == 1, err); + match self.0 { + AccumulateVec::Array(arr) => arr.into_iter().next().unwrap(), + AccumulateVec::Heap(vec) => vec.into_iter().next().unwrap(), + } + } + + /// Will reallocate onto the heap if needed. + pub fn push(&mut self, el: A::Element) { + self.reserve(1); + match self.0 { + AccumulateVec::Array(ref mut array) => array.push(el), + AccumulateVec::Heap(ref mut vec) => vec.push(el), + } + } + + pub fn reserve(&mut self, n: usize) { + match self.0 { + AccumulateVec::Array(_) => { + if self.len() + n > A::LEN { + let len = self.len(); + let array = mem::replace(&mut self.0, + AccumulateVec::Heap(Vec::with_capacity(len + n))); + if let AccumulateVec::Array(array) = array { + match self.0 { + AccumulateVec::Heap(ref mut vec) => vec.extend(array), + _ => unreachable!() + } + } + } + } + AccumulateVec::Heap(ref mut vec) => vec.reserve(n) + } + } + + pub unsafe fn set_len(&mut self, len: usize) { + match self.0 { + AccumulateVec::Array(ref mut arr) => arr.set_len(len), + AccumulateVec::Heap(ref mut vec) => vec.set_len(len), + } + } + + pub fn insert(&mut self, index: usize, element: A::Element) { + let len = self.len(); + + // Reserve space for shifting elements to the right + self.reserve(1); + + assert!(index <= len); + + unsafe { + // infallible + // The spot to put the new value + { + let p = self.as_mut_ptr().offset(index as isize); + // Shift everything over to make space. (Duplicating the + // `index`th element into two consecutive places.) + ptr::copy(p, p.offset(1), len - index); + // Write it in, overwriting the first copy of the `index`th + // element. + ptr::write(p, element); + } + self.set_len(len + 1); + } + } +} + +impl Deref for SmallVec { + type Target = AccumulateVec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for SmallVec { + fn deref_mut(&mut self) -> &mut AccumulateVec { + &mut self.0 + } +} + +impl FromIterator for SmallVec { + fn from_iter(iter: I) -> Self where I: IntoIterator { + SmallVec(iter.into_iter().collect()) + } +} + +impl Extend for SmallVec { + fn extend>(&mut self, iter: I) { + let iter = iter.into_iter(); + self.reserve(iter.size_hint().0); + for el in iter { + self.push(el); + } + } +} + +impl IntoIterator for SmallVec { + type Item = A::Element; + type IntoIter = IntoIter; + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl Default for SmallVec { + fn default() -> SmallVec { + SmallVec::new() + } +} + +impl Encodable for SmallVec + where A: Array, + A::Element: Encodable { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + try!(s.emit_seq_elt(i, |s| e.encode(s))); + } + Ok(()) + }) + } +} + +impl Decodable for SmallVec + where A: Array, + A::Element: Decodable { + fn decode(d: &mut D) -> Result, D::Error> { + d.read_seq(|d, len| { + let mut vec = SmallVec::with_capacity(len); + for i in 0..len { + vec.push(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); + } + Ok(vec) + }) + } +} diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index 8b61e1b0d3a3..0b38f5450b63 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -14,3 +14,4 @@ log = { path = "../liblog" } rustc_bitflags = { path = "../librustc_bitflags" } syntax_pos = { path = "../libsyntax_pos" } rustc_errors = { path = "../librustc_errors" } +rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 946257a16d5a..02429f02738f 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -277,7 +277,7 @@ impl<'a> fold::Folder for StripUnconfigured<'a> { fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { match self.configure_stmt(stmt) { Some(stmt) => fold::noop_fold_stmt(stmt, self), - None => return SmallVector::zero(), + None => return SmallVector::new(), } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 63eee7df9e85..b4ac576f57a5 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -440,7 +440,7 @@ impl MacResult for DummyResult { if self.expr_only { None } else { - Some(SmallVector::zero()) + Some(SmallVector::new()) } } @@ -448,7 +448,7 @@ impl MacResult for DummyResult { if self.expr_only { None } else { - Some(SmallVector::zero()) + Some(SmallVector::new()) } } @@ -456,7 +456,7 @@ impl MacResult for DummyResult { if self.expr_only { None } else { - Some(SmallVector::zero()) + Some(SmallVector::new()) } } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index c3608aac0b40..877b312539f9 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -89,7 +89,7 @@ macro_rules! expansions { Expansion::OptExpr(Some(ref expr)) => visitor.visit_expr(expr), Expansion::OptExpr(None) => {} $($( Expansion::$kind(ref ast) => visitor.$visit(ast), )*)* - $($( Expansion::$kind(ref ast) => for ast in ast.as_slice() { + $($( Expansion::$kind(ref ast) => for ast in &ast[..] { visitor.$visit_elt(ast); }, )*)* } @@ -511,28 +511,28 @@ impl<'a> Parser<'a> { -> PResult<'a, Expansion> { Ok(match kind { ExpansionKind::Items => { - let mut items = SmallVector::zero(); + let mut items = SmallVector::new(); while let Some(item) = self.parse_item()? { items.push(item); } Expansion::Items(items) } ExpansionKind::TraitItems => { - let mut items = SmallVector::zero(); + let mut items = SmallVector::new(); while self.token != token::Eof { items.push(self.parse_trait_item()?); } Expansion::TraitItems(items) } ExpansionKind::ImplItems => { - let mut items = SmallVector::zero(); + let mut items = SmallVector::new(); while self.token != token::Eof { items.push(self.parse_impl_item()?); } Expansion::ImplItems(items) } ExpansionKind::Stmts => { - let mut stmts = SmallVector::zero(); + let mut stmts = SmallVector::new(); while self.token != token::Eof && // won't make progress on a `}` self.token != token::CloseDelim(token::Brace) { @@ -573,7 +573,7 @@ macro_rules! fully_configure { ($this:ident, $node:ident, $noop_fold:ident) => { match $noop_fold($node, &mut $this.cfg).pop() { Some(node) => node, - None => return SmallVector::zero(), + None => return SmallVector::new(), } } } @@ -689,7 +689,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { let stmt = match self.cfg.configure_stmt(stmt) { Some(stmt) => stmt, - None => return SmallVector::zero(), + None => return SmallVector::new(), }; let (mac, style, attrs) = if let StmtKind::Mac(mac) = stmt.node { diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index ec48cae3f765..bda84cdaf39e 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -104,7 +104,7 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::T } fn make_items(mut self: Box>) -> Option>> { - let mut ret = SmallVector::zero(); + let mut ret = SmallVector::new(); while self.p.token != token::Eof { match panictry!(self.p.parse_item()) { Some(item) => ret.push(item), diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index feed400897c0..34280812421a 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -45,6 +45,7 @@ extern crate libc; extern crate rustc_unicode; pub extern crate rustc_errors as errors; extern crate syntax_pos; +extern crate rustc_data_structures; extern crate serialize as rustc_serialize; // used by deriving diff --git a/src/libsyntax/util/move_map.rs b/src/libsyntax/util/move_map.rs index e1078b719bf0..fe05e2958b3a 100644 --- a/src/libsyntax/util/move_map.rs +++ b/src/libsyntax/util/move_map.rs @@ -10,6 +10,8 @@ use std::ptr; +use util::small_vector::SmallVector; + pub trait MoveMap: Sized { fn move_map(self, mut f: F) -> Self where F: FnMut(T) -> T { self.move_flat_map(|e| Some(f(e))) @@ -75,3 +77,50 @@ impl MoveMap for ::ptr::P<[T]> { ::ptr::P::from_vec(self.into_vec().move_flat_map(f)) } } + +impl MoveMap for SmallVector { + fn move_flat_map(mut self, mut f: F) -> Self + where F: FnMut(T) -> I, + I: IntoIterator + { + let mut read_i = 0; + let mut write_i = 0; + unsafe { + let mut old_len = self.len(); + self.set_len(0); // make sure we just leak elements in case of panic + + while read_i < old_len { + // move the read_i'th item out of the vector and map it + // to an iterator + let e = ptr::read(self.get_unchecked(read_i)); + let mut iter = f(e).into_iter(); + read_i += 1; + + while let Some(e) = iter.next() { + if write_i < read_i { + ptr::write(self.get_unchecked_mut(write_i), e); + write_i += 1; + } else { + // If this is reached we ran out of space + // in the middle of the vector. + // However, the vector is in a valid state here, + // so we just do a somewhat inefficient insert. + self.set_len(old_len); + self.insert(write_i, e); + + old_len = self.len(); + self.set_len(0); + + read_i += 1; + write_i += 1; + } + } + } + + // write_i tracks the number of actually written new items. + self.set_len(write_i); + } + + self + } +} diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs index 9be7dbd68174..31e675836fc7 100644 --- a/src/libsyntax/util/small_vector.rs +++ b/src/libsyntax/util/small_vector.rs @@ -8,253 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use self::SmallVectorRepr::*; -use self::IntoIterRepr::*; +use rustc_data_structures::small_vec::SmallVec; -use core::ops; -use std::iter::{IntoIterator, FromIterator}; -use std::mem; -use std::slice; -use std::vec; - -use util::move_map::MoveMap; - -/// A vector type optimized for cases where the size is almost always 0 or 1 -#[derive(Clone)] -pub struct SmallVector { - repr: SmallVectorRepr, -} - -#[derive(Clone)] -enum SmallVectorRepr { - Zero, - One(T), - Many(Vec), -} - -impl Default for SmallVector { - fn default() -> Self { - SmallVector { repr: Zero } - } -} - -impl Into> for SmallVector { - fn into(self) -> Vec { - match self.repr { - Zero => Vec::new(), - One(t) => vec![t], - Many(vec) => vec, - } - } -} - -impl FromIterator for SmallVector { - fn from_iter>(iter: I) -> SmallVector { - let mut v = SmallVector::zero(); - v.extend(iter); - v - } -} - -impl Extend for SmallVector { - fn extend>(&mut self, iter: I) { - for val in iter { - self.push(val); - } - } -} - -impl SmallVector { - pub fn zero() -> SmallVector { - SmallVector { repr: Zero } - } - - pub fn one(v: T) -> SmallVector { - SmallVector { repr: One(v) } - } - - pub fn many(vs: Vec) -> SmallVector { - SmallVector { repr: Many(vs) } - } - - pub fn as_slice(&self) -> &[T] { - self - } - - pub fn as_mut_slice(&mut self) -> &mut [T] { - self - } - - pub fn pop(&mut self) -> Option { - match self.repr { - Zero => None, - One(..) => { - let one = mem::replace(&mut self.repr, Zero); - match one { - One(v1) => Some(v1), - _ => unreachable!() - } - } - Many(ref mut vs) => vs.pop(), - } - } - - pub fn push(&mut self, v: T) { - match self.repr { - Zero => self.repr = One(v), - One(..) => { - let one = mem::replace(&mut self.repr, Zero); - match one { - One(v1) => mem::replace(&mut self.repr, Many(vec![v1, v])), - _ => unreachable!() - }; - } - Many(ref mut vs) => vs.push(v) - } - } - - pub fn push_all(&mut self, other: SmallVector) { - for v in other.into_iter() { - self.push(v); - } - } - - pub fn get(&self, idx: usize) -> &T { - match self.repr { - One(ref v) if idx == 0 => v, - Many(ref vs) => &vs[idx], - _ => panic!("out of bounds access") - } - } - - pub fn expect_one(self, err: &'static str) -> T { - match self.repr { - One(v) => v, - Many(v) => { - if v.len() == 1 { - v.into_iter().next().unwrap() - } else { - panic!(err) - } - } - _ => panic!(err) - } - } - - pub fn len(&self) -> usize { - match self.repr { - Zero => 0, - One(..) => 1, - Many(ref vals) => vals.len() - } - } - - pub fn is_empty(&self) -> bool { self.len() == 0 } - - pub fn map U>(self, mut f: F) -> SmallVector { - let repr = match self.repr { - Zero => Zero, - One(t) => One(f(t)), - Many(vec) => Many(vec.into_iter().map(f).collect()), - }; - SmallVector { repr: repr } - } -} - -impl ops::Deref for SmallVector { - type Target = [T]; - - fn deref(&self) -> &[T] { - match self.repr { - Zero => { - let result: &[T] = &[]; - result - } - One(ref v) => { - unsafe { slice::from_raw_parts(v, 1) } - } - Many(ref vs) => vs - } - } -} - -impl ops::DerefMut for SmallVector { - fn deref_mut(&mut self) -> &mut [T] { - match self.repr { - Zero => { - let result: &mut [T] = &mut []; - result - } - One(ref mut v) => { - unsafe { slice::from_raw_parts_mut(v, 1) } - } - Many(ref mut vs) => vs - } - } -} - -impl IntoIterator for SmallVector { - type Item = T; - type IntoIter = IntoIter; - fn into_iter(self) -> Self::IntoIter { - let repr = match self.repr { - Zero => ZeroIterator, - One(v) => OneIterator(v), - Many(vs) => ManyIterator(vs.into_iter()) - }; - IntoIter { repr: repr } - } -} - -pub struct IntoIter { - repr: IntoIterRepr, -} - -enum IntoIterRepr { - ZeroIterator, - OneIterator(T), - ManyIterator(vec::IntoIter), -} - -impl Iterator for IntoIter { - type Item = T; - - fn next(&mut self) -> Option { - match self.repr { - ZeroIterator => None, - OneIterator(..) => { - let mut replacement = ZeroIterator; - mem::swap(&mut self.repr, &mut replacement); - match replacement { - OneIterator(v) => Some(v), - _ => unreachable!() - } - } - ManyIterator(ref mut inner) => inner.next() - } - } - - fn size_hint(&self) -> (usize, Option) { - match self.repr { - ZeroIterator => (0, Some(0)), - OneIterator(..) => (1, Some(1)), - ManyIterator(ref inner) => inner.size_hint() - } - } -} - -impl MoveMap for SmallVector { - fn move_flat_map(self, mut f: F) -> Self - where F: FnMut(T) -> I, - I: IntoIterator - { - match self.repr { - Zero => Self::zero(), - One(v) => f(v).into_iter().collect(), - Many(vs) => SmallVector { repr: Many(vs.move_flat_map(f)) }, - } - } -} +pub type SmallVector = SmallVec<[T; 1]>; #[cfg(test)] mod tests { @@ -262,7 +18,7 @@ mod tests { #[test] fn test_len() { - let v: SmallVector = SmallVector::zero(); + let v: SmallVector = SmallVector::new(); assert_eq!(0, v.len()); assert_eq!(1, SmallVector::one(1).len()); @@ -271,30 +27,30 @@ mod tests { #[test] fn test_push_get() { - let mut v = SmallVector::zero(); + let mut v = SmallVector::new(); v.push(1); assert_eq!(1, v.len()); - assert_eq!(&1, v.get(0)); + assert_eq!(1, v[0]); v.push(2); assert_eq!(2, v.len()); - assert_eq!(&2, v.get(1)); + assert_eq!(2, v[1]); v.push(3); assert_eq!(3, v.len()); - assert_eq!(&3, v.get(2)); + assert_eq!(3, v[2]); } #[test] fn test_from_iter() { let v: SmallVector = (vec![1, 2, 3]).into_iter().collect(); assert_eq!(3, v.len()); - assert_eq!(&1, v.get(0)); - assert_eq!(&2, v.get(1)); - assert_eq!(&3, v.get(2)); + assert_eq!(1, v[0]); + assert_eq!(2, v[1]); + assert_eq!(3, v[2]); } #[test] fn test_move_iter() { - let v = SmallVector::zero(); + let v = SmallVector::new(); let v: Vec = v.into_iter().collect(); assert_eq!(v, Vec::new()); @@ -308,7 +64,7 @@ mod tests { #[test] #[should_panic] fn test_expect_one_zero() { - let _: isize = SmallVector::zero().expect_one(""); + let _: isize = SmallVector::new().expect_one(""); } #[test] From 008cc2d999012780514abc5b0c7510e648b0728c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 11 Oct 2016 12:21:40 -0700 Subject: [PATCH 057/177] Move all Linux/OSX CI infastructure to Travis This commit configures our `.travis.yml` to test the full suite of tests we have on Buildbot right now. A whole mess of docker images are added to the `src/ci` directory which represent all the build environments for each configuration. Each of these environments is then configured in `.travis.yml` to run on the auto branch. Note that the full matrix of tests aren't intended to be run on all PRs. Instead, we continue to run only one entry in the matrix, forcing all others to finish quickly. Only the `auto` branch should run the full matrix of builds. Also note that the infrastructure hasn't quite been allocated yet to the rust-lang/rust repository, so everything is disabled for now except for the one build that happens on PRs. Once that infrastructure is allocated though we can enable this and let it fly! Notable modifications from the current test suite today: * Android tests are run in rustbuild instead of the makefiles, for whatever reason I couldn't get the makefiles to work on Travis. * A debuginfo test was updated to work with the current version of the Android NDK. * Some dependencies in `mk/tests.mk` were fixed to allow running tests in parallel. --- .travis.yml | 87 +++++++++++++---- mk/tests.mk | 2 + src/bootstrap/mk/Makefile.in | 5 +- src/ci/docker/arm-android/Dockerfile | 46 +++++++++ src/ci/docker/arm-android/accept-licenses.sh | 15 +++ src/ci/docker/arm-android/install-ndk.sh | 45 +++++++++ src/ci/docker/arm-android/install-sdk.sh | 33 +++++++ src/ci/docker/arm-android/start-emulator.sh | 15 +++ src/ci/docker/cross/Dockerfile | 66 +++++++++++++ src/ci/docker/i686-gnu-nopt/Dockerfile | 19 ++++ src/ci/docker/i686-gnu/Dockerfile | 19 ++++ src/ci/docker/run.sh | 42 ++++++++ src/ci/docker/x86_64-freebsd/Dockerfile | 29 ++++++ .../docker/x86_64-freebsd/build-toolchain.sh | 96 +++++++++++++++++++ src/ci/docker/x86_64-gnu-cargotest/Dockerfile | 20 ++++ src/ci/docker/x86_64-gnu-debug/Dockerfile | 22 +++++ src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile | 26 +++++ src/ci/docker/x86_64-gnu-nopt/Dockerfile | 19 ++++ src/ci/docker/x86_64-gnu-rustbuild/Dockerfile | 20 ++++ src/ci/docker/x86_64-gnu/Dockerfile | 19 ++++ src/ci/docker/x86_64-musl/Dockerfile | 27 ++++++ src/ci/docker/x86_64-musl/build-musl.sh | 33 +++++++ src/ci/run.sh | 44 +++++++++ src/test/debuginfo/vec-slices.rs | 10 +- 24 files changed, 734 insertions(+), 25 deletions(-) create mode 100644 src/ci/docker/arm-android/Dockerfile create mode 100755 src/ci/docker/arm-android/accept-licenses.sh create mode 100644 src/ci/docker/arm-android/install-ndk.sh create mode 100644 src/ci/docker/arm-android/install-sdk.sh create mode 100755 src/ci/docker/arm-android/start-emulator.sh create mode 100644 src/ci/docker/cross/Dockerfile create mode 100644 src/ci/docker/i686-gnu-nopt/Dockerfile create mode 100644 src/ci/docker/i686-gnu/Dockerfile create mode 100755 src/ci/docker/run.sh create mode 100644 src/ci/docker/x86_64-freebsd/Dockerfile create mode 100644 src/ci/docker/x86_64-freebsd/build-toolchain.sh create mode 100644 src/ci/docker/x86_64-gnu-cargotest/Dockerfile create mode 100644 src/ci/docker/x86_64-gnu-debug/Dockerfile create mode 100644 src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile create mode 100644 src/ci/docker/x86_64-gnu-nopt/Dockerfile create mode 100644 src/ci/docker/x86_64-gnu-rustbuild/Dockerfile create mode 100644 src/ci/docker/x86_64-gnu/Dockerfile create mode 100644 src/ci/docker/x86_64-musl/Dockerfile create mode 100644 src/ci/docker/x86_64-musl/build-musl.sh create mode 100755 src/ci/run.sh diff --git a/.travis.yml b/.travis.yml index 144329caa71a..e06444ddf6d0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,33 +1,82 @@ -language: generic +language: rust sudo: required +dist: trusty services: - docker -# LLVM takes awhile to check out and otherwise we'll manage the submodules in -# our configure script, so disable auto submodule management. git: - submodules: false depth: 1 + submodules: false -before_install: - - docker build -t rust -f src/etc/Dockerfile src/etc +matrix: + include: + # Linux builders, all docker images + - env: IMAGE=arm-android + - env: IMAGE=cross + - env: IMAGE=i686-gnu + - env: IMAGE=i686-gnu-nopt + - env: IMAGE=x86_64-freebsd + - env: IMAGE=x86_64-gnu + - env: IMAGE=x86_64-gnu-cargotest + - env: IMAGE=x86_64-gnu-debug + - env: IMAGE=x86_64-gnu-nopt + - env: IMAGE=x86_64-gnu-rustbuild + - env: IMAGE=x86_64-gnu-llvm-3.7 ALLOW_PR=1 + - env: IMAGE=x86_64-musl + + # OSX builders + - env: > + RUST_CHECK_TARGET=check + RUST_CONFIGURE_ARGS=--target=x86_64-apple-darwin + SRC=. + os: osx + install: brew install ccache + - env: > + RUST_CHECK_TARGET=check + RUST_CONFIGURE_ARGS=--target=i686-apple-darwin + SRC=. + os: osx + install: brew install ccache + - env: > + RUST_CHECK_TARGET=check + RUST_CONFIGURE_ARGS=--target=x86_64-apple-darwin --enable-rustbuild + SRC=. + os: osx + install: brew install ccache + - env: > + RUST_CHECK_TARGET= + RUST_CONFIGURE_ARGS=--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios + SRC=. + os: osx + install: brew install ccache script: - - docker run -v `pwd`:/build rust - sh -c " - ./configure --enable-vendor --enable-rustbuild --llvm-root=/usr/lib/llvm-3.7 --enable-quiet-tests && - make tidy && - make check -j4 - " + - if [ -z "$ALLOW_PR" ] && [ "$TRAVIS_BRANCH" != "auto" ]; then + echo skipping, not a full build; + elif [ -z "$ENABLE_AUTO" ] then + echo skipping, not quite ready yet + elif [ "$TRAVIS_OS_NAME" = "osx" ]; then + git submodule update --init; + src/ci/run.sh; + else + git submodule update --init; + src/ci/docker/run.sh $IMAGE; + fi -# Real testing happens on http://buildbot.rust-lang.org/ -# -# See https://github.com/rust-lang/rust-buildbot -# CONTRIBUTING.md#pull-requests +# Save tagged docker images we created and load them if they're available +before_cache: + - docker history -q rust-ci | + grep -v missing | + xargs docker save | + gzip -9 > $HOME/docker/rust-ci.tar.gz +before_install: + - zcat $HOME/docker/rust-ci.tar.gz | docker load || true notifications: email: false -branches: - only: - - master +cache: + directories: + - $HOME/docker + - $HOME/.ccache + - $HOME/.cargo diff --git a/mk/tests.mk b/mk/tests.mk index f3d8f0387bbd..35ee7697a7a6 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -697,6 +697,8 @@ CTEST_DEPS_ui_$(1)-T-$(2)-H-$(3) = $$(UI_TESTS) CTEST_DEPS_mir-opt_$(1)-T-$(2)-H-$(3) = $$(MIR_OPT_TESTS) CTEST_DEPS_rustdocck_$(1)-T-$(2)-H-$(3) = $$(RUSTDOCCK_TESTS) \ $$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \ + $$(CSREQ$(1)_T_$(3)_H_$(3)) \ + $$(SREQ$(1)_T_$(3)_H_$(3)) \ $(S)src/etc/htmldocck.py endef diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index d4031077639c..1e73595ec998 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -57,6 +57,9 @@ else $(Q)$(BOOTSTRAP) dist --install $(BOOTSTRAP_ARGS) endif tidy: - $(Q)$(BOOTSTRAP) test src/tools/tidy $(BOOTSTRAP_ARGS) + $(Q)$(BOOTSTRAP) test src/tools/tidy $(BOOTSTRAP_ARGS) --stage 0 + +check-stage2-android: + $(Q)$(BOOTSTRAP) --step check-target --target arm-linux-androideabi .PHONY: dist diff --git a/src/ci/docker/arm-android/Dockerfile b/src/ci/docker/arm-android/Dockerfile new file mode 100644 index 000000000000..c5b70c227c40 --- /dev/null +++ b/src/ci/docker/arm-android/Dockerfile @@ -0,0 +1,46 @@ +FROM ubuntu:16.04 + +RUN dpkg --add-architecture i386 && \ + apt-get update && \ + apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + python-minimal \ + git \ + cmake \ + ccache \ + unzip \ + expect \ + openjdk-9-jre \ + sudo \ + libstdc++6:i386 + +WORKDIR /android/ +ENV PATH=$PATH:/android/ndk-arm-9/bin:/android/sdk/tools:/android/sdk/platform-tools + +COPY install-ndk.sh install-sdk.sh accept-licenses.sh /android/ +RUN sh /android/install-ndk.sh +RUN sh /android/install-sdk.sh + +COPY start-emulator.sh /android/ +ENTRYPOINT ["/android/start-emulator.sh"] + +ENV TARGETS=arm-linux-androideabi +ENV TARGETS=$TARGETS,i686-linux-android +ENV TARGETS=$TARGETS,aarch64-linux-android +ENV TARGETS=$TARGETS,armv7-linux-androideabi + +ENV RUST_CONFIGURE_ARGS \ + --target=$TARGETS \ + --arm-linux-androideabi-ndk=/android/ndk-arm-9 \ + --armv7-linux-androideabi-ndk=/android/ndk-arm-9 \ + --i686-linux-android-ndk=/android/ndk-x86-9 \ + --aarch64-linux-android-ndk=/android/ndk-aarch64 \ + --enable-rustbuild +ENV RUST_CHECK_TARGET check-stage2-android +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/arm-android/accept-licenses.sh b/src/ci/docker/arm-android/accept-licenses.sh new file mode 100755 index 000000000000..8d8f60a5ec26 --- /dev/null +++ b/src/ci/docker/arm-android/accept-licenses.sh @@ -0,0 +1,15 @@ +#!/usr/bin/expect -f +# ignore-license + +set timeout 1800 +set cmd [lindex $argv 0] +set licenses [lindex $argv 1] + +spawn {*}$cmd +expect { + "Do you accept the license '*'*" { + exp_send "y\r" + exp_continue + } + eof +} diff --git a/src/ci/docker/arm-android/install-ndk.sh b/src/ci/docker/arm-android/install-ndk.sh new file mode 100644 index 000000000000..418ce69c5b1e --- /dev/null +++ b/src/ci/docker/arm-android/install-ndk.sh @@ -0,0 +1,45 @@ +#!/bin/sh +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +cpgdb() { + cp android-ndk-r11c/prebuilt/linux-x86_64/bin/gdb /android/$1/bin/$2-gdb + cp android-ndk-r11c/prebuilt/linux-x86_64/bin/gdb-orig /android/$1/bin/gdb-orig + cp -r android-ndk-r11c/prebuilt/linux-x86_64/share /android/$1/share +} + +# Prep the Android NDK +# +# See https://github.com/servo/servo/wiki/Building-for-Android +curl -O https://dl.google.com/android/repository/android-ndk-r11c-linux-x86_64.zip +unzip -q android-ndk-r11c-linux-x86_64.zip +bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ + --platform=android-9 \ + --toolchain=arm-linux-androideabi-4.9 \ + --install-dir=/android/ndk-arm-9 \ + --ndk-dir=/android/android-ndk-r11c \ + --arch=arm +cpgdb ndk-arm-9 arm-linux-androideabi +bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ + --platform=android-21 \ + --toolchain=aarch64-linux-android-4.9 \ + --install-dir=/android/ndk-aarch64 \ + --ndk-dir=/android/android-ndk-r11c \ + --arch=arm64 +bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ + --platform=android-9 \ + --toolchain=x86-4.9 \ + --install-dir=/android/ndk-x86-9 \ + --ndk-dir=/android/android-ndk-r11c \ + --arch=x86 + +rm -rf ./android-ndk-r11c-linux-x86_64.zip ./android-ndk-r11c diff --git a/src/ci/docker/arm-android/install-sdk.sh b/src/ci/docker/arm-android/install-sdk.sh new file mode 100644 index 000000000000..2db1d46ba227 --- /dev/null +++ b/src/ci/docker/arm-android/install-sdk.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +# Prep the SDK and emulator +# +# Note that the update process requires that we accept a bunch of licenses, and +# we can't just pipe `yes` into it for some reason, so we take the same strategy +# located in https://github.com/appunite/docker by just wrapping it in a script +# which apparently magically accepts the licenses. + +mkdir sdk +curl https://dl.google.com/android/android-sdk_r24.4-linux.tgz | \ + tar xzf - -C sdk --strip-components=1 + +filter="platform-tools,android-18" +filter="$filter,sys-img-armeabi-v7a-android-18" + +./accept-licenses.sh "android - update sdk -a --no-ui --filter $filter" + +echo "no" | android create avd \ + --name arm-18 \ + --target android-18 \ + --abi armeabi-v7a diff --git a/src/ci/docker/arm-android/start-emulator.sh b/src/ci/docker/arm-android/start-emulator.sh new file mode 100755 index 000000000000..93f20b28b868 --- /dev/null +++ b/src/ci/docker/arm-android/start-emulator.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +ANDROID_EMULATOR_FORCE_32BIT=true \ + emulator @arm-18 -no-window -partition-size 2047 & +exec "$@" diff --git a/src/ci/docker/cross/Dockerfile b/src/ci/docker/cross/Dockerfile new file mode 100644 index 000000000000..d8af878a9586 --- /dev/null +++ b/src/ci/docker/cross/Dockerfile @@ -0,0 +1,66 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + python-minimal \ + git \ + cmake \ + ccache \ + sudo \ + gcc-aarch64-linux-gnu libc6-dev-arm64-cross \ + gcc-arm-linux-gnueabi libc6-dev-armel-cross \ + gcc-arm-linux-gnueabihf libc6-dev-armhf-cross \ + gcc-mips-linux-gnu libc6-dev-mips-cross \ + gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \ + gcc-mips64-linux-gnuabi64 libc6-dev-mips64-cross \ + gcc-mips64el-linux-gnuabi64 libc6-dev-mips64el-cross \ + gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \ + gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \ + gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \ + gcc-s390x-linux-gnu libc6-dev-s390x-cross + +ENV TARGETS=aarch64-unknown-linux-gnu +ENV TARGETS=$TARGETS,arm-unknown-linux-gnueabi +ENV TARGETS=$TARGETS,arm-unknown-linux-gnueabihf +ENV TARGETS=$TARGETS,armv7-unknown-linux-gnueabihf +ENV TARGETS=$TARGETS,asmjs-unknown-emscripten +ENV TARGETS=$TARGETS,mips-unknown-linux-gnu +ENV TARGETS=$TARGETS,mips64-unknown-linux-gnuabi64 +ENV TARGETS=$TARGETS,mips64el-unknown-linux-gnuabi64 +ENV TARGETS=$TARGETS,mipsel-unknown-linux-gnu +ENV TARGETS=$TARGETS,powerpc-unknown-linux-gnu +ENV TARGETS=$TARGETS,powerpc64-unknown-linux-gnu +ENV TARGETS=$TARGETS,powerpc64le-unknown-linux-gnu +ENV TARGETS=$TARGETS,s390x-unknown-linux-gnu +ENV TARGETS=$TARGETS,wasm32-unknown-emscripten + +#ENV TARGETS=$TARGETS,mips-unknown-linux-musl +#ENV TARGETS=$TARGETS,arm-unknown-linux-musleabi +#ENV TARGETS=$TARGETS,arm-unknown-linux-musleabihf +#ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabihf +#ENV TARGETS=$TARGETS,x86_64-rumprun-netbsd + +ENV RUST_CONFIGURE_ARGS \ + --target=$TARGETS \ + --enable-rustbuild +ENV RUST_CHECK_TARGET "" + +ENV AR_s390x_unknown_linux_gnu=s390x-linux-gnu-ar \ + CC_s390x_unknown_linux_gnu=s390x-linux-gnu-gcc \ + AR_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-ar \ + CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \ + AR_mips64el_unknown_linux_gnuabi64=mips64el-linux-gnuabi64-ar \ + CC_mips64el_unknown_linux_gnuabi64=mips64el-linux-gnuabi64-gcc \ + AR_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-ar \ + CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc + +# FIXME(rust-lang/rust#36150): powerpc unfortunately aborts right now +ENV NO_LLVM_ASSERTIONS=1 + +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/i686-gnu-nopt/Dockerfile b/src/ci/docker/i686-gnu-nopt/Dockerfile new file mode 100644 index 000000000000..a9ef29daaf1a --- /dev/null +++ b/src/ci/docker/i686-gnu-nopt/Dockerfile @@ -0,0 +1,19 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++-multilib \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + ccache \ + sudo \ + gdb + +ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests +ENV RUST_CHECK_TARGET check +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/i686-gnu/Dockerfile b/src/ci/docker/i686-gnu/Dockerfile new file mode 100644 index 000000000000..d0ddde95b447 --- /dev/null +++ b/src/ci/docker/i686-gnu/Dockerfile @@ -0,0 +1,19 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++-multilib \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + ccache \ + sudo \ + gdb + +ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu +ENV RUST_CHECK_TARGET check +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh new file mode 100755 index 000000000000..c5b1d00fb7cc --- /dev/null +++ b/src/ci/docker/run.sh @@ -0,0 +1,42 @@ +#!/bin/sh +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -e + +script=`cd $(dirname $0) && pwd`/`basename $0` +image=$1 + +docker_dir="`dirname $script`" +ci_dir="`dirname $docker_dir`" +src_dir="`dirname $ci_dir`" +root_dir="`dirname $src_dir`" + +docker build \ + --rm \ + -t rust-ci \ + "`dirname "$script"`/$image" + +mkdir -p $HOME/.ccache +mkdir -p $HOME/.cargo + +exec docker run \ + --volume "$root_dir:/checkout:ro" \ + --workdir /tmp/obj \ + --env SRC=/checkout \ + --env CCACHE_DIR=/ccache \ + --volume "$HOME/.ccache:/ccache" \ + --env CARGO_HOME=/cargo \ + --env LOCAL_USER_ID=`id -u` \ + --volume "$HOME/.cargo:/cargo" \ + --interactive \ + --tty \ + rust-ci \ + /checkout/src/ci/run.sh diff --git a/src/ci/docker/x86_64-freebsd/Dockerfile b/src/ci/docker/x86_64-freebsd/Dockerfile new file mode 100644 index 000000000000..dc16c39961c4 --- /dev/null +++ b/src/ci/docker/x86_64-freebsd/Dockerfile @@ -0,0 +1,29 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + python-minimal \ + git \ + cmake \ + ccache \ + sudo \ + bzip2 \ + xz-utils \ + wget + +COPY build-toolchain.sh /tmp/ +RUN sh /tmp/build-toolchain.sh + +ENV \ + AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \ + CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc + +ENV RUST_CONFIGURE_ARGS --target=x86_64-unknown-freebsd --enable-rustbuild +ENV RUST_CHECK_TARGET "" +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/x86_64-freebsd/build-toolchain.sh b/src/ci/docker/x86_64-freebsd/build-toolchain.sh new file mode 100644 index 000000000000..d4bc886d50ea --- /dev/null +++ b/src/ci/docker/x86_64-freebsd/build-toolchain.sh @@ -0,0 +1,96 @@ +#!/bin/bash +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +ARCH=x86_64 +BINUTILS=2.25.1 +GCC=5.3.0 + +mkdir binutils +cd binutils + +# First up, build binutils +curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf - +mkdir binutils-build +cd binutils-build +../binutils-$BINUTILS/configure \ + --target=$ARCH-unknown-freebsd10 +make -j10 +make install +cd ../.. +rm -rf binutils + +# Next, download the FreeBSD libc and relevant header files + +mkdir freebsd +case "$ARCH" in + x86_64) + URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/10.2-RELEASE/base.txz + ;; + i686) + URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/i386/10.2-RELEASE/base.txz + ;; +esac +curl $URL | tar xJf - -C freebsd ./usr/include ./usr/lib ./lib + +dst=/usr/local/$ARCH-unknown-freebsd10 + +cp -r freebsd/usr/include $dst/ +cp freebsd/usr/lib/crt1.o $dst/lib +cp freebsd/usr/lib/Scrt1.o $dst/lib +cp freebsd/usr/lib/crti.o $dst/lib +cp freebsd/usr/lib/crtn.o $dst/lib +cp freebsd/usr/lib/libc.a $dst/lib +cp freebsd/usr/lib/libutil.a $dst/lib +cp freebsd/usr/lib/libutil_p.a $dst/lib +cp freebsd/usr/lib/libm.a $dst/lib +cp freebsd/usr/lib/librt.so.1 $dst/lib +cp freebsd/usr/lib/libexecinfo.so.1 $dst/lib +cp freebsd/lib/libc.so.7 $dst/lib +cp freebsd/lib/libm.so.5 $dst/lib +cp freebsd/lib/libutil.so.9 $dst/lib +cp freebsd/lib/libthr.so.3 $dst/lib/libpthread.so + +ln -s libc.so.7 $dst/lib/libc.so +ln -s libm.so.5 $dst/lib/libm.so +ln -s librt.so.1 $dst/lib/librt.so +ln -s libutil.so.9 $dst/lib/libutil.so +ln -s libexecinfo.so.1 $dst/lib/libexecinfo.so +rm -rf freebsd + +# Finally, download and build gcc to target FreeBSD +mkdir gcc +cd gcc +curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - +cd gcc-$GCC +./contrib/download_prerequisites + +mkdir ../gcc-build +cd ../gcc-build +../gcc-$GCC/configure \ + --enable-languages=c \ + --target=$ARCH-unknown-freebsd10 \ + --disable-multilib \ + --disable-nls \ + --disable-libgomp \ + --disable-libquadmath \ + --disable-libssp \ + --disable-libvtv \ + --disable-libcilkrts \ + --disable-libada \ + --disable-libsanitizer \ + --disable-libquadmath-support \ + --disable-lto +make -j10 +make install +cd ../.. +rm -rf gcc diff --git a/src/ci/docker/x86_64-gnu-cargotest/Dockerfile b/src/ci/docker/x86_64-gnu-cargotest/Dockerfile new file mode 100644 index 000000000000..1db01f2b48d4 --- /dev/null +++ b/src/ci/docker/x86_64-gnu-cargotest/Dockerfile @@ -0,0 +1,20 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + python-minimal \ + git \ + cmake \ + ccache \ + libssl-dev \ + sudo + +ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --enable-rustbuild +ENV RUST_CHECK_TARGET check-cargotest +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile new file mode 100644 index 000000000000..9e98215775e5 --- /dev/null +++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile @@ -0,0 +1,22 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + ccache \ + sudo \ + gdb + +ENV RUST_CONFIGURE_ARGS \ + --build=x86_64-unknown-linux-gnu \ + --enable-debug \ + --enable-optimize +ENV RUST_CHECK_TARGET "" +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile new file mode 100644 index 000000000000..ca06940ae5e2 --- /dev/null +++ b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile @@ -0,0 +1,26 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + python2.7-minimal \ + git \ + cmake \ + ccache \ + sudo \ + gdb \ + llvm-3.7-tools \ + libedit-dev \ + zlib1g-dev + +ENV RUST_CONFIGURE_ARGS \ + --build=x86_64-unknown-linux-gnu \ + --enable-rustbuild \ + --llvm-root=/usr/lib/llvm-3.7 +ENV RUST_CHECK_TARGET check +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/x86_64-gnu-nopt/Dockerfile new file mode 100644 index 000000000000..73a3e2c726ce --- /dev/null +++ b/src/ci/docker/x86_64-gnu-nopt/Dockerfile @@ -0,0 +1,19 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + ccache \ + sudo \ + gdb + +ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --disable-optimize-tests +ENV RUST_CHECK_TARGET check +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/x86_64-gnu-rustbuild/Dockerfile b/src/ci/docker/x86_64-gnu-rustbuild/Dockerfile new file mode 100644 index 000000000000..d4d0492e2a26 --- /dev/null +++ b/src/ci/docker/x86_64-gnu-rustbuild/Dockerfile @@ -0,0 +1,20 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + python-minimal \ + git \ + cmake \ + ccache \ + sudo \ + gdb + +ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --enable-rustbuild +ENV RUST_CHECK_TARGET check +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/x86_64-gnu/Dockerfile b/src/ci/docker/x86_64-gnu/Dockerfile new file mode 100644 index 000000000000..f125693e7ae1 --- /dev/null +++ b/src/ci/docker/x86_64-gnu/Dockerfile @@ -0,0 +1,19 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + ccache \ + sudo \ + gdb + +ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu +ENV RUST_CHECK_TARGET check +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/x86_64-musl/Dockerfile b/src/ci/docker/x86_64-musl/Dockerfile new file mode 100644 index 000000000000..1afaef2e0567 --- /dev/null +++ b/src/ci/docker/x86_64-musl/Dockerfile @@ -0,0 +1,27 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + ccache \ + xz-utils \ + sudo \ + gdb + +WORKDIR /build/ +COPY build-musl.sh /build/ +RUN sh /build/build-musl.sh && rm -rf /build + +ENV RUST_CONFIGURE_ARGS \ + --target=x86_64-unknown-linux-musl \ + --musl-root=/musl-x86_64 +ENV RUST_CHECK_TARGET check-stage2-T-x86_64-unknown-linux-musl-H-x86_64-unknown-linux-gnu + +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/x86_64-musl/build-musl.sh b/src/ci/docker/x86_64-musl/build-musl.sh new file mode 100644 index 000000000000..2bfbd646b75c --- /dev/null +++ b/src/ci/docker/x86_64-musl/build-musl.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +export CFLAGS="-fPIC" +MUSL=musl-1.1.14 +curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf - +cd $MUSL +./configure --prefix=/musl-x86_64 --disable-shared +make -j10 +make install +make clean +cd .. + +# To build MUSL we're going to need a libunwind lying around, so acquire that +# here and build it. +curl -L https://github.com/llvm-mirror/llvm/archive/release_37.tar.gz | tar xzf - +curl -L https://github.com/llvm-mirror/libunwind/archive/release_37.tar.gz | tar xzf - +mkdir libunwind-build +cd libunwind-build +cmake ../libunwind-release_37 -DLLVM_PATH=/build/llvm-release_37 \ + -DLIBUNWIND_ENABLE_SHARED=0 +make -j10 +cp lib/libunwind.a /musl-x86_64/lib diff --git a/src/ci/run.sh b/src/ci/run.sh new file mode 100755 index 000000000000..da238dddecac --- /dev/null +++ b/src/ci/run.sh @@ -0,0 +1,44 @@ +#!/bin/sh +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -e + +if [ "$LOCAL_USER_ID" != "" ]; then + useradd --shell /bin/bash -u $LOCAL_USER_ID -o -c "" -m user + export HOME=/home/user + export LOCAL_USER_ID= + exec sudo -E -u user env PATH=$PATH "$0" +fi + +if [ "$NO_LLVM_ASSERTIONS" = "" ]; then + LLVM_ASSERTIONS=--enable-llvm-assertions +fi + +set -ex + +$SRC/configure \ + --disable-manage-submodules \ + --enable-debug-assertions \ + --enable-quiet-tests \ + --enable-ccache \ + --enable-vendor \ + $LLVM_ASSERTIONS \ + $RUST_CONFIGURE_ARGS + +if [ "$TRAVIS_OS_NAME" = "osx" ]; then + ncpus=$(sysctl -n hw.ncpu) +else + ncpus=$(nproc) +fi + +make -j $ncpus tidy +make -j $ncpus +exec make $RUST_CHECK_TARGET -j $ncpus diff --git a/src/test/debuginfo/vec-slices.rs b/src/test/debuginfo/vec-slices.rs index 5553f8427e90..d321df8431b8 100644 --- a/src/test/debuginfo/vec-slices.rs +++ b/src/test/debuginfo/vec-slices.rs @@ -21,21 +21,21 @@ // gdb-command:print singleton.length // gdb-check:$2 = 1 -// gdbg-command:print *((int64_t[1]*)(singleton.data_ptr)) +// gdbg-command:print *((i64[1]*)(singleton.data_ptr)) // gdbr-command:print *(singleton.data_ptr as &[i64; 1]) // gdbg-check:$3 = {1} // gdbr-check:$3 = [1] // gdb-command:print multiple.length // gdb-check:$4 = 4 -// gdbg-command:print *((int64_t[4]*)(multiple.data_ptr)) +// gdbg-command:print *((i64[4]*)(multiple.data_ptr)) // gdbr-command:print *(multiple.data_ptr as &[i64; 4]) // gdbg-check:$5 = {2, 3, 4, 5} // gdbr-check:$5 = [2, 3, 4, 5] // gdb-command:print slice_of_slice.length // gdb-check:$6 = 2 -// gdbg-command:print *((int64_t[2]*)(slice_of_slice.data_ptr)) +// gdbg-command:print *((i64[2]*)(slice_of_slice.data_ptr)) // gdbr-command:print *(slice_of_slice.data_ptr as &[i64; 2]) // gdbg-check:$7 = {3, 4} // gdbr-check:$7 = [3, 4] @@ -61,14 +61,14 @@ // gdbg-command:print 'vec_slices::MUT_VECT_SLICE'.length // gdbr-command:print MUT_VECT_SLICE.length // gdb-check:$14 = 2 -// gdbg-command:print *((int64_t[2]*)('vec_slices::MUT_VECT_SLICE'.data_ptr)) +// gdbg-command:print *((i64[2]*)('vec_slices::MUT_VECT_SLICE'.data_ptr)) // gdbr-command:print *(MUT_VECT_SLICE.data_ptr as &[i64; 2]) // gdbg-check:$15 = {64, 65} // gdbr-check:$15 = [64, 65] //gdb-command:print mut_slice.length //gdb-check:$16 = 5 -//gdbg-command:print *((int64_t[5]*)(mut_slice.data_ptr)) +//gdbg-command:print *((i64[5]*)(mut_slice.data_ptr)) //gdbr-command:print *(mut_slice.data_ptr as &[i64; 5]) //gdbg-check:$17 = {1, 2, 3, 4, 5} //gdbr-check:$17 = [1, 2, 3, 4, 5] From 5cf07f1d60f38491339b3c3b963aca3622674891 Mon Sep 17 00:00:00 2001 From: nwin Date: Fri, 4 Nov 2016 10:50:58 +0100 Subject: [PATCH 058/177] Update patch with example. --- src/doc/book/traits.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/doc/book/traits.md b/src/doc/book/traits.md index 18e7f07f722e..d1166e686c7b 100644 --- a/src/doc/book/traits.md +++ b/src/doc/book/traits.md @@ -243,7 +243,21 @@ to know more about [operator traits][operators-and-overloading]. # Rules for implementing traits So far, we’ve only added trait implementations to structs, but you can -implement a trait for any type such as `i32`. +implement a trait for any type such as `f32`: + +```rust +trait ApproxEqual { + fn approx_equal(&self, other: &Self) -> bool; +} +impl ApproxEqual for f32 { + fn approx_equal(&self, other: &Self) -> bool { + // Appropriate for `self` and `other` being close to 1.0. + (self - other).abs() <= ::std::f32::EPSILON + } +} + +println!("{}", 1.0.approx_equal(&1.00000001)); +``` This may seem like the Wild West, but there are two restrictions around implementing traits that prevent this from getting out of hand. The first is From bfdf652f535475542adcd14dcd84b316fc888034 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 11 Nov 2016 18:49:16 +0100 Subject: [PATCH 059/177] Add missing urls for mem module --- src/libcore/mem.rs | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index e0aa25724c1f..209107ef92ce 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -337,7 +337,7 @@ pub unsafe fn zeroed() -> T { /// Bypasses Rust's normal memory-initialization checks by pretending to /// produce a value of type `T`, while doing nothing at all. /// -/// **This is incredibly dangerous, and should not be done lightly. Deeply +/// **This is incredibly dangerous and should not be done lightly. Deeply /// consider initializing your memory with a default value instead.** /// /// This is useful for [FFI] functions and initializing arrays sometimes, @@ -352,24 +352,18 @@ pub unsafe fn zeroed() -> T { /// a boolean, your program may take one, both, or neither of the branches. /// /// Writing to the uninitialized value is similarly dangerous. Rust believes the -/// value is initialized, and will therefore try to [`Drop`][drop] the uninitialized +/// value is initialized, and will therefore try to [`Drop`] the uninitialized /// value and its fields if you try to overwrite it in a normal manner. The only way /// to safely initialize an uninitialized value is with [`ptr::write`][write], /// [`ptr::copy`][copy], or [`ptr::copy_nonoverlapping`][copy_no]. /// -/// If the value does implement `Drop`, it must be initialized before +/// If the value does implement [`Drop`], it must be initialized before /// it goes out of scope (and therefore would be dropped). Note that this /// includes a `panic` occurring and unwinding the stack suddenly. /// -/// [ub]: ../../reference.html#behavior-considered-undefined -/// [write]: ../ptr/fn.write.html -/// [copy]: ../intrinsics/fn.copy.html -/// [copy_no]: ../intrinsics/fn.copy_nonoverlapping.html -/// [drop]: ../ops/trait.Drop.html -/// /// # Examples /// -/// Here's how to safely initialize an array of `Vec`s. +/// Here's how to safely initialize an array of [`Vec`]s. /// /// ``` /// use std::mem; @@ -410,8 +404,8 @@ pub unsafe fn zeroed() -> T { /// ``` /// /// This example emphasizes exactly how delicate and dangerous using `mem::uninitialized` -/// can be. Note that the `vec!` macro *does* let you initialize every element with a -/// value that is only `Clone`, so the following is semantically equivalent and +/// can be. Note that the [`vec!`] macro *does* let you initialize every element with a +/// value that is only [`Clone`], so the following is semantically equivalent and /// vastly less dangerous, as long as you can live with an extra heap /// allocation: /// @@ -419,6 +413,15 @@ pub unsafe fn zeroed() -> T { /// let data: Vec> = vec![Vec::new(); 1000]; /// println!("{:?}", &data[0]); /// ``` +/// +/// [`Vec`]: ../../std/vec/struct.Vec.html +/// [`vec!`]: ../../std/macro.vec.html +/// [`Clone`]: ../../std/clone/trait.Clone.html +/// [ub]: ../../reference.html#behavior-considered-undefined +/// [write]: ../ptr/fn.write.html +/// [copy]: ../intrinsics/fn.copy.html +/// [copy_no]: ../intrinsics/fn.copy_nonoverlapping.html +/// [`Drop`]: ../ops/trait.Drop.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn uninitialized() -> T { @@ -492,7 +495,7 @@ pub fn swap(x: &mut T, y: &mut T) { /// } /// ``` /// -/// Note that `T` does not necessarily implement `Clone`, so it can't even clone and reset +/// Note that `T` does not necessarily implement [`Clone`], so it can't even clone and reset /// `self.buf`. But `replace` can be used to disassociate the original value of `self.buf` from /// `self`, allowing it to be returned: /// @@ -507,6 +510,8 @@ pub fn swap(x: &mut T, y: &mut T) { /// } /// } /// ``` +/// +/// [`Clone`]: ../../std/clone/trait.Clone.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn replace(dest: &mut T, mut src: T) -> T { @@ -571,8 +576,8 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// v.push(4); // no problems /// ``` /// -/// Since `RefCell` enforces the borrow rules at runtime, `drop` can -/// release a `RefCell` borrow: +/// Since [`RefCell`] enforces the borrow rules at runtime, `drop` can +/// release a [`RefCell`] borrow: /// /// ``` /// use std::cell::RefCell; @@ -588,7 +593,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// println!("{}", *borrow); /// ``` /// -/// Integers and other types implementing `Copy` are unaffected by `drop`. +/// Integers and other types implementing [`Copy`] are unaffected by `drop`. /// /// ``` /// #[derive(Copy, Clone)] @@ -602,6 +607,8 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// println!("x: {}, y: {}", x, y.0); // still available /// ``` /// +/// [`RefCell`]: ../../std/cell/struct.RefCell.html +/// [`Copy`]: ../../std/marker/trait.Copy.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn drop(_x: T) { } From 3c17abc4d955080baa410e9b697bf5be37b0d079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 10 Nov 2016 12:48:55 -0800 Subject: [PATCH 060/177] On fmt string with unescaped `{` note how to escape On cases of malformed format strings where a `{` hasn't been properly escaped, like `println!("{");`, present a note explaining how to escape the `{` char. --- src/libfmt_macros/lib.rs | 23 ++++++++++++++++++---- src/libsyntax_ext/format.rs | 8 ++++++-- src/test/ui/fmt/format-string-error.rs | 16 +++++++++++++++ src/test/ui/fmt/format-string-error.stderr | 20 +++++++++++++++++++ 4 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/fmt/format-string-error.rs create mode 100644 src/test/ui/fmt/format-string-error.stderr diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index e7d401f0929f..b179a16e55e5 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -139,7 +139,7 @@ pub struct Parser<'a> { input: &'a str, cur: iter::Peekable>, /// Error messages accumulated during parsing - pub errors: Vec, + pub errors: Vec<(string::String, Option)>, /// Current position of implicit positional argument pointer curarg: usize, } @@ -165,7 +165,9 @@ impl<'a> Iterator for Parser<'a> { if self.consume('}') { Some(String(self.string(pos + 1))) } else { - self.err("unmatched `}` found"); + self.err_with_note("unmatched `}` found", + "if you intended to print `}`, \ + you can escape it using `}}`"); None } } @@ -192,7 +194,14 @@ impl<'a> Parser<'a> { /// String, but I think it does when this eventually uses conditions so it /// might as well start using it now. fn err(&mut self, msg: &str) { - self.errors.push(msg.to_owned()); + self.errors.push((msg.to_owned(), None)); + } + + /// Notifies of an error. The message doesn't actually need to be of type + /// String, but I think it does when this eventually uses conditions so it + /// might as well start using it now. + fn err_with_note(&mut self, msg: &str, note: &str) { + self.errors.push((msg.to_owned(), Some(note.to_owned()))); } /// Optionally consumes the specified character. If the character is not at @@ -222,7 +231,13 @@ impl<'a> Parser<'a> { self.err(&format!("expected `{:?}`, found `{:?}`", c, maybe)); } } else { - self.err(&format!("expected `{:?}` but string was terminated", c)); + let msg = &format!("expected `{:?}` but string was terminated", c); + if c == '}' { + self.err_with_note(msg, + "if you intended to print `{`, you can escape it using `{{`"); + } else { + self.err(msg); + } } } diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index de78f859f0f6..16c1ab795760 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -756,8 +756,12 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, } if !parser.errors.is_empty() { - cx.ecx.span_err(cx.fmtsp, - &format!("invalid format string: {}", parser.errors.remove(0))); + let (err, note) = parser.errors.remove(0); + let mut e = cx.ecx.struct_span_err(cx.fmtsp, &format!("invalid format string: {}", err)); + if let Some(note) = note { + e.note(¬e); + } + e.emit(); return DummyResult::raw_expr(sp); } if !cx.literal.is_empty() { diff --git a/src/test/ui/fmt/format-string-error.rs b/src/test/ui/fmt/format-string-error.rs new file mode 100644 index 000000000000..ec715b3f0ba6 --- /dev/null +++ b/src/test/ui/fmt/format-string-error.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + println!("{"); + println!("{{}}"); + println!("}"); +} + diff --git a/src/test/ui/fmt/format-string-error.stderr b/src/test/ui/fmt/format-string-error.stderr new file mode 100644 index 000000000000..58b392f0b8d6 --- /dev/null +++ b/src/test/ui/fmt/format-string-error.stderr @@ -0,0 +1,20 @@ +error: invalid format string: expected `'}'` but string was terminated + --> $DIR/format-string-error.rs:12:5 + | +12 | println!("{"); + | ^^^^^^^^^^^^^^ + | + = note: if you intended to print `{`, you can escape it using `{{` + = note: this error originates in a macro outside of the current crate + +error: invalid format string: unmatched `}` found + --> $DIR/format-string-error.rs:14:5 + | +14 | println!("}"); + | ^^^^^^^^^^^^^^ + | + = note: if you intended to print `}`, you can escape it using `}}` + = note: this error originates in a macro outside of the current crate + +error: aborting due to 2 previous errors + From 9d087455ba88c8c29fba6de1858e12055bf4bdae Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 11 Nov 2016 21:47:18 +0000 Subject: [PATCH 061/177] bootstrap: rust-docs is a default package This will cause it to be built as part of `make dist`. --- src/bootstrap/step.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 6f616434b10c..190a4cc67f92 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -424,6 +424,7 @@ pub fn build_rules(build: &Build) -> Rules { .host(true) .run(move |_| dist::rust_src(build)); rules.dist("dist-docs", "src/doc") + .default(true) .dep(|s| s.name("default:doc")) .run(move |s| dist::docs(build, s.stage, s.target)); rules.dist("install", "src") From 61b14e8aae4cfc3c51cf275742adcd23236ec865 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 11 Nov 2016 21:56:12 +0000 Subject: [PATCH 062/177] Bump verison to 1.15.0 --- mk/main.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mk/main.mk b/mk/main.mk index 2fa8ccf3621e..07b52593781c 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -13,7 +13,7 @@ ###################################################################### # The version number -CFG_RELEASE_NUM=1.14.0 +CFG_RELEASE_NUM=1.15.0 # An optional number to put after the label, e.g. '.2' -> '-beta.2' # NB Make sure it starts with a dot to conform to semver pre-release From 248a3d9fc08e7b7b7083530a72cc86f966ee4e38 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 12 Nov 2016 00:30:53 +0100 Subject: [PATCH 063/177] Fix invalid src url --- src/libcore/macros.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 3cf32d1a5591..b3f5363f5b15 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -550,8 +550,7 @@ macro_rules! unimplemented { /// into libsyntax itself. /// /// For more information, see documentation for `std`'s macros. -#[cfg(dox)] -pub mod builtin { +mod builtin { /// The core macro for formatted string creation & output. /// /// For more information, see the documentation for [`std::format_args!`]. @@ -559,6 +558,7 @@ pub mod builtin { /// [`std::format_args!`]: ../std/macro.format_args.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! format_args { ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) } @@ -570,6 +570,7 @@ pub mod builtin { /// [`std::env!`]: ../std/macro.env.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! env { ($name:expr) => ({ /* compiler built-in */ }) } /// Optionally inspect an environment variable at compile time. @@ -579,6 +580,7 @@ pub mod builtin { /// [`std::option_env!`]: ../std/macro.option_env.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }) } /// Concatenate identifiers into one identifier. @@ -588,6 +590,7 @@ pub mod builtin { /// [`std::concat_idents!`]: ../std/macro.concat_idents.html #[unstable(feature = "concat_idents_macro", issue = "29599")] #[macro_export] + #[cfg(dox)] macro_rules! concat_idents { ($($e:ident),*) => ({ /* compiler built-in */ }) } @@ -599,6 +602,7 @@ pub mod builtin { /// [`std::concat!`]: ../std/macro.concat.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! concat { ($($e:expr),*) => ({ /* compiler built-in */ }) } /// A macro which expands to the line number on which it was invoked. @@ -608,6 +612,7 @@ pub mod builtin { /// [`std::line!`]: ../std/macro.line.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! line { () => ({ /* compiler built-in */ }) } /// A macro which expands to the column number on which it was invoked. @@ -617,6 +622,7 @@ pub mod builtin { /// [`std::column!`]: ../std/macro.column.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! column { () => ({ /* compiler built-in */ }) } /// A macro which expands to the file name from which it was invoked. @@ -626,6 +632,7 @@ pub mod builtin { /// [`std::file!`]: ../std/macro.file.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! file { () => ({ /* compiler built-in */ }) } /// A macro which stringifies its argument. @@ -635,6 +642,7 @@ pub mod builtin { /// [`std::stringify!`]: ../std/macro.stringify.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! stringify { ($t:tt) => ({ /* compiler built-in */ }) } /// Includes a utf8-encoded file as a string. @@ -644,6 +652,7 @@ pub mod builtin { /// [`std::include_str!`]: ../std/macro.include_str.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }) } /// Includes a file as a reference to a byte array. @@ -653,6 +662,7 @@ pub mod builtin { /// [`std::include_bytes!`]: ../std/macro.include_bytes.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }) } /// Expands to a string that represents the current module path. @@ -662,6 +672,7 @@ pub mod builtin { /// [`std::module_path!`]: ../std/macro.module_path.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! module_path { () => ({ /* compiler built-in */ }) } /// Boolean evaluation of configuration flags. @@ -671,6 +682,7 @@ pub mod builtin { /// [`std::cfg!`]: ../std/macro.cfg.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) } /// Parse a file as an expression or an item according to the context. @@ -680,5 +692,6 @@ pub mod builtin { /// [`std::include!`]: ../std/macro.include.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }) } } From 0268cfaa1fff614311a4f7d4f9e7ded0207ebab9 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 10 Nov 2016 16:12:53 +0200 Subject: [PATCH 064/177] Set `RUST_BACKTRACE=1` on travis to be more helpful. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e06444ddf6d0..a1bbb8a884fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,7 @@ matrix: - env: IMAGE=x86_64-gnu-debug - env: IMAGE=x86_64-gnu-nopt - env: IMAGE=x86_64-gnu-rustbuild - - env: IMAGE=x86_64-gnu-llvm-3.7 ALLOW_PR=1 + - env: IMAGE=x86_64-gnu-llvm-3.7 ALLOW_PR=1 RUST_BACKTRACE=1 - env: IMAGE=x86_64-musl # OSX builders From 568874bc1007162276243e613324c710c72ec932 Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Sun, 6 Nov 2016 19:37:56 -0700 Subject: [PATCH 065/177] Cleanup macro_parser::parse, removing a few clones. --- src/libsyntax/ext/tt/macro_parser.rs | 86 +++++++++++----------------- 1 file changed, 35 insertions(+), 51 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 1066646aa8e8..da9692391dd8 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -287,15 +287,8 @@ pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseRes let mut next_eis = Vec::new(); // or proceed normally let mut eof_eis = Vec::new(); - let (sp, tok) = (parser.span, parser.token.clone()); - - /* we append new items to this while we go */ - loop { - let mut ei = match cur_eis.pop() { - None => break, /* for each Earley Item */ - Some(ei) => ei, - }; - + // for each Earley item + while let Some(mut ei) = cur_eis.pop() { // When unzipped trees end, remove them while ei.idx >= ei.top_elts.len() { match ei.stack.pop() { @@ -317,7 +310,6 @@ pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseRes // hack: a matcher sequence is repeating iff it has a // parent (the top level is just a container) - // disregard separator, try to go up // (remove this condition to make trailing seps ok) if idx == len { @@ -334,10 +326,10 @@ pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseRes // Only touch the binders we have actually bound for idx in ei.match_lo..ei.match_hi { - let sub = (ei.matches[idx]).clone(); - (&mut new_pos.matches[idx]) + let sub = ei.matches[idx].clone(); + new_pos.matches[idx] .push(Rc::new(MatchedSeq(sub, mk_sp(ei.sp_lo, - sp.hi)))); + parser.span.hi)))); } new_pos.match_cur = ei.match_hi; @@ -347,25 +339,21 @@ pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseRes // can we go around again? - // the *_t vars are workarounds for the lack of unary move - match ei.sep { - Some(ref t) if idx == len => { // we need a separator - // i'm conflicted about whether this should be hygienic.... - // though in this case, if the separators are never legal - // idents, it shouldn't matter. - if token_name_eq(&tok, t) { //pass the separator - let mut ei_t = ei.clone(); - // ei_t.match_cur = ei_t.match_lo; - ei_t.idx += 1; - next_eis.push(ei_t); - } - } - _ => { // we don't need a separator - let mut ei_t = ei; - ei_t.match_cur = ei_t.match_lo; - ei_t.idx = 0; - cur_eis.push(ei_t); + // Check if we need a separator + if idx == len && ei.sep.is_some() { + if ei.sep.as_ref().map(|ref sep| token_name_eq(&parser.token, sep)) + .unwrap_or(false) { + // i'm conflicted about whether this should be hygienic.... though in + // this case, if the separators are never legal idents, it shouldn't + // matter. + // ei.match_cur = ei.match_lo; + ei.idx += 1; + next_eis.push(ei); } + } else { // we don't need a separator + ei.match_cur = ei.match_lo; + ei.idx = 0; + cur_eis.push(ei); } } else { eof_eis.push(ei); @@ -380,7 +368,7 @@ pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseRes new_ei.idx += 1; //we specifically matched zero repeats. for idx in ei.match_cur..ei.match_cur + seq.num_captures { - (&mut new_ei.matches[idx]).push(Rc::new(MatchedSeq(vec![], sp))); + new_ei.matches[idx].push(Rc::new(MatchedSeq(vec![], sp))); } cur_eis.push(new_ei); @@ -388,16 +376,15 @@ pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseRes let matches: Vec<_> = (0..ei.matches.len()) .map(|_| Vec::new()).collect(); - let ei_t = ei; cur_eis.push(Box::new(MatcherPos { stack: vec![], sep: seq.separator.clone(), idx: 0, matches: matches, - match_lo: ei_t.match_cur, - match_cur: ei_t.match_cur, - match_hi: ei_t.match_cur + seq.num_captures, - up: Some(ei_t), + match_lo: ei.match_cur, + match_cur: ei.match_cur, + match_hi: ei.match_cur + seq.num_captures, + up: Some(ei), sp_lo: sp.lo, top_elts: Tt(TokenTree::Sequence(sp, seq)), })); @@ -405,7 +392,7 @@ pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseRes TokenTree::Token(_, MatchNt(..)) => { // Built-in nonterminals never start with these tokens, // so we can eliminate them from consideration. - match tok { + match parser.token { token::CloseDelim(_) => {}, _ => bb_eis.push(ei), } @@ -424,10 +411,9 @@ pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseRes cur_eis.push(ei); } TokenTree::Token(_, ref t) => { - if token_name_eq(t,&tok) { - let mut ei_t = ei.clone(); - ei_t.idx += 1; - next_eis.push(ei_t); + if token_name_eq(t, &parser.token) { + ei.idx += 1; + next_eis.push(ei); } } } @@ -435,17 +421,15 @@ pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseRes } /* error messages here could be improved with links to orig. rules */ - if token_name_eq(&tok, &token::Eof) { + if token_name_eq(&parser.token, &token::Eof) { if eof_eis.len() == 1 { - let mut v = Vec::new(); - for dv in &mut (&mut eof_eis[0]).matches { - v.push(dv.pop().unwrap()); - } + let v = eof_eis[0].matches.iter_mut() + .map(|dv| dv.pop().unwrap()).collect::>(); return nameize(sess, ms, &v[..]); } else if eof_eis.len() > 1 { - return Error(sp, "ambiguity: multiple successful parses".to_string()); + return Error(parser.span, "ambiguity: multiple successful parses".to_string()); } else { - return Failure(sp, token::Eof); + return Failure(parser.span, token::Eof); } } else { if (!bb_eis.is_empty() && !next_eis.is_empty()) @@ -457,7 +441,7 @@ pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseRes _ => panic!() }).collect::>().join(" or "); - return Error(sp, format!( + return Error(parser.span, format!( "local ambiguity: multiple parsing options: {}", match next_eis.len() { 0 => format!("built-in NTs {}.", nts), @@ -466,7 +450,7 @@ pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseRes } )) } else if bb_eis.is_empty() && next_eis.is_empty() { - return Failure(sp, tok); + return Failure(parser.span, parser.token); } else if !next_eis.is_empty() { /* Now process the next token */ while !next_eis.is_empty() { From 7221b07a075aacad2b0d5962568000ba7defe5f9 Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Mon, 7 Nov 2016 19:16:14 -0700 Subject: [PATCH 066/177] Remove unused argument from nameize. Also makes nameize non-public since it's only locally used. --- src/libsyntax/ext/tt/macro_parser.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index da9692391dd8..42c71d93a284 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -200,20 +200,20 @@ pub enum NamedMatch { MatchedNonterminal(Rc) } -pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc]) +fn nameize(ms: &[TokenTree], res: &[Rc]) -> ParseResult>> { - fn n_rec(p_s: &ParseSess, m: &TokenTree, res: &[Rc], + fn n_rec(m: &TokenTree, res: &[Rc], ret_val: &mut HashMap>, idx: &mut usize) -> Result<(), (syntax_pos::Span, String)> { match *m { TokenTree::Sequence(_, ref seq) => { for next_m in &seq.tts { - n_rec(p_s, next_m, res, ret_val, idx)? + n_rec(next_m, res, ret_val, idx)? } } TokenTree::Delimited(_, ref delim) => { for next_m in &delim.tts { - n_rec(p_s, next_m, res, ret_val, idx)?; + n_rec(next_m, res, ret_val, idx)?; } } TokenTree::Token(sp, MatchNt(bind_name, _)) => { @@ -239,7 +239,7 @@ pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc]) let mut ret_val = HashMap::new(); let mut idx = 0; for m in ms { - match n_rec(p_s, m, res, &mut ret_val, &mut idx) { + match n_rec(m, res, &mut ret_val, &mut idx) { Ok(_) => {}, Err((sp, msg)) => return Error(sp, msg), } @@ -425,7 +425,7 @@ pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseRes if eof_eis.len() == 1 { let v = eof_eis[0].matches.iter_mut() .map(|dv| dv.pop().unwrap()).collect::>(); - return nameize(sess, ms, &v[..]); + return nameize(ms, &v[..]); } else if eof_eis.len() > 1 { return Error(parser.span, "ambiguity: multiple successful parses".to_string()); } else { From c9e6089d29cd3263897d91e12519b79ba8721f85 Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Mon, 7 Nov 2016 19:17:17 -0700 Subject: [PATCH 067/177] Refactor to extending from a drain instead of while looping. --- src/libsyntax/ext/tt/macro_parser.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 42c71d93a284..5f976336ccd3 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -453,9 +453,7 @@ pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseRes return Failure(parser.span, parser.token); } else if !next_eis.is_empty() { /* Now process the next token */ - while !next_eis.is_empty() { - cur_eis.push(next_eis.pop().unwrap()); - } + cur_eis.extend(next_eis.drain(..)); parser.bump(); } else /* bb_eis.len() == 1 */ { let mut ei = bb_eis.pop().unwrap(); From eef10d0b5b9e0788442fc6c8ecce57ae7f5a4047 Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Mon, 7 Nov 2016 19:17:45 -0700 Subject: [PATCH 068/177] Clean up extraneous &mut. --- src/libsyntax/ext/tt/macro_parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 5f976336ccd3..9f055f33c3d0 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -459,7 +459,7 @@ pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseRes let mut ei = bb_eis.pop().unwrap(); if let TokenTree::Token(span, MatchNt(_, ident)) = ei.top_elts.get_tt(ei.idx) { let match_cur = ei.match_cur; - (&mut ei.matches[match_cur]).push(Rc::new(MatchedNonterminal( + ei.matches[match_cur].push(Rc::new(MatchedNonterminal( Rc::new(parse_nt(&mut parser, span, &ident.name.as_str()))))); ei.idx += 1; ei.match_cur += 1; From 68abb24e8d99f0fb7175c2102da3638814b6b2c7 Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Mon, 7 Nov 2016 19:40:00 -0700 Subject: [PATCH 069/177] Factor out NamedParseResult. --- src/libsyntax/ext/tt/macro_parser.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 9f055f33c3d0..29e1ea1d1edd 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -143,6 +143,8 @@ pub struct MatcherPos { sp_lo: BytePos, } +pub type NamedParseResult = ParseResult>>; + pub fn count_names(ms: &[TokenTree]) -> usize { ms.iter().fold(0, |count, elt| { count + match *elt { @@ -200,8 +202,7 @@ pub enum NamedMatch { MatchedNonterminal(Rc) } -fn nameize(ms: &[TokenTree], res: &[Rc]) - -> ParseResult>> { +fn nameize(ms: &[TokenTree], res: &[Rc]) -> NamedParseResult { fn n_rec(m: &TokenTree, res: &[Rc], ret_val: &mut HashMap>, idx: &mut usize) -> Result<(), (syntax_pos::Span, String)> { @@ -265,8 +266,6 @@ pub fn parse_failure_msg(tok: Token) -> String { } } -pub type NamedParseResult = ParseResult>>; - /// Perform a token equality check, ignoring syntax context (that is, an /// unhygienic comparison) pub fn token_name_eq(t1 : &Token, t2 : &Token) -> bool { From 27c09864bd04bc3f65e8ce5721eaa5621ee9ac6a Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Thu, 10 Nov 2016 17:30:01 -0700 Subject: [PATCH 070/177] Refactor parse_nt. --- src/libsyntax/ext/tt/macro_parser.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 29e1ea1d1edd..64acce19c1cc 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -479,14 +479,19 @@ pub fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { p.quote_depth += 1; //but in theory, non-quoted tts might be useful let mut tt = panictry!(p.parse_token_tree()); p.quote_depth -= 1; - loop { - let nt = match tt { - TokenTree::Token(_, token::Interpolated(ref nt)) => nt.clone(), - _ => break, - }; - match *nt { - token::NtTT(ref sub_tt) => tt = sub_tt.clone(), - _ => break, + while let TokenTree::Token(sp, token::Interpolated(nt)) = tt { + if let token::NtTT(..) = *nt { + match Rc::try_unwrap(nt) { + Ok(token::NtTT(sub_tt)) => tt = sub_tt, + Ok(_) => unreachable!(), + Err(nt_rc) => match *nt_rc { + token::NtTT(ref sub_tt) => tt = sub_tt.clone(), + _ => unreachable!(), + }, + } + } else { + tt = TokenTree::Token(sp, token::Interpolated(nt.clone())); + break } } return token::NtTT(tt); From b8d6686ef3c2998d29c7ef531895ee05305cfef1 Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Fri, 11 Nov 2016 16:28:47 -0700 Subject: [PATCH 071/177] Factor out inner current Earley item loop. Change multiple functions to be non-public. Change nameize to accept an iterator so as to avoid an allocation. --- src/libsyntax/ext/tt/macro_parser.rs | 291 ++++++++++++++------------- 1 file changed, 149 insertions(+), 142 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 64acce19c1cc..3c57f7a05c29 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -130,7 +130,7 @@ struct MatcherTtFrame { } #[derive(Clone)] -pub struct MatcherPos { +struct MatcherPos { stack: Vec, top_elts: TokenTreeOrTokenTreeVec, sep: Option, @@ -162,14 +162,13 @@ pub fn count_names(ms: &[TokenTree]) -> usize { }) } -pub fn initial_matcher_pos(ms: Vec, sep: Option, lo: BytePos) - -> Box { +fn initial_matcher_pos(ms: Vec, lo: BytePos) -> Box { let match_idx_hi = count_names(&ms[..]); - let matches: Vec<_> = (0..match_idx_hi).map(|_| Vec::new()).collect(); + let matches = create_matches(match_idx_hi); Box::new(MatcherPos { stack: vec![], top_elts: TtSeq(ms), - sep: sep, + sep: None, idx: 0, up: None, matches: matches, @@ -202,26 +201,25 @@ pub enum NamedMatch { MatchedNonterminal(Rc) } -fn nameize(ms: &[TokenTree], res: &[Rc]) -> NamedParseResult { - fn n_rec(m: &TokenTree, res: &[Rc], - ret_val: &mut HashMap>, idx: &mut usize) +fn nameize>>(ms: &[TokenTree], mut res: I) -> NamedParseResult { + fn n_rec>>(m: &TokenTree, mut res: &mut I, + ret_val: &mut HashMap>) -> Result<(), (syntax_pos::Span, String)> { match *m { TokenTree::Sequence(_, ref seq) => { for next_m in &seq.tts { - n_rec(next_m, res, ret_val, idx)? + n_rec(next_m, res.by_ref(), ret_val)? } } TokenTree::Delimited(_, ref delim) => { for next_m in &delim.tts { - n_rec(next_m, res, ret_val, idx)?; + n_rec(next_m, res.by_ref(), ret_val)?; } } TokenTree::Token(sp, MatchNt(bind_name, _)) => { match ret_val.entry(bind_name) { Vacant(spot) => { - spot.insert(res[*idx].clone()); - *idx += 1; + spot.insert(res.next().unwrap()); } Occupied(..) => { return Err((sp, format!("duplicated bind name: {}", bind_name))) @@ -238,9 +236,8 @@ fn nameize(ms: &[TokenTree], res: &[Rc]) -> NamedParseResult { } let mut ret_val = HashMap::new(); - let mut idx = 0; for m in ms { - match n_rec(m, res, &mut ret_val, &mut idx) { + match n_rec(m, res.by_ref(), &mut ret_val) { Ok(_) => {}, Err((sp, msg)) => return Error(sp, msg), } @@ -266,9 +263,8 @@ pub fn parse_failure_msg(tok: Token) -> String { } } -/// Perform a token equality check, ignoring syntax context (that is, an -/// unhygienic comparison) -pub fn token_name_eq(t1 : &Token, t2 : &Token) -> bool { +/// Perform a token equality check, ignoring syntax context (that is, an unhygienic comparison) +fn token_name_eq(t1 : &Token, t2 : &Token) -> bool { match (t1,t2) { (&token::Ident(id1),&token::Ident(id2)) | (&token::Lifetime(id1),&token::Lifetime(id2)) => @@ -277,154 +273,165 @@ pub fn token_name_eq(t1 : &Token, t2 : &Token) -> bool { } } -pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseResult { - let mut parser = Parser::new_with_doc_flag(sess, Box::new(rdr), true); - let mut cur_eis = SmallVector::one(initial_matcher_pos(ms.to_owned(), None, parser.span.lo)); +fn create_matches(len: usize) -> Vec>> { + (0..len).into_iter().map(|_| Vec::new()).collect() +} - loop { - let mut bb_eis = Vec::new(); // black-box parsed by parser.rs - let mut next_eis = Vec::new(); // or proceed normally - let mut eof_eis = Vec::new(); - - // for each Earley item - while let Some(mut ei) = cur_eis.pop() { - // When unzipped trees end, remove them - while ei.idx >= ei.top_elts.len() { - match ei.stack.pop() { - Some(MatcherTtFrame { elts, idx }) => { - ei.top_elts = elts; - ei.idx = idx + 1; - } - None => break +fn inner_parse_loop(cur_eis: &mut SmallVector>, + next_eis: &mut Vec>, + eof_eis: &mut Vec>, + bb_eis: &mut Vec>, + token: &Token, span: &syntax_pos::Span) -> ParseResult<()> { + while let Some(mut ei) = cur_eis.pop() { + // When unzipped trees end, remove them + while ei.idx >= ei.top_elts.len() { + match ei.stack.pop() { + Some(MatcherTtFrame { elts, idx }) => { + ei.top_elts = elts; + ei.idx = idx + 1; } + None => break } + } - let idx = ei.idx; - let len = ei.top_elts.len(); + let idx = ei.idx; + let len = ei.top_elts.len(); - /* at end of sequence */ - if idx >= len { - // can't move out of `match`es, so: - if ei.up.is_some() { - // hack: a matcher sequence is repeating iff it has a - // parent (the top level is just a container) + // at end of sequence + if idx >= len { + // We are repeating iff there is a parent + if ei.up.is_some() { + // Disregarding the separator, add the "up" case to the tokens that should be + // examined. + // (remove this condition to make trailing seps ok) + if idx == len { + let mut new_pos = ei.up.clone().unwrap(); - // disregard separator, try to go up - // (remove this condition to make trailing seps ok) - if idx == len { - // pop from the matcher position + // update matches (the MBE "parse tree") by appending + // each tree as a subtree. - let mut new_pos = ei.up.clone().unwrap(); + // I bet this is a perf problem: we're preemptively + // doing a lot of array work that will get thrown away + // most of the time. - // update matches (the MBE "parse tree") by appending - // each tree as a subtree. - - // I bet this is a perf problem: we're preemptively - // doing a lot of array work that will get thrown away - // most of the time. - - // Only touch the binders we have actually bound - for idx in ei.match_lo..ei.match_hi { - let sub = ei.matches[idx].clone(); - new_pos.matches[idx] - .push(Rc::new(MatchedSeq(sub, mk_sp(ei.sp_lo, - parser.span.hi)))); - } - - new_pos.match_cur = ei.match_hi; - new_pos.idx += 1; - cur_eis.push(new_pos); + // Only touch the binders we have actually bound + for idx in ei.match_lo..ei.match_hi { + let sub = ei.matches[idx].clone(); + new_pos.matches[idx] + .push(Rc::new(MatchedSeq(sub, mk_sp(ei.sp_lo, + span.hi)))); } - // can we go around again? + new_pos.match_cur = ei.match_hi; + new_pos.idx += 1; + cur_eis.push(new_pos); + } - // Check if we need a separator - if idx == len && ei.sep.is_some() { - if ei.sep.as_ref().map(|ref sep| token_name_eq(&parser.token, sep)) - .unwrap_or(false) { - // i'm conflicted about whether this should be hygienic.... though in - // this case, if the separators are never legal idents, it shouldn't - // matter. - // ei.match_cur = ei.match_lo; - ei.idx += 1; - next_eis.push(ei); - } - } else { // we don't need a separator - ei.match_cur = ei.match_lo; - ei.idx = 0; - cur_eis.push(ei); + // Check if we need a separator + if idx == len && ei.sep.is_some() { + // We have a separator, and it is the current token. + if ei.sep.as_ref().map(|ref sep| token_name_eq(&token, sep)).unwrap_or(false) { + ei.idx += 1; + next_eis.push(ei); } - } else { - eof_eis.push(ei); + } else { // we don't need a separator + ei.match_cur = ei.match_lo; + ei.idx = 0; + cur_eis.push(ei); } } else { - match ei.top_elts.get_tt(idx) { - /* need to descend into sequence */ - TokenTree::Sequence(sp, seq) => { - if seq.op == tokenstream::KleeneOp::ZeroOrMore { - let mut new_ei = ei.clone(); - new_ei.match_cur += seq.num_captures; - new_ei.idx += 1; - //we specifically matched zero repeats. - for idx in ei.match_cur..ei.match_cur + seq.num_captures { - new_ei.matches[idx].push(Rc::new(MatchedSeq(vec![], sp))); - } + // We aren't repeating, so we must be potentially at the end of the input. + eof_eis.push(ei); + } + } else { + match ei.top_elts.get_tt(idx) { + /* need to descend into sequence */ + TokenTree::Sequence(sp, seq) => { + if seq.op == tokenstream::KleeneOp::ZeroOrMore { + // Examine the case where there are 0 matches of this sequence + let mut new_ei = ei.clone(); + new_ei.match_cur += seq.num_captures; + new_ei.idx += 1; + for idx in ei.match_cur..ei.match_cur + seq.num_captures { + new_ei.matches[idx].push(Rc::new(MatchedSeq(vec![], sp))); + } + cur_eis.push(new_ei); + } - cur_eis.push(new_ei); - } - - let matches: Vec<_> = (0..ei.matches.len()) - .map(|_| Vec::new()).collect(); - cur_eis.push(Box::new(MatcherPos { - stack: vec![], - sep: seq.separator.clone(), - idx: 0, - matches: matches, - match_lo: ei.match_cur, - match_cur: ei.match_cur, - match_hi: ei.match_cur + seq.num_captures, - up: Some(ei), - sp_lo: sp.lo, - top_elts: Tt(TokenTree::Sequence(sp, seq)), - })); + // Examine the case where there is at least one match of this sequence + let matches = create_matches(ei.matches.len()); + cur_eis.push(Box::new(MatcherPos { + stack: vec![], + sep: seq.separator.clone(), + idx: 0, + matches: matches, + match_lo: ei.match_cur, + match_cur: ei.match_cur, + match_hi: ei.match_cur + seq.num_captures, + up: Some(ei), + sp_lo: sp.lo, + top_elts: Tt(TokenTree::Sequence(sp, seq)), + })); + } + TokenTree::Token(_, MatchNt(..)) => { + // Built-in nonterminals never start with these tokens, + // so we can eliminate them from consideration. + match *token { + token::CloseDelim(_) => {}, + _ => bb_eis.push(ei), } - TokenTree::Token(_, MatchNt(..)) => { - // Built-in nonterminals never start with these tokens, - // so we can eliminate them from consideration. - match parser.token { - token::CloseDelim(_) => {}, - _ => bb_eis.push(ei), - } - } - TokenTree::Token(sp, SubstNt(..)) => { - return Error(sp, "missing fragment specifier".to_string()) - } - seq @ TokenTree::Delimited(..) | seq @ TokenTree::Token(_, DocComment(..)) => { - let lower_elts = mem::replace(&mut ei.top_elts, Tt(seq)); - let idx = ei.idx; - ei.stack.push(MatcherTtFrame { - elts: lower_elts, - idx: idx, - }); - ei.idx = 0; - cur_eis.push(ei); - } - TokenTree::Token(_, ref t) => { - if token_name_eq(t, &parser.token) { - ei.idx += 1; - next_eis.push(ei); - } + } + TokenTree::Token(sp, SubstNt(..)) => { + return Error(sp, "missing fragment specifier".to_string()) + } + seq @ TokenTree::Delimited(..) | seq @ TokenTree::Token(_, DocComment(..)) => { + let lower_elts = mem::replace(&mut ei.top_elts, Tt(seq)); + let idx = ei.idx; + ei.stack.push(MatcherTtFrame { + elts: lower_elts, + idx: idx, + }); + ei.idx = 0; + cur_eis.push(ei); + } + TokenTree::Token(_, ref t) => { + if token_name_eq(t, &token) { + ei.idx += 1; + next_eis.push(ei); } } } } + } + + Success(()) +} + +pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseResult { + let mut parser = Parser::new_with_doc_flag(sess, Box::new(rdr), true); + let mut cur_eis = SmallVector::one(initial_matcher_pos(ms.to_owned(), parser.span.lo)); + + loop { + let mut bb_eis = Vec::new(); // black-box parsed by parser.rs + let mut next_eis = Vec::new(); // or proceed normally + + // FIXME: Use SmallVector since in the successful case we will only have one + let mut eof_eis = Vec::new(); + + match inner_parse_loop(&mut cur_eis, &mut next_eis, &mut eof_eis, &mut bb_eis, + &parser.token, &parser.span) { + Success(_) => {}, + Failure(sp, tok) => return Failure(sp, tok), + Error(sp, msg) => return Error(sp, msg), + } + + // inner parse loop handled all cur_eis, so it's empty + assert!(cur_eis.is_empty()); /* error messages here could be improved with links to orig. rules */ if token_name_eq(&parser.token, &token::Eof) { if eof_eis.len() == 1 { - let v = eof_eis[0].matches.iter_mut() - .map(|dv| dv.pop().unwrap()).collect::>(); - return nameize(ms, &v[..]); + return nameize(ms, eof_eis[0].matches.iter_mut().map(|mut dv| dv.pop().unwrap())); } else if eof_eis.len() > 1 { return Error(parser.span, "ambiguity: multiple successful parses".to_string()); } else { @@ -473,7 +480,7 @@ pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseRes } } -pub fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { +fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { match name { "tt" => { p.quote_depth += 1; //but in theory, non-quoted tts might be useful From 6046595e34737d7bec851bfd1352a01e58fe99e9 Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Fri, 11 Nov 2016 16:37:08 -0700 Subject: [PATCH 072/177] Use SmallVector for eof and bb eis. --- src/libsyntax/ext/tt/macro_parser.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 3c57f7a05c29..a072f2ba948c 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -279,8 +279,8 @@ fn create_matches(len: usize) -> Vec>> { fn inner_parse_loop(cur_eis: &mut SmallVector>, next_eis: &mut Vec>, - eof_eis: &mut Vec>, - bb_eis: &mut Vec>, + eof_eis: &mut SmallVector>, + bb_eis: &mut SmallVector>, token: &Token, span: &syntax_pos::Span) -> ParseResult<()> { while let Some(mut ei) = cur_eis.pop() { // When unzipped trees end, remove them @@ -412,12 +412,10 @@ pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseRes let mut cur_eis = SmallVector::one(initial_matcher_pos(ms.to_owned(), parser.span.lo)); loop { - let mut bb_eis = Vec::new(); // black-box parsed by parser.rs + let mut bb_eis = SmallVector::new(); // black-box parsed by parser.rs + let mut eof_eis = SmallVector::new(); let mut next_eis = Vec::new(); // or proceed normally - // FIXME: Use SmallVector since in the successful case we will only have one - let mut eof_eis = Vec::new(); - match inner_parse_loop(&mut cur_eis, &mut next_eis, &mut eof_eis, &mut bb_eis, &parser.token, &parser.span) { Success(_) => {}, From 38912ee3d43868651e8ac6fc3da1153f45ba5cf4 Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Sat, 12 Nov 2016 07:41:26 -0700 Subject: [PATCH 073/177] Move next_eis out of main loop to avoid re-allocating and dropping it. --- src/libsyntax/ext/tt/macro_parser.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index a072f2ba948c..d43718305622 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -410,11 +410,12 @@ fn inner_parse_loop(cur_eis: &mut SmallVector>, pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseResult { let mut parser = Parser::new_with_doc_flag(sess, Box::new(rdr), true); let mut cur_eis = SmallVector::one(initial_matcher_pos(ms.to_owned(), parser.span.lo)); + let mut next_eis = Vec::new(); // or proceed normally loop { let mut bb_eis = SmallVector::new(); // black-box parsed by parser.rs let mut eof_eis = SmallVector::new(); - let mut next_eis = Vec::new(); // or proceed normally + assert!(next_eis.is_empty()); match inner_parse_loop(&mut cur_eis, &mut next_eis, &mut eof_eis, &mut bb_eis, &parser.token, &parser.span) { From 2189f573caf93e389a56aefe0aeaa027feafd281 Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Sat, 12 Nov 2016 07:41:47 -0700 Subject: [PATCH 074/177] Remove extra level of nesting. --- src/libsyntax/ext/tt/macro_parser.rs | 67 +++++++++++++--------------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index d43718305622..39ffab4dc17a 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -436,43 +436,40 @@ pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseRes } else { return Failure(parser.span, token::Eof); } - } else { - if (!bb_eis.is_empty() && !next_eis.is_empty()) - || bb_eis.len() > 1 { - let nts = bb_eis.iter().map(|ei| match ei.top_elts.get_tt(ei.idx) { - TokenTree::Token(_, MatchNt(bind, name)) => { - format!("{} ('{}')", name, bind) - } - _ => panic!() - }).collect::>().join(" or "); - - return Error(parser.span, format!( - "local ambiguity: multiple parsing options: {}", - match next_eis.len() { - 0 => format!("built-in NTs {}.", nts), - 1 => format!("built-in NTs {} or 1 other option.", nts), - n => format!("built-in NTs {} or {} other options.", nts, n), - } - )) - } else if bb_eis.is_empty() && next_eis.is_empty() { - return Failure(parser.span, parser.token); - } else if !next_eis.is_empty() { - /* Now process the next token */ - cur_eis.extend(next_eis.drain(..)); - parser.bump(); - } else /* bb_eis.len() == 1 */ { - let mut ei = bb_eis.pop().unwrap(); - if let TokenTree::Token(span, MatchNt(_, ident)) = ei.top_elts.get_tt(ei.idx) { - let match_cur = ei.match_cur; - ei.matches[match_cur].push(Rc::new(MatchedNonterminal( - Rc::new(parse_nt(&mut parser, span, &ident.name.as_str()))))); - ei.idx += 1; - ei.match_cur += 1; - } else { - unreachable!() + } else if (!bb_eis.is_empty() && !next_eis.is_empty()) || bb_eis.len() > 1 { + let nts = bb_eis.iter().map(|ei| match ei.top_elts.get_tt(ei.idx) { + TokenTree::Token(_, MatchNt(bind, name)) => { + format!("{} ('{}')", name, bind) } - cur_eis.push(ei); + _ => panic!() + }).collect::>().join(" or "); + + return Error(parser.span, format!( + "local ambiguity: multiple parsing options: {}", + match next_eis.len() { + 0 => format!("built-in NTs {}.", nts), + 1 => format!("built-in NTs {} or 1 other option.", nts), + n => format!("built-in NTs {} or {} other options.", nts, n), + } + )); + } else if bb_eis.is_empty() && next_eis.is_empty() { + return Failure(parser.span, parser.token); + } else if !next_eis.is_empty() { + /* Now process the next token */ + cur_eis.extend(next_eis.drain(..)); + parser.bump(); + } else /* bb_eis.len() == 1 */ { + let mut ei = bb_eis.pop().unwrap(); + if let TokenTree::Token(span, MatchNt(_, ident)) = ei.top_elts.get_tt(ei.idx) { + let match_cur = ei.match_cur; + ei.matches[match_cur].push(Rc::new(MatchedNonterminal( + Rc::new(parse_nt(&mut parser, span, &ident.name.as_str()))))); + ei.idx += 1; + ei.match_cur += 1; + } else { + unreachable!() } + cur_eis.push(ei); } assert!(!cur_eis.is_empty()); From ca9b5664c3c4a052a044d63725239ff2e56136f4 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 3 Nov 2016 22:19:33 +0200 Subject: [PATCH 075/177] rustc: move closure upvar types to the closure substs This moves closures to the (DefId, Substs) scheme like all other items, and saves a word from the size of TyS now that Substs is 2 words. --- src/librustc/infer/mod.rs | 2 +- src/librustc/lib.rs | 1 + src/librustc/traits/select.rs | 6 +-- src/librustc/ty/contents.rs | 13 ++++--- src/librustc/ty/context.rs | 7 +--- src/librustc/ty/flags.rs | 3 +- src/librustc/ty/layout.rs | 12 +++++- src/librustc/ty/mod.rs | 4 +- src/librustc/ty/outlives.rs | 4 +- src/librustc/ty/relate.rs | 9 +---- src/librustc/ty/structural_impls.rs | 12 ++---- src/librustc/ty/sty.rs | 23 +++++++---- src/librustc/ty/subst.rs | 14 +++++++ src/librustc/ty/util.rs | 11 ++++++ src/librustc/ty/walk.rs | 3 +- src/librustc/util/ppaux.rs | 5 ++- .../borrowck/mir/elaborate_drops.rs | 8 ++-- src/librustc_metadata/encoder.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 4 +- src/librustc_mir/transform/type_check.rs | 12 ++++-- src/librustc_trans/adt.rs | 4 +- src/librustc_trans/closure.rs | 7 ++-- src/librustc_trans/collector.rs | 6 +-- src/librustc_trans/common.rs | 11 +++++- src/librustc_trans/debuginfo/metadata.rs | 5 ++- src/librustc_trans/debuginfo/mod.rs | 13 +++---- src/librustc_trans/glue.rs | 4 +- src/librustc_trans/mir/mod.rs | 4 +- src/librustc_trans/trans_item.rs | 6 ++- src/librustc_typeck/check/closure.rs | 38 +++++++++++++++++-- src/librustc_typeck/check/dropck.rs | 10 ++++- src/librustc_typeck/check/upvar.rs | 8 ++-- 32 files changed, 179 insertions(+), 92 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 46074f6c1f3c..24716c479513 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1657,7 +1657,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { if let InferTables::Local(tables) = self.tables { if let Some(ty) = tables.borrow().closure_tys.get(&def_id) { - return ty.subst(self.tcx, substs.func_substs); + return ty.subst(self.tcx, substs.substs); } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index fa49e5c72895..8c0d70c6d602 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -40,6 +40,7 @@ #![feature(rustc_private)] #![feature(slice_patterns)] #![feature(staged_api)] +#![feature(unboxed_closures)] #![cfg_attr(stage0, feature(question_mark))] #![cfg_attr(test, feature(test))] diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 3944c7e09c0b..6f6534cb2064 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1912,16 +1912,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { tys.to_vec() } - ty::TyClosure(_, ref substs) => { + ty::TyClosure(def_id, ref substs) => { // FIXME(#27086). We are invariant w/r/t our - // substs.func_substs, but we don't see them as + // func_substs, but we don't see them as // constituent types; this seems RIGHT but also like // something that a normal type couldn't simulate. Is // this just a gap with the way that PhantomData and // OIBIT interact? That is, there is no way to say // "make me invariant with respect to this TYPE, but // do not act as though I can reach it" - substs.upvar_tys.to_vec() + substs.upvar_tys(def_id, self.tcx()).collect() } // for `PhantomData`, we pass `T` diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs index 7ed4de38be97..9f80c2487fb2 100644 --- a/src/librustc/ty/contents.rs +++ b/src/librustc/ty/contents.rs @@ -98,10 +98,11 @@ impl TypeContents { TC::OwnsOwned | (*self & TC::OwnsAll) } - pub fn union(v: &[T], mut f: F) -> TypeContents where - F: FnMut(&T) -> TypeContents, + pub fn union(v: I, mut f: F) -> TypeContents where + I: IntoIterator, + F: FnMut(T) -> TypeContents, { - v.iter().fold(TC::None, |tc, ty| tc | f(ty)) + v.into_iter().fold(TC::None, |tc, ty| tc | f(ty)) } pub fn has_dtor(&self) -> bool { @@ -215,8 +216,10 @@ impl<'a, 'tcx> ty::TyS<'tcx> { } ty::TyStr => TC::None, - ty::TyClosure(_, ref substs) => { - TypeContents::union(&substs.upvar_tys, |ty| tc_ty(tcx, &ty, cache)) + ty::TyClosure(def_id, ref substs) => { + TypeContents::union( + substs.upvar_tys(def_id, tcx), + |ty| tc_ty(tcx, &ty, cache)) } ty::TyTuple(ref tys) => { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index ac1c4fc6a191..45450456e8a6 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1446,12 +1446,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn mk_closure(self, closure_id: DefId, - substs: &'tcx Substs<'tcx>, - tys: &[Ty<'tcx>]) + substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { self.mk_closure_from_closure_substs(closure_id, ClosureSubsts { - func_substs: substs, - upvar_tys: self.intern_type_list(tys) + substs: substs }) } @@ -1574,4 +1572,3 @@ impl InternIteratorElement for Result { Ok(f(&iter.collect::, _>>()?)) } } - diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 649d78f9d9e2..2c09b89beb23 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -88,8 +88,7 @@ impl FlagComputation { &ty::TyClosure(_, ref substs) => { self.add_flags(TypeFlags::HAS_TY_CLOSURE); self.add_flags(TypeFlags::HAS_LOCAL_NAMES); - self.add_substs(&substs.func_substs); - self.add_tys(&substs.upvar_tys); + self.add_substs(&substs.substs); } &ty::TyInfer(infer) => { diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 5ce43d905ec7..5ee1c3678d67 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -631,7 +631,9 @@ impl<'a, 'gcx, 'tcx> Struct { // Perhaps one of the upvars of this closure is non-zero // Let's recurse and find out! - (_, &ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. })) | + (_, &ty::TyClosure(def_id, ref substs)) => { + Struct::non_zero_field_path(infcx, substs.upvar_tys(def_id, tcx)) + } // Can we use one of the fields in this tuple? (_, &ty::TyTuple(tys)) => { Struct::non_zero_field_path(infcx, tys.iter().cloned()) @@ -961,7 +963,13 @@ impl<'a, 'gcx, 'tcx> Layout { } // Tuples and closures. - ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. }) | + ty::TyClosure(def_id, ref substs) => { + let mut st = Struct::new(dl, false); + let tys = substs.upvar_tys(def_id, tcx); + st.extend(dl, tys.map(|ty| ty.layout(infcx)), ty)?; + Univariant { variant: st, non_zero: false } + } + ty::TyTuple(tys) => { let mut st = Struct::new(dl, false); st.extend(dl, tys.iter().map(|ty| ty.layout(infcx)), ty)?; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 3db705140411..1de54f49a552 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2544,12 +2544,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // tables by typeck; else, it will be retreived from // the external crate metadata. if let Some(ty) = self.tables.borrow().closure_tys.get(&def_id) { - return ty.subst(self, substs.func_substs); + return ty.subst(self, substs.substs); } let ty = self.sess.cstore.closure_ty(self.global_tcx(), def_id); self.tables.borrow_mut().closure_tys.insert(def_id, ty.clone()); - ty.subst(self, substs.func_substs) + ty.subst(self, substs.substs) } /// Given the def_id of an impl, return the def_id of the trait it implements. diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index 51feab9d40c9..e3d13f593954 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -72,7 +72,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // in the `subtys` iterator (e.g., when encountering a // projection). match ty.sty { - ty::TyClosure(_, ref substs) => { + ty::TyClosure(def_id, ref substs) => { // FIXME(#27086). We do not accumulate from substs, since they // don't represent reachable data. This means that, in // practice, some of the lifetime parameters might not @@ -110,7 +110,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // what func/type parameters are used and unused, // taking into consideration UFCS and so forth. - for &upvar_ty in substs.upvar_tys { + for upvar_ty in substs.upvar_tys(def_id, *self) { self.compute_components(upvar_ty, out); } } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index cb90e6392cf0..2a01bad33c52 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -534,13 +534,8 @@ impl<'tcx> Relate<'tcx> for ty::ClosureSubsts<'tcx> { -> RelateResult<'tcx, ty::ClosureSubsts<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { - let substs = relate_substs(relation, None, a.func_substs, b.func_substs)?; - assert_eq!(a.upvar_tys.len(), b.upvar_tys.len()); - Ok(ty::ClosureSubsts { - func_substs: substs, - upvar_tys: relation.tcx().mk_type_list( - a.upvar_tys.iter().zip(b.upvar_tys).map(|(a, b)| relation.relate(a, b)))? - }) + let substs = relate_substs(relation, None, a.substs, b.substs)?; + Ok(ty::ClosureSubsts { substs: substs }) } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 282cb9f80f51..e73be23a42c7 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -198,11 +198,8 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder { impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> { type Lifted = ty::ClosureSubsts<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - tcx.lift(&(self.func_substs, self.upvar_tys)).map(|(substs, upvar_tys)| { - ty::ClosureSubsts { - func_substs: substs, - upvar_tys: upvar_tys - } + tcx.lift(&self.substs).map(|substs| { + ty::ClosureSubsts { substs: substs } }) } } @@ -654,13 +651,12 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Region { impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::ClosureSubsts { - func_substs: self.func_substs.fold_with(folder), - upvar_tys: self.upvar_tys.fold_with(folder), + substs: self.substs.fold_with(folder), } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.func_substs.visit_with(visitor) || self.upvar_tys.visit_with(visitor) + self.substs.visit_with(visitor) } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 7d209093ec77..56466d596829 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -11,6 +11,7 @@ //! This module contains TypeVariants and its major components use hir::def_id::DefId; + use middle::region; use ty::subst::Substs; use ty::{self, AdtDef, ToPredicate, TypeFlags, Ty, TyCtxt, TypeFoldable}; @@ -254,15 +255,23 @@ pub enum TypeVariants<'tcx> { /// handle). Plus it fixes an ICE. :P #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ClosureSubsts<'tcx> { - /// Lifetime and type parameters from the enclosing function. + /// Lifetime and type parameters from the enclosing function, + /// concatenated with the types of the upvars. + /// /// These are separated out because trans wants to pass them around /// when monomorphizing. - pub func_substs: &'tcx Substs<'tcx>, + pub substs: &'tcx Substs<'tcx>, +} - /// The types of the upvars. The list parallels the freevars and - /// `upvar_borrows` lists. These are kept distinct so that we can - /// easily index into them. - pub upvar_tys: &'tcx Slice> +impl<'a, 'gcx, 'acx, 'tcx> ClosureSubsts<'tcx> { + #[inline] + pub fn upvar_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'acx>) -> + impl Iterator> + 'tcx + { + let generics = tcx.item_generics(def_id); + self.substs[self.substs.len()-generics.own_count()..].iter().map( + |t| t.as_type().expect("unexpected region in upvars")) + } } #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] @@ -1234,7 +1243,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { substs.regions().collect() } TyClosure(_, ref substs) => { - substs.func_substs.regions().collect() + substs.substs.regions().collect() } TyProjection(ref data) => { data.trait_ref.substs.regions().collect() diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 15f4437ed0aa..76d512a20b26 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -274,6 +274,20 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { let defs = tcx.item_generics(source_ancestor); tcx.mk_substs(target_substs.iter().chain(&self[defs.own_count()..]).cloned()) } + + pub fn extend_with_types(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, + types: &[Ty<'tcx>]) + -> &'tcx Substs<'tcx> { + tcx.mk_substs( + self[..].iter().cloned().chain( + types.iter().map(|a| Kind::from(*a))) + ) + } + + pub fn truncate_to(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, generics: &ty::Generics<'tcx>) + -> &'tcx Substs<'tcx> { + tcx.mk_substs(self.iter().take(generics.count()).cloned()) + } } impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index b1aeaeb48d14..7d3e380a3b59 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -11,6 +11,7 @@ //! misc. type-system utilities too small to deserve their own file use hir::def_id::DefId; +use hir::map::DefPathData; use infer::InferCtxt; use hir::map as ast_map; use hir::pat_util; @@ -390,6 +391,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // (e.g. calling `foo.0.clone()` of `Foo`). return !self.has_attr(dtor_method, "unsafe_destructor_blind_to_params"); } + + pub fn closure_base_def_id(&self, def_id: DefId) -> DefId { + let mut def_id = def_id; + while self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr { + def_id = self.parent_def_id(def_id).unwrap_or_else(|| { + bug!("closure {:?} has no parent", def_id); + }); + } + def_id + } } /// When hashing a type this ends up affecting properties like symbol names. We diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index bebdebf127a5..a6ecfd2fb706 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -97,8 +97,7 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { stack.extend(substs.types().rev()); } ty::TyClosure(_, ref substs) => { - stack.extend(substs.func_substs.types().rev()); - stack.extend(substs.upvar_tys.iter().cloned().rev()); + stack.extend(substs.substs.types().rev()); } ty::TyTuple(ts) => { stack.extend(ts.iter().cloned().rev()); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 3ed4580336aa..a63c7ba6a25c 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -907,13 +907,14 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { } TyStr => write!(f, "str"), TyClosure(did, substs) => ty::tls::with(|tcx| { + let upvar_tys = substs.upvar_tys(did, tcx); write!(f, "[closure")?; if let Some(node_id) = tcx.map.as_local_node_id(did) { write!(f, "@{:?}", tcx.map.span(node_id))?; let mut sep = " "; tcx.with_freevars(node_id, |freevars| { - for (freevar, upvar_ty) in freevars.iter().zip(substs.upvar_tys) { + for (freevar, upvar_ty) in freevars.iter().zip(upvar_tys) { let def_id = freevar.def.def_id(); let node_id = tcx.map.as_local_node_id(def_id).unwrap(); write!(f, @@ -930,7 +931,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { // visible in trans bug reports, I imagine. write!(f, "@{:?}", did)?; let mut sep = " "; - for (index, upvar_ty) in substs.upvar_tys.iter().enumerate() { + for (index, upvar_ty) in upvar_tys.enumerate() { write!(f, "{}{}:{}", sep, index, upvar_ty)?; sep = ", "; } diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index eced5d1eb1b8..cdb19d164bf2 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -709,9 +709,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { ty::TyAdt(def, substs) => { self.open_drop_for_adt(c, def, substs) } - ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts { - upvar_tys: tys, .. - }) => { + ty::TyClosure(def_id, substs) => { + let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx).collect(); + self.open_drop_for_tuple(c, &tys) + } + ty::TyTuple(tys) => { self.open_drop_for_tuple(c, tys) } ty::TyBox(ty) => { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index f169ad664808..4d7aa43ce42d 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1059,7 +1059,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ty: None, inherent_impls: LazySeq::empty(), variances: LazySeq::empty(), - generics: None, + generics: Some(self.encode_generics(def_id)), predicates: None, ast: None, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index ba0d3b49a6c1..24c1ca574a01 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -521,8 +521,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; let upvars = cx.tcx.with_freevars(expr.id, |freevars| { freevars.iter() - .enumerate() - .map(|(i, fv)| capture_freevar(cx, expr, fv, substs.upvar_tys[i])) + .zip(substs.upvar_tys(def_id, cx.tcx)) + .map(|(fv, ty)| capture_freevar(cx, expr, fv, ty)) .collect() }); ExprKind::Closure { diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index ad525d210694..79bb14b7336c 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -274,9 +274,15 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ty::TyAdt(adt_def, substs) if adt_def.is_univariant() => { (&adt_def.variants[0], substs) } - ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts { - upvar_tys: tys, .. - }) => { + ty::TyClosure(def_id, substs) => { + return match substs.upvar_tys(def_id, tcx).nth(field.index()) { + Some(ty) => Ok(ty), + None => Err(FieldAccessError::OutOfRange { + field_count: substs.upvar_tys(def_id, tcx).count() + }) + } + } + ty::TyTuple(tys) => { return match tys.get(field.index()) { Some(&ty) => Ok(ty), None => Err(FieldAccessError::OutOfRange { diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index d028dd7e7b5a..c3340281d073 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -108,9 +108,9 @@ fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, }).collect::>() }, ty::TyTuple(fields) => fields.to_vec(), - ty::TyClosure(_, substs) => { + ty::TyClosure(def_id, substs) => { if variant_index > 0 { bug!("{} is a closure, which only has one variant", t);} - substs.upvar_tys.to_vec() + substs.upvar_tys(def_id, cx.tcx()).collect() }, _ => bug!("{} is not a type that can have fields.", t) } diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs index a1d645fb993b..0cefc49cb425 100644 --- a/src/librustc_trans/closure.rs +++ b/src/librustc_trans/closure.rs @@ -49,7 +49,7 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // duplicate declarations let tcx = ccx.tcx(); let substs = tcx.erase_regions(&substs); - let instance = Instance::new(closure_id, substs.func_substs); + let instance = Instance::new(closure_id, substs.substs); if let Some(&llfn) = ccx.instances().borrow().get(&instance) { debug!("get_or_create_closure_declaration(): found closure {:?}: {:?}", @@ -99,8 +99,7 @@ pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let tcx = ccx.tcx(); let _icx = push_ctxt("closure::trans_closure_expr"); - let param_substs = closure_substs.func_substs; - let instance = Instance::new(closure_def_id, param_substs); + let instance = Instance::new(closure_def_id, closure_substs.substs); // If we have not done so yet, translate this closure's body if !ccx.instances().borrow().contains_key(&instance) { @@ -138,7 +137,7 @@ pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, trans_closure(ccx, llfn, - Instance::new(closure_def_id, param_substs), + instance, &sig, Abi::RustCall); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 41071057274f..a79719a4d227 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -452,7 +452,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let concrete_substs = monomorphize::apply_param_substs(self.scx, self.param_substs, - &substs.func_substs); + &substs.substs); let concrete_substs = self.scx.tcx().erase_regions(&concrete_substs); let visitor = MirNeighborCollector { @@ -797,8 +797,8 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } } } - ty::TyClosure(_, substs) => { - for upvar_ty in substs.upvar_tys { + ty::TyClosure(def_id, substs) => { + for upvar_ty in substs.upvar_tys(def_id, scx.tcx()) { let upvar_ty = glue::get_drop_glue_type(scx.tcx(), upvar_ty); if glue::type_needs_drop(scx.tcx(), upvar_ty) { output.push(TransItem::DropGlue(DropGlueKind::Ty(upvar_ty))); diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index d238cf7bb458..6f3a72621520 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -109,7 +109,16 @@ pub fn type_pair_fields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) Some([monomorphize::field_ty(ccx.tcx(), substs, &fields[0]), monomorphize::field_ty(ccx.tcx(), substs, &fields[1])]) } - ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. }) | + ty::TyClosure(def_id, substs) => { + let mut tys = substs.upvar_tys(def_id, ccx.tcx()); + tys.next().and_then(|first_ty| tys.next().and_then(|second_ty| { + if tys.next().is_some() { + None + } else { + Some([first_ty, second_ty]) + } + })) + } ty::TyTuple(tys) => { if tys.len() != 2 { return None; diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 679e308c3454..5b9ef78ddc22 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -574,10 +574,11 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false) } - ty::TyClosure(_, ref substs) => { + ty::TyClosure(def_id, substs) => { + let upvar_tys : Vec<_> = substs.upvar_tys(def_id, cx.tcx()).collect(); prepare_tuple_metadata(cx, t, - &substs.upvar_tys, + &upvar_tys, unique_type_id, usage_site_span).finalize(cx) } diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 45b8ec1dc80b..482275d298bc 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -25,7 +25,6 @@ use llvm::{ModuleRef, ContextRef, ValueRef}; use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray, FlagPrototyped}; use rustc::hir::def_id::DefId; -use rustc::hir::map::DefPathData; use rustc::ty::subst::Substs; use abi::Abi; @@ -248,21 +247,19 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }; // Find the enclosing function, in case this is a closure. - let mut fn_def_id = instance.def; - let mut def_key = cx.tcx().def_key(fn_def_id); + let def_key = cx.tcx().def_key(instance.def); let mut name = def_key.disambiguated_data.data.to_string(); let name_len = name.len(); - while def_key.disambiguated_data.data == DefPathData::ClosureExpr { - fn_def_id.index = def_key.parent.expect("closure without a parent?"); - def_key = cx.tcx().def_key(fn_def_id); - } + + let fn_def_id = cx.tcx().closure_base_def_id(instance.def); // Get_template_parameters() will append a `<...>` clause to the function // name if necessary. let generics = cx.tcx().item_generics(fn_def_id); + let substs = instance.substs.truncate_to(cx.tcx(), generics); let template_parameters = get_template_parameters(cx, &generics, - instance.substs, + substs, file_metadata, &mut name); diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 648dd9f3e3ae..d6d4d33923f1 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -531,8 +531,8 @@ fn drop_structural_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, let mut cx = cx; match t.sty { - ty::TyClosure(_, ref substs) => { - for (i, upvar_ty) in substs.upvar_tys.iter().enumerate() { + ty::TyClosure(def_id, substs) => { + for (i, upvar_ty) in substs.upvar_tys(def_id, cx.tcx()).enumerate() { let llupvar = adt::trans_field_ptr(cx, t, value, Disr(0), i); cx = drop_ty(cx, llupvar, upvar_ty, DebugLoc::None); } diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index d2adf88c9168..12b17c26cbc4 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -470,8 +470,8 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, } else { (arg_ty, false) }; - let upvar_tys = if let ty::TyClosure(_, ref substs) = closure_ty.sty { - &substs.upvar_tys[..] + let upvar_tys = if let ty::TyClosure(def_id, substs) = closure_ty.sty { + substs.upvar_tys(def_id, tcx) } else { bug!("upvar_decls with non-closure arg0 type `{}`", closure_ty); }; diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 93790cc27bca..16bc7e212cf5 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -477,12 +477,14 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, push_unique_type_name(tcx, sig.output, output); } }, - ty::TyClosure(def_id, ref closure_substs) => { + ty::TyClosure(def_id, closure_substs) => { push_item_name(tcx, def_id, output); output.push_str("{"); output.push_str(&format!("{}:{}", def_id.krate, def_id.index.as_usize())); output.push_str("}"); - push_type_params(tcx, closure_substs.func_substs, &[], output); + let generics = tcx.item_generics(tcx.closure_base_def_id(def_id)); + let substs = closure_substs.substs.truncate_to(tcx, generics); + push_type_params(tcx, substs, &[], output); } ty::TyError | ty::TyInfer(_) | diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index af834f3f84d4..d48a129dfe1c 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -14,10 +14,13 @@ use super::{check_fn, Expectation, FnCtxt}; use astconv::AstConv; use rustc::ty::{self, ToPolyTraitRef, Ty}; +use rustc::util::common::MemoizationMap; use std::cmp; use syntax::abi::Abi; use rustc::hir; +use syntax::parse::token; + impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_expr_closure(&self, expr: &hir::Expr, @@ -48,6 +51,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expected_sig: Option>) -> Ty<'tcx> { let expr_def_id = self.tcx.map.local_def_id(expr.id); + let base_def_id = self.tcx.closure_base_def_id(expr_def_id); debug!("check_closure opt_kind={:?} expected_sig={:?}", opt_kind, @@ -62,16 +66,42 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Create type variables (for now) to represent the transformed // types of upvars. These will be unified during the upvar // inference phase (`upvar.rs`). - let num_upvars = self.tcx.with_freevars(expr.id, |fv| fv.len()); + let base_generics = self.tcx.item_generics(base_def_id); + // provide junk type parameter defs - the only place that + // cares about anything but the length is instantiation, + // and we don't do that for closures. + let upvar_decls : Vec<_> = self.tcx.with_freevars(expr.id, |fv| { + fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef { + index: (base_generics.count() as u32) + (i as u32), + name: token::intern(""), + def_id: expr_def_id, + default_def_id: base_def_id, + default: None, + object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, + pure_wrt_drop: false, + }).collect() + }); + let num_upvars = upvar_decls.len(); + + self.tcx.generics.memoize(expr_def_id, || self.tcx.alloc_generics(ty::Generics { + parent: Some(base_def_id), + parent_regions: base_generics.parent_regions + (base_generics.regions.len() as u32), + parent_types: base_generics.parent_types + (base_generics.types.len() as u32), + regions: vec![], + types: upvar_decls, + has_self: false, + })); + let upvar_tys = self.next_ty_vars(num_upvars); debug!("check_closure: expr.id={:?} upvar_tys={:?}", expr.id, upvar_tys); - let closure_type = self.tcx.mk_closure(expr_def_id, - self.parameter_environment.free_substs, - &upvar_tys); + let closure_type = self.tcx.mk_closure( + expr_def_id, + self.parameter_environment.free_substs.extend_with_types(self.tcx, &upvar_tys) + ); let fn_sig = self.tcx .liberate_late_bound_regions(self.tcx.region_maps.call_site_extent(expr.id, body.id), diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 8657b30bf8ee..09e1f6592c17 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -482,8 +482,14 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( Ok(()) } - ty::TyTuple(tys) | - ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. }) => { + ty::TyClosure(def_id, substs) => { + for ty in substs.upvar_tys(def_id, tcx) { + iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)? + } + Ok(()) + } + + ty::TyTuple(tys) => { for ty in tys { iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)? } diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 2fea86cb2120..1ea47107c3b1 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -183,8 +183,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // inference algorithm will reject it). // Extract the type variables UV0...UVn. - let closure_substs = match self.fcx.node_ty(id).sty { - ty::TyClosure(_, ref substs) => substs, + let (def_id, closure_substs) = match self.fcx.node_ty(id).sty { + ty::TyClosure(def_id, substs) => (def_id, substs), ref t => { span_bug!( span, @@ -197,7 +197,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { let final_upvar_tys = self.final_upvar_tys(id); debug!("analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}", id, closure_substs, final_upvar_tys); - for (&upvar_ty, final_upvar_ty) in closure_substs.upvar_tys.iter().zip(final_upvar_tys) { + for (upvar_ty, final_upvar_ty) in + closure_substs.upvar_tys(def_id, self.fcx.tcx).zip(final_upvar_tys) + { self.fcx.demand_eqtype(span, final_upvar_ty, upvar_ty); } From b6828fd1acf11272b05c32010f9071d3e8862e76 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 9 Nov 2016 20:41:03 +0200 Subject: [PATCH 076/177] rustc_typeck: register item types for closures This makes them closer to actual items and allows for more transparent treatment. --- src/librustc_metadata/encoder.rs | 2 +- src/librustc_typeck/check/closure.rs | 77 +++++++++++++++++----------- 2 files changed, 49 insertions(+), 30 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 4d7aa43ce42d..778a9d185e14 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1056,7 +1056,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { stability: None, deprecation: None, - ty: None, + ty: Some(self.encode_item_type(def_id)), inherent_impls: LazySeq::empty(), variances: LazySeq::empty(), generics: Some(self.encode_generics(def_id)), diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index d48a129dfe1c..3efbd6b30c22 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -13,7 +13,9 @@ use super::{check_fn, Expectation, FnCtxt}; use astconv::AstConv; +use rustc::hir::def_id::DefId; use rustc::ty::{self, ToPolyTraitRef, Ty}; +use rustc::ty::subst::Substs; use rustc::util::common::MemoizationMap; use std::cmp; use syntax::abi::Abi; @@ -43,6 +45,48 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_closure(expr, expected_kind, decl, body, expected_sig) } + fn declare_closure(&self, def_id: DefId) { + let tcx = self.tcx.global_tcx(); + + tcx.generics.memoize(def_id, || { + let node_id = tcx.map.as_local_node_id(def_id).unwrap(); + let base_def_id = self.tcx.closure_base_def_id(def_id); + let base_generics = tcx.item_generics(base_def_id); + + // provide junk type parameter defs - the only place that + // cares about anything but the length is instantiation, + // and we don't do that for closures. + let upvar_decls : Vec<_> = tcx.with_freevars(node_id, |fv| { + fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef { + index: (base_generics.count() as u32) + (i as u32), + name: token::intern(""), + def_id: def_id, + default_def_id: base_def_id, + default: None, + object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, + pure_wrt_drop: false, + }).collect() + }); + + tcx.alloc_generics(ty::Generics { + parent: Some(base_def_id), + parent_regions: base_generics.parent_regions + + (base_generics.regions.len() as u32), + parent_types: base_generics.parent_types + + (base_generics.types.len() as u32), + regions: vec![], + types: upvar_decls, + has_self: false, + }) + }); + + tcx.item_types.memoize(def_id, || tcx.mk_closure(def_id, Substs::for_item( + tcx, def_id, + |def, _| tcx.mk_region(def.to_early_bound_region()), + |def, _| tcx.mk_param_from_def(def) + ))); + } + fn check_closure(&self, expr: &hir::Expr, opt_kind: Option, @@ -50,13 +94,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { body: &'gcx hir::Expr, expected_sig: Option>) -> Ty<'tcx> { - let expr_def_id = self.tcx.map.local_def_id(expr.id); - let base_def_id = self.tcx.closure_base_def_id(expr_def_id); - debug!("check_closure opt_kind={:?} expected_sig={:?}", opt_kind, expected_sig); + let expr_def_id = self.tcx.map.local_def_id(expr.id); + self.declare_closure(expr_def_id); + let mut fn_ty = AstConv::ty_of_closure(self, hir::Unsafety::Normal, decl, @@ -66,32 +110,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Create type variables (for now) to represent the transformed // types of upvars. These will be unified during the upvar // inference phase (`upvar.rs`). - let base_generics = self.tcx.item_generics(base_def_id); - // provide junk type parameter defs - the only place that - // cares about anything but the length is instantiation, - // and we don't do that for closures. - let upvar_decls : Vec<_> = self.tcx.with_freevars(expr.id, |fv| { - fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef { - index: (base_generics.count() as u32) + (i as u32), - name: token::intern(""), - def_id: expr_def_id, - default_def_id: base_def_id, - default: None, - object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, - pure_wrt_drop: false, - }).collect() - }); - let num_upvars = upvar_decls.len(); - - self.tcx.generics.memoize(expr_def_id, || self.tcx.alloc_generics(ty::Generics { - parent: Some(base_def_id), - parent_regions: base_generics.parent_regions + (base_generics.regions.len() as u32), - parent_types: base_generics.parent_types + (base_generics.types.len() as u32), - regions: vec![], - types: upvar_decls, - has_self: false, - })); - + let num_upvars = self.tcx.with_freevars(expr.id, |fv| fv.len()); let upvar_tys = self.next_ty_vars(num_upvars); debug!("check_closure: expr.id={:?} upvar_tys={:?}", From 57950982b27c6ab45509c1f2db4a01fa1d2cfebb Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 9 Nov 2016 23:09:28 +0200 Subject: [PATCH 077/177] rustc_trans: translate closures using the collector Translate closures like normal functions, using the trans::collector interface. --- src/librustc_trans/base.rs | 65 +++--- src/librustc_trans/callee.rs | 177 +++++++++++++++- src/librustc_trans/closure.rs | 318 ----------------------------- src/librustc_trans/collector.rs | 28 +-- src/librustc_trans/common.rs | 31 +++ src/librustc_trans/declare.rs | 5 +- src/librustc_trans/lib.rs | 1 - src/librustc_trans/mir/constant.rs | 8 - src/librustc_trans/mir/rvalue.rs | 9 - src/librustc_trans/trans_item.rs | 5 + 10 files changed, 242 insertions(+), 405 deletions(-) delete mode 100644 src/librustc_trans/closure.rs diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index a990a7c507fd..c7cad6455bc3 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1003,34 +1003,41 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { } } -/// Builds an LLVM function out of a source function. -/// -/// If the function closes over its environment a closure will be returned. -pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - llfndecl: ValueRef, - instance: Instance<'tcx>, - sig: &ty::FnSig<'tcx>, - abi: Abi) { - ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1); - - let _icx = push_ctxt("trans_closure"); - if !ccx.sess().no_landing_pads() { - attributes::emit_uwtable(llfndecl, true); - } - +pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) { + let _s = StatRecorder::new(ccx, ccx.tcx().item_path_str(instance.def)); // this is an info! to allow collecting monomorphization statistics // and to allow finding the last function before LLVM aborts from // release builds. - info!("trans_closure(..., {})", instance); + info!("trans_instance({})", instance); - let fn_ty = FnType::new(ccx, abi, sig, &[]); + let _icx = push_ctxt("trans_instance"); + + let fn_ty = ccx.tcx().item_type(instance.def); + let fn_ty = ccx.tcx().erase_regions(&fn_ty); + let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty); + + let ty::BareFnTy { abi, ref sig, .. } = *common::ty_fn_ty(ccx, fn_ty); + let sig = ccx.tcx().erase_late_bound_regions_and_normalize(sig); + + let lldecl = match ccx.instances().borrow().get(&instance) { + Some(&val) => val, + None => bug!("Instance `{:?}` not already declared", instance) + }; + + ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1); + + if !ccx.sess().no_landing_pads() { + attributes::emit_uwtable(lldecl, true); + } + + let fn_ty = FnType::new(ccx, abi, &sig, &[]); let (arena, fcx): (TypedArena<_>, FunctionContext); arena = TypedArena::new(); fcx = FunctionContext::new(ccx, - llfndecl, + lldecl, fn_ty, - Some((instance, sig, abi)), + Some((instance, &sig, abi)), &arena); if fcx.mir.is_none() { @@ -1040,26 +1047,6 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, mir::trans_mir(&fcx); } -pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) { - let _s = StatRecorder::new(ccx, ccx.tcx().item_path_str(instance.def)); - debug!("trans_instance(instance={:?})", instance); - let _icx = push_ctxt("trans_instance"); - - let fn_ty = ccx.tcx().item_type(instance.def); - let fn_ty = ccx.tcx().erase_regions(&fn_ty); - let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty); - - let sig = ccx.tcx().erase_late_bound_regions_and_normalize(fn_ty.fn_sig()); - let abi = fn_ty.fn_abi(); - - let lldecl = match ccx.instances().borrow().get(&instance) { - Some(&val) => val, - None => bug!("Instance `{:?}` not already declared", instance) - }; - - trans_closure(ccx, lldecl, instance, &sig, abi); -} - pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>, diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index f49d63b83764..faf65f3f98b0 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -26,11 +26,11 @@ use attributes; use base; use base::*; use build::*; -use closure; use common::{self, Block, Result, CrateContext, FunctionContext, SharedCrateContext}; use consts; use debuginfo::DebugLoc; use declare; +use value::Value; use meth; use monomorphize::{self, Instance}; use trans_item::TransItem; @@ -147,11 +147,12 @@ impl<'tcx> Callee<'tcx> { // after passing through fulfill_obligation let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap(); let instance = Instance::new(def_id, substs); - let llfn = closure::trans_closure_method(ccx, - vtable_closure.closure_def_id, - vtable_closure.substs, - instance, - trait_closure_kind); + let llfn = trans_closure_method( + ccx, + vtable_closure.closure_def_id, + vtable_closure.substs, + instance, + trait_closure_kind); let method_ty = def_ty(ccx.shared(), def_id, substs); Callee::ptr(llfn, method_ty) @@ -250,6 +251,170 @@ fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, monomorphize::apply_param_substs(shared, substs, &ty) } + +fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, + def_id: DefId, + substs: ty::ClosureSubsts<'tcx>, + method_instance: Instance<'tcx>, + trait_closure_kind: ty::ClosureKind) + -> ValueRef +{ + // If this is a closure, redirect to it. + let (llfn, _) = get_fn(ccx, def_id, substs.substs); + + // If the closure is a Fn closure, but a FnOnce is needed (etc), + // then adapt the self type + let llfn_closure_kind = ccx.tcx().closure_kind(def_id); + + let _icx = push_ctxt("trans_closure_adapter_shim"); + + debug!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \ + trait_closure_kind={:?}, llfn={:?})", + llfn_closure_kind, trait_closure_kind, Value(llfn)); + + match (llfn_closure_kind, trait_closure_kind) { + (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | + (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => { + // No adapter needed. + llfn + } + (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { + // The closure fn `llfn` is a `fn(&self, ...)`. We want a + // `fn(&mut self, ...)`. In fact, at trans time, these are + // basically the same thing, so we can just return llfn. + llfn + } + (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { + // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut + // self, ...)`. We want a `fn(self, ...)`. We can produce + // this by doing something like: + // + // fn call_once(self, ...) { call_mut(&self, ...) } + // fn call_once(mut self, ...) { call_mut(&mut self, ...) } + // + // These are both the same at trans time. + trans_fn_once_adapter_shim(ccx, def_id, substs, method_instance, llfn) + } + _ => { + bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}", + llfn_closure_kind, + trait_closure_kind); + } + } +} + +fn trans_fn_once_adapter_shim<'a, 'tcx>( + ccx: &'a CrateContext<'a, 'tcx>, + def_id: DefId, + substs: ty::ClosureSubsts<'tcx>, + method_instance: Instance<'tcx>, + llreffn: ValueRef) + -> ValueRef +{ + if let Some(&llfn) = ccx.instances().borrow().get(&method_instance) { + return llfn; + } + + debug!("trans_fn_once_adapter_shim(def_id={:?}, substs={:?}, llreffn={:?})", + def_id, substs, Value(llreffn)); + + let tcx = ccx.tcx(); + + // Find a version of the closure type. Substitute static for the + // region since it doesn't really matter. + let closure_ty = tcx.mk_closure_from_closure_substs(def_id, substs); + let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), closure_ty); + + // Make a version with the type of by-ref closure. + let ty::ClosureTy { unsafety, abi, mut sig } = tcx.closure_type(def_id, substs); + sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet + let llref_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { + unsafety: unsafety, + abi: abi, + sig: sig.clone() + })); + debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}", + llref_fn_ty); + + + // Make a version of the closure type with the same arguments, but + // with argument #0 being by value. + assert_eq!(abi, Abi::RustCall); + sig.0.inputs[0] = closure_ty; + + let sig = tcx.erase_late_bound_regions_and_normalize(&sig); + let fn_ty = FnType::new(ccx, abi, &sig, &[]); + + let llonce_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { + unsafety: unsafety, + abi: abi, + sig: ty::Binder(sig) + })); + + // Create the by-value helper. + let function_name = method_instance.symbol_name(ccx.shared()); + let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty); + attributes::set_frame_pointer_elimination(ccx, lloncefn); + + let (block_arena, fcx): (TypedArena<_>, FunctionContext); + block_arena = TypedArena::new(); + fcx = FunctionContext::new(ccx, lloncefn, fn_ty, None, &block_arena); + let mut bcx = fcx.init(false); + + + // the first argument (`self`) will be the (by value) closure env. + + let mut llargs = get_params(fcx.llfn); + let mut self_idx = fcx.fn_ty.ret.is_indirect() as usize; + let env_arg = &fcx.fn_ty.args[0]; + let llenv = if env_arg.is_indirect() { + llargs[self_idx] + } else { + let scratch = alloc_ty(bcx, closure_ty, "self"); + let mut llarg_idx = self_idx; + env_arg.store_fn_arg(&bcx.build(), &mut llarg_idx, scratch); + scratch + }; + + debug!("trans_fn_once_adapter_shim: env={:?}", Value(llenv)); + // Adjust llargs such that llargs[self_idx..] has the call arguments. + // For zero-sized closures that means sneaking in a new argument. + if env_arg.is_ignore() { + if self_idx > 0 { + self_idx -= 1; + llargs[self_idx] = llenv; + } else { + llargs.insert(0, llenv); + } + } else { + llargs[self_idx] = llenv; + } + + let dest = fcx.llretslotptr.get(); + + let callee = Callee { + data: Fn(llreffn), + ty: llref_fn_ty + }; + + // Call the by-ref closure body with `self` in a cleanup scope, + // to drop `self` when the body returns, or in case it unwinds. + let self_scope = fcx.push_custom_cleanup_scope(); + fcx.schedule_drop_mem(self_scope, llenv, closure_ty); + + bcx = callee.call(bcx, DebugLoc::None, &llargs[self_idx..], dest).bcx; + + fcx.pop_and_trans_custom_cleanup_scope(bcx, self_scope); + + fcx.finish(bcx, DebugLoc::None); + + ccx.instances().borrow_mut().insert(method_instance, lloncefn); + + lloncefn +} + /// Translates an adapter that implements the `Fn` trait for a fn /// pointer. This is basically the equivalent of something like: /// diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs deleted file mode 100644 index 0cefc49cb425..000000000000 --- a/src/librustc_trans/closure.rs +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use arena::TypedArena; -use llvm::{self, ValueRef, get_params}; -use rustc::hir::def_id::DefId; -use abi::{Abi, FnType}; -use attributes; -use base::*; -use callee::{self, Callee}; -use common::*; -use debuginfo::{DebugLoc}; -use declare; -use monomorphize::{Instance}; -use value::Value; -use rustc::ty::{self, Ty, TyCtxt}; - -use rustc::hir; - -fn get_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - closure_id: DefId, - fn_ty: Ty<'tcx>) - -> Ty<'tcx> { - match tcx.closure_kind(closure_id) { - ty::ClosureKind::Fn => { - tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), fn_ty) - } - ty::ClosureKind::FnMut => { - tcx.mk_mut_ref(tcx.mk_region(ty::ReErased), fn_ty) - } - ty::ClosureKind::FnOnce => fn_ty, - } -} - -/// Returns the LLVM function declaration for a closure, creating it if -/// necessary. If the ID does not correspond to a closure ID, returns None. -fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - closure_id: DefId, - substs: ty::ClosureSubsts<'tcx>) - -> ValueRef { - // Normalize type so differences in regions and typedefs don't cause - // duplicate declarations - let tcx = ccx.tcx(); - let substs = tcx.erase_regions(&substs); - let instance = Instance::new(closure_id, substs.substs); - - if let Some(&llfn) = ccx.instances().borrow().get(&instance) { - debug!("get_or_create_closure_declaration(): found closure {:?}: {:?}", - instance, Value(llfn)); - return llfn; - } - - let symbol = instance.symbol_name(ccx.shared()); - - // Compute the rust-call form of the closure call method. - let sig = &tcx.closure_type(closure_id, substs).sig; - let sig = tcx.erase_late_bound_regions_and_normalize(sig); - let closure_type = tcx.mk_closure_from_closure_substs(closure_id, substs); - let function_type = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { - unsafety: hir::Unsafety::Normal, - abi: Abi::RustCall, - sig: ty::Binder(ty::FnSig { - inputs: Some(get_self_type(tcx, closure_id, closure_type)) - .into_iter().chain(sig.inputs).collect(), - output: sig.output, - variadic: false - }) - })); - let llfn = declare::declare_fn(ccx, &symbol, function_type); - - attributes::set_frame_pointer_elimination(ccx, llfn); - - debug!("get_or_create_declaration_if_closure(): inserting new \ - closure {:?}: {:?}", - instance, Value(llfn)); - - // NOTE: We do *not* store llfn in the ccx.instances() map here, - // that is only done, when the closures body is translated. - - llfn -} - -pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - closure_def_id: DefId, - closure_substs: ty::ClosureSubsts<'tcx>) { - // (*) Note that in the case of inlined functions, the `closure_def_id` will be the - // defid of the closure in its original crate, whereas `id` will be the id of the local - // inlined copy. - debug!("trans_closure_body_via_mir(closure_def_id={:?}, closure_substs={:?})", - closure_def_id, closure_substs); - - let tcx = ccx.tcx(); - let _icx = push_ctxt("closure::trans_closure_expr"); - - let instance = Instance::new(closure_def_id, closure_substs.substs); - - // If we have not done so yet, translate this closure's body - if !ccx.instances().borrow().contains_key(&instance) { - let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs); - - unsafe { - if ccx.sess().target.target.options.allows_weak_linkage { - llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::WeakODRLinkage); - llvm::SetUniqueComdat(ccx.llmod(), llfn); - } else { - llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage); - } - } - - // set an inline hint for all closures - attributes::inline(llfn, attributes::InlineAttr::Hint); - - // Get the type of this closure. Use the current `param_substs` as - // the closure substitutions. This makes sense because the closure - // takes the same set of type arguments as the enclosing fn, and - // this function (`trans_closure`) is invoked at the point - // of the closure expression. - - let sig = &tcx.closure_type(closure_def_id, closure_substs).sig; - let sig = tcx.erase_late_bound_regions_and_normalize(sig); - - let closure_type = tcx.mk_closure_from_closure_substs(closure_def_id, - closure_substs); - let sig = ty::FnSig { - inputs: Some(get_self_type(tcx, closure_def_id, closure_type)) - .into_iter().chain(sig.inputs).collect(), - output: sig.output, - variadic: false - }; - - trans_closure(ccx, - llfn, - instance, - &sig, - Abi::RustCall); - - ccx.instances().borrow_mut().insert(instance, llfn); - } -} - -pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, - closure_def_id: DefId, - substs: ty::ClosureSubsts<'tcx>, - method_instance: Instance<'tcx>, - trait_closure_kind: ty::ClosureKind) - -> ValueRef -{ - // If this is a closure, redirect to it. - let llfn = get_or_create_closure_declaration(ccx, closure_def_id, substs); - - // If weak linkage is not allowed, we have to make sure that a local, - // private copy of the closure is available in this codegen unit - if !ccx.sess().target.target.options.allows_weak_linkage && - !ccx.sess().opts.single_codegen_unit() { - - trans_closure_body_via_mir(ccx, closure_def_id, substs); - } - - // If the closure is a Fn closure, but a FnOnce is needed (etc), - // then adapt the self type - let llfn_closure_kind = ccx.tcx().closure_kind(closure_def_id); - - let _icx = push_ctxt("trans_closure_adapter_shim"); - - debug!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \ - trait_closure_kind={:?}, llfn={:?})", - llfn_closure_kind, trait_closure_kind, Value(llfn)); - - match (llfn_closure_kind, trait_closure_kind) { - (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | - (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => { - // No adapter needed. - llfn - } - (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { - // The closure fn `llfn` is a `fn(&self, ...)`. We want a - // `fn(&mut self, ...)`. In fact, at trans time, these are - // basically the same thing, so we can just return llfn. - llfn - } - (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { - // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut - // self, ...)`. We want a `fn(self, ...)`. We can produce - // this by doing something like: - // - // fn call_once(self, ...) { call_mut(&self, ...) } - // fn call_once(mut self, ...) { call_mut(&mut self, ...) } - // - // These are both the same at trans time. - trans_fn_once_adapter_shim(ccx, closure_def_id, substs, method_instance, llfn) - } - _ => { - bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}", - llfn_closure_kind, - trait_closure_kind); - } - } -} - -fn trans_fn_once_adapter_shim<'a, 'tcx>( - ccx: &'a CrateContext<'a, 'tcx>, - closure_def_id: DefId, - substs: ty::ClosureSubsts<'tcx>, - method_instance: Instance<'tcx>, - llreffn: ValueRef) - -> ValueRef -{ - if let Some(&llfn) = ccx.instances().borrow().get(&method_instance) { - return llfn; - } - - debug!("trans_fn_once_adapter_shim(closure_def_id={:?}, substs={:?}, llreffn={:?})", - closure_def_id, substs, Value(llreffn)); - - let tcx = ccx.tcx(); - - // Find a version of the closure type. Substitute static for the - // region since it doesn't really matter. - let closure_ty = tcx.mk_closure_from_closure_substs(closure_def_id, substs); - let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), closure_ty); - - // Make a version with the type of by-ref closure. - let ty::ClosureTy { unsafety, abi, mut sig } = - tcx.closure_type(closure_def_id, substs); - sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet - let llref_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { - unsafety: unsafety, - abi: abi, - sig: sig.clone() - })); - debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}", - llref_fn_ty); - - - // Make a version of the closure type with the same arguments, but - // with argument #0 being by value. - assert_eq!(abi, Abi::RustCall); - sig.0.inputs[0] = closure_ty; - - let sig = tcx.erase_late_bound_regions_and_normalize(&sig); - let fn_ty = FnType::new(ccx, abi, &sig, &[]); - - let llonce_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { - unsafety: unsafety, - abi: abi, - sig: ty::Binder(sig) - })); - - // Create the by-value helper. - let function_name = method_instance.symbol_name(ccx.shared()); - let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty); - attributes::set_frame_pointer_elimination(ccx, lloncefn); - - let (block_arena, fcx): (TypedArena<_>, FunctionContext); - block_arena = TypedArena::new(); - fcx = FunctionContext::new(ccx, lloncefn, fn_ty, None, &block_arena); - let mut bcx = fcx.init(false); - - - // the first argument (`self`) will be the (by value) closure env. - - let mut llargs = get_params(fcx.llfn); - let mut self_idx = fcx.fn_ty.ret.is_indirect() as usize; - let env_arg = &fcx.fn_ty.args[0]; - let llenv = if env_arg.is_indirect() { - llargs[self_idx] - } else { - let scratch = alloc_ty(bcx, closure_ty, "self"); - let mut llarg_idx = self_idx; - env_arg.store_fn_arg(&bcx.build(), &mut llarg_idx, scratch); - scratch - }; - - debug!("trans_fn_once_adapter_shim: env={:?}", Value(llenv)); - // Adjust llargs such that llargs[self_idx..] has the call arguments. - // For zero-sized closures that means sneaking in a new argument. - if env_arg.is_ignore() { - if self_idx > 0 { - self_idx -= 1; - llargs[self_idx] = llenv; - } else { - llargs.insert(0, llenv); - } - } else { - llargs[self_idx] = llenv; - } - - let dest = fcx.llretslotptr.get(); - - let callee = Callee { - data: callee::Fn(llreffn), - ty: llref_fn_ty - }; - - // Call the by-ref closure body with `self` in a cleanup scope, - // to drop `self` when the body returns, or in case it unwinds. - let self_scope = fcx.push_custom_cleanup_scope(); - fcx.schedule_drop_mem(self_scope, llenv, closure_ty); - - bcx = callee.call(bcx, DebugLoc::None, &llargs[self_idx..], dest).bcx; - - fcx.pop_and_trans_custom_cleanup_scope(bcx, self_scope); - - fcx.finish(bcx, DebugLoc::None); - - ccx.instances().borrow_mut().insert(method_instance, lloncefn); - - lloncefn -} diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index a79719a4d227..2728a666556e 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -446,24 +446,6 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { debug!("visiting rvalue {:?}", *rvalue); match *rvalue { - mir::Rvalue::Aggregate(mir::AggregateKind::Closure(def_id, - ref substs), _) => { - let mir = self.scx.tcx().item_mir(def_id); - - let concrete_substs = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &substs.substs); - let concrete_substs = self.scx.tcx().erase_regions(&concrete_substs); - - let visitor = MirNeighborCollector { - scx: self.scx, - mir: &mir, - output: self.output, - param_substs: concrete_substs - }; - - visit_mir_and_promoted(visitor, &mir); - } // When doing an cast from a regular pointer to a fat pointer, we // have to instantiate all methods of the trait being cast to, so we // can build the appropriate vtable. @@ -888,10 +870,12 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, traits::VtableImpl(impl_data) => { Some(traits::find_method(tcx, trait_method.name, rcvr_substs, &impl_data)) } - // If we have a closure or a function pointer, we will also encounter - // the concrete closure/function somewhere else (during closure or fn - // pointer construction). That's where we track those things. - traits::VtableClosure(..) | + traits::VtableClosure(closure_data) => { + Some((closure_data.closure_def_id, closure_data.substs.substs)) + } + // Trait object and function pointer shims are always + // instantiated in-place, and as they are just an ABI-adjusting + // indirect call they do not have any dependencies. traits::VtableFnPointer(..) | traits::VtableObject(..) => { None diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 6f3a72621520..a0fac9cc6599 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -44,6 +44,8 @@ use rustc::hir; use arena::TypedArena; use libc::{c_uint, c_char}; +use std::borrow::Cow; +use std::iter; use std::ops::Deref; use std::ffi::CString; use std::cell::{Cell, RefCell, Ref}; @@ -1069,3 +1071,32 @@ pub fn shift_mask_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, _ => bug!("shift_mask_val: expected Integer or Vector, found {:?}", kind), } } + +pub fn ty_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + ty: Ty<'tcx>) + -> Cow<'tcx, ty::BareFnTy<'tcx>> +{ + match ty.sty { + ty::TyFnDef(_, _, fty) => Cow::Borrowed(fty), + // Shims currently have type TyFnPtr. Not sure this should remain. + ty::TyFnPtr(fty) => Cow::Borrowed(fty), + ty::TyClosure(def_id, substs) => { + let tcx = ccx.tcx(); + let ty::ClosureTy { unsafety, abi, sig } = tcx.closure_type(def_id, substs); + + let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv); + let env_ty = match tcx.closure_kind(def_id) { + ty::ClosureKind::Fn => tcx.mk_imm_ref(tcx.mk_region(env_region), ty), + ty::ClosureKind::FnMut => tcx.mk_mut_ref(tcx.mk_region(env_region), ty), + ty::ClosureKind::FnOnce => ty, + }; + + let sig = sig.map_bound(|sig| ty::FnSig { + inputs: iter::once(env_ty).chain(sig.inputs).collect(), + ..sig + }); + Cow::Owned(ty::BareFnTy { unsafety: unsafety, abi: abi, sig: sig }) + } + _ => bug!("unexpected type {:?} to ty_fn_sig", ty) + } +} diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index 1ec5ca4a563a..662e3bec66db 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -25,6 +25,7 @@ use rustc::ty; use abi::{Abi, FnType}; use attributes; use context::CrateContext; +use common; use type_::Type; use value::Value; @@ -103,8 +104,8 @@ pub fn declare_cfn(ccx: &CrateContext, name: &str, fn_type: Type) -> ValueRef { pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, fn_type: ty::Ty<'tcx>) -> ValueRef { debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type); - let abi = fn_type.fn_abi(); - let sig = ccx.tcx().erase_late_bound_regions_and_normalize(fn_type.fn_sig()); + let ty::BareFnTy { abi, ref sig, .. } = *common::ty_fn_ty(ccx, fn_type); + let sig = ccx.tcx().erase_late_bound_regions_and_normalize(sig); debug!("declare_rust_fn (after region erasure) sig={:?}", sig); let fty = FnType::new(ccx, abi, &sig, &[]); diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 8ef7f04d4ee1..0757343a8af5 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -109,7 +109,6 @@ mod cabi_x86_64; mod cabi_x86_win64; mod callee; mod cleanup; -mod closure; mod collector; mod common; mod consts; diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index b8d346b11c13..bca81fa36458 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -553,14 +553,6 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } failure?; - // FIXME Shouldn't need to manually trigger closure instantiations. - if let mir::AggregateKind::Closure(def_id, substs) = *kind { - use closure; - closure::trans_closure_body_via_mir(self.ccx, - def_id, - self.monomorphize(&substs)); - } - match *kind { mir::AggregateKind::Array => { self.const_array(dest_ty, &fields) diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index f25877b1de12..bf01db0ffd32 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -133,15 +133,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } }, _ => { - // FIXME Shouldn't need to manually trigger closure instantiations. - if let mir::AggregateKind::Closure(def_id, substs) = *kind { - use closure; - - closure::trans_closure_body_via_mir(bcx.ccx(), - def_id, - bcx.monomorphize(&substs)); - } - for (i, operand) in operands.iter().enumerate() { let op = self.trans_operand(&bcx, operand); // Do not generate stores and GEPis for zero-sized fields. diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 16bc7e212cf5..c5a7dbbcf548 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -166,6 +166,11 @@ impl<'a, 'tcx> TransItem<'tcx> { llvm::SetUniqueComdat(ccx.llmod(), lldecl); } + if let ty::TyClosure(..) = mono_ty.sty { + // set an inline hint for all closures + attributes::inline(lldecl, attributes::InlineAttr::Hint); + } + attributes::from_fn_attrs(ccx, &attrs, lldecl); ccx.instances().borrow_mut().insert(instance, lldecl); From 88b46460fa1483b3283b7f1e37c7abd033610a68 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 11 Nov 2016 08:21:22 -0800 Subject: [PATCH 078/177] rustc: Flag all builtins functions as hidden When compiling compiler-rt you typically compile with `-fvisibility=hidden` which to ensure that all symbols are hidden in shared objects and don't show up in symbol tables. This is important for these intrinsics being linked in every crate to ensure that we're not unnecessarily bloating the public ABI of Rust crates. This should help allow the compiler-builtins project with Rust-defined builtins start landing in-tree as well. --- src/libcompiler_builtins/Cargo.toml | 1 + src/librustc_llvm/ffi.rs | 12 ++++++++++-- src/librustc_trans/declare.rs | 12 ++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/libcompiler_builtins/Cargo.toml b/src/libcompiler_builtins/Cargo.toml index a52873fc326b..9e91e390a572 100644 --- a/src/libcompiler_builtins/Cargo.toml +++ b/src/libcompiler_builtins/Cargo.toml @@ -7,6 +7,7 @@ version = "0.0.0" [lib] name = "compiler_builtins" path = "lib.rs" +test = false [dependencies] core = { path = "../libcore" } diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 78a9d67ed770..8f21bf32c9e4 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -426,6 +426,14 @@ pub type OperandBundleDefRef = *mut OperandBundleDef_opaque; pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void); pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint); +/// LLVMVisibility +#[repr(C)] +pub enum Visibility { + Default, + Hidden, + Protected, +} + pub mod debuginfo { pub use self::DIDescriptorFlags::*; use super::MetadataRef; @@ -746,8 +754,8 @@ extern "C" { pub fn LLVMRustSetLinkage(Global: ValueRef, RustLinkage: Linkage); pub fn LLVMGetSection(Global: ValueRef) -> *const c_char; pub fn LLVMSetSection(Global: ValueRef, Section: *const c_char); - pub fn LLVMGetVisibility(Global: ValueRef) -> c_uint; - pub fn LLVMSetVisibility(Global: ValueRef, Viz: c_uint); + pub fn LLVMGetVisibility(Global: ValueRef) -> Visibility; + pub fn LLVMSetVisibility(Global: ValueRef, Viz: Visibility); pub fn LLVMGetAlignment(Global: ValueRef) -> c_uint; pub fn LLVMSetAlignment(Global: ValueRef, Bytes: c_uint); pub fn LLVMSetDLLStorageClass(V: ValueRef, C: DLLStorageClass); diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index 1ec5ca4a563a..9ed3bfa04a89 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -19,6 +19,7 @@ //! interested in defining the ValueRef they return. //! * Use define_* family of methods when you might be defining the ValueRef. //! * When in doubt, define. + use llvm::{self, ValueRef}; use llvm::AttributePlace::Function; use rustc::ty; @@ -27,6 +28,7 @@ use attributes; use context::CrateContext; use type_::Type; use value::Value; +use syntax::attr; use std::ffi::CString; @@ -69,6 +71,16 @@ fn declare_raw_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty: llvm::Attribute::NoRedZone.apply_llfn(Function, llfn); } + // If we're compiling the compiler-builtins crate, e.g. the equivalent of + // compiler-rt, then we want to implicitly compile everything with hidden + // visibility as we're going to link this object all over the place but + // don't want the symbols to get exported. + if attr::contains_name(ccx.tcx().map.krate_attrs(), "compiler_builtins") { + unsafe { + llvm::LLVMSetVisibility(llfn, llvm::Visibility::Hidden); + } + } + match ccx.tcx().sess.opts.cg.opt_level.as_ref().map(String::as_ref) { Some("s") => { llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn); From 8a06740a1074adacac7c43cc4441107455815163 Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Sat, 12 Nov 2016 12:20:58 -0700 Subject: [PATCH 079/177] Remove macro work-around. --- src/libcore/tuple.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/libcore/tuple.rs b/src/libcore/tuple.rs index c3608b60a31a..55d55079ddc1 100644 --- a/src/libcore/tuple.rs +++ b/src/libcore/tuple.rs @@ -13,11 +13,6 @@ use cmp::*; use cmp::Ordering::*; -// FIXME(#19630) Remove this work-around -macro_rules! e { - ($e:expr) => { $e } -} - // macro for implementing n-ary tuple functions and operations macro_rules! tuple_impls { ($( @@ -29,7 +24,7 @@ macro_rules! tuple_impls { #[stable(feature = "rust1", since = "1.0.0")] impl<$($T:Clone),+> Clone for ($($T,)+) { fn clone(&self) -> ($($T,)+) { - ($(e!(self.$idx.clone()),)+) + ($(self.$idx.clone(),)+) } } @@ -37,11 +32,11 @@ macro_rules! tuple_impls { impl<$($T:PartialEq),+> PartialEq for ($($T,)+) { #[inline] fn eq(&self, other: &($($T,)+)) -> bool { - e!($(self.$idx == other.$idx)&&+) + $(self.$idx == other.$idx)&&+ } #[inline] fn ne(&self, other: &($($T,)+)) -> bool { - e!($(self.$idx != other.$idx)||+) + $(self.$idx != other.$idx)||+ } } From fff921672f8e679c42d0659c475ee57fddac13b6 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Fri, 11 Nov 2016 16:41:00 -0600 Subject: [PATCH 080/177] rustdoc: fold fields for enum struct variants into a docblock --- src/librustdoc/html/render.rs | 11 ++++++++--- src/librustdoc/html/static/main.js | 16 ++++++++++++++++ src/librustdoc/html/static/rustdoc.css | 8 ++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 2db771d77111..ddbdb28c2ade 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2467,8 +2467,13 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, if let clean::VariantItem(Variant { kind: VariantKind::Struct(ref s) }) = variant.inner { - write!(w, "

Fields

\n - ")?; + let variant_id = derive_id(format!("{}.{}.fields", + ItemType::Variant, + variant.name.as_ref().unwrap())); + write!(w, "", + id = variant_id)?; + write!(w, "

Fields of {name}

\n +
", name = variant.name.as_ref().unwrap())?; for field in &s.fields { use clean::StructFieldItem; if let StructFieldItem(ref ty) = field.inner { @@ -2492,7 +2497,7 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, write!(w, "")?; } } - write!(w, "
")?; + write!(w, "
")?; } render_stability_since(w, variant, it)?; } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 474d2bbe7fcb..5ffab949d019 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1013,6 +1013,22 @@ .html(' Expand description')); var wrapper = $("
").append(mainToggle); $("#main > .docblock").before(wrapper); + + $(".docblock.autohide").each(function() { + var wrap = $(this).prev(); + if (wrap.is(".toggle-wrapper")) { + var toggle = wrap.children().first(); + if ($(this).children().first().is("h3")) { + toggle.children(".toggle-label") + .text(" Show " + $(this).children().first().text()); + } + $(this).hide(); + wrap.addClass("collapsed"); + toggle.children(".inner").text(labelForToggleButton(true)); + toggle.children(".toggle-label").show(); + } + }); + var mainToggle = $(toggle).append( $('', {'class': 'toggle-label'}) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 46b34b5a638b..35d43314c702 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -339,6 +339,10 @@ h4 > code, h3 > code, .invisible > code { border-bottom: 1px solid; } +.fields + table { + margin-bottom: 1em; +} + .content .item-list { list-style-type: none; padding: 0; @@ -663,6 +667,10 @@ span.since { margin-top: 5px; } +.sub-variant, .sub-variant > h3 { + margin-top: 0 !important; +} + .enum > .toggle-wrapper + .docblock, .struct > .toggle-wrapper + .docblock { margin-left: 30px; margin-bottom: 20px; From d394e75ef6b6b8ea41e62bcbd3023a3e29eb4ee7 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 12 Nov 2016 23:20:02 +0200 Subject: [PATCH 081/177] address review comments --- src/librustc/infer/mod.rs | 4 -- src/librustc/ty/subst.rs | 33 ++++++++++---- src/librustc_typeck/check/closure.rs | 66 +++------------------------- src/librustc_typeck/collect.rs | 50 ++++++++++++++++++++- 4 files changed, 80 insertions(+), 73 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 24716c479513..2d4b36ec1876 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1150,10 +1150,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.mk_var(self.next_ty_var_id(true)) } - pub fn next_ty_vars(&self, n: usize) -> Vec> { - (0..n).map(|_i| self.next_ty_var()).collect() - } - pub fn next_int_var_id(&self) -> IntVid { self.int_unification_table .borrow_mut() diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 76d512a20b26..41fcb09fb2dc 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -183,6 +183,22 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { tcx.intern_substs(&substs) } + pub fn extend_to(&self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + def_id: DefId, + mut mk_region: FR, + mut mk_type: FT) + -> &'tcx Substs<'tcx> + where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region, + FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> + { + let defs = tcx.item_generics(def_id); + let mut result = Vec::with_capacity(defs.count()); + result.extend(self[..].iter().cloned()); + Substs::fill_single(&mut result, defs, &mut mk_region, &mut mk_type); + tcx.intern_substs(&result) + } + fn fill_item(substs: &mut Vec>, tcx: TyCtxt<'a, 'gcx, 'tcx>, defs: &ty::Generics<'tcx>, @@ -195,7 +211,15 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { let parent_defs = tcx.item_generics(def_id); Substs::fill_item(substs, tcx, parent_defs, mk_region, mk_type); } + Substs::fill_single(substs, defs, mk_region, mk_type) + } + fn fill_single(substs: &mut Vec>, + defs: &ty::Generics<'tcx>, + mk_region: &mut FR, + mk_type: &mut FT) + where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region, + FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> { // Handle Self first, before all regions. let mut types = defs.types.iter(); if defs.parent.is_none() && defs.has_self { @@ -275,15 +299,6 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { tcx.mk_substs(target_substs.iter().chain(&self[defs.own_count()..]).cloned()) } - pub fn extend_with_types(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - types: &[Ty<'tcx>]) - -> &'tcx Substs<'tcx> { - tcx.mk_substs( - self[..].iter().cloned().chain( - types.iter().map(|a| Kind::from(*a))) - ) - } - pub fn truncate_to(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, generics: &ty::Generics<'tcx>) -> &'tcx Substs<'tcx> { tcx.mk_substs(self.iter().take(generics.count()).cloned()) diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 3efbd6b30c22..75287d4064ae 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -13,16 +13,11 @@ use super::{check_fn, Expectation, FnCtxt}; use astconv::AstConv; -use rustc::hir::def_id::DefId; use rustc::ty::{self, ToPolyTraitRef, Ty}; -use rustc::ty::subst::Substs; -use rustc::util::common::MemoizationMap; use std::cmp; use syntax::abi::Abi; use rustc::hir; -use syntax::parse::token; - impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_expr_closure(&self, expr: &hir::Expr, @@ -45,48 +40,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_closure(expr, expected_kind, decl, body, expected_sig) } - fn declare_closure(&self, def_id: DefId) { - let tcx = self.tcx.global_tcx(); - - tcx.generics.memoize(def_id, || { - let node_id = tcx.map.as_local_node_id(def_id).unwrap(); - let base_def_id = self.tcx.closure_base_def_id(def_id); - let base_generics = tcx.item_generics(base_def_id); - - // provide junk type parameter defs - the only place that - // cares about anything but the length is instantiation, - // and we don't do that for closures. - let upvar_decls : Vec<_> = tcx.with_freevars(node_id, |fv| { - fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef { - index: (base_generics.count() as u32) + (i as u32), - name: token::intern(""), - def_id: def_id, - default_def_id: base_def_id, - default: None, - object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, - pure_wrt_drop: false, - }).collect() - }); - - tcx.alloc_generics(ty::Generics { - parent: Some(base_def_id), - parent_regions: base_generics.parent_regions + - (base_generics.regions.len() as u32), - parent_types: base_generics.parent_types + - (base_generics.types.len() as u32), - regions: vec![], - types: upvar_decls, - has_self: false, - }) - }); - - tcx.item_types.memoize(def_id, || tcx.mk_closure(def_id, Substs::for_item( - tcx, def_id, - |def, _| tcx.mk_region(def.to_early_bound_region()), - |def, _| tcx.mk_param_from_def(def) - ))); - } - fn check_closure(&self, expr: &hir::Expr, opt_kind: Option, @@ -99,8 +52,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expected_sig); let expr_def_id = self.tcx.map.local_def_id(expr.id); - self.declare_closure(expr_def_id); - let mut fn_ty = AstConv::ty_of_closure(self, hir::Unsafety::Normal, decl, @@ -110,18 +61,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Create type variables (for now) to represent the transformed // types of upvars. These will be unified during the upvar // inference phase (`upvar.rs`). - let num_upvars = self.tcx.with_freevars(expr.id, |fv| fv.len()); - let upvar_tys = self.next_ty_vars(num_upvars); - - debug!("check_closure: expr.id={:?} upvar_tys={:?}", - expr.id, - upvar_tys); - - let closure_type = self.tcx.mk_closure( - expr_def_id, - self.parameter_environment.free_substs.extend_with_types(self.tcx, &upvar_tys) + let closure_type = self.tcx.mk_closure(expr_def_id, + self.parameter_environment.free_substs.extend_to(self.tcx, expr_def_id, + |_, _| span_bug!(expr.span, "closure has region param"), + |_, _| self.infcx.next_ty_var() + ) ); + debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type); + let fn_sig = self.tcx .liberate_late_bound_regions(self.tcx.region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 968d5d73e7a8..816243b3eab4 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -80,7 +80,7 @@ use std::cell::RefCell; use std::collections::hash_map::Entry::{Occupied, Vacant}; use syntax::{abi, ast, attr}; -use syntax::parse::token::keywords; +use syntax::parse::token::{self, keywords}; use syntax_pos::Span; use rustc::hir::{self, intravisit, map as hir_map, print as pprust}; @@ -134,6 +134,13 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> intravisit::walk_item(self, item); } + fn visit_expr(&mut self, expr: &hir::Expr) { + if let hir::ExprClosure(..) = expr.node { + convert_closure(self.ccx, expr.id); + } + intravisit::walk_expr(self, expr); + } + fn visit_ty(&mut self, ty: &hir::Ty) { if let hir::TyImplTrait(..) = ty.node { let def_id = self.ccx.tcx.map.local_def_id(ty.id); @@ -559,6 +566,40 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ccx.tcx.predicates.borrow_mut().insert(def_id, struct_predicates.clone()); } +fn convert_closure<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + node_id: ast::NodeId) +{ + let tcx = ccx.tcx; + let def_id = tcx.map.local_def_id(node_id); + let base_def_id = tcx.closure_base_def_id(def_id); + let base_generics = generics_of_def_id(ccx, base_def_id); + + // provide junk type parameter defs - the only place that + // cares about anything but the length is instantiation, + // and we don't do that for closures. + let upvar_decls : Vec<_> = tcx.with_freevars(node_id, |fv| { + fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef { + index: (base_generics.count() as u32) + (i as u32), + name: token::intern(""), + def_id: def_id, + default_def_id: base_def_id, + default: None, + object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, + pure_wrt_drop: false, + }).collect() + }); + tcx.generics.borrow_mut().insert(def_id, tcx.alloc_generics(ty::Generics { + parent: Some(base_def_id), + parent_regions: base_generics.parent_regions + (base_generics.regions.len() as u32), + parent_types: base_generics.parent_types + (base_generics.types.len() as u32), + regions: vec![], + types: upvar_decls, + has_self: base_generics.has_self, + })); + + type_of_def_id(ccx, def_id); +} + fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, container: AssociatedItemContainer, id: ast::NodeId, @@ -1504,6 +1545,13 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } } + NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => { + ccx.tcx.mk_closure(def_id, Substs::for_item( + ccx.tcx, def_id, + |def, _| ccx.tcx.mk_region(def.to_early_bound_region()), + |def, _| ccx.tcx.mk_param_from_def(def) + )) + } x => { bug!("unexpected sort of node in type_of_def_id(): {:?}", x); } From f5a05adb25753e73107843fd010abc12c38841ee Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 9 Nov 2016 14:00:26 -0500 Subject: [PATCH 082/177] enable the MSP430 LLVM backend to let people experiment with this target out of tree. The MSP430 architecture is used in 16-bit microcontrollers commonly used in Digital Signal Processing applications. --- src/librustc_llvm/build.rs | 2 +- src/librustc_llvm/lib.rs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 8656bb8bf003..ca80a5269c95 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -66,7 +66,7 @@ fn main() { let is_crossed = target != host; let optional_components = - ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz", "jsbackend"]; + ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz", "jsbackend", "msp430"]; // FIXME: surely we don't need all these components, right? Stuff like mcjit // or interpreter the compiler itself never uses. diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 07b87072c435..65e0dbcad3a6 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -413,6 +413,11 @@ pub fn initialize_available_targets() { LLVMInitializeJSBackendTargetInfo, LLVMInitializeJSBackendTarget, LLVMInitializeJSBackendTargetMC); + init_target!(llvm_component = "msp430", + LLVMInitializeMSP430TargetInfo, + LLVMInitializeMSP430Target, + LLVMInitializeMSP430TargetMC, + LLVMInitializeMSP430AsmPrinter); } pub fn last_error() -> Option { From 30e5667607ca6eb6b6fb8fbe44c420a8de2ea749 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 9 Nov 2016 14:45:44 -0500 Subject: [PATCH 083/177] fix #37673 --- src/librustc_trans/mir/rvalue.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index f25877b1de12..fc691649ae4a 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -729,11 +729,13 @@ fn get_overflow_intrinsic(oop: OverflowOp, bcx: &BlockAndBuilder, ty: Ty) -> Val let new_sty = match ty.sty { TyInt(Is) => match &tcx.sess.target.target.target_pointer_width[..] { + "16" => TyInt(I16), "32" => TyInt(I32), "64" => TyInt(I64), _ => panic!("unsupported target word size") }, TyUint(Us) => match &tcx.sess.target.target.target_pointer_width[..] { + "16" => TyUint(U16), "32" => TyUint(U32), "64" => TyUint(U64), _ => panic!("unsupported target word size") From 4f9f7b014eecc940c06d0cc75f46f153c64c4d2d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 9 Nov 2016 16:56:10 -0500 Subject: [PATCH 084/177] also enable the MSP430 backend in Makefiles --- configure | 2 +- mk/main.mk | 2 +- src/rustllvm/PassWrapper.cpp | 9 ++++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 9c055e7217aa..16d6a90bf391 100755 --- a/configure +++ b/configure @@ -1782,7 +1782,7 @@ do CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=ON" fi - CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend'" + CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430'" CMAKE_ARGS="$CMAKE_ARGS -G '$CFG_CMAKE_GENERATOR'" CMAKE_ARGS="$CMAKE_ARGS $CFG_LLVM_SRC_DIR" diff --git a/mk/main.mk b/mk/main.mk index 07b52593781c..9936c5b59be5 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -285,7 +285,7 @@ endif # LLVM macros ###################################################################### -LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz jsbackend +LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz jsbackend msp430 LLVM_REQUIRED_COMPONENTS=ipo bitreader bitwriter linker asmparser mcjit \ interpreter instrumentation diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 60093e9bd37a..a5ba1d219c36 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -137,13 +137,20 @@ LLVMRustAddPass(LLVMPassManagerRef PM, LLVMPassRef rust_pass) { #define SUBTARGET_SYSTEMZ #endif +#ifdef LLVM_COMPONENT_MSP430 +#define SUBTARGET_MSP430 SUBTARGET(MSP430) +#else +#define SUBTARGET_MSP430 +#endif + #define GEN_SUBTARGETS \ SUBTARGET_X86 \ SUBTARGET_ARM \ SUBTARGET_AARCH64 \ SUBTARGET_MIPS \ SUBTARGET_PPC \ - SUBTARGET_SYSTEMZ + SUBTARGET_SYSTEMZ \ + SUBTARGET_MSP430 #define SUBTARGET(x) namespace llvm { \ extern const SubtargetFeatureKV x##FeatureKV[]; \ From 7b559368699c1d4c0df1e3d813c8a84dba3118aa Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 9 Nov 2016 16:57:14 -0500 Subject: [PATCH 085/177] oops, forgot to commit a rustbuild related file --- src/bootstrap/native.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 358cfac74277..96d1b695dd70 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -79,7 +79,8 @@ pub fn llvm(build: &Build, target: &str) { .out_dir(&dst) .profile(profile) .define("LLVM_ENABLE_ASSERTIONS", assertions) - .define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend") + .define("LLVM_TARGETS_TO_BUILD", + "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430") .define("LLVM_INCLUDE_EXAMPLES", "OFF") .define("LLVM_INCLUDE_TESTS", "OFF") .define("LLVM_INCLUDE_DOCS", "OFF") From fcde9904dbe7c4426a72b39a49b892eadb5a8940 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 9 Nov 2016 19:05:32 -0500 Subject: [PATCH 086/177] use msp430-as to emit object files from the assembly that LLVM emits --- src/librustc_back/target/mod.rs | 7 +++ src/librustc_trans/back/write.rs | 83 +++++++++++++++++++++++++++++--- 2 files changed, 83 insertions(+), 7 deletions(-) diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 14fe02269d14..f6a0946dd5b8 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -359,6 +359,10 @@ pub struct TargetOptions { // will 'just work'. pub obj_is_bitcode: bool, + // LLVM can't produce object files for MSP430. Instead, we'll make LLVM emit + // assembly and then use `msp430-as` to turn that assembly into an object file + pub obj_needs_as: bool, + /// Don't use this field; instead use the `.max_atomic_width()` method. pub max_atomic_width: Option, @@ -416,6 +420,7 @@ impl Default for TargetOptions { allow_asm: true, has_elf_tls: false, obj_is_bitcode: false, + obj_needs_as: false, max_atomic_width: None, panic_strategy: PanicStrategy::Unwind, abi_blacklist: vec![], @@ -576,6 +581,7 @@ impl Target { key!(exe_allocation_crate); key!(has_elf_tls, bool); key!(obj_is_bitcode, bool); + key!(obj_needs_as, bool); key!(max_atomic_width, Option); try!(key!(panic_strategy, PanicStrategy)); @@ -735,6 +741,7 @@ impl ToJson for Target { target_option_val!(exe_allocation_crate); target_option_val!(has_elf_tls); target_option_val!(obj_is_bitcode); + target_option_val!(obj_needs_as); target_option_val!(max_atomic_width); target_option_val!(panic_strategy); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 9012914deeb0..0af7c66ccd42 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -26,6 +26,9 @@ use errors::emitter::Emitter; use syntax_pos::MultiSpan; use context::{is_pie_binary, get_reloc_model}; +use std::ascii; +use std::char; +use std::process::Command; use std::ffi::{CStr, CString}; use std::fs; use std::path::{Path, PathBuf}; @@ -262,6 +265,9 @@ pub struct ModuleConfig { // make the object file bitcode. Provides easy compatibility with // emscripten's ecc compiler, when used as the linker. obj_is_bitcode: bool, + // LLVM can't produce object files for MSP430. Instead, we'll make LLVM emit + // assembly and then use `msp430-as` to turn that assembly into an object file + obj_needs_as: bool, } unsafe impl Send for ModuleConfig { } @@ -281,6 +287,7 @@ impl ModuleConfig { emit_asm: false, emit_obj: false, obj_is_bitcode: false, + obj_needs_as: false, no_verify: false, no_prepopulate_passes: false, @@ -300,6 +307,7 @@ impl ModuleConfig { self.time_passes = sess.time_passes(); self.inline_threshold = sess.opts.cg.inline_threshold; self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode; + self.obj_needs_as = sess.target.target.options.obj_needs_as; // Copy what clang does by turning on loop vectorization at O2 and // slp vectorization at O3. Otherwise configure other optimization aspects @@ -557,10 +565,13 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, // machine code, instead copy the .o file from the .bc let write_bc = config.emit_bc || config.obj_is_bitcode; let rm_bc = !config.emit_bc && config.obj_is_bitcode; + let write_asm = config.emit_asm || config.obj_needs_as; + let rm_asm = !config.emit_obj && config.obj_needs_as; let write_obj = config.emit_obj && !config.obj_is_bitcode; let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode; let bc_out = output_names.temp_path(OutputType::Bitcode, module_name); + let asm_out = output_names.temp_path(OutputType::Assembly, module_name); let obj_out = output_names.temp_path(OutputType::Object, module_name); if write_bc { @@ -578,27 +589,25 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, }) } - if config.emit_asm { - let path = output_names.temp_path(OutputType::Assembly, module_name); - + if write_asm { // We can't use the same module for asm and binary output, because that triggers // various errors like invalid IR or broken binaries, so we might have to clone the // module to produce the asm output - let llmod = if config.emit_obj { + let llmod = if config.emit_obj && !config.obj_needs_as { llvm::LLVMCloneModule(llmod) } else { llmod }; with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file(cgcx.handler, tm, cpm, llmod, &path, + write_output_file(cgcx.handler, tm, cpm, llmod, &asm_out, llvm::FileType::AssemblyFile); }); - if config.emit_obj { + if config.emit_obj && !config.obj_needs_as { llvm::LLVMDisposeModule(llmod); } } - if write_obj { + if write_obj && !config.obj_needs_as { with_codegen(tm, llmod, config.no_builtins, |cpm| { write_output_file(cgcx.handler, tm, cpm, llmod, &obj_out, llvm::FileType::ObjectFile); @@ -613,6 +622,59 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, } } + if config.obj_needs_as { + // XXX most of the logic here has been copied from the link_natively + // function (src/librustc_trans/back/link.rs) + // TODO don't hardcode, maybe expose as a `as` field in the target + // specification + // TODO how to properly access `sess` here? + let mut cmd = Command::new("msp430-as"); + cmd.arg("-o"); + cmd.arg(obj_out); + cmd.arg(&asm_out); + + info!("{:?}", &cmd); + // let prog = time(sess.time_passes(), "running assembler", + // || cmd.output()); + let prog = cmd.output(); + match prog { + Ok(prog) => { + fn escape_string(s: &[u8]) -> String { + str::from_utf8(s).map(|s| s.to_owned()) + .unwrap_or_else(|_| { + let mut x = "Non-UTF-8 output: ".to_string(); + x.extend(s.iter() + .flat_map(|&b| ascii::escape_default(b)) + .map(|b| char::from_u32(b as u32).unwrap())); + x + }) + } + if !prog.status.success() { + let mut output = prog.stderr.clone(); + output.extend_from_slice(&prog.stdout); + // sess.struct_err(&format!("assembling with `msp430-as` failed: {}", + // prog.status)) + // .note(&format!("{:?}", &cmd)) + // .note(&escape_string(&output[..])) + // .emit(); + // sess.abort_if_errors(); + } + info!("linker stderr:\n{}", escape_string(&prog.stderr[..])); + info!("linker stdout:\n{}", escape_string(&prog.stdout[..])); + }, + Err(_) => { + // sess.struct_err(&format!("could not exec the assembler `msp430-as`: {}", e)) + // .note(&format!("{:?}", &cmd)) + // .emit(); + // if e.kind() == io::ErrorKind::NotFound { + // sess.note_without_error("MSP430 targets depend on the MSP430 assembler \ + // but `msp430-as` was not found"); + // } + // sess.abort_if_errors(); + }, + } + } + if rm_bc { debug!("removing_bitcode {:?}", bc_out); if let Err(e) = fs::remove_file(&bc_out) { @@ -620,6 +682,13 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, } } + if rm_asm { + debug!("removing_assembly {:?}", bc_out); + if let Err(e) = fs::remove_file(&asm_out) { + cgcx.handler.err(&format!("failed to remove assembly: {}", e)); + } + } + llvm::LLVMRustDisposeTargetMachine(tm); } From a6a247798619cf513fcab2421bade4dc99994e67 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 12 Nov 2016 17:30:06 -0500 Subject: [PATCH 087/177] use write::run_assembler --- src/librustc_back/target/mod.rs | 13 ++--- src/librustc_driver/driver.rs | 13 ++++- src/librustc_trans/back/write.rs | 83 +++----------------------------- 3 files changed, 26 insertions(+), 83 deletions(-) diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index f6a0946dd5b8..cc04582b19e2 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -359,9 +359,10 @@ pub struct TargetOptions { // will 'just work'. pub obj_is_bitcode: bool, - // LLVM can't produce object files for MSP430. Instead, we'll make LLVM emit - // assembly and then use `msp430-as` to turn that assembly into an object file - pub obj_needs_as: bool, + // LLVM can't produce object files for this target. Instead, we'll make LLVM + // emit assembly and then use `gcc` to turn that assembly into an object + // file + pub no_integrated_as: bool, /// Don't use this field; instead use the `.max_atomic_width()` method. pub max_atomic_width: Option, @@ -420,7 +421,7 @@ impl Default for TargetOptions { allow_asm: true, has_elf_tls: false, obj_is_bitcode: false, - obj_needs_as: false, + no_integrated_as: false, max_atomic_width: None, panic_strategy: PanicStrategy::Unwind, abi_blacklist: vec![], @@ -581,7 +582,7 @@ impl Target { key!(exe_allocation_crate); key!(has_elf_tls, bool); key!(obj_is_bitcode, bool); - key!(obj_needs_as, bool); + key!(no_integrated_as, bool); key!(max_atomic_width, Option); try!(key!(panic_strategy, PanicStrategy)); @@ -741,7 +742,7 @@ impl ToJson for Target { target_option_val!(exe_allocation_crate); target_option_val!(has_elf_tls); target_option_val!(obj_is_bitcode); - target_option_val!(obj_needs_as); + target_option_val!(no_integrated_as); target_option_val!(max_atomic_width); target_option_val!(panic_strategy); diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index d83918495676..48bf490d685b 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1056,7 +1056,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn phase_5_run_llvm_passes(sess: &Session, trans: &trans::CrateTranslation, outputs: &OutputFilenames) -> CompileResult { - if sess.opts.cg.no_integrated_as { + if sess.opts.cg.no_integrated_as || sess.target.target.options.no_integrated_as { let output_types = OutputTypes::new(&[(OutputType::Assembly, None)]); time(sess.time_passes(), "LLVM passes", @@ -1064,6 +1064,17 @@ pub fn phase_5_run_llvm_passes(sess: &Session, write::run_assembler(sess, outputs); + // HACK the linker expects the object file to be named foo.0.o but + // `run_assembler` produces an object named just foo.o. Rename it if we + // are going to build an executable + if sess.opts.output_types.contains_key(&OutputType::Exe) { + let f = outputs.path(OutputType::Object); + fs::copy(&f, + f.with_file_name(format!("{}.0.o", + f.file_stem().unwrap().to_string_lossy()))).unwrap(); + fs::remove_file(f).unwrap(); + } + // Remove assembly source, unless --save-temps was specified if !sess.opts.cg.save_temps { fs::remove_file(&outputs.temp_path(OutputType::Assembly, None)).unwrap(); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 0af7c66ccd42..9012914deeb0 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -26,9 +26,6 @@ use errors::emitter::Emitter; use syntax_pos::MultiSpan; use context::{is_pie_binary, get_reloc_model}; -use std::ascii; -use std::char; -use std::process::Command; use std::ffi::{CStr, CString}; use std::fs; use std::path::{Path, PathBuf}; @@ -265,9 +262,6 @@ pub struct ModuleConfig { // make the object file bitcode. Provides easy compatibility with // emscripten's ecc compiler, when used as the linker. obj_is_bitcode: bool, - // LLVM can't produce object files for MSP430. Instead, we'll make LLVM emit - // assembly and then use `msp430-as` to turn that assembly into an object file - obj_needs_as: bool, } unsafe impl Send for ModuleConfig { } @@ -287,7 +281,6 @@ impl ModuleConfig { emit_asm: false, emit_obj: false, obj_is_bitcode: false, - obj_needs_as: false, no_verify: false, no_prepopulate_passes: false, @@ -307,7 +300,6 @@ impl ModuleConfig { self.time_passes = sess.time_passes(); self.inline_threshold = sess.opts.cg.inline_threshold; self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode; - self.obj_needs_as = sess.target.target.options.obj_needs_as; // Copy what clang does by turning on loop vectorization at O2 and // slp vectorization at O3. Otherwise configure other optimization aspects @@ -565,13 +557,10 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, // machine code, instead copy the .o file from the .bc let write_bc = config.emit_bc || config.obj_is_bitcode; let rm_bc = !config.emit_bc && config.obj_is_bitcode; - let write_asm = config.emit_asm || config.obj_needs_as; - let rm_asm = !config.emit_obj && config.obj_needs_as; let write_obj = config.emit_obj && !config.obj_is_bitcode; let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode; let bc_out = output_names.temp_path(OutputType::Bitcode, module_name); - let asm_out = output_names.temp_path(OutputType::Assembly, module_name); let obj_out = output_names.temp_path(OutputType::Object, module_name); if write_bc { @@ -589,25 +578,27 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, }) } - if write_asm { + if config.emit_asm { + let path = output_names.temp_path(OutputType::Assembly, module_name); + // We can't use the same module for asm and binary output, because that triggers // various errors like invalid IR or broken binaries, so we might have to clone the // module to produce the asm output - let llmod = if config.emit_obj && !config.obj_needs_as { + let llmod = if config.emit_obj { llvm::LLVMCloneModule(llmod) } else { llmod }; with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file(cgcx.handler, tm, cpm, llmod, &asm_out, + write_output_file(cgcx.handler, tm, cpm, llmod, &path, llvm::FileType::AssemblyFile); }); - if config.emit_obj && !config.obj_needs_as { + if config.emit_obj { llvm::LLVMDisposeModule(llmod); } } - if write_obj && !config.obj_needs_as { + if write_obj { with_codegen(tm, llmod, config.no_builtins, |cpm| { write_output_file(cgcx.handler, tm, cpm, llmod, &obj_out, llvm::FileType::ObjectFile); @@ -622,59 +613,6 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, } } - if config.obj_needs_as { - // XXX most of the logic here has been copied from the link_natively - // function (src/librustc_trans/back/link.rs) - // TODO don't hardcode, maybe expose as a `as` field in the target - // specification - // TODO how to properly access `sess` here? - let mut cmd = Command::new("msp430-as"); - cmd.arg("-o"); - cmd.arg(obj_out); - cmd.arg(&asm_out); - - info!("{:?}", &cmd); - // let prog = time(sess.time_passes(), "running assembler", - // || cmd.output()); - let prog = cmd.output(); - match prog { - Ok(prog) => { - fn escape_string(s: &[u8]) -> String { - str::from_utf8(s).map(|s| s.to_owned()) - .unwrap_or_else(|_| { - let mut x = "Non-UTF-8 output: ".to_string(); - x.extend(s.iter() - .flat_map(|&b| ascii::escape_default(b)) - .map(|b| char::from_u32(b as u32).unwrap())); - x - }) - } - if !prog.status.success() { - let mut output = prog.stderr.clone(); - output.extend_from_slice(&prog.stdout); - // sess.struct_err(&format!("assembling with `msp430-as` failed: {}", - // prog.status)) - // .note(&format!("{:?}", &cmd)) - // .note(&escape_string(&output[..])) - // .emit(); - // sess.abort_if_errors(); - } - info!("linker stderr:\n{}", escape_string(&prog.stderr[..])); - info!("linker stdout:\n{}", escape_string(&prog.stdout[..])); - }, - Err(_) => { - // sess.struct_err(&format!("could not exec the assembler `msp430-as`: {}", e)) - // .note(&format!("{:?}", &cmd)) - // .emit(); - // if e.kind() == io::ErrorKind::NotFound { - // sess.note_without_error("MSP430 targets depend on the MSP430 assembler \ - // but `msp430-as` was not found"); - // } - // sess.abort_if_errors(); - }, - } - } - if rm_bc { debug!("removing_bitcode {:?}", bc_out); if let Err(e) = fs::remove_file(&bc_out) { @@ -682,13 +620,6 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, } } - if rm_asm { - debug!("removing_assembly {:?}", bc_out); - if let Err(e) = fs::remove_file(&asm_out) { - cgcx.handler.err(&format!("failed to remove assembly: {}", e)); - } - } - llvm::LLVMRustDisposeTargetMachine(tm); } From 2b3a37bd2e35458b4d66f13c4d3ad924455ac2bb Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Sun, 13 Nov 2016 00:11:16 +0100 Subject: [PATCH 088/177] Restore Vec::from_iter() specialization Since I said "no intentional functional change" in the previous commit, I guess it was inevitable there were unintentional changes. Not functional, but optimization-wise. This restores the extend specialization's use in Vec::from_iter. --- src/libcollections/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 53b7ae0703bf..5477a1f6331b 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1517,7 +1517,7 @@ impl FromIterator for Vec { vector } }; - vector.extend_desugared(iterator); + vector.extend(iterator); vector } } From c36edc726156c7868c6845c0e39b5231e35bc1ff Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Sun, 13 Nov 2016 01:09:27 +0100 Subject: [PATCH 089/177] vec: Use less code bloat specialized Vec::from_iter Vec::from_iter's general case allocates the vector up front; this is redundant for the TrustedLen case, and can then be avoided to reduce the size of the code. --- src/libcollections/vec.rs | 51 ++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 5477a1f6331b..24f8e3a2d918 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1499,26 +1499,7 @@ impl ops::DerefMut for Vec { impl FromIterator for Vec { #[inline] fn from_iter>(iter: I) -> Vec { - // Unroll the first iteration, as the vector is going to be - // expanded on this iteration in every case when the iterable is not - // empty, but the loop in extend_desugared() is not going to see the - // vector being full in the few subsequent loop iterations. - // So we get better branch prediction. - let mut iterator = iter.into_iter(); - let mut vector = match iterator.next() { - None => return Vec::new(), - Some(element) => { - let (lower, _) = iterator.size_hint(); - let mut vector = Vec::with_capacity(lower.saturating_add(1)); - unsafe { - ptr::write(vector.get_unchecked_mut(0), element); - vector.set_len(1); - } - vector - } - }; - vector.extend(iterator); - vector + >::from_iter(iter.into_iter()) } } @@ -1590,13 +1571,37 @@ impl Extend for Vec { } } +// Specialization trait used for Vec::from_iter and Vec::extend trait SpecExtend { + fn from_iter(iter: I) -> Self; fn spec_extend(&mut self, iter: I); } impl SpecExtend for Vec where I: Iterator, { + default fn from_iter(mut iterator: I) -> Self { + // Unroll the first iteration, as the vector is going to be + // expanded on this iteration in every case when the iterable is not + // empty, but the loop in extend_desugared() is not going to see the + // vector being full in the few subsequent loop iterations. + // So we get better branch prediction. + let mut vector = match iterator.next() { + None => return Vec::new(), + Some(element) => { + let (lower, _) = iterator.size_hint(); + let mut vector = Vec::with_capacity(lower.saturating_add(1)); + unsafe { + ptr::write(vector.get_unchecked_mut(0), element); + vector.set_len(1); + } + vector + } + }; + vector.spec_extend(iterator); + vector + } + default fn spec_extend(&mut self, iter: I) { self.extend_desugared(iter) } @@ -1605,6 +1610,12 @@ impl SpecExtend for Vec impl SpecExtend for Vec where I: TrustedLen, { + fn from_iter(iterator: I) -> Self { + let mut vector = Vec::new(); + vector.spec_extend(iterator); + vector + } + fn spec_extend(&mut self, iterator: I) { // This is the case for a TrustedLen iterator. let (low, high) = iterator.size_hint(); From 7a91d4a25b2b063bf1e1f8cfd1b8d0fd89d84dd0 Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Sat, 12 Nov 2016 19:13:22 -0600 Subject: [PATCH 090/177] Add llvm debuginfo configure option --- configure | 4 ++++ mk/llvm.mk | 2 ++ 2 files changed, 6 insertions(+) diff --git a/configure b/configure index 9c055e7217aa..c6f818299ff0 100755 --- a/configure +++ b/configure @@ -642,6 +642,7 @@ opt_nosave optimize-cxx 1 "build optimized C++ code" opt_nosave optimize-llvm 1 "build optimized LLVM" opt_nosave llvm-assertions 0 "build LLVM with assertions" opt_nosave debug-assertions 0 "build with debugging assertions" +opt_nosave llvm-debuginfo 0 "build LLVM with debugger metadata" opt_nosave debuginfo 0 "build with debugger metadata" opt_nosave debuginfo-lines 0 "build with line number debugger metadata" opt_nosave debug-jemalloc 0 "build jemalloc with --enable-debug --enable-fill" @@ -778,6 +779,7 @@ if [ -n "$CFG_DISABLE_OPTIMIZE_CXX" ]; then putvar CFG_DISABLE_OPTIMIZE_CXX; fi if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then putvar CFG_DISABLE_OPTIMIZE_LLVM; fi if [ -n "$CFG_ENABLE_LLVM_ASSERTIONS" ]; then putvar CFG_ENABLE_LLVM_ASSERTIONS; fi if [ -n "$CFG_ENABLE_DEBUG_ASSERTIONS" ]; then putvar CFG_ENABLE_DEBUG_ASSERTIONS; fi +if [ -n "$CFG_ENABLE_LLVM_DEBUGINFO" ]; then putvar CFG_ENABLE_LLVM_DEBUGINFO; fi if [ -n "$CFG_ENABLE_DEBUGINFO" ]; then putvar CFG_ENABLE_DEBUGINFO; fi if [ -n "$CFG_ENABLE_DEBUGINFO_LINES" ]; then putvar CFG_ENABLE_DEBUGINFO_LINES; fi if [ -n "$CFG_ENABLE_DEBUG_JEMALLOC" ]; then putvar CFG_ENABLE_DEBUG_JEMALLOC; fi @@ -1772,6 +1774,8 @@ do if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Debug" + elif [ -n "$CFG_ENABLE_LLVM_DEBUGINFO" ]; then + CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=RelWithDebInfo" else CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release" fi diff --git a/mk/llvm.mk b/mk/llvm.mk index 5a91f5fcaa48..842f1bcee119 100644 --- a/mk/llvm.mk +++ b/mk/llvm.mk @@ -21,6 +21,8 @@ endif ifdef CFG_DISABLE_OPTIMIZE_LLVM LLVM_BUILD_CONFIG_MODE := Debug +else ifdef CFG_ENABLE_LLVM_DEBUGINFO +LLVM_BUILD_CONFIG_MODE := RelWithDebInfo else LLVM_BUILD_CONFIG_MODE := Release endif From 48b5192cf7ac6d16fd9c981c5cc745967c6504ef Mon Sep 17 00:00:00 2001 From: Reza Akhavan Date: Sat, 12 Nov 2016 18:24:16 -0800 Subject: [PATCH 091/177] Minor grammar fix to ffi.md --- src/doc/book/ffi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 8709c3f4b7b1..cae5d3eb46a7 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -95,7 +95,7 @@ internal details. Wrapping the functions which expect buffers involves using the `slice::raw` module to manipulate Rust vectors as pointers to memory. Rust's vectors are guaranteed to be a contiguous block of memory. The -length is number of elements currently contained, and the capacity is the total size in elements of +length is the number of elements currently contained, and the capacity is the total size in elements of the allocated memory. The length is less than or equal to the capacity. ```rust From e7cae415ea207732a199dbdd23fb2baee1946d63 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 13 Nov 2016 11:03:44 -0500 Subject: [PATCH 092/177] add cabi_msp430 --- src/librustc_trans/abi.rs | 2 ++ src/librustc_trans/cabi_msp430.rs | 59 +++++++++++++++++++++++++++++++ src/librustc_trans/lib.rs | 1 + 3 files changed, 62 insertions(+) create mode 100644 src/librustc_trans/cabi_msp430.rs diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 0a5b013c79ac..f2e15a8973c9 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -24,6 +24,7 @@ use cabi_s390x; use cabi_mips; use cabi_mips64; use cabi_asmjs; +use cabi_msp430; use machine::{llalign_of_min, llsize_of, llsize_of_alloc}; use type_::Type; use type_of; @@ -520,6 +521,7 @@ impl FnType { "s390x" => cabi_s390x::compute_abi_info(ccx, self), "asmjs" => cabi_asmjs::compute_abi_info(ccx, self), "wasm32" => cabi_asmjs::compute_abi_info(ccx, self), + "msp430" => cabi_msp430::compute_abi_info(ccx, self), a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a)) } diff --git a/src/librustc_trans/cabi_msp430.rs b/src/librustc_trans/cabi_msp430.rs new file mode 100644 index 000000000000..aa90bb7ab753 --- /dev/null +++ b/src/librustc_trans/cabi_msp430.rs @@ -0,0 +1,59 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Reference: MSP430 Embedded Application Binary Interface +// http://www.ti.com/lit/an/slaa534/slaa534.pdf + +#![allow(non_upper_case_globals)] + +use llvm::Struct; + +use abi::{self, ArgType, FnType}; +use context::CrateContext; +use type_::Type; + +fn ty_size(ty: Type) -> usize { + abi::ty_size(ty, 2) +} + +// 3.5 Structures or Unions Passed and Returned by Reference +// +// "Structures (including classes) and unions larger than 32 bits are passed and +// returned by reference. To pass a structure or union by reference, the caller +// places its address in the appropriate location: either in a register or on +// the stack, according to its position in the argument list. (..)" +fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { + if ret.ty.kind() == Struct && ty_size(ret.ty) > 32 { + ret.make_indirect(ccx); + } else { + ret.extend_integer_width_to(16); + } +} + +fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { + if arg.ty.kind() == Struct && ty_size(arg.ty) > 32 { + arg.make_indirect(ccx); + } else { + arg.extend_integer_width_to(16); + } +} + +pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { + if !fty.ret.is_ignore() { + classify_ret_ty(ccx, &mut fty.ret); + } + + for arg in &mut fty.args { + if arg.is_ignore() { + continue; + } + classify_arg_ty(ccx, arg); + } +} diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 8ef7f04d4ee1..f189f22d925b 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -101,6 +101,7 @@ mod cabi_arm; mod cabi_asmjs; mod cabi_mips; mod cabi_mips64; +mod cabi_msp430; mod cabi_powerpc; mod cabi_powerpc64; mod cabi_s390x; From b8fc5120df92b5e5b7293f90230322a2b419178f Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 13 Nov 2016 18:54:39 +0200 Subject: [PATCH 093/177] coherence: skip impls with an erroneous trait ref Impls with a erroneous trait ref are already ignored in the first part of coherence, so ignore them in the second part too. This avoids cascading coherence errors when 1 impl of a trait has an error. --- src/librustc_typeck/coherence/overlap.rs | 8 +++++- .../coherence-error-suppression.rs | 25 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/coherence-error-suppression.rs diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index b5aba512a66b..df3a79f09bd0 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -14,7 +14,7 @@ use hir::def_id::DefId; use rustc::traits::{self, Reveal}; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, TyCtxt, TypeFoldable}; use syntax::ast; use rustc::dep_graph::DepNode; use rustc::hir; @@ -134,6 +134,12 @@ impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap(); let trait_def_id = trait_ref.def_id; + if trait_ref.references_error() { + debug!("coherence: skipping impl {:?} with error {:?}", + impl_def_id, trait_ref); + return + } + let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id)); diff --git a/src/test/compile-fail/coherence-error-suppression.rs b/src/test/compile-fail/coherence-error-suppression.rs new file mode 100644 index 000000000000..b33f27fbc8a0 --- /dev/null +++ b/src/test/compile-fail/coherence-error-suppression.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// check that error types in coherence do not cause error cascades. + +trait Foo {} + +impl Foo for i8 {} +impl Foo for i16 {} +impl Foo for i32 {} +impl Foo for i64 {} +impl Foo for DoesNotExist {} //~ ERROR `DoesNotExist` is undefined +impl Foo for u8 {} +impl Foo for u16 {} +impl Foo for u32 {} +impl Foo for u64 {} + +fn main() {} From 34f33ec789297716995045f7067aeb4d77947d89 Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 13 Nov 2016 17:55:17 +0100 Subject: [PATCH 094/177] Fix empty lifetime list or one with trailing comma being rejected Fixes #37733 --- src/libsyntax/parse/parser.rs | 6 +++--- src/test/run-pass/issue-37733.rs | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 src/test/run-pass/issue-37733.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b80aa667be6a..064c93c2866e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1943,12 +1943,12 @@ impl<'a> Parser<'a> { if let Some(recv) = followed_by_ty_params { assert!(recv.is_empty()); *recv = attrs; - } else { + debug!("parse_lifetime_defs ret {:?}", res); + return Ok(res); + } else if !attrs.is_empty() { let msg = "trailing attribute after lifetime parameters"; return Err(self.fatal(msg)); } - debug!("parse_lifetime_defs ret {:?}", res); - return Ok(res); } } diff --git a/src/test/run-pass/issue-37733.rs b/src/test/run-pass/issue-37733.rs new file mode 100644 index 000000000000..358b93254de9 --- /dev/null +++ b/src/test/run-pass/issue-37733.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +type A = for<> fn(); + +type B = for<'a,> fn(); + +pub fn main() {} From f53d062d427f31211ebcb664dc4d7716ef66d8d8 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 13 Nov 2016 12:57:03 -0500 Subject: [PATCH 095/177] Minor rewriting of `std::path::Path::push` doc example. --- src/libstd/path.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index bb6883236e80..281e2f17ae61 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -983,17 +983,24 @@ impl PathBuf { /// /// # Examples /// + /// Pushing a relative path extends the existing path: + /// /// ``` /// use std::path::PathBuf; /// - /// let mut path = PathBuf::new(); - /// path.push("/tmp"); + /// let mut path = PathBuf::from("/tmp"); /// path.push("file.bk"); /// assert_eq!(path, PathBuf::from("/tmp/file.bk")); + /// ``` /// - /// // Pushing an absolute path replaces the current path - /// path.push("/etc/passwd"); - /// assert_eq!(path, PathBuf::from("/etc/passwd")); + /// Pushing an absolute path replaces the existing path: + /// + /// ``` + /// use std::path::PathBuf; + /// + /// let mut path = PathBuf::from("/tmp"); + /// path.push("/etc"); + /// assert_eq!(path, PathBuf::from("/etc")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn push>(&mut self, path: P) { From aea1a5156177932c4ec8cf5a24a5c05e0a6b15aa Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Sun, 13 Nov 2016 12:27:57 -0600 Subject: [PATCH 096/177] Let rustbuild parse llvm debuginfo option update_with_config_mk() needs to read the new llvm debuginfo config option from config.mk. Other than that, rustbuild already supports LLVM's RelWithDebInfo build type. --- src/bootstrap/config.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 50c703a73540..bea475fb07b2 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -339,6 +339,7 @@ impl Config { ("COMPILER_DOCS", self.compiler_docs), ("DOCS", self.docs), ("LLVM_ASSERTIONS", self.llvm_assertions), + ("LLVM_DEBUGINFO", self.llvm_release_debuginfo), ("OPTIMIZE_LLVM", self.llvm_optimize), ("LLVM_VERSION_CHECK", self.llvm_version_check), ("LLVM_STATIC_STDCPP", self.llvm_static_stdcpp), From 28548db57d0acbc00ee80b43816953dbe31d53ba Mon Sep 17 00:00:00 2001 From: Angelo Polo Date: Sun, 13 Nov 2016 13:31:34 -0500 Subject: [PATCH 097/177] Improved punctuation, capitalization, and sentence structure of code snippet comments --- src/doc/book/associated-types.md | 4 +- src/doc/book/benchmark-tests.md | 2 +- src/doc/book/box-syntax-and-patterns.md | 4 +- src/doc/book/casting-between-types.md | 8 ++-- src/doc/book/choosing-your-guarantees.md | 6 +-- src/doc/book/closures.md | 2 +- src/doc/book/comments.md | 2 +- src/doc/book/compiler-plugins.md | 2 +- src/doc/book/concurrency.md | 8 ++-- src/doc/book/crates-and-modules.md | 2 +- src/doc/book/custom-allocators.md | 16 ++++---- src/doc/book/deref-coercions.md | 16 ++++---- src/doc/book/documentation.md | 4 +- src/doc/book/drop.md | 4 +- src/doc/book/enums.md | 2 +- src/doc/book/error-handling.md | 24 ++++++------ src/doc/book/ffi.md | 14 +++---- src/doc/book/functions.md | 10 ++--- src/doc/book/generics.md | 2 +- src/doc/book/guessing-game.md | 4 +- src/doc/book/inline-assembly.md | 4 +- src/doc/book/lang-items.md | 2 +- src/doc/book/lifetimes.md | 45 ++++++++++++----------- src/doc/book/loops.md | 4 +- src/doc/book/macros.md | 20 +++++----- src/doc/book/mutability.md | 8 ++-- src/doc/book/no-stdlib.md | 8 ++-- src/doc/book/operators-and-overloading.md | 2 +- src/doc/book/ownership.md | 10 ++--- src/doc/book/patterns.md | 4 +- src/doc/book/primitive-types.md | 12 +++--- src/doc/book/raw-pointers.md | 4 +- src/doc/book/references-and-borrowing.md | 26 ++++++------- src/doc/book/strings.md | 6 +-- src/doc/book/structs.md | 10 ++--- src/doc/book/testing.md | 2 +- src/doc/book/trait-objects.md | 20 +++++----- src/doc/book/traits.md | 18 ++++----- src/doc/book/unsafe.md | 4 +- src/doc/book/variable-bindings.md | 16 ++++---- src/doc/book/vectors.md | 6 +-- 41 files changed, 184 insertions(+), 183 deletions(-) diff --git a/src/doc/book/associated-types.md b/src/doc/book/associated-types.md index 0998a88c4d24..f416e600415b 100644 --- a/src/doc/book/associated-types.md +++ b/src/doc/book/associated-types.md @@ -11,7 +11,7 @@ this: trait Graph { fn has_edge(&self, &N, &N) -> bool; fn edges(&self, &N) -> Vec; - // etc + // Etc. } ``` @@ -36,7 +36,7 @@ trait Graph { fn has_edge(&self, &Self::N, &Self::N) -> bool; fn edges(&self, &Self::N) -> Vec; - // etc + // Etc. } ``` diff --git a/src/doc/book/benchmark-tests.md b/src/doc/book/benchmark-tests.md index 797ec94774d7..e054736eb30b 100644 --- a/src/doc/book/benchmark-tests.md +++ b/src/doc/book/benchmark-tests.md @@ -110,7 +110,7 @@ computation entirely. This could be done for the example above by adjusting the # struct X; # impl X { fn iter(&self, _: F) where F: FnMut() -> T {} } let b = X; b.iter(|| { - // note lack of `;` (could also use an explicit `return`). + // Note lack of `;` (could also use an explicit `return`). (0..1000).fold(0, |old, new| old ^ new) }); ``` diff --git a/src/doc/book/box-syntax-and-patterns.md b/src/doc/book/box-syntax-and-patterns.md index 8d83b64d6831..cbf65dfa9ba8 100644 --- a/src/doc/book/box-syntax-and-patterns.md +++ b/src/doc/book/box-syntax-and-patterns.md @@ -38,7 +38,7 @@ so as to avoid copying a large data structure. For example: struct BigStruct { one: i32, two: i32, - // etc + // Etc. one_hundred: i32, } @@ -68,7 +68,7 @@ This is an antipattern in Rust. Instead, write this: struct BigStruct { one: i32, two: i32, - // etc + // Etc. one_hundred: i32, } diff --git a/src/doc/book/casting-between-types.md b/src/doc/book/casting-between-types.md index a101f397c379..296384ab6efd 100644 --- a/src/doc/book/casting-between-types.md +++ b/src/doc/book/casting-between-types.md @@ -106,7 +106,7 @@ from integers, and to cast between pointers to different types subject to some constraints. It is only unsafe to dereference the pointer: ```rust -let a = 300 as *const char; // a pointer to location 300 +let a = 300 as *const char; // `a` is a pointer to location 300. let b = a as u32; ``` @@ -135,14 +135,14 @@ cast four bytes into a `u32`: ```rust,ignore let a = [0u8, 0u8, 0u8, 0u8]; -let b = a as u32; // four u8s makes a u32 +let b = a as u32; // Four u8s makes a u32. ``` This errors with: ```text error: non-scalar cast: `[u8; 4]` as `u32` -let b = a as u32; // four u8s makes a u32 +let b = a as u32; // Four u8s makes a u32. ^~~~~~~~ ``` @@ -170,7 +170,7 @@ fn main() { let a = [0u8, 1u8, 0u8, 0u8]; let b = mem::transmute::<[u8; 4], u32>(a); println!("{}", b); // 256 - // or, more concisely: + // Or, more concisely: let c: u32 = mem::transmute(a); println!("{}", c); // 256 } diff --git a/src/doc/book/choosing-your-guarantees.md b/src/doc/book/choosing-your-guarantees.md index d88f619260ac..9dca3479d35e 100644 --- a/src/doc/book/choosing-your-guarantees.md +++ b/src/doc/book/choosing-your-guarantees.md @@ -25,7 +25,7 @@ the following: ```rust let x = Box::new(1); let y = x; -// x no longer accessible here +// `x` is no longer accessible here. ``` Here, the box was _moved_ into `y`. As `x` no longer owns it, the compiler will no longer allow the @@ -291,9 +291,9 @@ the inner data (mutably), and the lock will be released when the guard goes out ```rust,ignore { let guard = mutex.lock(); - // guard dereferences mutably to the inner type + // `guard` dereferences mutably to the inner type. *guard += 1; -} // lock released when destructor runs +} // Lock is released when destructor runs. ``` diff --git a/src/doc/book/closures.md b/src/doc/book/closures.md index fa9f66d43baa..a3c7333c6bec 100644 --- a/src/doc/book/closures.md +++ b/src/doc/book/closures.md @@ -116,7 +116,7 @@ let mut num = 5; { let plus_num = |x: i32| x + num; -} // plus_num goes out of scope, borrow of num ends +} // `plus_num` goes out of scope; borrow of `num` ends. let y = &mut num; ``` diff --git a/src/doc/book/comments.md b/src/doc/book/comments.md index e7eb48dc42c5..8fa397cd9a66 100644 --- a/src/doc/book/comments.md +++ b/src/doc/book/comments.md @@ -10,7 +10,7 @@ and *doc comments*. ```rust // Line comments are anything after ‘//’ and extend to the end of the line. -let x = 5; // this is also a line comment. +let x = 5; // This is also a line comment. // If you have a long explanation for something, you can put line comments next // to each other. Put a space between the // and your comment so that it’s diff --git a/src/doc/book/compiler-plugins.md b/src/doc/book/compiler-plugins.md index a9a81843ab19..ff29358df940 100644 --- a/src/doc/book/compiler-plugins.md +++ b/src/doc/book/compiler-plugins.md @@ -48,7 +48,7 @@ extern crate rustc_plugin; use syntax::parse::token; use syntax::tokenstream::TokenTree; use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; -use syntax::ext::build::AstBuilder; // trait for expr_usize +use syntax::ext::build::AstBuilder; // A trait for expr_usize. use syntax::ext::quote::rt::Span; use rustc_plugin::Registry; diff --git a/src/doc/book/concurrency.md b/src/doc/book/concurrency.md index 41d8345b7209..67d89d5484ca 100644 --- a/src/doc/book/concurrency.md +++ b/src/doc/book/concurrency.md @@ -213,10 +213,10 @@ fn main() { let mut data = Rc::new(vec![1, 2, 3]); for i in 0..3 { - // create a new owned reference + // Create a new owned reference: let data_ref = data.clone(); - // use it in a thread + // Use it in a thread: thread::spawn(move || { data_ref[0] += i; }); @@ -390,8 +390,8 @@ use std::sync::mpsc; fn main() { let data = Arc::new(Mutex::new(0)); - // `tx` is the "transmitter" or "sender" - // `rx` is the "receiver" + // `tx` is the "transmitter" or "sender". + // `rx` is the "receiver". let (tx, rx) = mpsc::channel(); for _ in 0..10 { diff --git a/src/doc/book/crates-and-modules.md b/src/doc/book/crates-and-modules.md index fcb7e0bc7eac..0e336635235b 100644 --- a/src/doc/book/crates-and-modules.md +++ b/src/doc/book/crates-and-modules.md @@ -126,7 +126,7 @@ Instead of declaring a module like this: ```rust,ignore mod english { - // contents of our module go here + // Contents of our module go here. } ``` diff --git a/src/doc/book/custom-allocators.md b/src/doc/book/custom-allocators.md index d69ef6cf7e83..1996305f09e7 100644 --- a/src/doc/book/custom-allocators.md +++ b/src/doc/book/custom-allocators.md @@ -41,7 +41,7 @@ which allocator is in use is done simply by linking to the desired allocator: extern crate alloc_system; fn main() { - let a = Box::new(4); // allocates from the system allocator + let a = Box::new(4); // Allocates from the system allocator. println!("{}", a); } ``` @@ -57,7 +57,7 @@ uses jemalloc by default one would write: extern crate alloc_jemalloc; pub fn foo() { - let a = Box::new(4); // allocates from jemalloc + let a = Box::new(4); // Allocates from jemalloc. println!("{}", a); } # fn main() {} @@ -72,11 +72,11 @@ crate which implements the allocator API (e.g. the same as `alloc_system` or annotated version of `alloc_system` ```rust,no_run -# // only needed for rustdoc --test down below +# // Only needed for rustdoc --test down below. # #![feature(lang_items)] // The compiler needs to be instructed that this crate is an allocator in order // to realize that when this is linked in another allocator like jemalloc should -// not be linked in +// not be linked in. #![feature(allocator)] #![allocator] @@ -85,7 +85,7 @@ annotated version of `alloc_system` // however, can use all of libcore. #![no_std] -// Let's give a unique name to our custom allocator +// Let's give a unique name to our custom allocator: #![crate_name = "my_allocator"] #![crate_type = "rlib"] @@ -126,7 +126,7 @@ pub extern fn __rust_reallocate(ptr: *mut u8, _old_size: usize, size: usize, #[no_mangle] pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, old_size: usize, _size: usize, _align: usize) -> usize { - old_size // this api is not supported by libc + old_size // This api is not supported by libc. } #[no_mangle] @@ -134,7 +134,7 @@ pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize { size } -# // only needed to get rustdoc to test this +# // Only needed to get rustdoc to test this: # fn main() {} # #[lang = "panic_fmt"] fn panic_fmt() {} # #[lang = "eh_personality"] fn eh_personality() {} @@ -149,7 +149,7 @@ After we compile this crate, it can be used as follows: extern crate my_allocator; fn main() { - let a = Box::new(8); // allocates memory via our custom allocator crate + let a = Box::new(8); // Allocates memory via our custom allocator crate. println!("{}", a); } ``` diff --git a/src/doc/book/deref-coercions.md b/src/doc/book/deref-coercions.md index cabe66f5b228..864cd282d937 100644 --- a/src/doc/book/deref-coercions.md +++ b/src/doc/book/deref-coercions.md @@ -33,13 +33,13 @@ automatically coerce to a `&T`. Here’s an example: ```rust fn foo(s: &str) { - // borrow a string for a second + // Borrow a string for a second. } -// String implements Deref +// String implements Deref. let owned = "Hello".to_string(); -// therefore, this works: +// Therefore, this works: foo(&owned); ``` @@ -55,14 +55,14 @@ type implements `Deref`, so this works: use std::rc::Rc; fn foo(s: &str) { - // borrow a string for a second + // Borrow a string for a second. } -// String implements Deref +// String implements Deref. let owned = "Hello".to_string(); let counted = Rc::new(owned); -// therefore, this works: +// Therefore, this works: foo(&counted); ``` @@ -76,10 +76,10 @@ Another very common implementation provided by the standard library is: ```rust fn foo(s: &[i32]) { - // borrow a slice for a second + // Borrow a slice for a second. } -// Vec implements Deref +// Vec implements Deref. let owned = vec![1, 2, 3]; foo(&owned); diff --git a/src/doc/book/documentation.md b/src/doc/book/documentation.md index 6292ba9aac40..f30a95b4e789 100644 --- a/src/doc/book/documentation.md +++ b/src/doc/book/documentation.md @@ -28,7 +28,7 @@ code. You can use documentation comments for this purpose: /// let five = Rc::new(5); /// ``` pub fn new(value: T) -> Rc { - // implementation goes here + // Implementation goes here. } ``` @@ -483,7 +483,7 @@ you have a module in `foo.rs`, you'll often open its code and see this: ```rust //! A module for using `foo`s. //! -//! The `foo` module contains a lot of useful functionality blah blah blah +//! The `foo` module contains a lot of useful functionality blah blah blah... ``` ### Crate documentation diff --git a/src/doc/book/drop.md b/src/doc/book/drop.md index 5513523e56b9..0b7ddcfbe885 100644 --- a/src/doc/book/drop.md +++ b/src/doc/book/drop.md @@ -18,9 +18,9 @@ impl Drop for HasDrop { fn main() { let x = HasDrop; - // do stuff + // Do stuff. -} // x goes out of scope here +} // `x` goes out of scope here. ``` When `x` goes out of scope at the end of `main()`, the code for `Drop` will diff --git a/src/doc/book/enums.md b/src/doc/book/enums.md index 5e05b4ebbdfa..790d6ff85469 100644 --- a/src/doc/book/enums.md +++ b/src/doc/book/enums.md @@ -51,7 +51,7 @@ possible variants: ```rust,ignore fn process_color_change(msg: Message) { - let Message::ChangeColor(r, g, b) = msg; // compile-time error + let Message::ChangeColor(r, g, b) = msg; // This causes a compile-time error. } ``` diff --git a/src/doc/book/error-handling.md b/src/doc/book/error-handling.md index a62e1b7dfa9c..0d9f49d66cbd 100644 --- a/src/doc/book/error-handling.md +++ b/src/doc/book/error-handling.md @@ -65,7 +65,7 @@ and in most cases, the entire program aborts.) Here's an example: ```rust,should_panic // Guess a number between 1 and 10. -// If it matches the number we had in mind, return true. Else, return false. +// If it matches the number we had in mind, return `true`. Else, return `false`. fn guess(n: i32) -> bool { if n < 1 || n > 10 { panic!("Invalid number: {}", n); @@ -350,7 +350,7 @@ fn file_path_ext_explicit(file_path: &str) -> Option<&str> { } fn file_name(file_path: &str) -> Option<&str> { - // implementation elided + // Implementation elided. unimplemented!() } ``` @@ -360,7 +360,7 @@ analysis, but its type doesn't quite fit... ```rust,ignore fn file_path_ext(file_path: &str) -> Option<&str> { - file_name(file_path).map(|x| extension(x)) //Compilation error + file_name(file_path).map(|x| extension(x)) // This causes a compilation error. } ``` @@ -1235,11 +1235,11 @@ use std::fs; use std::io; use std::num; -// We have to jump through some hoops to actually get error values. +// We have to jump through some hoops to actually get error values: let io_err: io::Error = io::Error::last_os_error(); let parse_err: num::ParseIntError = "not a number".parse::().unwrap_err(); -// OK, here are the conversions. +// OK, here are the conversions: let err1: Box = From::from(io_err); let err2: Box = From::from(parse_err); ``` @@ -1609,7 +1609,7 @@ fn main() { let data_path = &matches.free[0]; let city: &str = &matches.free[1]; - // Do stuff with information + // Do stuff with information. } ``` @@ -1747,7 +1747,7 @@ simply ignoring that row. use std::path::Path; struct Row { - // unchanged + // This struct remains unchanged. } struct PopulationCount { @@ -1769,7 +1769,7 @@ fn search>(file_path: P, city: &str) -> Vec { for row in rdr.decode::() { let row = row.unwrap(); match row.population { - None => { } // skip it + None => { } // Skip it. Some(count) => if row.city == city { found.push(PopulationCount { city: row.city, @@ -1825,7 +1825,7 @@ Let's try it: ```rust,ignore use std::error::Error; -// The rest of the code before this is unchanged +// The rest of the code before this is unchanged. fn search> (file_path: P, city: &str) @@ -1836,7 +1836,7 @@ fn search> for row in rdr.decode::() { let row = try!(row); match row.population { - None => { } // skip it + None => { } // Skip it. Some(count) => if row.city == city { found.push(PopulationCount { city: row.city, @@ -1957,7 +1957,7 @@ that it is generic on some type parameter `R` that satisfies ```rust,ignore use std::io; -// The rest of the code before this is unchanged +// The rest of the code before this is unchanged. fn search> (file_path: &Option")?; - // sidebar refers to the enclosing module, not this module + // Sidebar refers to the enclosing module, not this module. let relpath = if it.is_mod() { "../" } else { "" }; write!(fmt, "", From f13391a60386fc022761c2aa03f13958d757f2ce Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 16 Nov 2016 23:28:14 -0800 Subject: [PATCH 146/177] rustbuild: allow dynamically linking LLVM The makefiles and `mklldeps.py` called `llvm-config --shared-mode` to find out if LLVM defaulted to shared or static libraries, and just went with that. But under rustbuild, `librustc_llvm/build.rs` was assuming that LLVM should be static, and even forcing `--link-static` for 3.9+. Now that build script also uses `--shared-mode` to learn the default, which should work better for pre-3.9 configured for dynamic linking, as it wasn't possible back then to choose differently via `llvm-config`. Further, the configure script now has a new `--enable-llvm-link-shared` option, which allows one to manually override `--link-shared` on 3.9+ instead of forcing static. --- configure | 1 + src/bootstrap/compile.rs | 3 +++ src/bootstrap/config.rs | 2 ++ src/librustc_llvm/build.rs | 23 ++++++++++++++++++++--- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 15bfb5e3ec26..4cdf7d085db0 100755 --- a/configure +++ b/configure @@ -624,6 +624,7 @@ opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds" opt local-rust 0 "use an installed rustc rather than downloading a snapshot" opt local-rebuild 0 "assume local-rust matches the current version, for rebuilds; implies local-rust, and is implied if local-rust already matches the current version" opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM" +opt llvm-link-shared 0 "prefer shared linking to LLVM (llvm-config --link-shared)" opt rpath 1 "build rpaths into rustc itself" opt stage0-landing-pads 1 "enable landing pads during bootstrap with stage0" # This is used by the automation to produce single-target nightlies diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 5fc4f006729d..236989dbcfeb 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -212,6 +212,9 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { cargo.env("LLVM_STATIC_STDCPP", compiler_file(build.cxx(target), "libstdc++.a")); } + if build.config.llvm_link_shared { + cargo.env("LLVM_LINK_SHARED", "1"); + } if let Some(ref s) = build.config.rustc_default_linker { cargo.env("CFG_DEFAULT_LINKER", s); } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 945d482c2aac..17796a1eacf4 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -53,6 +53,7 @@ pub struct Config { pub llvm_release_debuginfo: bool, pub llvm_version_check: bool, pub llvm_static_stdcpp: bool, + pub llvm_link_shared: bool, // rust codegen options pub rust_optimize: bool, @@ -343,6 +344,7 @@ impl Config { ("OPTIMIZE_LLVM", self.llvm_optimize), ("LLVM_VERSION_CHECK", self.llvm_version_check), ("LLVM_STATIC_STDCPP", self.llvm_static_stdcpp), + ("LLVM_LINK_SHARED", self.llvm_link_shared), ("OPTIMIZE", self.rust_optimize), ("DEBUG_ASSERTIONS", self.rust_debug_assertions), ("DEBUGINFO", self.rust_debuginfo), diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index ca80a5269c95..eb4a1da484d1 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -123,13 +123,24 @@ fn main() { .cpp_link_stdlib(None) // we handle this below .compile("librustllvm.a"); + // Find out LLVM's default linking mode. + let mut cmd = Command::new(&llvm_config); + cmd.arg("--shared-mode"); + let mut llvm_kind = if output(&mut cmd).trim() == "shared" { + "dylib" + } else { + "static" + }; + // Link in all LLVM libraries, if we're uwring the "wrong" llvm-config then // we don't pick up system libs because unfortunately they're for the host // of llvm-config, not the target that we're attempting to link. let mut cmd = Command::new(&llvm_config); cmd.arg("--libs"); - // Force static linking with "--link-static" if available. + // Force static linking with "--link-static" if available, or + // force "--link-shared" if the configuration requested it. + let llvm_link_shared = env::var_os("LLVM_LINK_SHARED").is_some(); let mut version_cmd = Command::new(&llvm_config); version_cmd.arg("--version"); let version_output = output(&mut version_cmd); @@ -137,7 +148,13 @@ fn main() { if let (Some(major), Some(minor)) = (parts.next().and_then(|s| s.parse::().ok()), parts.next().and_then(|s| s.parse::().ok())) { if major > 3 || (major == 3 && minor >= 9) { - cmd.arg("--link-static"); + if llvm_link_shared { + cmd.arg("--link-shared"); + llvm_kind = "dylib"; + } else { + cmd.arg("--link-static"); + llvm_kind = "static"; + } } } @@ -174,7 +191,7 @@ fn main() { } let kind = if name.starts_with("LLVM") { - "static" + llvm_kind } else { "dylib" }; From 907120637ec1c28f116e612266cdb83cb5a854a9 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 11 Nov 2016 10:51:15 +0000 Subject: [PATCH 147/177] Add field `module.unresolved_invocations`. --- src/librustc_resolve/build_reduced_graph.rs | 4 +++- src/librustc_resolve/lib.rs | 4 ++++ src/librustc_resolve/macros.rs | 1 + src/librustc_resolve/resolve_imports.rs | 8 ++++++-- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 99e7a9042c0c..2caa78a95ef9 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -638,7 +638,9 @@ pub struct BuildReducedGraphVisitor<'a, 'b: 'a> { impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> { - let invocation = self.resolver.invocations[&Mark::from_placeholder_id(id)]; + let mark = Mark::from_placeholder_id(id); + self.resolver.current_module.unresolved_invocations.borrow_mut().insert(mark); + let invocation = self.resolver.invocations[&mark]; invocation.module.set(self.resolver.current_module); invocation.legacy_scope.set(self.legacy_scope); invocation diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 73b7b185b240..8f743cb6d06c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -799,6 +799,9 @@ pub struct ModuleS<'a> { resolutions: RefCell>>>, + // Macro invocations that can expand into items in this module. + unresolved_invocations: RefCell>, + no_implicit_prelude: bool, glob_importers: RefCell>>, @@ -822,6 +825,7 @@ impl<'a> ModuleS<'a> { kind: kind, normal_ancestor_id: None, resolutions: RefCell::new(FxHashMap()), + unresolved_invocations: RefCell::new(FxHashSet()), no_implicit_prelude: false, glob_importers: RefCell::new(Vec::new()), globs: RefCell::new((Vec::new())), diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index f30c129c48fd..afbe6f0d518b 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -131,6 +131,7 @@ impl<'a> base::Resolver for Resolver<'a> { self.collect_def_ids(invocation, expansion); self.current_module = invocation.module.get(); + self.current_module.unresolved_invocations.borrow_mut().remove(&mark); let mut visitor = BuildReducedGraphVisitor { resolver: self, legacy_scope: LegacyScope::Invocation(invocation), diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 5d66caec31b3..44ce48fe615f 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -192,7 +192,7 @@ impl<'a> Resolver<'a> { } // If the resolution doesn't depend on glob definability, check privacy and return. - if let Some(result) = self.try_result(&resolution, ns) { + if let Some(result) = self.try_result(&resolution, module, ns) { return result.and_then(|binding| { if self.is_accessible(binding.vis) && !is_disallowed_private_import(binding) || binding.is_extern_crate() { // c.f. issue #37020 @@ -222,7 +222,7 @@ impl<'a> Resolver<'a> { // Returns Some(the resolution of the name), or None if the resolution depends // on whether more globs can define the name. - fn try_result(&mut self, resolution: &NameResolution<'a>, ns: Namespace) + fn try_result(&mut self, resolution: &NameResolution<'a>, module: Module<'a>, ns: Namespace) -> Option>> { match resolution.binding { Some(binding) if !binding.is_glob_import() => @@ -250,6 +250,10 @@ impl<'a> Resolver<'a> { SingleImports::MaybeOne(_) | SingleImports::None => {}, } + if !module.unresolved_invocations.borrow().is_empty() { + return Some(Indeterminate); + } + resolution.binding.map(Success) } From 641274f9072a3c2b5400d99d671d64ef2d696624 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 10 Nov 2016 10:11:25 +0000 Subject: [PATCH 148/177] Resolve imports during expansion. --- src/librustc_driver/driver.rs | 2 -- src/librustc_resolve/lib.rs | 3 ++- src/librustc_resolve/macros.rs | 5 +++++ src/librustc_resolve/resolve_imports.rs | 25 ++++++------------------- src/libsyntax/ext/base.rs | 2 ++ src/libsyntax/ext/expand.rs | 13 +++++++++++-- 6 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 2dd83f708235..5466c8871d49 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -755,8 +755,6 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, || ast_validation::check_crate(sess, &krate)); time(sess.time_passes(), "name resolution", || -> CompileResult { - resolver.resolve_imports(); - // Since import resolution will eventually happen in expansion, // don't perform `after_expand` until after import resolution. after_expand(&krate)?; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8f743cb6d06c..d2f2b0788610 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -76,7 +76,7 @@ use std::fmt; use std::mem::replace; use std::rc::Rc; -use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution}; +use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver}; use macros::{InvocationData, LegacyBinding, LegacyScope}; // NB: This module needs to be declared first so diagnostics are @@ -1335,6 +1335,7 @@ impl<'a> Resolver<'a> { /// Entry point to crate resolution. pub fn resolve_crate(&mut self, krate: &Crate) { + ImportResolver { resolver: self }.finalize_imports(); self.current_module = self.graph_root; visit::walk_crate(self, krate); diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index afbe6f0d518b..82f271e10b95 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -10,6 +10,7 @@ use {Module, ModuleKind, Resolver}; use build_reduced_graph::BuildReducedGraphVisitor; +use resolve_imports::ImportResolver; use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex}; use rustc::hir::def::{Def, Export}; use rustc::hir::map::{self, DefCollector}; @@ -185,6 +186,10 @@ impl<'a> base::Resolver for Resolver<'a> { self.macros_at_scope.insert(id, macros); } + fn resolve_imports(&mut self) { + ImportResolver { resolver: self }.resolve_imports() + } + fn find_attr_invoc(&mut self, attrs: &mut Vec) -> Option { for i in 0..attrs.len() { let name = intern(&attrs[i].name()); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 44ce48fe615f..159b5706ec10 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -32,12 +32,6 @@ use syntax_pos::Span; use std::cell::{Cell, RefCell}; use std::mem; -impl<'a> Resolver<'a> { - pub fn resolve_imports(&mut self) { - ImportResolver { resolver: self }.resolve_imports(); - } -} - /// Contains data for specific types of import directives. #[derive(Clone, Debug)] pub enum ImportDirectiveSubclass<'a> { @@ -399,8 +393,8 @@ impl<'a> Resolver<'a> { } } -struct ImportResolver<'a, 'b: 'a> { - resolver: &'a mut Resolver<'b>, +pub struct ImportResolver<'a, 'b: 'a> { + pub resolver: &'a mut Resolver<'b>, } impl<'a, 'b: 'a> ::std::ops::Deref for ImportResolver<'a, 'b> { @@ -433,28 +427,21 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { /// Resolves all imports for the crate. This method performs the fixed- /// point iteration. - fn resolve_imports(&mut self) { - let mut i = 0; + pub fn resolve_imports(&mut self) { let mut prev_num_indeterminates = self.indeterminate_imports.len() + 1; - while self.indeterminate_imports.len() < prev_num_indeterminates { prev_num_indeterminates = self.indeterminate_imports.len(); - debug!("(resolving imports) iteration {}, {} imports left", i, prev_num_indeterminates); - - let mut imports = Vec::new(); - ::std::mem::swap(&mut imports, &mut self.indeterminate_imports); - - for import in imports { + for import in mem::replace(&mut self.indeterminate_imports, Vec::new()) { match self.resolve_import(&import) { Failed(_) => self.determined_imports.push(import), Indeterminate => self.indeterminate_imports.push(import), Success(()) => self.determined_imports.push(import), } } - - i += 1; } + } + pub fn finalize_imports(&mut self) { for module in self.arenas.local_modules().iter() { self.finalize_resolutions_in(module); } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index b4ac576f57a5..7f66b060052e 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -524,6 +524,7 @@ pub trait Resolver { fn add_ext(&mut self, ident: ast::Ident, ext: Rc); fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec); + fn resolve_imports(&mut self); fn find_attr_invoc(&mut self, attrs: &mut Vec) -> Option; fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool) -> Result, Determinacy>; @@ -547,6 +548,7 @@ impl Resolver for DummyResolver { fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc) {} fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec) {} + fn resolve_imports(&mut self) {} fn find_attr_invoc(&mut self, _attrs: &mut Vec) -> Option { None } fn resolve_macro(&mut self, _scope: Mark, _path: &ast::Path, _force: bool) -> Result, Determinacy> { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 877b312539f9..8e0c3ce8448d 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -222,6 +222,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.current_expansion.depth = 0; let (expansion, mut invocations) = self.collect_invocations(expansion); + self.resolve_imports(); invocations.reverse(); let mut expansions = Vec::new(); @@ -230,9 +231,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { loop { let invoc = if let Some(invoc) = invocations.pop() { invoc - } else if undetermined_invocations.is_empty() { - break } else { + self.resolve_imports(); + if undetermined_invocations.is_empty() { break } invocations = mem::replace(&mut undetermined_invocations, Vec::new()); force = !mem::replace(&mut progress, false); continue @@ -292,6 +293,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { expansion.fold_with(&mut placeholder_expander) } + fn resolve_imports(&mut self) { + if self.monotonic { + let err_count = self.cx.parse_sess.span_diagnostic.err_count(); + self.cx.resolver.resolve_imports(); + self.cx.resolve_err_count += self.cx.parse_sess.span_diagnostic.err_count() - err_count; + } + } + fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec) { let result = { let mut collector = InvocationCollector { From 83aac43f520463ea7fe86fe73bb1cc8f7e22abaf Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 7 Nov 2016 22:08:26 +0000 Subject: [PATCH 149/177] Refactor `Resolver::builtin_macros` to use `NameBinding`s instead of `DefId`s. --- src/librustc_resolve/build_reduced_graph.rs | 12 +++++++----- src/librustc_resolve/lib.rs | 2 +- src/librustc_resolve/macros.rs | 18 ++++++++++++------ 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 2caa78a95ef9..4e631a2076b2 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -518,10 +518,12 @@ impl<'b> Resolver<'b> { module.populated.set(true) } - fn legacy_import_macro(&mut self, name: Name, def: Def, span: Span, allow_shadowing: bool) { - self.used_crates.insert(def.def_id().krate); + fn legacy_import_macro( + &mut self, name: Name, binding: &'b NameBinding<'b>, span: Span, allow_shadowing: bool, + ) { + self.used_crates.insert(binding.def().def_id().krate); self.macro_names.insert(name); - if self.builtin_macros.insert(name, def.def_id()).is_some() && !allow_shadowing { + if self.builtin_macros.insert(name, binding).is_some() && !allow_shadowing { let msg = format!("`{}` is already in scope", name); let note = "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)"; @@ -548,13 +550,13 @@ impl<'b> Resolver<'b> { if let Some(span) = legacy_imports.import_all { module.for_each_child(|name, ns, binding| if ns == MacroNS { - self.legacy_import_macro(name, binding.def(), span, allow_shadowing); + self.legacy_import_macro(name, binding, span, allow_shadowing); }); } else { for (name, span) in legacy_imports.imports { let result = self.resolve_name_in_module(module, name, MacroNS, false, None); if let Success(binding) = result { - self.legacy_import_macro(name, binding.def(), span, allow_shadowing); + self.legacy_import_macro(name, binding, span, allow_shadowing); } else { span_err!(self.session, span, E0469, "imported macro not found"); } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d2f2b0788610..d8fb56018a1c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1115,7 +1115,7 @@ pub struct Resolver<'a> { pub exported_macros: Vec, crate_loader: &'a mut CrateLoader, macro_names: FxHashSet, - builtin_macros: FxHashMap, + builtin_macros: FxHashMap>, lexical_macro_resolutions: Vec<(Name, LegacyScope<'a>)>, macro_map: FxHashMap>, macro_exports: Vec, diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 82f271e10b95..8c6a1ab49ecb 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use {Module, ModuleKind, Resolver}; +use {Module, ModuleKind, NameBinding, NameBindingKind, Resolver}; use build_reduced_graph::BuildReducedGraphVisitor; use resolve_imports::ImportResolver; use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex}; use rustc::hir::def::{Def, Export}; use rustc::hir::map::{self, DefCollector}; +use rustc::ty; use std::cell::Cell; use std::rc::Rc; use syntax::ast; @@ -28,7 +29,7 @@ use syntax::parse::token::intern; use syntax::ptr::P; use syntax::util::lev_distance::find_best_match_for_name; use syntax::visit::Visitor; -use syntax_pos::Span; +use syntax_pos::{Span, DUMMY_SP}; #[derive(Clone)] pub struct InvocationData<'a> { @@ -179,7 +180,12 @@ impl<'a> base::Resolver for Resolver<'a> { index: DefIndex::new(self.macro_map.len()), }; self.macro_map.insert(def_id, ext); - self.builtin_macros.insert(ident.name, def_id); + let binding = self.arenas.alloc_name_binding(NameBinding { + kind: NameBindingKind::Def(Def::Macro(def_id)), + span: DUMMY_SP, + vis: ty::Visibility::PrivateExternal, + }); + self.builtin_macros.insert(ident.name, binding); } fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec) { @@ -193,8 +199,8 @@ impl<'a> base::Resolver for Resolver<'a> { fn find_attr_invoc(&mut self, attrs: &mut Vec) -> Option { for i in 0..attrs.len() { let name = intern(&attrs[i].name()); - match self.builtin_macros.get(&name) { - Some(&def_id) => match *self.get_macro(Def::Macro(def_id)) { + match self.builtin_macros.get(&name).cloned() { + Some(binding) => match *self.get_macro(binding.def()) { MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => { return Some(attrs.remove(i)) } @@ -273,7 +279,7 @@ impl<'a> Resolver<'a> { if let Some(scope) = possible_time_travel { self.lexical_macro_resolutions.push((name, scope)); } - self.builtin_macros.get(&name).cloned().map(|def_id| self.get_macro(Def::Macro(def_id))) + self.builtin_macros.get(&name).cloned().map(|binding| self.get_macro(binding.def())) } fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) { From 1bbf7a43d3c9f35d7066c5382fa2db898c1e467a Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 7 Nov 2016 22:23:26 +0000 Subject: [PATCH 150/177] Add field `expansion: Mark` to `NameBinding`. --- src/librustc_resolve/build_reduced_graph.rs | 100 ++++++++++++-------- src/librustc_resolve/lib.rs | 2 + src/librustc_resolve/macros.rs | 1 + src/librustc_resolve/resolve_imports.rs | 8 +- 4 files changed, 68 insertions(+), 43 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 4e631a2076b2..bfbc5b3163ac 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -45,15 +45,25 @@ use syntax::visit::{self, Visitor}; use syntax_pos::{Span, DUMMY_SP}; -impl<'a> ToNameBinding<'a> for (Module<'a>, Span, ty::Visibility) { +impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, Mark) { fn to_name_binding(self) -> NameBinding<'a> { - NameBinding { kind: NameBindingKind::Module(self.0), span: self.1, vis: self.2 } + NameBinding { + kind: NameBindingKind::Module(self.0), + vis: self.1, + span: self.2, + expansion: self.3, + } } } -impl<'a> ToNameBinding<'a> for (Def, Span, ty::Visibility) { +impl<'a> ToNameBinding<'a> for (Def, ty::Visibility, Span, Mark) { fn to_name_binding(self) -> NameBinding<'a> { - NameBinding { kind: NameBindingKind::Def(self.0), span: self.1, vis: self.2 } + NameBinding { + kind: NameBindingKind::Def(self.0), + vis: self.1, + span: self.2, + expansion: self.3, + } } } @@ -148,8 +158,9 @@ impl<'b> Resolver<'b> { } let subclass = ImportDirectiveSubclass::single(binding.name, source.name); - let span = view_path.span; - self.add_import_directive(module_path, subclass, span, item.id, vis); + self.add_import_directive( + module_path, subclass, view_path.span, item.id, vis, expansion, + ); } ViewPathList(_, ref source_items) => { // Make sure there's at most one `mod` import in the list. @@ -196,8 +207,10 @@ impl<'b> Resolver<'b> { } }; let subclass = ImportDirectiveSubclass::single(rename, name); - let (span, id) = (source_item.span, source_item.node.id); - self.add_import_directive(module_path, subclass, span, id, vis); + let id = source_item.node.id; + self.add_import_directive( + module_path, subclass, source_item.span, id, vis, expansion, + ); } } ViewPathGlob(_) => { @@ -205,8 +218,9 @@ impl<'b> Resolver<'b> { is_prelude: is_prelude, max_vis: Cell::new(ty::Visibility::PrivateExternal), }; - let span = view_path.span; - self.add_import_directive(module_path, subclass, span, item.id, vis); + self.add_import_directive( + module_path, subclass, view_path.span, item.id, vis, expansion, + ); } } } @@ -217,7 +231,7 @@ impl<'b> Resolver<'b> { // n.b. we don't need to look at the path option here, because cstore already did let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id).unwrap(); let module = self.get_extern_crate_root(crate_id); - let binding = (module, sp, ty::Visibility::Public).to_name_binding(); + let binding = (module, ty::Visibility::Public, sp, expansion).to_name_binding(); let binding = self.arenas.alloc_name_binding(binding); let directive = self.arenas.alloc_import_directive(ImportDirective { id: item.id, @@ -227,6 +241,7 @@ impl<'b> Resolver<'b> { span: item.span, module_path: Vec::new(), vis: Cell::new(vis), + expansion: expansion, }); let imported_binding = self.import(binding, directive); self.define(parent, name, TypeNS, imported_binding); @@ -245,7 +260,7 @@ impl<'b> Resolver<'b> { normal_ancestor_id: Some(item.id), ..ModuleS::new(Some(parent), ModuleKind::Def(def, name)) }); - self.define(parent, name, TypeNS, (module, sp, vis)); + self.define(parent, name, TypeNS, (module, vis, sp, expansion)); self.module_map.insert(item.id, module); // Descend into the module. @@ -258,30 +273,30 @@ impl<'b> Resolver<'b> { ItemKind::Static(_, m, _) => { let mutbl = m == Mutability::Mutable; let def = Def::Static(self.definitions.local_def_id(item.id), mutbl); - self.define(parent, name, ValueNS, (def, sp, vis)); + self.define(parent, name, ValueNS, (def, vis, sp, expansion)); } ItemKind::Const(..) => { let def = Def::Const(self.definitions.local_def_id(item.id)); - self.define(parent, name, ValueNS, (def, sp, vis)); + self.define(parent, name, ValueNS, (def, vis, sp, expansion)); } ItemKind::Fn(..) => { let def = Def::Fn(self.definitions.local_def_id(item.id)); - self.define(parent, name, ValueNS, (def, sp, vis)); + self.define(parent, name, ValueNS, (def, vis, sp, expansion)); } // These items live in the type namespace. ItemKind::Ty(..) => { let def = Def::TyAlias(self.definitions.local_def_id(item.id)); - self.define(parent, name, TypeNS, (def, sp, vis)); + self.define(parent, name, TypeNS, (def, vis, sp, expansion)); } ItemKind::Enum(ref enum_definition, _) => { let def = Def::Enum(self.definitions.local_def_id(item.id)); let module = self.new_module(parent, ModuleKind::Def(def, name), true); - self.define(parent, name, TypeNS, (module, sp, vis)); + self.define(parent, name, TypeNS, (module, vis, sp, expansion)); for variant in &(*enum_definition).variants { - self.build_reduced_graph_for_variant(variant, module, vis); + self.build_reduced_graph_for_variant(variant, module, vis, expansion); } } @@ -289,14 +304,14 @@ impl<'b> Resolver<'b> { ItemKind::Struct(ref struct_def, _) => { // Define a name in the type namespace. let def = Def::Struct(self.definitions.local_def_id(item.id)); - self.define(parent, name, TypeNS, (def, sp, vis)); + self.define(parent, name, TypeNS, (def, vis, sp, expansion)); // If this is a tuple or unit struct, define a name // in the value namespace as well. if !struct_def.is_struct() { let ctor_def = Def::StructCtor(self.definitions.local_def_id(struct_def.id()), CtorKind::from_ast(struct_def)); - self.define(parent, name, ValueNS, (ctor_def, sp, vis)); + self.define(parent, name, ValueNS, (ctor_def, vis, sp, expansion)); } // Record field names for error reporting. @@ -310,7 +325,7 @@ impl<'b> Resolver<'b> { ItemKind::Union(ref vdata, _) => { let def = Def::Union(self.definitions.local_def_id(item.id)); - self.define(parent, name, TypeNS, (def, sp, vis)); + self.define(parent, name, TypeNS, (def, vis, sp, expansion)); // Record field names for error reporting. let field_names = vdata.fields().iter().filter_map(|field| { @@ -329,7 +344,7 @@ impl<'b> Resolver<'b> { // Add all the items within to a new module. let module = self.new_module(parent, ModuleKind::Def(Def::Trait(def_id), name), true); - self.define(parent, name, TypeNS, (module, sp, vis)); + self.define(parent, name, TypeNS, (module, vis, sp, expansion)); self.current_module = module; } ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"), @@ -338,27 +353,28 @@ impl<'b> Resolver<'b> { // Constructs the reduced graph for one variant. Variants exist in the // type and value namespaces. - fn build_reduced_graph_for_variant(&mut self, - variant: &Variant, - parent: Module<'b>, - vis: ty::Visibility) { + fn build_reduced_graph_for_variant( + &mut self, variant: &Variant, parent: Module<'b>, vis: ty::Visibility, expansion: Mark, + ) { let name = variant.node.name.name; let def_id = self.definitions.local_def_id(variant.node.data.id()); // Define a name in the type namespace. let def = Def::Variant(def_id); - self.define(parent, name, TypeNS, (def, variant.span, vis)); + self.define(parent, name, TypeNS, (def, vis, variant.span, expansion)); // Define a constructor name in the value namespace. // Braced variants, unlike structs, generate unusable names in // value namespace, they are reserved for possible future use. let ctor_kind = CtorKind::from_ast(&variant.node.data); let ctor_def = Def::VariantCtor(def_id, ctor_kind); - self.define(parent, name, ValueNS, (ctor_def, variant.span, vis)); + self.define(parent, name, ValueNS, (ctor_def, vis, variant.span, expansion)); } /// Constructs the reduced graph for one foreign item. - fn build_reduced_graph_for_foreign_item(&mut self, foreign_item: &ForeignItem) { + fn build_reduced_graph_for_foreign_item( + &mut self, foreign_item: &ForeignItem, expansion: Mark, + ) { let parent = self.current_module; let name = foreign_item.ident.name; @@ -371,7 +387,7 @@ impl<'b> Resolver<'b> { } }; let vis = self.resolve_visibility(&foreign_item.vis); - self.define(parent, name, ValueNS, (def, foreign_item.span, vis)); + self.define(parent, name, ValueNS, (def, vis, foreign_item.span, expansion)); } fn build_reduced_graph_for_block(&mut self, block: &Block) { @@ -404,24 +420,24 @@ impl<'b> Resolver<'b> { match def { Def::Mod(..) | Def::Enum(..) => { let module = self.new_module(parent, ModuleKind::Def(def, name), false); - self.define(parent, name, TypeNS, (module, DUMMY_SP, vis)); + self.define(parent, name, TypeNS, (module, vis, DUMMY_SP, Mark::root())); } Def::Variant(..) => { - self.define(parent, name, TypeNS, (def, DUMMY_SP, vis)); + self.define(parent, name, TypeNS, (def, vis, DUMMY_SP, Mark::root())); } Def::VariantCtor(..) => { - self.define(parent, name, ValueNS, (def, DUMMY_SP, vis)); + self.define(parent, name, ValueNS, (def, vis, DUMMY_SP, Mark::root())); } Def::Fn(..) | Def::Static(..) | Def::Const(..) | Def::AssociatedConst(..) | Def::Method(..) => { - self.define(parent, name, ValueNS, (def, DUMMY_SP, vis)); + self.define(parent, name, ValueNS, (def, vis, DUMMY_SP, Mark::root())); } Def::Trait(..) => { let module = self.new_module(parent, ModuleKind::Def(def, name), false); - self.define(parent, name, TypeNS, (module, DUMMY_SP, vis)); + self.define(parent, name, TypeNS, (module, vis, DUMMY_SP, Mark::root())); // If this is a trait, add all the trait item names to the trait info. let trait_item_def_ids = self.session.cstore.associated_item_def_ids(def_id); @@ -433,27 +449,27 @@ impl<'b> Resolver<'b> { } } Def::TyAlias(..) | Def::AssociatedTy(..) => { - self.define(parent, name, TypeNS, (def, DUMMY_SP, vis)); + self.define(parent, name, TypeNS, (def, vis, DUMMY_SP, Mark::root())); } Def::Struct(..) => { - self.define(parent, name, TypeNS, (def, DUMMY_SP, vis)); + self.define(parent, name, TypeNS, (def, vis, DUMMY_SP, Mark::root())); // Record field names for error reporting. let field_names = self.session.cstore.struct_field_names(def_id); self.insert_field_names(def_id, field_names); } Def::StructCtor(..) => { - self.define(parent, name, ValueNS, (def, DUMMY_SP, vis)); + self.define(parent, name, ValueNS, (def, vis, DUMMY_SP, Mark::root())); } Def::Union(..) => { - self.define(parent, name, TypeNS, (def, DUMMY_SP, vis)); + self.define(parent, name, TypeNS, (def, vis, DUMMY_SP, Mark::root())); // Record field names for error reporting. let field_names = self.session.cstore.struct_field_names(def_id); self.insert_field_names(def_id, field_names); } Def::Macro(..) => { - self.define(parent, name, MacroNS, (def, DUMMY_SP, vis)); + self.define(parent, name, MacroNS, (def, vis, DUMMY_SP, Mark::root())); } Def::Local(..) | Def::PrimTy(..) | @@ -695,7 +711,7 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> { } fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) { - self.resolver.build_reduced_graph_for_foreign_item(foreign_item); + self.resolver.build_reduced_graph_for_foreign_item(foreign_item, self.expansion); visit::walk_foreign_item(self, foreign_item); } @@ -732,7 +748,7 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> { self.resolver.trait_item_map.insert((item.ident.name, def_id), is_static_method); let vis = ty::Visibility::Public; - self.resolver.define(parent, item.ident.name, ns, (def, item.span, vis)); + self.resolver.define(parent, item.ident.name, ns, (def, vis, item.span, self.expansion)); self.resolver.current_module = parent.parent.unwrap(); // nearest normal ancestor visit::walk_trait_item(self, item); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d8fb56018a1c..4164f3a897d6 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -881,6 +881,7 @@ impl<'a> fmt::Debug for ModuleS<'a> { #[derive(Clone, Debug)] pub struct NameBinding<'a> { kind: NameBindingKind<'a>, + expansion: Mark, span: Span, vis: ty::Visibility, } @@ -1304,6 +1305,7 @@ impl<'a> Resolver<'a> { arenas: arenas, dummy_binding: arenas.alloc_name_binding(NameBinding { kind: NameBindingKind::Def(Def::Err), + expansion: Mark::root(), span: DUMMY_SP, vis: ty::Visibility::Public, }), diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 8c6a1ab49ecb..2d434d660ea5 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -184,6 +184,7 @@ impl<'a> base::Resolver for Resolver<'a> { kind: NameBindingKind::Def(Def::Macro(def_id)), span: DUMMY_SP, vis: ty::Visibility::PrivateExternal, + expansion: Mark::root(), }); self.builtin_macros.insert(ident.name, binding); } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 159b5706ec10..01d09a3b7c4b 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -26,6 +26,7 @@ use rustc::hir::def::*; use syntax::ast::{Ident, NodeId, Name}; use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; +use syntax::ext::hygiene::Mark; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::Span; @@ -70,6 +71,7 @@ pub struct ImportDirective<'a> { pub subclass: ImportDirectiveSubclass<'a>, pub span: Span, pub vis: Cell, + pub expansion: Mark, } impl<'a> ImportDirective<'a> { @@ -257,7 +259,8 @@ impl<'a> Resolver<'a> { subclass: ImportDirectiveSubclass<'a>, span: Span, id: NodeId, - vis: ty::Visibility) { + vis: ty::Visibility, + expansion: Mark) { let current_module = self.current_module; let directive = self.arenas.alloc_import_directive(ImportDirective { parent: current_module, @@ -267,6 +270,7 @@ impl<'a> Resolver<'a> { span: span, id: id, vis: Cell::new(vis), + expansion: expansion, }); self.indeterminate_imports.push(directive); @@ -310,6 +314,7 @@ impl<'a> Resolver<'a> { }, span: directive.span, vis: vis, + expansion: directive.expansion, } } @@ -336,6 +341,7 @@ impl<'a> Resolver<'a> { binding.vis }, span: old_binding.span, + expansion: Mark::root(), })); } else if !old_binding.vis.is_at_least(binding.vis, this) { // We are glob-importing the same item but with greater visibility. From b25c063caa5e4ab8202527e3cfcfe04196e0836f Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 10 Nov 2016 06:19:54 +0000 Subject: [PATCH 151/177] Refactor out `PerNS`. --- src/librustc_resolve/build_reduced_graph.rs | 15 +- src/librustc_resolve/check_unused.rs | 6 +- src/librustc_resolve/lib.rs | 144 +++++++------ src/librustc_resolve/resolve_imports.rs | 195 ++++++++---------- .../blind-item-block-item-shadow.rs | 2 +- src/test/compile-fail/double-type-import.rs | 2 +- 6 files changed, 186 insertions(+), 178 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index bfbc5b3163ac..5917a1a0d175 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -15,7 +15,7 @@ use macros::{InvocationData, LegacyScope}; use resolve_imports::ImportDirective; -use resolve_imports::ImportDirectiveSubclass::{self, GlobImport}; +use resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport}; use {Resolver, Module, ModuleS, ModuleKind, NameBinding, NameBindingKind, ToNameBinding}; use Namespace::{self, TypeNS, ValueNS, MacroNS}; use ResolveResult::Success; @@ -37,6 +37,7 @@ use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind}; use syntax::ast::{Mutability, StmtKind, TraitItem, TraitItemKind}; use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple}; use syntax::ext::base::SyntaxExtension; +use syntax::ext::base::Determinacy::Undetermined; use syntax::ext::expand::mark_tts; use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; @@ -157,7 +158,11 @@ impl<'b> Resolver<'b> { .emit(); } - let subclass = ImportDirectiveSubclass::single(binding.name, source.name); + let subclass = SingleImport { + target: binding.name, + source: source.name, + result: self.per_ns(|_, _| Cell::new(Err(Undetermined))), + }; self.add_import_directive( module_path, subclass, view_path.span, item.id, vis, expansion, ); @@ -206,7 +211,11 @@ impl<'b> Resolver<'b> { (module_path.to_vec(), name, rename) } }; - let subclass = ImportDirectiveSubclass::single(rename, name); + let subclass = SingleImport { + target: rename, + source: name, + result: self.per_ns(|_, _| Cell::new(Err(Undetermined))), + }; let id = source_item.node.id; self.add_import_directive( module_path, subclass, source_item.span, id, vis, expansion, diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index 36e05a433414..492c5e695bbb 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -22,7 +22,6 @@ use std::ops::{Deref, DerefMut}; use Resolver; -use Namespace::{TypeNS, ValueNS}; use rustc::lint; use rustc::util::nodemap::NodeMap; @@ -56,8 +55,9 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> { // We have information about whether `use` (import) directives are actually // used now. If an import is not used at all, we signal a lint error. fn check_import(&mut self, item_id: ast::NodeId, id: ast::NodeId, span: Span) { - if !self.used_imports.contains(&(id, TypeNS)) && - !self.used_imports.contains(&(id, ValueNS)) { + let mut used = false; + self.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns))); + if !used { if self.maybe_unused_trait_imports.contains(&id) { // Check later. return; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 4164f3a897d6..af7297702425 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -536,6 +536,33 @@ pub enum Namespace { MacroNS, } +#[derive(Clone, Default, Debug)] +pub struct PerNS { + value_ns: T, + type_ns: T, +} + +impl ::std::ops::Index for PerNS { + type Output = T; + fn index(&self, ns: Namespace) -> &T { + match ns { + ValueNS => &self.value_ns, + TypeNS => &self.type_ns, + MacroNS => unreachable!(), + } + } +} + +impl ::std::ops::IndexMut for PerNS { + fn index_mut(&mut self, ns: Namespace) -> &mut T { + match ns { + ValueNS => &mut self.value_ns, + TypeNS => &mut self.type_ns, + MacroNS => unreachable!(), + } + } +} + impl<'a> Visitor for Resolver<'a> { fn visit_item(&mut self, item: &Item) { self.resolve_item(item); @@ -612,7 +639,7 @@ impl<'a> Visitor for Resolver<'a> { }; // Create a value rib for the function. - self.value_ribs.push(Rib::new(rib_kind)); + self.ribs[ValueNS].push(Rib::new(rib_kind)); // Create a label rib for the function. self.label_ribs.push(Rib::new(rib_kind)); @@ -642,7 +669,7 @@ impl<'a> Visitor for Resolver<'a> { debug!("(resolving function) leaving function"); self.label_ribs.pop(); - self.value_ribs.pop(); + self.ribs[ValueNS].pop(); } } @@ -1049,12 +1076,9 @@ pub struct Resolver<'a> { // The module that represents the current item scope. current_module: Module<'a>, - // The current set of local scopes, for values. + // The current set of local scopes for types and values. // FIXME #4948: Reuse ribs to avoid allocation. - value_ribs: Vec>, - - // The current set of local scopes, for types. - type_ribs: Vec>, + ribs: PerNS>>, // The current set of local scopes, for labels. label_ribs: Vec>, @@ -1273,8 +1297,10 @@ impl<'a> Resolver<'a> { indeterminate_imports: Vec::new(), current_module: graph_root, - value_ribs: vec![Rib::new(ModuleRibKind(graph_root))], - type_ribs: vec![Rib::new(ModuleRibKind(graph_root))], + ribs: PerNS { + value_ns: vec![Rib::new(ModuleRibKind(graph_root))], + type_ns: vec![Rib::new(ModuleRibKind(graph_root))], + }, label_ribs: Vec::new(), current_trait_ref: None, @@ -1335,6 +1361,13 @@ impl<'a> Resolver<'a> { } } + fn per_ns T>(&mut self, mut f: F) -> PerNS { + PerNS { + type_ns: f(self, TypeNS), + value_ns: f(self, ValueNS), + } + } + /// Entry point to crate resolution. pub fn resolve_crate(&mut self, krate: &Crate) { ImportResolver { resolver: self }.finalize_imports(); @@ -1354,14 +1387,6 @@ impl<'a> Resolver<'a> { }) } - fn get_ribs<'b>(&'b mut self, ns: Namespace) -> &'b mut Vec> { - match ns { - ValueNS => &mut self.value_ribs, - TypeNS => &mut self.type_ribs, - MacroNS => panic!("The macro namespace has no ribs"), - } - } - fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>, span: Span) -> bool /* true if an error was reported */ { // track extern crates for unused_extern_crate lint @@ -1577,8 +1602,8 @@ impl<'a> Resolver<'a> { } // Walk backwards up the ribs in scope. - for i in (0 .. self.get_ribs(ns).len()).rev() { - if let Some(def) = self.get_ribs(ns)[i].bindings.get(&ident).cloned() { + for i in (0 .. self.ribs[ns].len()).rev() { + if let Some(def) = self.ribs[ns][i].bindings.get(&ident).cloned() { // The ident resolves to a type parameter or local variable. return Some(LexicalScopeBinding::LocalDef(LocalDef { ribs: Some((ns, i)), @@ -1586,7 +1611,7 @@ impl<'a> Resolver<'a> { })); } - if let ModuleRibKind(module) = self.get_ribs(ns)[i].kind { + if let ModuleRibKind(module) = self.ribs[ns][i].kind { let name = ident.name; let item = self.resolve_name_in_module(module, name, ns, true, record_used); if let Success(binding) = item { @@ -1604,7 +1629,7 @@ impl<'a> Resolver<'a> { } } - if let MacroDefinition(mac) = self.get_ribs(ns)[i].kind { + if let MacroDefinition(mac) = self.ribs[ns][i].kind { // If an invocation of this macro created `ident`, give up on `ident` // and switch to `ident`'s source from the macro definition. let (source_ctxt, source_macro) = ident.ctxt.source(); @@ -1689,14 +1714,14 @@ impl<'a> Resolver<'a> { if let Some(module) = module { // Move down in the graph. let orig_module = replace(&mut self.current_module, module); - self.value_ribs.push(Rib::new(ModuleRibKind(module))); - self.type_ribs.push(Rib::new(ModuleRibKind(module))); + self.ribs[ValueNS].push(Rib::new(ModuleRibKind(module))); + self.ribs[TypeNS].push(Rib::new(ModuleRibKind(module))); f(self); self.current_module = orig_module; - self.value_ribs.pop(); - self.type_ribs.pop(); + self.ribs[ValueNS].pop(); + self.ribs[TypeNS].pop(); } else { f(self); } @@ -1871,7 +1896,7 @@ impl<'a> Resolver<'a> { function_type_rib.bindings.insert(Ident::with_empty_ctxt(name), def); self.record_def(type_parameter.id, PathResolution::new(def)); } - self.type_ribs.push(function_type_rib); + self.ribs[TypeNS].push(function_type_rib); } NoTypeParameters => { @@ -1882,7 +1907,7 @@ impl<'a> Resolver<'a> { f(self); if let HasTypeParameters(..) = type_parameters { - self.type_ribs.pop(); + self.ribs[TypeNS].pop(); } } @@ -1897,11 +1922,11 @@ impl<'a> Resolver<'a> { fn with_constant_rib(&mut self, f: F) where F: FnOnce(&mut Resolver) { - self.value_ribs.push(Rib::new(ConstantItemRibKind)); - self.type_ribs.push(Rib::new(ConstantItemRibKind)); + self.ribs[ValueNS].push(Rib::new(ConstantItemRibKind)); + self.ribs[TypeNS].push(Rib::new(ConstantItemRibKind)); f(self); - self.type_ribs.pop(); - self.value_ribs.pop(); + self.ribs[TypeNS].pop(); + self.ribs[ValueNS].pop(); } fn resolve_trait_reference(&mut self, @@ -2011,9 +2036,9 @@ impl<'a> Resolver<'a> { // plain insert (no renaming, types are not currently hygienic....) self_type_rib.bindings.insert(keywords::SelfType.ident(), self_def); - self.type_ribs.push(self_type_rib); + self.ribs[TypeNS].push(self_type_rib); f(self); - self.type_ribs.pop(); + self.ribs[TypeNS].pop(); } fn resolve_implementation(&mut self, @@ -2167,7 +2192,7 @@ impl<'a> Resolver<'a> { } fn resolve_arm(&mut self, arm: &Arm) { - self.value_ribs.push(Rib::new(NormalRibKind)); + self.ribs[ValueNS].push(Rib::new(NormalRibKind)); let mut bindings_list = FxHashMap(); for pattern in &arm.pats { @@ -2181,7 +2206,7 @@ impl<'a> Resolver<'a> { walk_list!(self, visit_expr, &arm.guard); self.visit_expr(&arm.body); - self.value_ribs.pop(); + self.ribs[ValueNS].pop(); } fn resolve_block(&mut self, block: &Block) { @@ -2193,11 +2218,11 @@ impl<'a> Resolver<'a> { let mut num_macro_definition_ribs = 0; if let Some(anonymous_module) = anonymous_module { debug!("(resolving block) found anonymous module, moving down"); - self.value_ribs.push(Rib::new(ModuleRibKind(anonymous_module))); - self.type_ribs.push(Rib::new(ModuleRibKind(anonymous_module))); + self.ribs[ValueNS].push(Rib::new(ModuleRibKind(anonymous_module))); + self.ribs[TypeNS].push(Rib::new(ModuleRibKind(anonymous_module))); self.current_module = anonymous_module; } else { - self.value_ribs.push(Rib::new(NormalRibKind)); + self.ribs[ValueNS].push(Rib::new(NormalRibKind)); } // Descend into the block. @@ -2205,7 +2230,7 @@ impl<'a> Resolver<'a> { if let Some(marks) = self.macros_at_scope.remove(&stmt.id) { num_macro_definition_ribs += marks.len() as u32; for mark in marks { - self.value_ribs.push(Rib::new(MacroDefinition(mark))); + self.ribs[ValueNS].push(Rib::new(MacroDefinition(mark))); self.label_ribs.push(Rib::new(MacroDefinition(mark))); } } @@ -2216,12 +2241,12 @@ impl<'a> Resolver<'a> { // Move back up. self.current_module = orig_module; for _ in 0 .. num_macro_definition_ribs { - self.value_ribs.pop(); + self.ribs[ValueNS].pop(); self.label_ribs.pop(); } - self.value_ribs.pop(); + self.ribs[ValueNS].pop(); if let Some(_) = anonymous_module { - self.type_ribs.pop(); + self.ribs[TypeNS].pop(); } debug!("(resolving block) leaving block"); } @@ -2340,7 +2365,7 @@ impl<'a> Resolver<'a> { Some(..) if pat_src == PatternSource::Match => { // `Variant1(a) | Variant2(a)`, ok // Reuse definition from the first `a`. - def = self.value_ribs.last_mut().unwrap().bindings[&ident.node]; + def = self.ribs[ValueNS].last_mut().unwrap().bindings[&ident.node]; } Some(..) => { span_bug!(ident.span, "two bindings with the same name from \ @@ -2350,7 +2375,7 @@ impl<'a> Resolver<'a> { // A completely fresh binding, add to the lists if it's valid. if ident.node.name != keywords::Invalid.name() { bindings.insert(ident.node, outer_pat_id); - self.value_ribs.last_mut().unwrap().bindings.insert(ident.node, def); + self.ribs[ValueNS].last_mut().unwrap().bindings.insert(ident.node, def); } } } @@ -2634,9 +2659,8 @@ impl<'a> Resolver<'a> { // Resolve a local definition, potentially adjusting for closures. fn adjust_local_def(&mut self, local_def: LocalDef, span: Span) -> Option { let ribs = match local_def.ribs { - Some((TypeNS, i)) => &self.type_ribs[i + 1..], - Some((ValueNS, i)) => &self.value_ribs[i + 1..], - _ => &[] as &[_], + Some((ns, i)) => &self.ribs[ns][i + 1..], + None => &[] as &[_], }; let mut def = local_def.def; match def { @@ -2798,8 +2822,8 @@ impl<'a> Resolver<'a> { where F: FnOnce(&mut Resolver<'a>) -> T, { self.with_empty_ribs(|this| { - this.value_ribs.push(Rib::new(ModuleRibKind(module))); - this.type_ribs.push(Rib::new(ModuleRibKind(module))); + this.ribs[ValueNS].push(Rib::new(ModuleRibKind(module))); + this.ribs[TypeNS].push(Rib::new(ModuleRibKind(module))); f(this) }) } @@ -2807,13 +2831,11 @@ impl<'a> Resolver<'a> { fn with_empty_ribs(&mut self, f: F) -> T where F: FnOnce(&mut Resolver<'a>) -> T, { - let value_ribs = replace(&mut self.value_ribs, Vec::new()); - let type_ribs = replace(&mut self.type_ribs, Vec::new()); + let ribs = replace(&mut self.ribs, PerNS::>::default()); let label_ribs = replace(&mut self.label_ribs, Vec::new()); let result = f(self); - self.value_ribs = value_ribs; - self.type_ribs = type_ribs; + self.ribs = ribs; self.label_ribs = label_ribs; result } @@ -2865,7 +2887,7 @@ impl<'a> Resolver<'a> { return SuggestionType::Macro(format!("{}!", macro_name)); } - let names = self.value_ribs + let names = self.ribs[ValueNS] .iter() .rev() .flat_map(|rib| rib.bindings.keys().map(|ident| &ident.name)); @@ -2968,7 +2990,7 @@ impl<'a> Resolver<'a> { } else { let mut method_scope = false; let mut is_static = false; - self.value_ribs.iter().rev().all(|rib| { + self.ribs[ValueNS].iter().rev().all(|rib| { method_scope = match rib.kind { MethodRibKind(is_static_) => { is_static = is_static_; @@ -3079,10 +3101,10 @@ impl<'a> Resolver<'a> { ExprKind::IfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => { self.visit_expr(subexpression); - self.value_ribs.push(Rib::new(NormalRibKind)); + self.ribs[ValueNS].push(Rib::new(NormalRibKind)); self.resolve_pattern(pattern, PatternSource::IfLet, &mut FxHashMap()); self.visit_block(if_block); - self.value_ribs.pop(); + self.ribs[ValueNS].pop(); optional_else.as_ref().map(|expr| self.visit_expr(expr)); } @@ -3096,22 +3118,22 @@ impl<'a> Resolver<'a> { ExprKind::WhileLet(ref pattern, ref subexpression, ref block, label) => { self.visit_expr(subexpression); - self.value_ribs.push(Rib::new(NormalRibKind)); + self.ribs[ValueNS].push(Rib::new(NormalRibKind)); self.resolve_pattern(pattern, PatternSource::WhileLet, &mut FxHashMap()); self.resolve_labeled_block(label, expr.id, block); - self.value_ribs.pop(); + self.ribs[ValueNS].pop(); } ExprKind::ForLoop(ref pattern, ref subexpression, ref block, label) => { self.visit_expr(subexpression); - self.value_ribs.push(Rib::new(NormalRibKind)); + self.ribs[ValueNS].push(Rib::new(NormalRibKind)); self.resolve_pattern(pattern, PatternSource::For, &mut FxHashMap()); self.resolve_labeled_block(label, expr.id, block); - self.value_ribs.pop(); + self.ribs[ValueNS].pop(); } ExprKind::Field(ref subexpression, _) => { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 01d09a3b7c4b..f04f3bf45ee9 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -10,8 +10,8 @@ use self::ImportDirectiveSubclass::*; -use Module; -use Namespace::{self, TypeNS, ValueNS}; +use {Module, PerNS}; +use Namespace::{self, TypeNS}; use {NameBinding, NameBindingKind, PrivacyError, ToNameBinding}; use ResolveResult; use ResolveResult::*; @@ -39,8 +39,7 @@ pub enum ImportDirectiveSubclass<'a> { SingleImport { target: Name, source: Name, - value_result: Cell, Determinacy>>, - type_result: Cell, Determinacy>>, + result: PerNS, Determinacy>>>, }, GlobImport { is_prelude: bool, @@ -50,17 +49,6 @@ pub enum ImportDirectiveSubclass<'a> { ExternCrate, } -impl<'a> ImportDirectiveSubclass<'a> { - pub fn single(target: Name, source: Name) -> Self { - SingleImport { - target: target, - source: source, - type_result: Cell::new(Err(Undetermined)), - value_result: Cell::new(Err(Undetermined)), - } - } -} - /// One import directive. #[derive(Debug,Clone)] pub struct ImportDirective<'a> { @@ -276,10 +264,10 @@ impl<'a> Resolver<'a> { self.indeterminate_imports.push(directive); match directive.subclass { SingleImport { target, .. } => { - for &ns in &[ValueNS, TypeNS] { - let mut resolution = self.resolution(current_module, target, ns).borrow_mut(); + self.per_ns(|this, ns| { + let mut resolution = this.resolution(current_module, target, ns).borrow_mut(); resolution.single_imports.add_directive(directive); - } + }); } // We don't add prelude imports to the globs since they only affect lexical scopes, // which are not relevant to import resolution. @@ -397,6 +385,18 @@ impl<'a> Resolver<'a> { t } + + // Define a "dummy" resolution containing a Def::Err as a placeholder for a + // failed resolution + fn import_dummy_binding(&mut self, directive: &'a ImportDirective<'a>) { + if let SingleImport { target, .. } = directive.subclass { + let dummy_binding = self.dummy_binding; + let dummy_binding = self.import(dummy_binding, directive); + self.per_ns(|this, ns| { + let _ = this.try_define(directive.parent, target, ns, dummy_binding.clone()); + }); + } + } } pub struct ImportResolver<'a, 'b: 'a> { @@ -481,17 +481,6 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } } - // Define a "dummy" resolution containing a Def::Err as a placeholder for a - // failed resolution - fn import_dummy_binding(&mut self, directive: &'b ImportDirective<'b>) { - if let SingleImport { target, .. } = directive.subclass { - let dummy_binding = self.dummy_binding; - let dummy_binding = self.import(dummy_binding, directive); - let _ = self.try_define(directive.parent, target, ValueNS, dummy_binding.clone()); - let _ = self.try_define(directive.parent, target, TypeNS, dummy_binding); - } - } - /// Attempts to resolve the given import. The return value indicates /// failure if we're certain the name does not exist, indeterminate if we /// don't know whether the name exists at the moment due to other @@ -523,9 +512,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { }; directive.imported_module.set(Some(module)); - let (source, target, value_result, type_result) = match directive.subclass { - SingleImport { source, target, ref value_result, ref type_result } => - (source, target, value_result, type_result), + let (source, target, result) = match directive.subclass { + SingleImport { source, target, ref result } => (source, target, result), GlobImport { .. } => { self.resolve_glob_import(directive); return Success(()); @@ -534,46 +522,45 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { }; let mut indeterminate = false; - for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] { - if let Err(Undetermined) = result.get() { - result.set({ - match self.resolve_name_in_module(module, source, ns, false, None) { + self.per_ns(|this, ns| { + if let Err(Undetermined) = result[ns].get() { + result[ns].set({ + match this.resolve_name_in_module(module, source, ns, false, None) { Success(binding) => Ok(binding), Indeterminate => Err(Undetermined), Failed(_) => Err(Determined), } }); } else { - continue + return }; - match result.get() { + match result[ns].get() { Err(Undetermined) => indeterminate = true, Err(Determined) => { - self.update_resolution(directive.parent, target, ns, |_, resolution| { + this.update_resolution(directive.parent, target, ns, |_, resolution| { resolution.single_imports.directive_failed() }); } Ok(binding) if !binding.is_importable() => { let msg = format!("`{}` is not directly importable", target); - struct_span_err!(self.session, directive.span, E0253, "{}", &msg) + struct_span_err!(this.session, directive.span, E0253, "{}", &msg) .span_label(directive.span, &format!("cannot be imported directly")) .emit(); // Do not import this illegal binding. Import a dummy binding and pretend // everything is fine - self.import_dummy_binding(directive); - return Success(()); + this.import_dummy_binding(directive); } Ok(binding) => { - let imported_binding = self.import(binding, directive); - let conflict = self.try_define(directive.parent, target, ns, imported_binding); + let imported_binding = this.import(binding, directive); + let conflict = this.try_define(directive.parent, target, ns, imported_binding); if let Err(old_binding) = conflict { - let binding = &self.import(binding, directive); - self.report_conflict(directive.parent, target, ns, binding, old_binding); + let binding = &this.import(binding, directive); + this.report_conflict(directive.parent, target, ns, binding, old_binding); } } } - } + }); if indeterminate { Indeterminate } else { Success(()) } } @@ -601,9 +588,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { }, }; - let (name, value_result, type_result) = match directive.subclass { - SingleImport { source, ref value_result, ref type_result, .. } => - (source, value_result.get(), type_result.get()), + let (name, result) = match directive.subclass { + SingleImport { source, ref result, .. } => (source, result), GlobImport { .. } if module.def_id() == directive.parent.def_id() => { // Importing a module into itself is not allowed. let msg = "Cannot glob-import a module into itself.".into(); @@ -621,21 +607,27 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { _ => unreachable!(), }; - for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] { - if let Ok(binding) = result { - if self.record_use(name, ns, binding, directive.span) { - self.resolution(module, name, ns).borrow_mut().binding = - Some(self.dummy_binding); + let mut all_ns_err = true; + self.per_ns(|this, ns| { + if let Ok(binding) = result[ns].get() { + all_ns_err = false; + if this.record_use(name, ns, binding, directive.span) { + this.resolution(module, name, ns).borrow_mut().binding = + Some(this.dummy_binding); } } - } + }); - if value_result.is_err() && type_result.is_err() { - let (value_result, type_result); - value_result = self.resolve_name_in_module(module, name, ValueNS, false, Some(span)); - type_result = self.resolve_name_in_module(module, name, TypeNS, false, Some(span)); + if all_ns_err { + let mut all_ns_failed = true; + self.per_ns(|this, ns| { + match this.resolve_name_in_module(module, name, ns, false, Some(span)) { + Success(_) => all_ns_failed = false, + _ => {} + } + }); - return if let (Failed(_), Failed(_)) = (value_result, type_result) { + return if all_ns_failed { let resolutions = module.resolutions.borrow(); let names = resolutions.iter().filter_map(|(&(ref n, _), resolution)| { if *n == name { return None; } // Never suggest the same name @@ -663,64 +655,49 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } } - let session = self.session; - let reexport_error = || { - let msg = format!("`{}` is private, and cannot be reexported", name); - let note_msg = - format!("consider marking `{}` as `pub` in the imported module", name); - struct_span_err!(session, directive.span, E0364, "{}", &msg) - .span_note(directive.span, ¬e_msg) - .emit(); - }; - - let extern_crate_lint = || { - let msg = format!("extern crate `{}` is private, and cannot be reexported \ - (error E0364), consider declaring with `pub`", - name); - session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg); - }; - - match (value_result, type_result) { - // All namespaces must be re-exported with extra visibility for an error to occur. - (Ok(value_binding), Ok(type_binding)) => { + let mut reexport_error = None; + let mut any_successful_reexport = false; + self.per_ns(|this, ns| { + if let Ok(binding) = result[ns].get() { let vis = directive.vis.get(); - if !value_binding.pseudo_vis().is_at_least(vis, self) && - !type_binding.pseudo_vis().is_at_least(vis, self) { - reexport_error(); - } else if type_binding.is_extern_crate() && - !type_binding.vis.is_at_least(vis, self) { - extern_crate_lint(); - } - } - - (Ok(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => { - reexport_error(); - } - - (_, Ok(binding)) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => { - if binding.is_extern_crate() { - extern_crate_lint(); + if !binding.pseudo_vis().is_at_least(vis, this) { + reexport_error = Some((ns, binding)); } else { - struct_span_err!(self.session, directive.span, E0365, - "`{}` is private, and cannot be reexported", name) - .span_label(directive.span, &format!("reexport of private `{}`", name)) - .note(&format!("consider declaring type or module `{}` with `pub`", name)) - .emit(); + any_successful_reexport = true; } } + }); - _ => {} + // All namespaces must be re-exported with extra visibility for an error to occur. + if !any_successful_reexport { + let (ns, binding) = reexport_error.unwrap(); + if ns == TypeNS && binding.is_extern_crate() { + let msg = format!("extern crate `{}` is private, and cannot be reexported \ + (error E0364), consider declaring with `pub`", + name); + self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg); + } else if ns == TypeNS { + struct_span_err!(self.session, directive.span, E0365, + "`{}` is private, and cannot be reexported", name) + .span_label(directive.span, &format!("reexport of private `{}`", name)) + .note(&format!("consider declaring type or module `{}` with `pub`", name)) + .emit(); + } else { + let msg = format!("`{}` is private, and cannot be reexported", name); + let note_msg = + format!("consider marking `{}` as `pub` in the imported module", name); + struct_span_err!(self.session, directive.span, E0364, "{}", &msg) + .span_note(directive.span, ¬e_msg) + .emit(); + } } // Record what this import resolves to for later uses in documentation, // this may resolve to either a value or a type, but for documentation // purposes it's good enough to just favor one over the other. - let def = match type_result.ok().map(NameBinding::def) { - Some(def) => def, - None => value_result.ok().map(NameBinding::def).unwrap(), - }; - let path_resolution = PathResolution::new(def); - self.def_map.insert(directive.id, path_resolution); + self.per_ns(|this, ns| if let Some(binding) = result[ns].get().ok() { + this.def_map.entry(directive.id).or_insert(PathResolution::new(binding.def())); + }); debug!("(resolving single import) successfully resolved import"); return Success(()); diff --git a/src/test/compile-fail/blind-item-block-item-shadow.rs b/src/test/compile-fail/blind-item-block-item-shadow.rs index a26b9e3c7aa2..2d53aee39e95 100644 --- a/src/test/compile-fail/blind-item-block-item-shadow.rs +++ b/src/test/compile-fail/blind-item-block-item-shadow.rs @@ -14,6 +14,6 @@ fn main() { { struct Bar; use foo::Bar; - //~^ ERROR a value named `Bar` has already been defined in this block + //~^ ERROR a type named `Bar` has already been defined in this block } } diff --git a/src/test/compile-fail/double-type-import.rs b/src/test/compile-fail/double-type-import.rs index e51ef5e32e81..760612c05ce4 100644 --- a/src/test/compile-fail/double-type-import.rs +++ b/src/test/compile-fail/double-type-import.rs @@ -11,7 +11,7 @@ mod foo { pub use self::bar::X; use self::bar::X; - //~^ ERROR a value named `X` has already been imported in this module + //~^ ERROR a type named `X` has already been imported in this module mod bar { pub struct X; From 9c886500801fe7cbdc4c9a7dfd2294df8b10db8b Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 10 Nov 2016 10:29:36 +0000 Subject: [PATCH 152/177] Add feature `use_extern_macros`. --- src/librustc_resolve/build_reduced_graph.rs | 12 +- src/librustc_resolve/lib.rs | 80 ++++++----- src/librustc_resolve/macros.rs | 150 ++++++++++++++++---- src/librustc_resolve/resolve_imports.rs | 135 +++++++++--------- src/libsyntax/feature_gate.rs | 2 + src/test/compile-fail/imports/duplicate.rs | 4 +- 6 files changed, 243 insertions(+), 140 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 5917a1a0d175..6816789cf284 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -504,9 +504,11 @@ impl<'b> Resolver<'b> { }) } - pub fn get_macro(&mut self, def: Def) -> Rc { - let def_id = match def { - Def::Macro(def_id) => def_id, + pub fn get_macro(&mut self, binding: &'b NameBinding<'b>) -> Rc { + let def_id = match binding.kind { + NameBindingKind::Def(Def::Macro(def_id)) => def_id, + NameBindingKind::Import { binding, .. } => return self.get_macro(binding), + NameBindingKind::Ambiguity { b1, .. } => return self.get_macro(b1), _ => panic!("Expected Def::Macro(..)"), }; if let Some(ext) = self.macro_map.get(&def_id) { @@ -579,7 +581,7 @@ impl<'b> Resolver<'b> { }); } else { for (name, span) in legacy_imports.imports { - let result = self.resolve_name_in_module(module, name, MacroNS, false, None); + let result = self.resolve_name_in_module(module, name, MacroNS, false, false, None); if let Success(binding) = result { self.legacy_import_macro(name, binding, span, allow_shadowing); } else { @@ -589,7 +591,7 @@ impl<'b> Resolver<'b> { } for (name, span) in legacy_imports.reexports { self.used_crates.insert(module.def_id().unwrap().krate); - let result = self.resolve_name_in_module(module, name, MacroNS, false, None); + let result = self.resolve_name_in_module(module, name, MacroNS, false, false, None); if let Success(binding) = result { self.macro_exports.push(Export { name: name, def: binding.def() }); } else { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index af7297702425..a3a60e4f6d75 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -540,6 +540,7 @@ pub enum Namespace { pub struct PerNS { value_ns: T, type_ns: T, + macro_ns: Option, } impl ::std::ops::Index for PerNS { @@ -548,7 +549,7 @@ impl ::std::ops::Index for PerNS { match ns { ValueNS => &self.value_ns, TypeNS => &self.type_ns, - MacroNS => unreachable!(), + MacroNS => self.macro_ns.as_ref().unwrap(), } } } @@ -558,7 +559,7 @@ impl ::std::ops::IndexMut for PerNS { match ns { ValueNS => &mut self.value_ns, TypeNS => &mut self.type_ns, - MacroNS => unreachable!(), + MacroNS => self.macro_ns.as_mut().unwrap(), } } } @@ -675,7 +676,7 @@ impl<'a> Visitor for Resolver<'a> { pub type ErrorMessage = Option<(Span, String)>; -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq, Debug)] pub enum ResolveResult { Failed(ErrorMessage), // Failed to resolve the name, optional helpful error message. Indeterminate, // Couldn't determine due to unresolved globs. @@ -683,14 +684,6 @@ pub enum ResolveResult { } impl ResolveResult { - fn and_then ResolveResult>(self, f: F) -> ResolveResult { - match self { - Failed(msg) => Failed(msg), - Indeterminate => Indeterminate, - Success(t) => f(t), - } - } - fn success(self) -> Option { match self { Success(t) => Some(t), @@ -825,6 +818,7 @@ pub struct ModuleS<'a> { normal_ancestor_id: Option, resolutions: RefCell>>>, + legacy_macro_resolutions: RefCell>, // Macro invocations that can expand into items in this module. unresolved_invocations: RefCell>, @@ -852,6 +846,7 @@ impl<'a> ModuleS<'a> { kind: kind, normal_ancestor_id: None, resolutions: RefCell::new(FxHashMap()), + legacy_macro_resolutions: RefCell::new(Vec::new()), unresolved_invocations: RefCell::new(FxHashSet()), no_implicit_prelude: false, glob_importers: RefCell::new(Vec::new()), @@ -943,6 +938,7 @@ struct PrivacyError<'a>(Span, Name, &'a NameBinding<'a>); struct AmbiguityError<'a> { span: Span, name: Name, + lexical: bool, b1: &'a NameBinding<'a>, b2: &'a NameBinding<'a>, } @@ -1001,7 +997,7 @@ impl<'a> NameBinding<'a> { fn is_glob_import(&self) -> bool { match self.kind { NameBindingKind::Import { directive, .. } => directive.is_glob(), - NameBindingKind::Ambiguity { .. } => true, + NameBindingKind::Ambiguity { b1, .. } => b1.is_glob_import(), _ => false, } } @@ -1136,6 +1132,7 @@ pub struct Resolver<'a> { arenas: &'a ResolverArenas<'a>, dummy_binding: &'a NameBinding<'a>, new_import_semantics: bool, // true if `#![feature(item_like_imports)]` + use_extern_macros: bool, // true if `#![feature(use_extern_macros)]` pub exported_macros: Vec, crate_loader: &'a mut CrateLoader, @@ -1300,6 +1297,7 @@ impl<'a> Resolver<'a> { ribs: PerNS { value_ns: vec![Rib::new(ModuleRibKind(graph_root))], type_ns: vec![Rib::new(ModuleRibKind(graph_root))], + macro_ns: None, }, label_ribs: Vec::new(), @@ -1336,6 +1334,7 @@ impl<'a> Resolver<'a> { vis: ty::Visibility::Public, }), new_import_semantics: session.features.borrow().item_like_imports, + use_extern_macros: session.features.borrow().use_extern_macros, exported_macros: Vec::new(), crate_loader: crate_loader, @@ -1365,6 +1364,10 @@ impl<'a> Resolver<'a> { PerNS { type_ns: f(self, TypeNS), value_ns: f(self, ValueNS), + macro_ns: match self.use_extern_macros { + true => Some(f(self, MacroNS)), + false => None, + }, } } @@ -1403,8 +1406,9 @@ impl<'a> Resolver<'a> { } NameBindingKind::Import { .. } => false, NameBindingKind::Ambiguity { b1, b2 } => { - let ambiguity_error = AmbiguityError { span: span, name: name, b1: b1, b2: b2 }; - self.ambiguity_errors.push(ambiguity_error); + self.ambiguity_errors.push(AmbiguityError { + span: span, name: name, lexical: false, b1: b1, b2: b2, + }); true } _ => false @@ -1438,7 +1442,7 @@ impl<'a> Resolver<'a> { -> ResolveResult> { fn search_parent_externals<'a>(this: &mut Resolver<'a>, needle: Name, module: Module<'a>) -> Option> { - match this.resolve_name_in_module(module, needle, TypeNS, false, None) { + match this.resolve_name_in_module(module, needle, TypeNS, false, false, None) { Success(binding) if binding.is_extern_crate() => Some(module), _ => if let (&ModuleKind::Def(..), Some(parent)) = (&module.kind, module.parent) { search_parent_externals(this, needle, parent) @@ -1456,7 +1460,7 @@ impl<'a> Resolver<'a> { // modules as we go. while index < module_path_len { let name = module_path[index].name; - match self.resolve_name_in_module(search_module, name, TypeNS, false, span) { + match self.resolve_name_in_module(search_module, name, TypeNS, false, false, span) { Failed(_) => { let segment_name = name.as_str(); let module_name = module_to_string(search_module); @@ -1613,7 +1617,7 @@ impl<'a> Resolver<'a> { if let ModuleRibKind(module) = self.ribs[ns][i].kind { let name = ident.name; - let item = self.resolve_name_in_module(module, name, ns, true, record_used); + let item = self.resolve_name_in_module(module, name, ns, true, false, record_used); if let Success(binding) = item { // The ident resolves to an item. return Some(LexicalScopeBinding::Item(binding)); @@ -1622,7 +1626,7 @@ impl<'a> Resolver<'a> { if let ModuleKind::Block(..) = module.kind { // We can see through blocks } else if !module.no_implicit_prelude { return self.prelude.and_then(|prelude| { - self.resolve_name_in_module(prelude, name, ns, false, None).success() + self.resolve_name_in_module(prelude, name, ns, false, false, None).success() }).map(LexicalScopeBinding::Item) } else { return None; @@ -1717,6 +1721,7 @@ impl<'a> Resolver<'a> { self.ribs[ValueNS].push(Rib::new(ModuleRibKind(module))); self.ribs[TypeNS].push(Rib::new(ModuleRibKind(module))); + self.finalize_current_module_macro_resolutions(); f(self); self.current_module = orig_module; @@ -2221,6 +2226,7 @@ impl<'a> Resolver<'a> { self.ribs[ValueNS].push(Rib::new(ModuleRibKind(anonymous_module))); self.ribs[TypeNS].push(Rib::new(ModuleRibKind(anonymous_module))); self.current_module = anonymous_module; + self.finalize_current_module_macro_resolutions(); } else { self.ribs[ValueNS].push(Rib::new(NormalRibKind)); } @@ -2754,8 +2760,7 @@ impl<'a> Resolver<'a> { let module_path = segments.split_last().unwrap().1.iter().map(|ps| ps.identifier).collect::>(); - let containing_module; - match self.resolve_module_path(&module_path, UseLexicalScope, Some(span)) { + let module = match self.resolve_module_path(&module_path, UseLexicalScope, Some(span)) { Failed(err) => { if let Some((span, msg)) = err { resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); @@ -2763,14 +2768,11 @@ impl<'a> Resolver<'a> { return Err(true); } Indeterminate => return Err(false), - Success(resulting_module) => { - containing_module = resulting_module; - } - } + Success(module) => module, + }; let name = segments.last().unwrap().identifier.name; - let result = - self.resolve_name_in_module(containing_module, name, namespace, false, Some(span)); + let result = self.resolve_name_in_module(module, name, namespace, false, false, Some(span)); result.success().ok_or(false) } @@ -2782,10 +2784,9 @@ impl<'a> Resolver<'a> { where T: Named, { let module_path = segments.split_last().unwrap().1.iter().map(T::ident).collect::>(); - let root_module = self.graph_root; + let root = self.graph_root; - let containing_module; - match self.resolve_module_path_from_root(root_module, &module_path, 0, Some(span)) { + let module = match self.resolve_module_path_from_root(root, &module_path, 0, Some(span)) { Failed(err) => { if let Some((span, msg)) = err { resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); @@ -2795,14 +2796,11 @@ impl<'a> Resolver<'a> { Indeterminate => return Err(false), - Success(resulting_module) => { - containing_module = resulting_module; - } - } + Success(module) => module, + }; let name = segments.last().unwrap().ident().name; - let result = - self.resolve_name_in_module(containing_module, name, namespace, false, Some(span)); + let result = self.resolve_name_in_module(module, name, namespace, false, false, Some(span)); result.success().ok_or(false) } @@ -3383,14 +3381,18 @@ impl<'a> Resolver<'a> { self.report_shadowing_errors(); let mut reported_spans = FxHashSet(); - for &AmbiguityError { span, name, b1, b2 } in &self.ambiguity_errors { + for &AmbiguityError { span, name, b1, b2, lexical } in &self.ambiguity_errors { if !reported_spans.insert(span) { continue } let msg1 = format!("`{}` could resolve to the name imported here", name); let msg2 = format!("`{}` could also resolve to the name imported here", name); self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)) .span_note(b1.span, &msg1) .span_note(b2.span, &msg2) - .note(&format!("Consider adding an explicit import of `{}` to disambiguate", name)) + .note(&if lexical || !b1.is_glob_import() { + "macro-expanded macro imports do not shadow".to_owned() + } else { + format!("consider adding an explicit import of `{}` to disambiguate", name) + }) .emit(); } @@ -3413,12 +3415,12 @@ impl<'a> Resolver<'a> { fn report_shadowing_errors(&mut self) { for (name, scope) in replace(&mut self.lexical_macro_resolutions, Vec::new()) { - self.resolve_macro_name(scope, name); + self.resolve_legacy_scope(scope, name, true); } let mut reported_errors = FxHashSet(); for binding in replace(&mut self.disallowed_shadowing, Vec::new()) { - if self.resolve_macro_name(binding.parent, binding.name).is_some() && + if self.resolve_legacy_scope(binding.parent, binding.name, false).is_some() && reported_errors.insert((binding.name, binding.span)) { let msg = format!("`{}` is already in scope", binding.name); self.session.struct_span_err(binding.span, &msg) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 2d434d660ea5..56d76272e235 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -8,7 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use {Module, ModuleKind, NameBinding, NameBindingKind, Resolver}; +use {Module, ModuleKind, NameBinding, NameBindingKind, Resolver, AmbiguityError}; +use Namespace::{self, MacroNS}; +use ResolveResult::{Success, Indeterminate, Failed}; use build_reduced_graph::BuildReducedGraphVisitor; use resolve_imports::ImportResolver; use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex}; @@ -17,7 +19,7 @@ use rustc::hir::map::{self, DefCollector}; use rustc::ty; use std::cell::Cell; use std::rc::Rc; -use syntax::ast; +use syntax::ast::{self, Name}; use syntax::errors::DiagnosticBuilder; use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator}; use syntax::ext::base::{NormalTT, SyntaxExtension}; @@ -85,6 +87,11 @@ pub struct LegacyBinding<'a> { pub span: Span, } +pub enum MacroBinding<'a> { + Legacy(&'a LegacyBinding<'a>), + Modern(&'a NameBinding<'a>), +} + impl<'a> base::Resolver for Resolver<'a> { fn next_node_id(&mut self) -> ast::NodeId { self.session.next_node_id() @@ -140,6 +147,7 @@ impl<'a> base::Resolver for Resolver<'a> { expansion: mark, }; expansion.visit_with(&mut visitor); + self.current_module.unresolved_invocations.borrow_mut().remove(&mark); invocation.expansion.set(visitor.legacy_scope); } @@ -201,7 +209,7 @@ impl<'a> base::Resolver for Resolver<'a> { for i in 0..attrs.len() { let name = intern(&attrs[i].name()); match self.builtin_macros.get(&name).cloned() { - Some(binding) => match *self.get_macro(binding.def()) { + Some(binding) => match *self.get_macro(binding) { MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => { return Some(attrs.remove(i)) } @@ -225,25 +233,77 @@ impl<'a> base::Resolver for Resolver<'a> { if let LegacyScope::Expansion(parent) = invocation.legacy_scope.get() { invocation.legacy_scope.set(LegacyScope::simplify_expansion(parent)); } - self.resolve_macro_name(invocation.legacy_scope.get(), name).ok_or_else(|| { - if force { - let msg = format!("macro undefined: '{}!'", name); - let mut err = self.session.struct_span_err(path.span, &msg); - self.suggest_macro_name(&name.as_str(), &mut err); - err.emit(); - Determinacy::Determined - } else { - Determinacy::Undetermined - } - }) + + self.current_module = invocation.module.get(); + let result = match self.resolve_legacy_scope(invocation.legacy_scope.get(), name, false) { + Some(MacroBinding::Legacy(binding)) => Ok(binding.ext.clone()), + Some(MacroBinding::Modern(binding)) => Ok(self.get_macro(binding)), + None => match self.resolve_in_item_lexical_scope(name, MacroNS, None) { + Some(binding) => Ok(self.get_macro(binding)), + None => return Err(if force { + let msg = format!("macro undefined: '{}!'", name); + let mut err = self.session.struct_span_err(path.span, &msg); + self.suggest_macro_name(&name.as_str(), &mut err); + err.emit(); + Determinacy::Determined + } else { + Determinacy::Undetermined + }), + }, + }; + + if self.use_extern_macros { + self.current_module.legacy_macro_resolutions.borrow_mut() + .push((scope, name, path.span)); + } + result } } impl<'a> Resolver<'a> { - pub fn resolve_macro_name(&mut self, mut scope: LegacyScope<'a>, name: ast::Name) - -> Option> { + // Resolve the name in the module's lexical scope, excluding non-items. + fn resolve_in_item_lexical_scope( + &mut self, name: Name, ns: Namespace, record_used: Option, + ) -> Option<&'a NameBinding<'a>> { + let mut module = self.current_module; + let mut potential_expanded_shadower = None; + loop { + // Since expanded macros may not shadow the lexical scope (enforced below), + // we can ignore unresolved invocations (indicated by the penultimate argument). + match self.resolve_name_in_module(module, name, ns, true, true, record_used) { + Success(binding) => { + let span = match record_used { + Some(span) => span, + None => return Some(binding), + }; + if let Some(shadower) = potential_expanded_shadower { + self.ambiguity_errors.push(AmbiguityError { + span: span, name: name, b1: shadower, b2: binding, lexical: true, + }); + return Some(shadower); + } else if binding.expansion == Mark::root() { + return Some(binding); + } else { + potential_expanded_shadower = Some(binding); + } + }, + Indeterminate => return None, + Failed(..) => {} + } + + match module.kind { + ModuleKind::Block(..) => module = module.parent.unwrap(), + ModuleKind::Def(..) => return potential_expanded_shadower, + } + } + } + + pub fn resolve_legacy_scope( + &mut self, mut scope: LegacyScope<'a>, name: ast::Name, record_used: bool, + ) -> Option> { let mut possible_time_travel = None; let mut relative_depth: u32 = 0; + let mut binding = None; loop { scope = match scope { LegacyScope::Empty => break, @@ -262,25 +322,59 @@ impl<'a> Resolver<'a> { relative_depth = relative_depth.saturating_sub(1); invocation.legacy_scope.get() } - LegacyScope::Binding(binding) => { - if binding.name == name { - if let Some(scope) = possible_time_travel { - // Check for disallowed shadowing later - self.lexical_macro_resolutions.push((name, scope)); - } else if relative_depth > 0 { - self.disallowed_shadowing.push(binding); + LegacyScope::Binding(potential_binding) => { + if potential_binding.name == name { + if (!self.use_extern_macros || record_used) && relative_depth > 0 { + self.disallowed_shadowing.push(potential_binding); } - return Some(binding.ext.clone()); + binding = Some(potential_binding); + break } - binding.parent + potential_binding.parent } }; } - if let Some(scope) = possible_time_travel { - self.lexical_macro_resolutions.push((name, scope)); + let binding = match binding { + Some(binding) => MacroBinding::Legacy(binding), + None => match self.builtin_macros.get(&name).cloned() { + Some(binding) => MacroBinding::Modern(binding), + None => return None, + }, + }; + + if !self.use_extern_macros { + if let Some(scope) = possible_time_travel { + // Check for disallowed shadowing later + self.lexical_macro_resolutions.push((name, scope)); + } + } + + Some(binding) + } + + pub fn finalize_current_module_macro_resolutions(&mut self) { + let module = self.current_module; + for &(mark, name, span) in module.legacy_macro_resolutions.borrow().iter() { + let legacy_scope = self.invocations[&mark].legacy_scope.get(); + let legacy_resolution = self.resolve_legacy_scope(legacy_scope, name, true); + let resolution = self.resolve_in_item_lexical_scope(name, MacroNS, Some(span)); + let (legacy_resolution, resolution) = match (legacy_resolution, resolution) { + (Some(legacy_resolution), Some(resolution)) => (legacy_resolution, resolution), + _ => continue, + }; + let (legacy_span, participle) = match legacy_resolution { + MacroBinding::Modern(binding) if binding.def() == resolution.def() => continue, + MacroBinding::Modern(binding) => (binding.span, "imported"), + MacroBinding::Legacy(binding) => (binding.span, "defined"), + }; + let msg1 = format!("`{}` could resolve to the macro {} here", name, participle); + let msg2 = format!("`{}` could also resolve to the macro imported here", name); + self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)) + .span_note(legacy_span, &msg1) + .span_note(resolution.span, &msg2) + .emit(); } - self.builtin_macros.get(&name).cloned().map(|binding| self.get_macro(binding.def())) } fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index f04f3bf45ee9..d0ce1acaadf6 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -11,7 +11,7 @@ use self::ImportDirectiveSubclass::*; use {Module, PerNS}; -use Namespace::{self, TypeNS}; +use Namespace::{self, TypeNS, MacroNS}; use {NameBinding, NameBindingKind, PrivacyError, ToNameBinding}; use ResolveResult; use ResolveResult::*; @@ -142,6 +142,7 @@ impl<'a> Resolver<'a> { name: Name, ns: Namespace, allow_private_imports: bool, + ignore_unresolved_invocations: bool, record_used: Option) -> ResolveResult<&'a NameBinding<'a>> { self.populate_module_if_necessary(module); @@ -175,23 +176,55 @@ impl<'a> Resolver<'a> { return resolution.binding.map(Success).unwrap_or(Failed(None)); } - // If the resolution doesn't depend on glob definability, check privacy and return. - if let Some(result) = self.try_result(&resolution, module, ns) { - return result.and_then(|binding| { - if self.is_accessible(binding.vis) && !is_disallowed_private_import(binding) || - binding.is_extern_crate() { // c.f. issue #37020 - Success(binding) - } else { - Failed(None) + let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| { + let usable = + this.is_accessible(binding.vis) && !is_disallowed_private_import(binding) || + binding.is_extern_crate(); // c.f. issue #37020 + if usable { Success(binding) } else { Failed(None) } + }; + + // Items and single imports are not shadowable. + if let Some(binding) = resolution.binding { + if !binding.is_glob_import() { + return check_usable(self, binding); + } + } + + // Check if a single import can still define the name. + match resolution.single_imports { + SingleImports::AtLeastOne => return Indeterminate, + SingleImports::MaybeOne(directive) if self.is_accessible(directive.vis.get()) => { + let module = match directive.imported_module.get() { + Some(module) => module, + None => return Indeterminate, + }; + let name = match directive.subclass { + SingleImport { source, .. } => source, + _ => unreachable!(), + }; + match self.resolve_name_in_module(module, name, ns, true, false, None) { + Failed(_) => {} + _ => return Indeterminate, } - }); + } + SingleImports::MaybeOne(_) | SingleImports::None => {}, + } + + let no_unresolved_invocations = + ignore_unresolved_invocations || module.unresolved_invocations.borrow().is_empty(); + match resolution.binding { + // In `MacroNS`, expanded bindings do not shadow (enforced in `try_define`). + Some(binding) if no_unresolved_invocations || ns == MacroNS => + return check_usable(self, binding), + None if no_unresolved_invocations => {} + _ => return Indeterminate, } // Check if the globs are determined for directive in module.globs.borrow().iter() { if self.is_accessible(directive.vis.get()) { if let Some(module) = directive.imported_module.get() { - let result = self.resolve_name_in_module(module, name, ns, true, None); + let result = self.resolve_name_in_module(module, name, ns, true, false, None); if let Indeterminate = result { return Indeterminate; } @@ -204,43 +237,6 @@ impl<'a> Resolver<'a> { Failed(None) } - // Returns Some(the resolution of the name), or None if the resolution depends - // on whether more globs can define the name. - fn try_result(&mut self, resolution: &NameResolution<'a>, module: Module<'a>, ns: Namespace) - -> Option>> { - match resolution.binding { - Some(binding) if !binding.is_glob_import() => - return Some(Success(binding)), // Items and single imports are not shadowable. - _ => {} - }; - - // Check if a single import can still define the name. - match resolution.single_imports { - SingleImports::AtLeastOne => return Some(Indeterminate), - SingleImports::MaybeOne(directive) if self.is_accessible(directive.vis.get()) => { - let module = match directive.imported_module.get() { - Some(module) => module, - None => return Some(Indeterminate), - }; - let name = match directive.subclass { - SingleImport { source, .. } => source, - _ => unreachable!(), - }; - match self.resolve_name_in_module(module, name, ns, true, None) { - Failed(_) => {} - _ => return Some(Indeterminate), - } - } - SingleImports::MaybeOne(_) | SingleImports::None => {}, - } - - if !module.unresolved_invocations.borrow().is_empty() { - return Some(Indeterminate); - } - - resolution.binding.map(Success) - } - // Add an import directive to the current module. pub fn add_import_directive(&mut self, module_path: Vec, @@ -315,29 +311,26 @@ impl<'a> Resolver<'a> { self.update_resolution(module, name, ns, |this, resolution| { if let Some(old_binding) = resolution.binding { if binding.is_glob_import() { - if !this.new_import_semantics || !old_binding.is_glob_import() { + if !this.new_import_semantics { resolution.duplicate_globs.push(binding); + } else if !old_binding.is_glob_import() && + !(ns == MacroNS && old_binding.expansion != Mark::root()) { } else if binding.def() != old_binding.def() { - resolution.binding = Some(this.arenas.alloc_name_binding(NameBinding { - kind: NameBindingKind::Ambiguity { - b1: old_binding, - b2: binding, - }, - vis: if old_binding.vis.is_at_least(binding.vis, this) { - old_binding.vis - } else { - binding.vis - }, - span: old_binding.span, - expansion: Mark::root(), - })); + resolution.binding = Some(this.ambiguity(old_binding, binding)); } else if !old_binding.vis.is_at_least(binding.vis, this) { // We are glob-importing the same item but with greater visibility. resolution.binding = Some(binding); } } else if old_binding.is_glob_import() { - resolution.duplicate_globs.push(old_binding); - resolution.binding = Some(binding); + if !this.new_import_semantics { + resolution.duplicate_globs.push(old_binding); + resolution.binding = Some(binding); + } else if ns == MacroNS && binding.expansion != Mark::root() && + binding.def() != old_binding.def() { + resolution.binding = Some(this.ambiguity(binding, old_binding)); + } else { + resolution.binding = Some(binding); + } } else { return Err(old_binding); } @@ -349,6 +342,16 @@ impl<'a> Resolver<'a> { }) } + pub fn ambiguity(&mut self, b1: &'a NameBinding<'a>, b2: &'a NameBinding<'a>) + -> &'a NameBinding<'a> { + self.arenas.alloc_name_binding(NameBinding { + kind: NameBindingKind::Ambiguity { b1: b1, b2: b2 }, + vis: if b1.vis.is_at_least(b2.vis, self) { b1.vis } else { b2.vis }, + span: b1.span, + expansion: Mark::root(), + }) + } + // Use `f` to mutate the resolution of the name in the module. // If the resolution becomes a success, define it in the module's glob importers. fn update_resolution(&mut self, module: Module<'a>, name: Name, ns: Namespace, f: F) -> T @@ -525,7 +528,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.per_ns(|this, ns| { if let Err(Undetermined) = result[ns].get() { result[ns].set({ - match this.resolve_name_in_module(module, source, ns, false, None) { + match this.resolve_name_in_module(module, source, ns, false, false, None) { Success(binding) => Ok(binding), Indeterminate => Err(Undetermined), Failed(_) => Err(Determined), @@ -621,7 +624,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if all_ns_err { let mut all_ns_failed = true; self.per_ns(|this, ns| { - match this.resolve_name_in_module(module, name, ns, false, Some(span)) { + match this.resolve_name_in_module(module, name, ns, false, false, Some(span)) { Success(_) => all_ns_failed = false, _ => {} } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 27f720b76099..ea66fdc31cf0 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -314,6 +314,8 @@ declare_features! ( // Allows #[link(..., cfg(..))] (active, link_cfg, "1.14.0", Some(37406)), + + (active, use_extern_macros, "1.15.0", Some(35896)), ); declare_features! ( diff --git a/src/test/compile-fail/imports/duplicate.rs b/src/test/compile-fail/imports/duplicate.rs index fb61bb8e489b..faf85a523e8f 100644 --- a/src/test/compile-fail/imports/duplicate.rs +++ b/src/test/compile-fail/imports/duplicate.rs @@ -46,9 +46,9 @@ mod g { fn main() { e::foo(); f::foo(); //~ ERROR `foo` is ambiguous - //~| NOTE Consider adding an explicit import of `foo` to disambiguate + //~| NOTE consider adding an explicit import of `foo` to disambiguate g::foo(); //~ ERROR `foo` is ambiguous - //~| NOTE Consider adding an explicit import of `foo` to disambiguate + //~| NOTE consider adding an explicit import of `foo` to disambiguate } mod ambiguous_module_errors { From d8722f3fe138804dc2cef4764405a17f0f759808 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 12 Nov 2016 09:38:12 +0000 Subject: [PATCH 153/177] Add tests. --- .../imports/auxiliary/two_macros.rs | 15 +++++ src/test/compile-fail/imports/macros.rs | 55 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 src/test/compile-fail/imports/auxiliary/two_macros.rs create mode 100644 src/test/compile-fail/imports/macros.rs diff --git a/src/test/compile-fail/imports/auxiliary/two_macros.rs b/src/test/compile-fail/imports/auxiliary/two_macros.rs new file mode 100644 index 000000000000..2ac8e3ef983d --- /dev/null +++ b/src/test/compile-fail/imports/auxiliary/two_macros.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[macro_export] +macro_rules! m { ($($t:tt)*) => { $($t)* } } + +#[macro_export] +macro_rules! n { ($($t:tt)*) => { $($t)* } } diff --git a/src/test/compile-fail/imports/macros.rs b/src/test/compile-fail/imports/macros.rs new file mode 100644 index 000000000000..c11d2aab7c62 --- /dev/null +++ b/src/test/compile-fail/imports/macros.rs @@ -0,0 +1,55 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:two_macros.rs + +#![feature(item_like_imports, use_extern_macros)] + +extern crate two_macros; // two identity macros `m` and `n` + +mod foo { + pub use two_macros::n as m; +} + +mod m1 { + m!(use two_macros::*;); + use foo::m; // This shadows the glob import +} + +mod m2 { + use two_macros::*; //~ NOTE could also resolve + m! { //~ ERROR ambiguous + //~| NOTE macro-expanded macro imports do not shadow + use foo::m; //~ NOTE could resolve to the name imported here + //~^^^ NOTE in this expansion + } +} + +mod m3 { + use two_macros::m; //~ NOTE could also resolve + fn f() { + use two_macros::n as m; // This shadows the above import + m!(); + } + + fn g() { + m! { //~ ERROR ambiguous + //~| NOTE macro-expanded macro imports do not shadow + use two_macros::n as m; //~ NOTE could resolve to the name imported here + //~^^^ NOTE in this expansion + } + } +} + +mod m4 { + macro_rules! m { () => {} } //~ NOTE could resolve to the macro defined here + use two_macros::m; //~ NOTE could also resolve to the macro imported here + m!(); //~ ERROR ambiguous +} From 6cb33a089fc4727bc070899f57aab3be1b215785 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 17 Nov 2016 08:16:32 +0000 Subject: [PATCH 154/177] Cleanup formatting. --- src/librustc_resolve/build_reduced_graph.rs | 35 +++++++++++---------- src/librustc_resolve/macros.rs | 16 ++++++---- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 6816789cf284..627c72ff8c92 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -362,9 +362,11 @@ impl<'b> Resolver<'b> { // Constructs the reduced graph for one variant. Variants exist in the // type and value namespaces. - fn build_reduced_graph_for_variant( - &mut self, variant: &Variant, parent: Module<'b>, vis: ty::Visibility, expansion: Mark, - ) { + fn build_reduced_graph_for_variant(&mut self, + variant: &Variant, + parent: Module<'b>, + vis: ty::Visibility, + expansion: Mark) { let name = variant.node.name.name; let def_id = self.definitions.local_def_id(variant.node.data.id()); @@ -381,22 +383,20 @@ impl<'b> Resolver<'b> { } /// Constructs the reduced graph for one foreign item. - fn build_reduced_graph_for_foreign_item( - &mut self, foreign_item: &ForeignItem, expansion: Mark, - ) { + fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem, expansion: Mark) { let parent = self.current_module; - let name = foreign_item.ident.name; + let name = item.ident.name; - let def = match foreign_item.node { + let def = match item.node { ForeignItemKind::Fn(..) => { - Def::Fn(self.definitions.local_def_id(foreign_item.id)) + Def::Fn(self.definitions.local_def_id(item.id)) } ForeignItemKind::Static(_, m) => { - Def::Static(self.definitions.local_def_id(foreign_item.id), m) + Def::Static(self.definitions.local_def_id(item.id), m) } }; - let vis = self.resolve_visibility(&foreign_item.vis); - self.define(parent, name, ValueNS, (def, vis, foreign_item.span, expansion)); + let vis = self.resolve_visibility(&item.vis); + self.define(parent, name, ValueNS, (def, vis, item.span, expansion)); } fn build_reduced_graph_for_block(&mut self, block: &Block) { @@ -415,8 +415,7 @@ impl<'b> Resolver<'b> { } /// Builds the reduced graph for a single item in an external crate. - fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>, - child: Export) { + fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>, child: Export) { let name = child.name; let def = child.def; let def_id = def.def_id(); @@ -545,9 +544,11 @@ impl<'b> Resolver<'b> { module.populated.set(true) } - fn legacy_import_macro( - &mut self, name: Name, binding: &'b NameBinding<'b>, span: Span, allow_shadowing: bool, - ) { + fn legacy_import_macro(&mut self, + name: Name, + binding: &'b NameBinding<'b>, + span: Span, + allow_shadowing: bool) { self.used_crates.insert(binding.def().def_id().krate); self.macro_names.insert(name); if self.builtin_macros.insert(name, binding).is_some() && !allow_shadowing { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 56d76272e235..524d491a464e 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -262,9 +262,11 @@ impl<'a> base::Resolver for Resolver<'a> { impl<'a> Resolver<'a> { // Resolve the name in the module's lexical scope, excluding non-items. - fn resolve_in_item_lexical_scope( - &mut self, name: Name, ns: Namespace, record_used: Option, - ) -> Option<&'a NameBinding<'a>> { + fn resolve_in_item_lexical_scope(&mut self, + name: Name, + ns: Namespace, + record_used: Option) + -> Option<&'a NameBinding<'a>> { let mut module = self.current_module; let mut potential_expanded_shadower = None; loop { @@ -298,9 +300,11 @@ impl<'a> Resolver<'a> { } } - pub fn resolve_legacy_scope( - &mut self, mut scope: LegacyScope<'a>, name: ast::Name, record_used: bool, - ) -> Option> { + pub fn resolve_legacy_scope(&mut self, + mut scope: LegacyScope<'a>, + name: Name, + record_used: bool) + -> Option> { let mut possible_time_travel = None; let mut relative_depth: u32 = 0; let mut binding = None; From b9ed51c8f179da643bc7186c35d1beb3c5239723 Mon Sep 17 00:00:00 2001 From: Josh Driver Date: Thu, 17 Nov 2016 22:06:36 +1030 Subject: [PATCH 155/177] Show a better error when using --test with #[proc_macro_derive] --- src/librustc_driver/driver.rs | 2 ++ src/libsyntax_ext/proc_macro_registrar.rs | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 2dd83f708235..97dff3396c53 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -709,10 +709,12 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, let crate_types = sess.crate_types.borrow(); let num_crate_types = crate_types.len(); let is_proc_macro_crate = crate_types.contains(&config::CrateTypeProcMacro); + let is_test_crate = sess.opts.test; syntax_ext::proc_macro_registrar::modify(&sess.parse_sess, &mut resolver, krate, is_proc_macro_crate, + is_test_crate, num_crate_types, sess.diagnostic(), &sess.features.borrow()) diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index d6d31200a994..36fd6408b4f3 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -38,12 +38,14 @@ struct CollectCustomDerives<'a> { in_root: bool, handler: &'a errors::Handler, is_proc_macro_crate: bool, + is_test_crate: bool, } pub fn modify(sess: &ParseSess, resolver: &mut ::syntax::ext::base::Resolver, mut krate: ast::Crate, is_proc_macro_crate: bool, + is_test_crate: bool, num_crate_types: usize, handler: &errors::Handler, features: &Features) -> ast::Crate { @@ -55,6 +57,7 @@ pub fn modify(sess: &ParseSess, in_root: true, handler: handler, is_proc_macro_crate: is_proc_macro_crate, + is_test_crate: is_test_crate, }; visit::walk_crate(&mut collect, &krate); @@ -137,6 +140,12 @@ impl<'a> Visitor for CollectCustomDerives<'a> { attributes found"); } + if self.is_test_crate { + self.handler.span_err(attr.span(), + "`--test` cannot be used with proc-macro crates"); + return; + } + if !self.is_proc_macro_crate { self.handler.span_err(attr.span(), "the `#[proc_macro_derive]` attribute is \ From 3254fabf8e4a81a595579fa19abd5ec49bff270d Mon Sep 17 00:00:00 2001 From: Josh Driver Date: Fri, 18 Nov 2016 02:11:20 +1030 Subject: [PATCH 156/177] Add tests --- .../proc-macro/error-on-test.rs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/test/compile-fail-fulldeps/proc-macro/error-on-test.rs diff --git a/src/test/compile-fail-fulldeps/proc-macro/error-on-test.rs b/src/test/compile-fail-fulldeps/proc-macro/error-on-test.rs new file mode 100644 index 000000000000..1fd48f075deb --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/error-on-test.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --test + +#![crate_type = "proc-macro"] +#![feature(proc_macro)] + +extern crate proc_macro; + +#[proc_macro_derive(A)] +//~^ ERROR: `--test` cannot be used with proc-macro crates +pub fn foo1(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + "".parse().unwrap() +} From 34c361cfb2e7aa3efffe8783d2c31afc9e43f040 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 11 Nov 2016 18:22:41 -0500 Subject: [PATCH 157/177] when creating an AssociatedItem, read data from impl, not impl item Before, when we created an AssociatedItem for impl item X, we would read the impl item itself. Now we instead load up the impl I that contains X and read the data from the `ImplItemRef` for X; actually, we do it for all impl items in I pre-emptively. This kills the last source of edges between a method X and a call to a method Y defined in the same impl. Fixes #37121 --- src/librustc/hir/def.rs | 2 +- src/librustc/traits/project.rs | 5 +- src/librustc/ty/mod.rs | 163 +++++++++++------- src/librustc_typeck/collect.rs | 6 +- src/librustdoc/visit_ast.rs | 4 +- .../struct_point.rs | 11 +- .../struct_point.rs | 26 +-- 7 files changed, 128 insertions(+), 89 deletions(-) diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 044e36e5c9cd..feefc43f4013 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -106,7 +106,7 @@ pub type DefMap = NodeMap; // within. pub type ExportMap = NodeMap>; -#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] pub struct Export { pub name: ast::Name, // The name of the target. pub def: Def, // The definition of the target. diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index f1b69feb545e..ac2f3ad9b899 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -1007,8 +1007,9 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // types, which appear not to unify -- so the // overlap check succeeds, when it should // fail. - bug!("Tried to project an inherited associated type during \ - coherence checking, which is currently not supported."); + span_bug!(obligation.cause.span, + "Tried to project an inherited associated type during \ + coherence checking, which is currently not supported."); }; candidate_set.vec.extend(new_candidate); } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 4db788a92d64..9984dd42f566 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2113,69 +2113,111 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { .expect("missing AssociatedItem in metadata"); } + // When the user asks for a given associated item, we + // always go ahead and convert all the associated items in + // the container. Note that we are also careful only to + // ever register a read on the *container* of the assoc + // item, not the assoc item itself. This prevents changes + // in the details of an item (for example, the type to + // which an associated type is bound) from contaminating + // those tasks that just need to scan the names of items + // and so forth. + let id = self.map.as_local_node_id(def_id).unwrap(); let parent_id = self.map.get_parent(id); let parent_def_id = self.map.local_def_id(parent_id); - match self.map.get(id) { - ast_map::NodeTraitItem(trait_item) => { - let (kind, has_self, has_value) = match trait_item.node { - hir::MethodTraitItem(ref sig, ref body) => { - (AssociatedKind::Method, sig.decl.get_self().is_some(), - body.is_some()) - } - hir::ConstTraitItem(_, ref value) => { - (AssociatedKind::Const, false, value.is_some()) - } - hir::TypeTraitItem(_, ref ty) => { - (AssociatedKind::Type, false, ty.is_some()) - } - }; - - AssociatedItem { - name: trait_item.name, - kind: kind, - vis: Visibility::from_hir(&hir::Inherited, id, self), - defaultness: hir::Defaultness::Default, - has_value: has_value, - def_id: def_id, - container: TraitContainer(parent_def_id), - method_has_self_argument: has_self + let parent_item = self.map.expect_item(parent_id); + match parent_item.node { + hir::ItemImpl(.., ref impl_trait_ref, _, ref impl_item_refs) => { + for impl_item_ref in impl_item_refs { + let assoc_item = + self.associated_item_from_impl_item_ref(parent_def_id, + impl_trait_ref.is_some(), + impl_item_ref); + self.associated_items.borrow_mut().insert(assoc_item.def_id, assoc_item); } } - ast_map::NodeImplItem(impl_item) => { - let (kind, has_self) = match impl_item.node { - hir::ImplItemKind::Method(ref sig, _) => { - (AssociatedKind::Method, sig.decl.get_self().is_some()) - } - hir::ImplItemKind::Const(..) => (AssociatedKind::Const, false), - hir::ImplItemKind::Type(..) => (AssociatedKind::Type, false) - }; - // Trait impl items are always public. - let public = hir::Public; - let parent_item = self.map.expect_item(parent_id); - let vis = if let hir::ItemImpl(.., Some(_), _, _) = parent_item.node { - &public - } else { - &impl_item.vis - }; - - AssociatedItem { - name: impl_item.name, - kind: kind, - vis: Visibility::from_hir(vis, id, self), - defaultness: impl_item.defaultness, - has_value: true, - def_id: def_id, - container: ImplContainer(parent_def_id), - method_has_self_argument: has_self + hir::ItemTrait(.., ref trait_items) => { + for trait_item in trait_items { + let assoc_item = + self.associated_item_from_trait_item_ref(parent_def_id, trait_item); + self.associated_items.borrow_mut().insert(assoc_item.def_id, assoc_item); } } - item => bug!("associated_item: {:?} not an associated item", item) + + ref r => { + panic!("unexpected container of associated items: {:?}", r) + } } + + // memoize wants us to return something, so return + // the one we generated for this def-id + *self.associated_items.borrow().get(&def_id).unwrap() }) } + fn associated_item_from_trait_item_ref(self, + parent_def_id: DefId, + trait_item: &hir::TraitItem) + -> AssociatedItem { + let def_id = self.map.local_def_id(trait_item.id); + + let (kind, has_self, has_value) = match trait_item.node { + hir::MethodTraitItem(ref sig, ref body) => { + (AssociatedKind::Method, sig.decl.get_self().is_some(), + body.is_some()) + } + hir::ConstTraitItem(_, ref value) => { + (AssociatedKind::Const, false, value.is_some()) + } + hir::TypeTraitItem(_, ref ty) => { + (AssociatedKind::Type, false, ty.is_some()) + } + }; + + AssociatedItem { + name: trait_item.name, + kind: kind, + vis: Visibility::from_hir(&hir::Inherited, trait_item.id, self), + defaultness: hir::Defaultness::Default, + has_value: has_value, + def_id: def_id, + container: TraitContainer(parent_def_id), + method_has_self_argument: has_self + } + } + + fn associated_item_from_impl_item_ref(self, + parent_def_id: DefId, + from_trait_impl: bool, + impl_item_ref: &hir::ImplItemRef) + -> AssociatedItem { + let def_id = self.map.local_def_id(impl_item_ref.id.node_id); + let (kind, has_self) = match impl_item_ref.kind { + hir::AssociatedItemKind::Const => (ty::AssociatedKind::Const, false), + hir::AssociatedItemKind::Method { has_self } => { + (ty::AssociatedKind::Method, has_self) + } + hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false), + }; + + // Trait impl items are always public. + let public = hir::Public; + let vis = if from_trait_impl { &public } else { &impl_item_ref.vis }; + + ty::AssociatedItem { + name: impl_item_ref.name, + kind: kind, + vis: ty::Visibility::from_hir(vis, impl_item_ref.id.node_id, self), + defaultness: impl_item_ref.defaultness, + has_value: true, + def_id: def_id, + container: ImplContainer(parent_def_id), + method_has_self_argument: has_self + } + } + pub fn associated_item_def_ids(self, def_id: DefId) -> Rc> { self.associated_item_def_ids.memoize(def_id, || { if !def_id.is_local() { @@ -2184,19 +2226,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let id = self.map.as_local_node_id(def_id).unwrap(); let item = self.map.expect_item(id); - match item.node { + let vec: Vec<_> = match item.node { hir::ItemTrait(.., ref trait_items) => { - Rc::new(trait_items.iter().map(|trait_item| { - self.map.local_def_id(trait_item.id) - }).collect()) + trait_items.iter() + .map(|trait_item| trait_item.id) + .map(|id| self.map.local_def_id(id)) + .collect() } hir::ItemImpl(.., ref impl_item_refs) => { - Rc::new(impl_item_refs.iter().map(|impl_item_ref| { - self.map.local_def_id(impl_item_ref.id.node_id) - }).collect()) + impl_item_refs.iter() + .map(|impl_item_ref| impl_item_ref.id) + .map(|id| self.map.local_def_id(id.node_id)) + .collect() } _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait") - } + }; + Rc::new(vec) }) } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index c20e1d1d4d74..535b6bcdcba1 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -731,11 +731,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { ref generics, ref opt_trait_ref, ref selfty, - ref _impl_item_ids /* [1] */) => { - // [1]: We really don't want to be inspecting the details - // of impl-items here; it creates bad edges in the - // incr. comp. graph. - + _) => { // Create generics from the generics specified in the impl head. debug!("convert: ast_generics={:?}", generics); let def_id = ccx.tcx.map.local_def_id(it.id); diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 6587392e18ff..939fd6ccfc88 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -507,7 +507,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // regardless of where they're located. if !self.inlining { let items = item_ids.iter() - .map(|&id| self.cx.map.impl_item(id).clone()) + .map(|ii| self.cx.map.impl_item(ii.id).clone()) .collect(); let i = Impl { unsafety: unsafety, @@ -515,7 +515,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { generics: gen.clone(), trait_: tr.clone(), for_: ty.clone(), - items: items.clone(), + items: items, attrs: item.attrs.clone(), id: item.id, whence: item.span, diff --git a/src/test/incremental/change_private_impl_method/struct_point.rs b/src/test/incremental/change_private_impl_method/struct_point.rs index 8fa34bde1705..46e5a88eef94 100644 --- a/src/test/incremental/change_private_impl_method/struct_point.rs +++ b/src/test/incremental/change_private_impl_method/struct_point.rs @@ -20,9 +20,8 @@ #![rustc_partition_translated(module="struct_point-point", cfg="rpass2")] -// FIXME(#37121) -- the following two modules *should* be reused but are not -#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")] -#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")] #![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")] #![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")] #![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")] @@ -60,8 +59,7 @@ mod point { mod fn_calls_methods_in_same_impl { use point::Point; - // FIXME(#37121) -- we should not need to typeck this again - #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; x.distance_from_origin(); @@ -72,8 +70,7 @@ mod fn_calls_methods_in_same_impl { mod fn_calls_methods_in_another_impl { use point::Point; - // FIXME(#37121) -- we should not need to typeck this again - #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] pub fn check() { let mut x = Point { x: 2.0, y: 2.0 }; x.translate(3.0, 3.0); diff --git a/src/test/incremental/change_private_impl_method_cc/struct_point.rs b/src/test/incremental/change_private_impl_method_cc/struct_point.rs index d8e5fbadad8b..a8779e3f92d9 100644 --- a/src/test/incremental/change_private_impl_method_cc/struct_point.rs +++ b/src/test/incremental/change_private_impl_method_cc/struct_point.rs @@ -19,12 +19,15 @@ #![feature(stmt_expr_attributes)] #![allow(dead_code)] -// FIXME(#37333) -- the following modules *should* be reused but are not +#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")] + +// FIXME(#37333) the struct fields get entangled with inherent methods +#![rustc_partition_translated(module="struct_point-fn_make_struct", cfg="rpass2")] + +// FIXME(#37720) these two should be reused, but data gets entangled across crates #![rustc_partition_translated(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")] #![rustc_partition_translated(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")] -#![rustc_partition_translated(module="struct_point-fn_make_struct", cfg="rpass2")] -#![rustc_partition_translated(module="struct_point-fn_read_field", cfg="rpass2")] -#![rustc_partition_translated(module="struct_point-fn_write_field", cfg="rpass2")] extern crate point; @@ -32,7 +35,7 @@ extern crate point; mod fn_calls_methods_in_same_impl { use point::Point; - // FIXME(#37333) -- we should not need to typeck this again + // FIXME(#37720) data gets entangled across crates #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; @@ -44,9 +47,9 @@ mod fn_calls_methods_in_same_impl { mod fn_calls_methods_in_another_impl { use point::Point; - // FIXME(#37333) -- we should not need to typeck this again + // FIXME(#37720) data gets entangled across crates #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] - pub fn check() { + pub fn dirty() { let mut x = Point { x: 2.0, y: 2.0 }; x.translate(3.0, 3.0); } @@ -56,8 +59,7 @@ mod fn_calls_methods_in_another_impl { mod fn_make_struct { use point::Point; - // FIXME(#37333) -- we should not need to typeck this again - #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] pub fn make_origin() -> Point { Point { x: 2.0, y: 2.0 } } @@ -67,8 +69,7 @@ mod fn_make_struct { mod fn_read_field { use point::Point; - // FIXME(#37333) -- we should not need to typeck this again - #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] pub fn get_x(p: Point) -> f32 { p.x } @@ -78,8 +79,7 @@ mod fn_read_field { mod fn_write_field { use point::Point; - // FIXME(#37333) -- we should not need to typeck this again - #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } From c17be9ea110a1158e6a1ad131941ec6965ce6ac9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 11 Nov 2016 09:52:46 -0500 Subject: [PATCH 158/177] move impl wf check so they occur earlier Needed to keep coherence from freaking out. --- .../check/impl_item_duplicate.rs | 46 --------- src/librustc_typeck/check/mod.rs | 12 +-- ...pl_parameters_used.rs => impl_wf_check.rs} | 96 ++++++++++++++++--- src/librustc_typeck/lib.rs | 6 ++ src/test/compile-fail/issue-3214.rs | 1 - 5 files changed, 92 insertions(+), 69 deletions(-) delete mode 100644 src/librustc_typeck/check/impl_item_duplicate.rs rename src/librustc_typeck/{check/impl_parameters_used.rs => impl_wf_check.rs} (51%) diff --git a/src/librustc_typeck/check/impl_item_duplicate.rs b/src/librustc_typeck/check/impl_item_duplicate.rs deleted file mode 100644 index 7b33aa694a26..000000000000 --- a/src/librustc_typeck/check/impl_item_duplicate.rs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use rustc::hir; -use rustc_data_structures::fx::FxHashMap; -use std::collections::hash_map::Entry::{Occupied, Vacant}; - -use CrateCtxt; - -/// Enforce that we do not have two items in an impl with the same name. -pub fn enforce_impl_items_are_distinct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - impl_item_refs: &[hir::ImplItemRef]) -{ - let tcx = ccx.tcx; - let mut seen_type_items = FxHashMap(); - let mut seen_value_items = FxHashMap(); - for &impl_item_ref in impl_item_refs { - let impl_item = tcx.map.impl_item(impl_item_ref.id); - let seen_items = match impl_item.node { - hir::ImplItemKind::Type(_) => &mut seen_type_items, - _ => &mut seen_value_items, - }; - match seen_items.entry(impl_item.name) { - Occupied(entry) => { - let mut err = struct_span_err!(tcx.sess, impl_item.span, E0201, - "duplicate definitions with name `{}`:", - impl_item.name); - err.span_label(*entry.get(), - &format!("previous definition of `{}` here", - impl_item.name)); - err.span_label(impl_item.span, &format!("duplicate definition")); - err.emit(); - } - Vacant(entry) => { - entry.insert(impl_item.span); - } - } - } -} diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a8e38a362b56..2197ecc10a18 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -143,8 +143,6 @@ mod closure; mod callee; mod compare_method; mod intrinsic; -mod impl_item_duplicate; -mod impl_parameters_used; mod op; /// closures defined within the function. For example: @@ -817,7 +815,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { it.id); } hir::ItemFn(..) => {} // entirely within check_item_body - hir::ItemImpl(_, _, ref hir_generics, _, _, ref impl_item_refs) => { + hir::ItemImpl(.., ref impl_item_refs) => { debug!("ItemImpl {} with id {}", it.name, it.id); let impl_def_id = ccx.tcx.map.local_def_id(it.id); if let Some(impl_trait_ref) = ccx.tcx.impl_trait_ref(impl_def_id) { @@ -829,14 +827,6 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { let trait_def_id = impl_trait_ref.def_id; check_on_unimplemented(ccx, trait_def_id, it); } - - impl_parameters_used::enforce_impl_params_are_constrained(ccx, - hir_generics, - impl_def_id, - impl_item_refs); - - impl_item_duplicate::enforce_impl_items_are_distinct(ccx, - impl_item_refs); } hir::ItemTrait(..) => { let def_id = ccx.tcx.map.local_def_id(it.id); diff --git a/src/librustc_typeck/check/impl_parameters_used.rs b/src/librustc_typeck/impl_wf_check.rs similarity index 51% rename from src/librustc_typeck/check/impl_parameters_used.rs rename to src/librustc_typeck/impl_wf_check.rs index 650e959ba01f..1572d04f68c1 100644 --- a/src/librustc_typeck/check/impl_parameters_used.rs +++ b/src/librustc_typeck/impl_wf_check.rs @@ -8,11 +8,24 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! This pass enforces various "well-formedness constraints" on impls. +//! Logically, it is part of wfcheck -- but we do it early so that we +//! can stop compilation afterwards, since part of the trait matching +//! infrastructure gets very grumpy if these conditions don't hold. In +//! particular, if there are type parameters that are not part of the +//! impl, then coherence will report strange inference ambiguity +//! errors; if impls have duplicate items, we get misleading +//! specialization errors. These things can (and probably should) be +//! fixed, but for the moment it's easier to do these checks early. + use constrained_type_params as ctp; +use rustc::dep_graph::DepNode; use rustc::hir; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::def_id::DefId; use rustc::ty; -use rustc::util::nodemap::FxHashSet; +use rustc::util::nodemap::{FxHashMap, FxHashSet}; +use std::collections::hash_map::Entry::{Occupied, Vacant}; use syntax_pos::Span; @@ -48,22 +61,52 @@ use CrateCtxt; /// impl<'a> Trait for Bar { type X = &'a i32; } /// ^ 'a is unused and appears in assoc type, error /// ``` -pub fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - impl_hir_generics: &hir::Generics, - impl_def_id: DefId, - impl_item_refs: &[hir::ImplItemRef]) +pub fn impl_wf_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>) { + // We will tag this as part of the WF check -- logically, it is, + // but it's one that we must perform earlier than the rest of + // WfCheck. + ccx.tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut ImplWfCheck { ccx: ccx }); +} + +struct ImplWfCheck<'a, 'tcx: 'a> { + ccx: &'a CrateCtxt<'a, 'tcx>, +} + +impl<'a, 'tcx> ItemLikeVisitor<'tcx> for ImplWfCheck<'a, 'tcx> { + fn visit_item(&mut self, item: &'tcx hir::Item) { + match item.node { + hir::ItemImpl(.., ref generics, _, _, ref impl_item_refs) => { + let impl_def_id = self.ccx.tcx.map.local_def_id(item.id); + enforce_impl_params_are_constrained(self.ccx, + generics, + impl_def_id, + impl_item_refs); + enforce_impl_items_are_distinct(self.ccx, impl_item_refs); + } + _ => { } + } + } + + fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) { } +} + +fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + impl_hir_generics: &hir::Generics, + impl_def_id: DefId, + impl_item_refs: &[hir::ImplItemRef]) { // Every lifetime used in an associated type must be constrained. - let impl_scheme = ccx.tcx.lookup_item_type(impl_def_id); - let impl_predicates = ccx.tcx.lookup_predicates(impl_def_id); + let impl_self_ty = ccx.tcx.item_type(impl_def_id); + let impl_generics = ccx.tcx.item_generics(impl_def_id); + let impl_predicates = ccx.tcx.item_predicates(impl_def_id); let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id); - let mut input_parameters = ctp::parameters_for_impl(impl_scheme.ty, impl_trait_ref); + let mut input_parameters = ctp::parameters_for_impl(impl_self_ty, impl_trait_ref); ctp::identify_constrained_type_params( &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters); // Disallow ANY unconstrained type parameters. - for (ty_param, param) in impl_scheme.generics.types.iter().zip(&impl_hir_generics.ty_params) { + for (ty_param, param) in impl_generics.types.iter().zip(&impl_hir_generics.ty_params) { let param_ty = ty::ParamTy::for_def(ty_param); if !input_parameters.contains(&ctp::Parameter::from(param_ty)) { report_unused_parameter(ccx, param.span, "type", ¶m_ty.to_string()); @@ -78,9 +121,9 @@ pub fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, item.kind == ty::AssociatedKind::Type && item.has_value }) .flat_map(|def_id| { - ctp::parameters_for(&ccx.tcx.lookup_item_type(def_id).ty, true) + ctp::parameters_for(&ccx.tcx.item_type(def_id), true) }).collect(); - for (ty_lifetime, lifetime) in impl_scheme.generics.regions.iter() + for (ty_lifetime, lifetime) in impl_generics.regions.iter() .zip(&impl_hir_generics.lifetimes) { let param = ctp::Parameter::from(ty_lifetime.to_early_bound_region_data()); @@ -127,3 +170,34 @@ fn report_unused_parameter(ccx: &CrateCtxt, .span_label(span, &format!("unconstrained {} parameter", kind)) .emit(); } + +/// Enforce that we do not have two items in an impl with the same name. +fn enforce_impl_items_are_distinct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + impl_item_refs: &[hir::ImplItemRef]) +{ + let tcx = ccx.tcx; + let mut seen_type_items = FxHashMap(); + let mut seen_value_items = FxHashMap(); + for impl_item_ref in impl_item_refs { + let impl_item = tcx.map.impl_item(impl_item_ref.id); + let seen_items = match impl_item.node { + hir::ImplItemKind::Type(_) => &mut seen_type_items, + _ => &mut seen_value_items, + }; + match seen_items.entry(impl_item.name) { + Occupied(entry) => { + let mut err = struct_span_err!(tcx.sess, impl_item.span, E0201, + "duplicate definitions with name `{}`:", + impl_item.name); + err.span_label(*entry.get(), + &format!("previous definition of `{}` here", + impl_item.name)); + err.span_label(impl_item.span, &format!("duplicate definition")); + err.emit(); + } + Vacant(entry) => { + entry.insert(impl_item.span); + } + } + } +} diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 222e60bb0545..f2e8bb2e9614 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -131,6 +131,7 @@ mod rscope; mod astconv; pub mod collect; mod constrained_type_params; +mod impl_wf_check; pub mod coherence; pub mod variance; @@ -334,6 +335,11 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) time(time_passes, "variance inference", || variance::infer_variance(tcx)); + tcx.sess.track_errors(|| { + time(time_passes, "impl wf inference", || + impl_wf_check::impl_wf_check(&ccx)); + })?; + tcx.sess.track_errors(|| { time(time_passes, "coherence checking", || coherence::check_coherence(&ccx)); diff --git a/src/test/compile-fail/issue-3214.rs b/src/test/compile-fail/issue-3214.rs index d3b932fbc53e..010cfb54c1ae 100644 --- a/src/test/compile-fail/issue-3214.rs +++ b/src/test/compile-fail/issue-3214.rs @@ -15,7 +15,6 @@ fn foo() { impl Drop for foo { //~^ ERROR wrong number of type arguments - //~^^ ERROR the type parameter `T` is not constrained fn drop(&mut self) {} } } From b10b98169ff7350236e96f99ddb2f5d4cbef732b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 14 Nov 2016 11:00:02 -0500 Subject: [PATCH 159/177] hash the contents of impl-item-ref by adding them to visitor Also simplify some of the `ty::AssociatedItem` representation, in particular by folding `has_value` into `hir::Defaultness` --- src/librustc/hir/intravisit.rs | 39 +++++- src/librustc/hir/lowering.rs | 19 ++- src/librustc/hir/mod.rs | 15 +- src/librustc/hir/print.rs | 5 +- src/librustc/traits/project.rs | 4 +- src/librustc/ty/mod.rs | 7 +- .../calculate_svh/svh_visitor.rs | 14 ++ src/librustc_metadata/decoder.rs | 3 - src/librustc_metadata/encoder.rs | 17 ++- src/librustc_metadata/schema.rs | 19 +-- src/librustc_save_analysis/lib.rs | 2 +- src/librustc_typeck/check/mod.rs | 4 +- src/librustc_typeck/check/wfcheck.rs | 2 +- src/librustc_typeck/impl_wf_check.rs | 2 +- src/librustdoc/clean/inline.rs | 4 +- src/librustdoc/clean/mod.rs | 5 +- src/test/incremental/hashes/inherent_impls.rs | 128 ++++++++++++++++++ 17 files changed, 234 insertions(+), 55 deletions(-) create mode 100644 src/test/incremental/hashes/inherent_impls.rs diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 887b1febf65d..4cfa889ec561 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -267,6 +267,12 @@ pub trait Visitor<'v> : Sized { fn visit_vis(&mut self, vis: &'v Visibility) { walk_vis(self, vis) } + fn visit_associated_item_kind(&mut self, kind: &'v AssociatedItemKind) { + walk_associated_item_kind(self, kind); + } + fn visit_defaultness(&mut self, defaultness: &'v Defaultness) { + walk_defaultness(self, defaultness); + } } pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: Option) { @@ -740,10 +746,14 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai } pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem) { - visitor.visit_vis(&impl_item.vis); - visitor.visit_name(impl_item.span, impl_item.name); - walk_list!(visitor, visit_attribute, &impl_item.attrs); - match impl_item.node { + // NB: Deliberately force a compilation error if/when new fields are added. + let ImplItem { id: _, name, ref vis, ref defaultness, ref attrs, ref node, span } = *impl_item; + + visitor.visit_name(span, name); + visitor.visit_vis(vis); + visitor.visit_defaultness(defaultness); + walk_list!(visitor, visit_attribute, attrs); + match *node { ImplItemKind::Const(ref ty, ref expr) => { visitor.visit_id(impl_item.id); visitor.visit_ty(ty); @@ -767,8 +777,13 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt } pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef) { - visitor.visit_nested_impl_item(impl_item_ref.id); - visitor.visit_name(impl_item_ref.span, impl_item_ref.name); + // NB: Deliberately force a compilation error if/when new fields are added. + let ImplItemRef { id, name, ref kind, span, ref vis, ref defaultness } = *impl_item_ref; + visitor.visit_nested_impl_item(id); + visitor.visit_name(span, name); + visitor.visit_associated_item_kind(kind); + visitor.visit_vis(vis); + visitor.visit_defaultness(defaultness); } @@ -941,6 +956,18 @@ pub fn walk_vis<'v, V: Visitor<'v>>(visitor: &mut V, vis: &'v Visibility) { } } +pub fn walk_associated_item_kind<'v, V: Visitor<'v>>(_: &mut V, _: &'v AssociatedItemKind) { + // No visitable content here: this fn exists so you can call it if + // the right thing to do, should content be added in the future, + // would be to walk it. +} + +pub fn walk_defaultness<'v, V: Visitor<'v>>(_: &mut V, _: &'v Defaultness) { + // No visitable content here: this fn exists so you can call it if + // the right thing to do, should content be added in the future, + // would be to walk it. +} + #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq)] pub struct IdRange { pub min: NodeId, diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index d1b57586ffdb..05c4ae521803 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -699,7 +699,7 @@ impl<'a> LoweringContext<'a> { name: i.ident.name, attrs: this.lower_attrs(&i.attrs), vis: this.lower_visibility(&i.vis), - defaultness: this.lower_defaultness(i.defaultness), + defaultness: this.lower_defaultness(i.defaultness, true /* [1] */), node: match i.node { ImplItemKind::Const(ref ty, ref expr) => { hir::ImplItemKind::Const(this.lower_ty(ty), this.lower_expr(expr)) @@ -715,6 +715,8 @@ impl<'a> LoweringContext<'a> { span: i.span, } }) + + // [1] since `default impl` is not yet implemented, this is always true in impls } fn lower_impl_item_ref(&mut self, i: &ImplItem) -> hir::ImplItemRef { @@ -723,7 +725,7 @@ impl<'a> LoweringContext<'a> { name: i.ident.name, span: i.span, vis: self.lower_visibility(&i.vis), - defaultness: self.lower_defaultness(i.defaultness), + defaultness: self.lower_defaultness(i.defaultness, true /* [1] */), kind: match i.node { ImplItemKind::Const(..) => hir::AssociatedItemKind::Const, ImplItemKind::Type(..) => hir::AssociatedItemKind::Type, @@ -732,9 +734,9 @@ impl<'a> LoweringContext<'a> { }, ImplItemKind::Macro(..) => unimplemented!(), }, - // since `default impl` is not yet implemented, this is always true in impls - has_value: true, } + + // [1] since `default impl` is not yet implemented, this is always true in impls } fn lower_mod(&mut self, m: &Mod) -> hir::Mod { @@ -1650,10 +1652,13 @@ impl<'a> LoweringContext<'a> { } } - fn lower_defaultness(&mut self, d: Defaultness) -> hir::Defaultness { + fn lower_defaultness(&mut self, d: Defaultness, has_value: bool) -> hir::Defaultness { match d { - Defaultness::Default => hir::Defaultness::Default, - Defaultness::Final => hir::Defaultness::Final, + Defaultness::Default => hir::Defaultness::Default { has_value: has_value }, + Defaultness::Final => { + assert!(has_value); + hir::Defaultness::Final + } } } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 9dac6fac1009..9f5ff6914b0c 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1259,17 +1259,27 @@ pub enum Constness { #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Defaultness { - Default, + Default { has_value: bool }, Final, } impl Defaultness { + pub fn has_value(&self) -> bool { + match *self { + Defaultness::Default { has_value, .. } => has_value, + Defaultness::Final => true, + } + } + pub fn is_final(&self) -> bool { *self == Defaultness::Final } pub fn is_default(&self) -> bool { - *self == Defaultness::Default + match *self { + Defaultness::Default { .. } => true, + _ => false, + } } } @@ -1584,7 +1594,6 @@ pub struct ImplItemRef { pub span: Span, pub vis: Visibility, pub defaultness: Defaultness, - pub has_value: bool, } #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 5a381a189fc1..807bbec3b588 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1036,8 +1036,9 @@ impl<'a> State<'a> { self.maybe_print_comment(ii.span.lo)?; self.print_outer_attributes(&ii.attrs)?; - if let hir::Defaultness::Default = ii.defaultness { - self.word_nbsp("default")?; + match ii.defaultness { + hir::Defaultness::Default { .. } => self.word_nbsp("default")?, + hir::Defaultness::Final => (), } match ii.node { diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index ac2f3ad9b899..ca7d2ac3c69a 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -943,7 +943,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // an error when we confirm the candidate // (which will ultimately lead to `normalize_to_error` // being invoked). - node_item.item.has_value + node_item.item.defaultness.has_value() } else { node_item.item.defaultness.is_default() }; @@ -1304,7 +1304,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( match assoc_ty { Some(node_item) => { - let ty = if !node_item.item.has_value { + let ty = if !node_item.item.defaultness.has_value() { // This means that the impl is missing a definition for the // associated type. This error will be reported by the type // checker method `check_impl_items_against_trait`, so here we diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 9984dd42f566..f5c23401a4e6 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -189,7 +189,6 @@ pub struct AssociatedItem { pub kind: AssociatedKind, pub vis: Visibility, pub defaultness: hir::Defaultness, - pub has_value: bool, pub container: AssociatedItemContainer, /// Whether this is a method with an explicit self @@ -2072,7 +2071,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn provided_trait_methods(self, id: DefId) -> Vec { self.associated_items(id) - .filter(|item| item.kind == AssociatedKind::Method && item.has_value) + .filter(|item| item.kind == AssociatedKind::Method && item.defaultness.has_value()) .collect() } @@ -2180,8 +2179,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { name: trait_item.name, kind: kind, vis: Visibility::from_hir(&hir::Inherited, trait_item.id, self), - defaultness: hir::Defaultness::Default, - has_value: has_value, + defaultness: hir::Defaultness::Default { has_value: has_value }, def_id: def_id, container: TraitContainer(parent_def_id), method_has_self_argument: has_self @@ -2211,7 +2209,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { kind: kind, vis: ty::Visibility::from_hir(vis, impl_item_ref.id.node_id, self), defaultness: impl_item_ref.defaultness, - has_value: true, def_id: def_id, container: ImplContainer(parent_def_id), method_has_self_argument: has_self diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 318cc83d9ad4..fa2eff817eaa 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -199,6 +199,8 @@ enum SawAbiComponent<'a> { SawExpr(SawExprComponent<'a>), SawStmt, SawVis, + SawAssociatedItemKind(hir::AssociatedItemKind), + SawDefaultness(hir::Defaultness), SawWherePredicate, SawTyParamBound, SawPolyTraitRef, @@ -693,6 +695,18 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has visit::walk_vis(self, v) } + fn visit_associated_item_kind(&mut self, kind: &'tcx AssociatedItemKind) { + debug!("visit_associated_item_kind: st={:?}", self.st); + SawAssociatedItemKind(*kind).hash(self.st); + visit::walk_associated_item_kind(self, kind); + } + + fn visit_defaultness(&mut self, defaultness: &'tcx Defaultness) { + debug!("visit_associated_item_kind: st={:?}", self.st); + SawDefaultness(*defaultness).hash(self.st); + visit::walk_defaultness(self, defaultness); + } + fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate) { debug!("visit_where_predicate: st={:?}", self.st); SawWherePredicate.hash(self.st); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index ba85544326f8..6dbcfc8523dc 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -834,7 +834,6 @@ impl<'a, 'tcx> CrateMetadata { kind: ty::AssociatedKind::Const, vis: item.visibility, defaultness: container.defaultness(), - has_value: container.has_value(), def_id: self.local_def_id(id), container: container.with_def_id(parent), method_has_self_argument: false @@ -848,7 +847,6 @@ impl<'a, 'tcx> CrateMetadata { kind: ty::AssociatedKind::Method, vis: item.visibility, defaultness: data.container.defaultness(), - has_value: data.container.has_value(), def_id: self.local_def_id(id), container: data.container.with_def_id(parent), method_has_self_argument: data.has_self @@ -861,7 +859,6 @@ impl<'a, 'tcx> CrateMetadata { kind: ty::AssociatedKind::Type, vis: item.visibility, defaultness: container.defaultness(), - has_value: container.has_value(), def_id: self.local_def_id(id), container: container.with_def_id(parent), method_has_self_argument: false diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 2d96eeb8f201..d1508d7e9b39 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -460,10 +460,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let ast_item = tcx.map.expect_trait_item(node_id); let trait_item = tcx.associated_item(def_id); - let container = if trait_item.has_value { - AssociatedContainer::TraitWithDefault - } else { - AssociatedContainer::TraitRequired + let container = match trait_item.defaultness { + hir::Defaultness::Default { has_value: true } => + AssociatedContainer::TraitWithDefault, + hir::Defaultness::Default { has_value: false } => + AssociatedContainer::TraitRequired, + hir::Defaultness::Final => + span_bug!(ast_item.span, "traits cannot have final items"), }; let kind = match trait_item.kind { @@ -501,7 +504,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { Some(self.encode_item_type(def_id)) } ty::AssociatedKind::Type => { - if trait_item.has_value { + if trait_item.defaultness.has_value() { Some(self.encode_item_type(def_id)) } else { None @@ -530,8 +533,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let impl_def_id = impl_item.container.id(); let container = match impl_item.defaultness { - hir::Defaultness::Default => AssociatedContainer::ImplDefault, + hir::Defaultness::Default { has_value: true } => AssociatedContainer::ImplDefault, hir::Defaultness::Final => AssociatedContainer::ImplFinal, + hir::Defaultness::Default { has_value: false } => + span_bug!(ast_item.span, "impl items always have values (currently)"), }; let kind = match impl_item.kind { diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index d7a5f7ad7154..7553b2e05a73 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -310,21 +310,16 @@ impl AssociatedContainer { } } - pub fn has_value(&self) -> bool { - match *self { - AssociatedContainer::TraitRequired => false, - - AssociatedContainer::TraitWithDefault | - AssociatedContainer::ImplDefault | - AssociatedContainer::ImplFinal => true, - } - } - pub fn defaultness(&self) -> hir::Defaultness { match *self { - AssociatedContainer::TraitRequired | + AssociatedContainer::TraitRequired => hir::Defaultness::Default { + has_value: false, + }, + AssociatedContainer::TraitWithDefault | - AssociatedContainer::ImplDefault => hir::Defaultness::Default, + AssociatedContainer::ImplDefault => hir::Defaultness::Default { + has_value: true, + }, AssociatedContainer::ImplFinal => hir::Defaultness::Final, } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 4fb11509a1c1..778f01841416 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -536,7 +536,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let def_id = if decl_id.is_local() { let ti = self.tcx.associated_item(decl_id); self.tcx.associated_items(ti.container.id()) - .find(|item| item.name == ti.name && item.has_value) + .find(|item| item.name == ti.name && item.defaultness.has_value()) .map(|item| item.def_id) } else { None diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2197ecc10a18..d2939316219e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1110,7 +1110,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } hir::ImplItemKind::Type(_) => { if ty_trait_item.kind == ty::AssociatedKind::Type { - if ty_trait_item.has_value { + if ty_trait_item.defaultness.has_value() { overridden_associated_type = Some(impl_item); } } else { @@ -1144,7 +1144,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, .unwrap_or(false); if !is_implemented { - if !trait_item.has_value { + if !trait_item.defaultness.has_value() { missing_items.push(trait_item); } else if associated_type_overridden { invalidated_items.push(trait_item.name); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 066b3d4be088..2c55e8fbfd22 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -204,7 +204,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { free_id_outlive, self_ty); } ty::AssociatedKind::Type => { - if item.has_value { + if item.defaultness.has_value() { let ty = fcx.tcx.item_type(item.def_id); let ty = fcx.instantiate_type_scheme(span, free_substs, &ty); fcx.register_wf_obligation(ty, span, code.clone()); diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs index 1572d04f68c1..9f5b73d9b307 100644 --- a/src/librustc_typeck/impl_wf_check.rs +++ b/src/librustc_typeck/impl_wf_check.rs @@ -118,7 +118,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, .map(|item_ref| ccx.tcx.map.local_def_id(item_ref.id.node_id)) .filter(|&def_id| { let item = ccx.tcx.associated_item(def_id); - item.kind == ty::AssociatedKind::Type && item.has_value + item.kind == ty::AssociatedKind::Type && item.defaultness.has_value() }) .flat_map(|def_id| { ctp::parameters_for(&ccx.tcx.item_type(def_id), true) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e8367bca2ef2..185f897c1baa 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -364,7 +364,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, let trait_items = tcx.associated_items(did).filter_map(|item| { match item.kind { ty::AssociatedKind::Const => { - let default = if item.has_value { + let default = if item.defaultness.has_value() { Some(pprust::expr_to_string( lookup_const_by_id(tcx, item.def_id, None).unwrap().0)) } else { @@ -407,7 +407,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, abi: abi }) } - _ => panic!("not a tymethod"), + ref r => panic!("not a tymethod: {:?}", r), }; Some(cleaned) } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4d70c64634fb..a141d0e4788d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1373,9 +1373,10 @@ impl<'tcx> Clean for ty::AssociatedItem { } } } + let provided = match self.container { ty::ImplContainer(_) => false, - ty::TraitContainer(_) => self.has_value + ty::TraitContainer(_) => self.defaultness.has_value() }; if provided { MethodItem(Method { @@ -1440,7 +1441,7 @@ impl<'tcx> Clean for ty::AssociatedItem { None => bounds.push(TyParamBound::maybe_sized(cx)), } - let ty = if self.has_value { + let ty = if self.defaultness.has_value() { Some(cx.tcx().item_type(self.def_id)) } else { None diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs new file mode 100644 index 000000000000..f7a390e87450 --- /dev/null +++ b/src/test/incremental/hashes/inherent_impls.rs @@ -0,0 +1,128 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// This test case tests the incremental compilation hash (ICH) implementation +// for let expressions. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph + + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![crate_type="rlib"] + +struct Foo; + +// Change Method Name ----------------------------------------------------------- +#[cfg(cfail1)] +impl Foo { + pub fn method_name() { } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + pub fn method_name2() { } +} + +// Change Method Body ----------------------------------------------------------- +// +// This should affect the method itself, but not the impl. +#[cfg(cfail1)] +impl Foo { + pub fn method_body() { } +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + pub fn method_body() { + println!("Hello, world!"); + } +} + +// Change Method Privacy ----------------------------------------------------------- +#[cfg(cfail1)] +impl Foo { + pub fn method_privacy() { } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method_privacy() { } +} + +// Change Method Selfness ----------------------------------------------------------- +#[cfg(cfail1)] +impl Foo { + pub fn method_selfness() { } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + pub fn method_selfness(&self) { } +} + +// Change Method Selfmutness ----------------------------------------------------------- +#[cfg(cfail1)] +impl Foo { + pub fn method_selfmutness(&self) { } +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + pub fn method_selfmutness(&mut self) { } +} + From b8116dabdaf5952ce676239b1e2d0a7684ce0c34 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 14 Nov 2016 18:23:07 -0500 Subject: [PATCH 160/177] fix oversight in closure translation (Unrelated to this PR series) --- src/librustc_trans/callee.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index a7553ce4995e..df56e27128c7 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -600,13 +600,8 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // reference. It also occurs when testing libcore and in some // other weird situations. Annoying. - let fn_ptr_ty = match fn_ty.sty { - ty::TyFnDef(.., fty) => { - // Create a fn pointer with the substituted signature. - tcx.mk_fn_ptr(fty) - } - _ => bug!("expected fn item type for {:?}, found {}", def_id, fn_ty) - }; + // Create a fn pointer with the substituted signature. + let fn_ptr_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(common::ty_fn_ty(ccx, fn_ty).into_owned())); let llptrty = type_of::type_of(ccx, fn_ptr_ty); let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) { From 4e844ad1e5d0f62cfac00ad0c0f50474d99331f7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 14 Nov 2016 21:02:29 -0500 Subject: [PATCH 161/177] fix change_private_impl_method_cc test --- .../incremental/change_private_impl_method_cc/struct_point.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/test/incremental/change_private_impl_method_cc/struct_point.rs b/src/test/incremental/change_private_impl_method_cc/struct_point.rs index a8779e3f92d9..bb7f7025c590 100644 --- a/src/test/incremental/change_private_impl_method_cc/struct_point.rs +++ b/src/test/incremental/change_private_impl_method_cc/struct_point.rs @@ -21,9 +21,7 @@ #![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")] #![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")] - -// FIXME(#37333) the struct fields get entangled with inherent methods -#![rustc_partition_translated(module="struct_point-fn_make_struct", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")] // FIXME(#37720) these two should be reused, but data gets entangled across crates #![rustc_partition_translated(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")] From ab79438d68dbc79da41fd97b2ffc3238d039b02d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 17 Nov 2016 12:44:46 -0500 Subject: [PATCH 162/177] canonicalize base incremental path on windows This sidesteps problems with long paths because the canonical path includes the "magic long path prefix" on Windows. --- src/librustc_incremental/persist/fs.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index 223200957cb7..2572a9c1d78f 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -201,6 +201,19 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result { debug!("crate-dir: {}", crate_dir.display()); try!(create_dir(tcx.sess, &crate_dir, "crate")); + // Hack: canonicalize the path *after creating the directory* + // because, on windows, long paths can cause problems; + // canonicalization inserts this weird prefix that makes windows + // tolerate long paths. + let crate_dir = match crate_dir.canonicalize() { + Ok(v) => v, + Err(err) => { + tcx.sess.err(&format!("incremental compilation: error canonicalizing path `{}`: {}", + crate_dir.display(), err)); + return Err(()); + } + }; + let mut source_directories_already_tried = FxHashSet(); loop { From 30daedf60355d105d92ad011b9e115b01350593e Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Wed, 16 Nov 2016 23:36:08 +0100 Subject: [PATCH 163/177] Use llvm::Attribute API instead of "raw value" APIs, which will be removed in LLVM 4.0. The librustc_llvm API remains mostly unchanged, except that llvm::Attribute is no longer a bitflag but represents only a *single* attribute. The ability to store many attributes in a small number of bits and modify them without interacting with LLVM is only used in rustc_trans::abi and closely related modules, and only attributes for function arguments are considered there. Thus rustc_trans::abi now has its own bit-packed representation of argument attributes, which are translated to rustc_llvm::Attribute when applying the attributes. --- src/Cargo.lock | 2 +- src/librustc_llvm/Cargo.toml | 3 - src/librustc_llvm/ffi.rs | 101 +++++++++--------------- src/librustc_llvm/lib.rs | 64 ++-------------- src/librustc_trans/Cargo.toml | 1 + src/librustc_trans/abi.rs | 123 +++++++++++++++++++++++++----- src/librustc_trans/attributes.rs | 7 +- src/librustc_trans/cabi_asmjs.rs | 6 +- src/librustc_trans/cabi_x86.rs | 4 +- src/librustc_trans/cabi_x86_64.rs | 8 +- src/librustc_trans/lib.rs | 4 + src/rustllvm/RustWrapper.cpp | 115 +++++++++++++++++----------- src/rustllvm/rustllvm.h | 22 ++++++ 13 files changed, 261 insertions(+), 199 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index ee38a043b122..4e5f0b2a3ec3 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -409,7 +409,6 @@ version = "0.0.0" dependencies = [ "build_helper 0.1.0", "gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_bitflags 0.0.0", ] [[package]] @@ -520,6 +519,7 @@ dependencies = [ "log 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", + "rustc_bitflags 0.0.0", "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", diff --git a/src/librustc_llvm/Cargo.toml b/src/librustc_llvm/Cargo.toml index f97daa22ff66..88f8c0553adc 100644 --- a/src/librustc_llvm/Cargo.toml +++ b/src/librustc_llvm/Cargo.toml @@ -12,9 +12,6 @@ crate-type = ["dylib"] [features] static-libstdcpp = [] -[dependencies] -rustc_bitflags = { path = "../librustc_bitflags" } - [build-dependencies] build_helper = { path = "../build_helper" } gcc = "0.3.27" diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 78a9d67ed770..f64bd6626b78 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -82,59 +82,31 @@ pub enum DLLStorageClass { DllExport = 2, // Function to be accessible from DLL. } -bitflags! { - #[derive(Default, Debug)] - flags Attribute : u64 { - const ZExt = 1 << 0, - const SExt = 1 << 1, - const NoReturn = 1 << 2, - const InReg = 1 << 3, - const StructRet = 1 << 4, - const NoUnwind = 1 << 5, - const NoAlias = 1 << 6, - const ByVal = 1 << 7, - const Nest = 1 << 8, - const ReadNone = 1 << 9, - const ReadOnly = 1 << 10, - const NoInline = 1 << 11, - const AlwaysInline = 1 << 12, - const OptimizeForSize = 1 << 13, - const StackProtect = 1 << 14, - const StackProtectReq = 1 << 15, - const NoCapture = 1 << 21, - const NoRedZone = 1 << 22, - const NoImplicitFloat = 1 << 23, - const Naked = 1 << 24, - const InlineHint = 1 << 25, - const ReturnsTwice = 1 << 29, - const UWTable = 1 << 30, - const NonLazyBind = 1 << 31, - - // Some of these are missing from the LLVM C API, the rest are - // present, but commented out, and preceded by the following warning: - // FIXME: These attributes are currently not included in the C API as - // a temporary measure until the API/ABI impact to the C API is understood - // and the path forward agreed upon. - const SanitizeAddress = 1 << 32, - const MinSize = 1 << 33, - const NoDuplicate = 1 << 34, - const StackProtectStrong = 1 << 35, - const SanitizeThread = 1 << 36, - const SanitizeMemory = 1 << 37, - const NoBuiltin = 1 << 38, - const Returned = 1 << 39, - const Cold = 1 << 40, - const Builtin = 1 << 41, - const OptimizeNone = 1 << 42, - const InAlloca = 1 << 43, - const NonNull = 1 << 44, - const JumpTable = 1 << 45, - const Convergent = 1 << 46, - const SafeStack = 1 << 47, - const NoRecurse = 1 << 48, - const InaccessibleMemOnly = 1 << 49, - const InaccessibleMemOrArgMemOnly = 1 << 50, - } +/// Matches LLVMRustAttribute in rustllvm.h +/// Semantically a subset of the C++ enum llvm::Attribute::AttrKind, +/// though it is not ABI compatible (since it's a C++ enum) +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub enum Attribute { + AlwaysInline = 0, + ByVal = 1, + Cold = 2, + InlineHint = 3, + MinSize = 4, + Naked = 5, + NoAlias = 6, + NoCapture = 7, + NoInline = 8, + NonNull = 9, + NoRedZone = 10, + NoReturn = 11, + NoUnwind = 12, + OptimizeForSize = 13, + ReadOnly = 14, + SExt = 15, + StructRet = 16, + UWTable = 17, + ZExt = 18, } /// LLVMIntPredicate @@ -422,6 +394,9 @@ pub type RustArchiveMemberRef = *mut RustArchiveMember_opaque; #[allow(missing_copy_implementations)] pub enum OperandBundleDef_opaque {} pub type OperandBundleDefRef = *mut OperandBundleDef_opaque; +#[allow(missing_copy_implementations)] +pub enum Attribute_opaque {} +pub type AttributeRef = *mut Attribute_opaque; pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void); pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint); @@ -521,6 +496,9 @@ extern "C" { /// See llvm::LLVMType::getContext. pub fn LLVMGetTypeContext(Ty: TypeRef) -> ContextRef; + /// See llvm::Value::getContext + pub fn LLVMRustGetValueContext(V: ValueRef) -> ContextRef; + // Operations on integer types pub fn LLVMInt1TypeInContext(C: ContextRef) -> TypeRef; pub fn LLVMInt8TypeInContext(C: ContextRef) -> TypeRef; @@ -783,6 +761,8 @@ extern "C" { Name: *const c_char) -> ValueRef; + pub fn LLVMRustCreateAttribute(C: ContextRef, kind: Attribute, val: u64) -> AttributeRef; + // Operations on functions pub fn LLVMAddFunction(M: ModuleRef, Name: *const c_char, FunctionTy: TypeRef) -> ValueRef; pub fn LLVMGetNamedFunction(M: ModuleRef, Name: *const c_char) -> ValueRef; @@ -801,16 +781,12 @@ extern "C" { pub fn LLVMGetGC(Fn: ValueRef) -> *const c_char; pub fn LLVMSetGC(Fn: ValueRef, Name: *const c_char); pub fn LLVMRustAddDereferenceableAttr(Fn: ValueRef, index: c_uint, bytes: u64); - pub fn LLVMRustAddFunctionAttribute(Fn: ValueRef, index: c_uint, PA: u64); - pub fn LLVMRustAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); + pub fn LLVMRustAddFunctionAttribute(Fn: ValueRef, index: c_uint, attr: AttributeRef); pub fn LLVMRustAddFunctionAttrStringValue(Fn: ValueRef, index: c_uint, Name: *const c_char, Value: *const c_char); - pub fn LLVMRustRemoveFunctionAttributes(Fn: ValueRef, index: c_uint, attr: u64); - pub fn LLVMRustRemoveFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); - pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_uint; - pub fn LLVMRemoveFunctionAttr(Fn: ValueRef, val: c_uint); + pub fn LLVMRustRemoveFunctionAttributes(Fn: ValueRef, index: c_uint, attr: AttributeRef); // Operations on parameters pub fn LLVMCountParams(Fn: ValueRef) -> c_uint; @@ -821,9 +797,8 @@ extern "C" { pub fn LLVMGetLastParam(Fn: ValueRef) -> ValueRef; pub fn LLVMGetNextParam(Arg: ValueRef) -> ValueRef; pub fn LLVMGetPreviousParam(Arg: ValueRef) -> ValueRef; - pub fn LLVMAddAttribute(Arg: ValueRef, PA: c_uint); - pub fn LLVMRemoveAttribute(Arg: ValueRef, PA: c_uint); - pub fn LLVMGetAttribute(Arg: ValueRef) -> c_uint; + pub fn LLVMAddAttribute(Arg: ValueRef, attr: AttributeRef); + pub fn LLVMRemoveAttribute(Arg: ValueRef, attr: AttributeRef); pub fn LLVMSetParamAlignment(Arg: ValueRef, align: c_uint); // Operations on basic blocks @@ -867,7 +842,7 @@ extern "C" { pub fn LLVMAddInstrAttribute(Instr: ValueRef, index: c_uint, IA: c_uint); pub fn LLVMRemoveInstrAttribute(Instr: ValueRef, index: c_uint, IA: c_uint); pub fn LLVMSetInstrParamAlignment(Instr: ValueRef, index: c_uint, align: c_uint); - pub fn LLVMRustAddCallSiteAttribute(Instr: ValueRef, index: c_uint, Val: u64); + pub fn LLVMRustAddCallSiteAttribute(Instr: ValueRef, index: c_uint, attr: AttributeRef); pub fn LLVMRustAddDereferenceableCallSiteAttr(Instr: ValueRef, index: c_uint, bytes: u64); // Operations on call instructions (only) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 07b87072c435..32d9d9a3efc0 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -29,12 +29,8 @@ #![feature(staged_api)] #![feature(linked_from)] #![feature(concat_idents)] -#![cfg_attr(not(stage0), feature(rustc_private))] extern crate libc; -#[macro_use] -#[no_link] -extern crate rustc_bitflags; pub use self::IntPredicate::*; pub use self::RealPredicate::*; @@ -68,54 +64,6 @@ impl LLVMRustResult { } } -#[derive(Copy, Clone, Default, Debug)] -pub struct Attributes { - regular: Attribute, - dereferenceable_bytes: u64, -} - -impl Attributes { - pub fn set(&mut self, attr: Attribute) -> &mut Self { - self.regular = self.regular | attr; - self - } - - pub fn unset(&mut self, attr: Attribute) -> &mut Self { - self.regular = self.regular - attr; - self - } - - pub fn set_dereferenceable(&mut self, bytes: u64) -> &mut Self { - self.dereferenceable_bytes = bytes; - self - } - - pub fn unset_dereferenceable(&mut self) -> &mut Self { - self.dereferenceable_bytes = 0; - self - } - - pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { - unsafe { - self.regular.apply_llfn(idx, llfn); - if self.dereferenceable_bytes != 0 { - LLVMRustAddDereferenceableAttr(llfn, idx.as_uint(), self.dereferenceable_bytes); - } - } - } - - pub fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) { - unsafe { - self.regular.apply_callsite(idx, callsite); - if self.dereferenceable_bytes != 0 { - LLVMRustAddDereferenceableCallSiteAttr(callsite, - idx.as_uint(), - self.dereferenceable_bytes); - } - } - } -} - pub fn AddFunctionAttrStringValue(llfn: ValueRef, idx: AttributePlace, attr: &'static str, @@ -140,7 +88,7 @@ impl AttributePlace { AttributePlace::Argument(0) } - fn as_uint(self) -> c_uint { + pub fn as_uint(self) -> c_uint { match self { AttributePlace::Function => !0, AttributePlace::Argument(i) => i, @@ -228,16 +176,20 @@ pub fn set_thread_local(global: ValueRef, is_thread_local: bool) { } impl Attribute { + fn as_object(&self, value: ValueRef) -> AttributeRef { + unsafe { LLVMRustCreateAttribute(LLVMRustGetValueContext(value), *self, 0) } + } + pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { - unsafe { LLVMRustAddFunctionAttribute(llfn, idx.as_uint(), self.bits()) } + unsafe { LLVMRustAddFunctionAttribute(llfn, idx.as_uint(), self.as_object(llfn)) } } pub fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) { - unsafe { LLVMRustAddCallSiteAttribute(callsite, idx.as_uint(), self.bits()) } + unsafe { LLVMRustAddCallSiteAttribute(callsite, idx.as_uint(), self.as_object(callsite)) } } pub fn unapply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { - unsafe { LLVMRustRemoveFunctionAttributes(llfn, idx.as_uint(), self.bits()) } + unsafe { LLVMRustRemoveFunctionAttributes(llfn, idx.as_uint(), self.as_object(llfn)) } } pub fn toggle_llfn(&self, idx: AttributePlace, llfn: ValueRef, set: bool) { diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index 38f9e7ab0c51..796a80d08094 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -16,6 +16,7 @@ graphviz = { path = "../libgraphviz" } log = { path = "../liblog" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } +rustc_bitflags = { path = "../librustc_bitflags" } rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 0a5b013c79ac..16d3fc1b904e 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use llvm::{self, ValueRef, Integer, Pointer, Float, Double, Struct, Array, Vector}; +use llvm::{self, ValueRef, Integer, Pointer, Float, Double, Struct, Array, Vector, AttributePlace}; use base; use build::AllocaFcx; use common::{type_is_fat_ptr, BlockAndBuilder, C_uint}; @@ -49,6 +49,93 @@ enum ArgKind { Ignore, } +// Hack to disable non_upper_case_globals only for the bitflags! and not for the rest +// of this module +pub use self::attr_impl::ArgAttribute; + +#[allow(non_upper_case_globals)] +mod attr_impl { + // The subset of llvm::Attribute needed for arguments, packed into a bitfield. + bitflags! { + #[derive(Default, Debug)] + flags ArgAttribute : u8 { + const ByVal = 1 << 0, + const NoAlias = 1 << 1, + const NoCapture = 1 << 2, + const NonNull = 1 << 3, + const ReadOnly = 1 << 4, + const SExt = 1 << 5, + const StructRet = 1 << 6, + const ZExt = 1 << 7, + } + } +} + +macro_rules! for_each_kind { + ($flags: ident, $f: ident, $($kind: ident),+) => ({ + $(if $flags.contains(ArgAttribute::$kind) { $f(llvm::Attribute::$kind) })+ + }) +} + +impl ArgAttribute { + fn for_each_kind(&self, mut f: F) where F: FnMut(llvm::Attribute) { + for_each_kind!(self, f, + ByVal, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt) + } +} + +/// A compact representation of LLVM attributes (at least those relevant for this module) +/// that can be manipulated without interacting with LLVM's Attribute machinery. +#[derive(Copy, Clone, Debug, Default)] +pub struct ArgAttributes { + regular: ArgAttribute, + dereferenceable_bytes: u64, +} + +impl ArgAttributes { + pub fn set(&mut self, attr: ArgAttribute) -> &mut Self { + self.regular = self.regular | attr; + self + } + + pub fn unset(&mut self, attr: ArgAttribute) -> &mut Self { + self.regular = self.regular - attr; + self + } + + pub fn set_dereferenceable(&mut self, bytes: u64) -> &mut Self { + self.dereferenceable_bytes = bytes; + self + } + + pub fn unset_dereferenceable(&mut self) -> &mut Self { + self.dereferenceable_bytes = 0; + self + } + + pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { + unsafe { + self.regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn)); + if self.dereferenceable_bytes != 0 { + llvm::LLVMRustAddDereferenceableAttr(llfn, + idx.as_uint(), + self.dereferenceable_bytes); + } + } + } + + pub fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) { + unsafe { + self.regular.for_each_kind(|attr| attr.apply_callsite(idx, callsite)); + if self.dereferenceable_bytes != 0 { + llvm::LLVMRustAddDereferenceableCallSiteAttr(callsite, + idx.as_uint(), + self.dereferenceable_bytes); + } + } + } +} + /// Information about how a specific C type /// should be passed to or returned from a function /// @@ -80,7 +167,7 @@ pub struct ArgType { /// Dummy argument, which is emitted before the real argument pub pad: Option, /// LLVM attributes of argument - pub attrs: llvm::Attributes + pub attrs: ArgAttributes } impl ArgType { @@ -92,7 +179,7 @@ impl ArgType { signedness: None, cast: None, pad: None, - attrs: llvm::Attributes::default() + attrs: ArgAttributes::default() } } @@ -100,15 +187,15 @@ impl ArgType { assert_eq!(self.kind, ArgKind::Direct); // Wipe old attributes, likely not valid through indirection. - self.attrs = llvm::Attributes::default(); + self.attrs = ArgAttributes::default(); let llarg_sz = llsize_of_alloc(ccx, self.ty); // For non-immediate arguments the callee gets its own copy of // the value on the stack, so there are no aliases. It's also // program-invisible so can't possibly capture - self.attrs.set(llvm::Attribute::NoAlias) - .set(llvm::Attribute::NoCapture) + self.attrs.set(ArgAttribute::NoAlias) + .set(ArgAttribute::NoCapture) .set_dereferenceable(llarg_sz); self.kind = ArgKind::Indirect; @@ -124,9 +211,9 @@ impl ArgType { if let Some(signed) = self.signedness { if self.ty.int_width() < bits { self.attrs.set(if signed { - llvm::Attribute::SExt + ArgAttribute::SExt } else { - llvm::Attribute::ZExt + ArgAttribute::ZExt }); } } @@ -314,7 +401,7 @@ impl FnType { if ty.is_bool() { let llty = Type::i1(ccx); let mut arg = ArgType::new(llty, llty); - arg.attrs.set(llvm::Attribute::ZExt); + arg.attrs.set(ArgAttribute::ZExt); arg } else { let mut arg = ArgType::new(type_of::type_of(ccx, ty), @@ -349,7 +436,7 @@ impl FnType { if let ty::TyBox(_) = ret_ty.sty { // `Box` pointer return values never alias because ownership // is transferred - ret.attrs.set(llvm::Attribute::NoAlias); + ret.attrs.set(ArgAttribute::NoAlias); } // We can also mark the return value as `dereferenceable` in certain cases @@ -371,7 +458,7 @@ impl FnType { let rust_ptr_attrs = |ty: Ty<'tcx>, arg: &mut ArgType| match ty.sty { // `Box` pointer parameters never alias because ownership is transferred ty::TyBox(inner) => { - arg.attrs.set(llvm::Attribute::NoAlias); + arg.attrs.set(ArgAttribute::NoAlias); Some(inner) } @@ -386,18 +473,18 @@ impl FnType { let interior_unsafe = mt.ty.type_contents(ccx.tcx()).interior_unsafe(); if mt.mutbl != hir::MutMutable && !interior_unsafe { - arg.attrs.set(llvm::Attribute::NoAlias); + arg.attrs.set(ArgAttribute::NoAlias); } if mt.mutbl == hir::MutImmutable && !interior_unsafe { - arg.attrs.set(llvm::Attribute::ReadOnly); + arg.attrs.set(ArgAttribute::ReadOnly); } // When a reference in an argument has no named lifetime, it's // impossible for that reference to escape this function // (returned or stored beyond the call by a closure). if let ReLateBound(_, BrAnon(_)) = *b { - arg.attrs.set(llvm::Attribute::NoCapture); + arg.attrs.set(ArgAttribute::NoCapture); } Some(mt.ty) @@ -417,9 +504,9 @@ impl FnType { let mut info = ArgType::new(original_tys[1], sizing_tys[1]); if let Some(inner) = rust_ptr_attrs(ty, &mut data) { - data.attrs.set(llvm::Attribute::NonNull); + data.attrs.set(ArgAttribute::NonNull); if ccx.tcx().struct_tail(inner).is_trait() { - info.attrs.set(llvm::Attribute::NonNull); + info.attrs.set(ArgAttribute::NonNull); } } args.push(data); @@ -490,7 +577,7 @@ impl FnType { fixup(arg); } if self.ret.is_indirect() { - self.ret.attrs.set(llvm::Attribute::StructRet); + self.ret.attrs.set(ArgAttribute::StructRet); } return; } @@ -524,7 +611,7 @@ impl FnType { } if self.ret.is_indirect() { - self.ret.attrs.set(llvm::Attribute::StructRet); + self.ret.attrs.set(ArgAttribute::StructRet); } } diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs index 62eac35e0abd..f1e90419a49e 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_trans/attributes.rs @@ -24,10 +24,9 @@ pub fn inline(val: ValueRef, inline: InlineAttr) { Always => Attribute::AlwaysInline.apply_llfn(Function, val), Never => Attribute::NoInline.apply_llfn(Function, val), None => { - let attr = Attribute::InlineHint | - Attribute::AlwaysInline | - Attribute::NoInline; - attr.unapply_llfn(Function, val) + Attribute::InlineHint.unapply_llfn(Function, val); + Attribute::AlwaysInline.unapply_llfn(Function, val); + Attribute::NoInline.unapply_llfn(Function, val); }, }; } diff --git a/src/librustc_trans/cabi_asmjs.rs b/src/librustc_trans/cabi_asmjs.rs index 3cbc378ab021..f410627400c3 100644 --- a/src/librustc_trans/cabi_asmjs.rs +++ b/src/librustc_trans/cabi_asmjs.rs @@ -10,8 +10,8 @@ #![allow(non_upper_case_globals)] -use llvm::{Struct, Array, Attribute}; -use abi::{FnType, ArgType}; +use llvm::{Struct, Array}; +use abi::{FnType, ArgType, ArgAttribute}; use context::CrateContext; // Data layout: e-p:32:32-i64:64-v128:32:128-n32-S128 @@ -39,7 +39,7 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { if arg.ty.is_aggregate() { arg.make_indirect(ccx); - arg.attrs.set(Attribute::ByVal); + arg.attrs.set(ArgAttribute::ByVal); } } diff --git a/src/librustc_trans/cabi_x86.rs b/src/librustc_trans/cabi_x86.rs index b52231fa6b43..5377b49a2b44 100644 --- a/src/librustc_trans/cabi_x86.rs +++ b/src/librustc_trans/cabi_x86.rs @@ -9,7 +9,7 @@ // except according to those terms. use llvm::*; -use abi::FnType; +use abi::{ArgAttribute, FnType}; use type_::Type; use super::common::*; use super::machine::*; @@ -45,7 +45,7 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { if arg.is_ignore() { continue; } if arg.ty.kind() == Struct { arg.make_indirect(ccx); - arg.attrs.set(Attribute::ByVal); + arg.attrs.set(ArgAttribute::ByVal); } else { arg.extend_integer_width_to(32); } diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs index 33990148c8b7..7f2fdbf000b6 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_trans/cabi_x86_64.rs @@ -15,8 +15,8 @@ use self::RegClass::*; use llvm::{Integer, Pointer, Float, Double}; -use llvm::{Struct, Array, Attribute, Vector}; -use abi::{self, ArgType, FnType}; +use llvm::{Struct, Array, Vector}; +use abi::{self, ArgType, ArgAttribute, FnType}; use context::CrateContext; use type_::Type; @@ -334,7 +334,7 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { fn x86_64_ty(ccx: &CrateContext, arg: &mut ArgType, is_mem_cls: F, - ind_attr: Option) + ind_attr: Option) where F: FnOnce(&[RegClass]) -> bool { if !arg.ty.is_reg_ty() { @@ -384,7 +384,7 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { sse_regs -= needed_sse; } in_mem - }, Some(Attribute::ByVal)); + }, Some(ArgAttribute::ByVal)); // An integer, pointer, double or float parameter // thus the above closure passed to `x86_64_ty` won't diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 0757343a8af5..f2c828c2f1f7 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -23,6 +23,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] +#![feature(associated_consts)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(cell_extras)] @@ -55,6 +56,9 @@ extern crate rustc_platform_intrinsics as intrinsics; extern crate serialize; extern crate rustc_const_math; extern crate rustc_const_eval; +#[macro_use] +#[no_link] +extern crate rustc_bitflags; #[macro_use] extern crate log; #[macro_use] extern crate syntax; diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 369388caa049..7f0c7e2e5c9f 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -109,37 +109,84 @@ extern "C" LLVMTypeRef LLVMRustMetadataTypeInContext(LLVMContextRef C) { return wrap(Type::getMetadataTy(*unwrap(C))); } -extern "C" void LLVMRustAddCallSiteAttribute(LLVMValueRef Instr, unsigned index, uint64_t Val) { +static Attribute::AttrKind +from_rust(LLVMRustAttribute kind) { + switch (kind) { + case AlwaysInline: + return Attribute::AlwaysInline; + case ByVal: + return Attribute::ByVal; + case Cold: + return Attribute::Cold; + case InlineHint: + return Attribute::InlineHint; + case MinSize: + return Attribute::MinSize; + case Naked: + return Attribute::Naked; + case NoAlias: + return Attribute::NoAlias; + case NoCapture: + return Attribute::NoCapture; + case NoInline: + return Attribute::NoInline; + case NonNull: + return Attribute::NonNull; + case NoRedZone: + return Attribute::NoRedZone; + case NoReturn: + return Attribute::NoReturn; + case NoUnwind: + return Attribute::NoUnwind; + case OptimizeForSize: + return Attribute::OptimizeForSize; + case ReadOnly: + return Attribute::ReadOnly; + case SExt: + return Attribute::SExt; + case StructRet: + return Attribute::StructRet; + case UWTable: + return Attribute::UWTable; + case ZExt: + return Attribute::ZExt; + default: + llvm_unreachable("bad AttributeKind"); + } +} + +extern "C" LLVMAttributeRef LLVMRustCreateAttribute(LLVMContextRef C, LLVMRustAttribute Kind, uint64_t Val) { + return wrap(Attribute::get(*unwrap(C), from_rust(Kind), Val)); +} + +extern "C" void LLVMRustAddCallSiteAttribute(LLVMValueRef Instr, unsigned index, LLVMAttributeRef attr) { CallSite Call = CallSite(unwrap(Instr)); - AttrBuilder B; - B.addRawValue(Val); + AttrBuilder B(unwrap(attr)); Call.setAttributes( Call.getAttributes().addAttributes(Call->getContext(), index, AttributeSet::get(Call->getContext(), index, B))); } - extern "C" void LLVMRustAddDereferenceableCallSiteAttr(LLVMValueRef Instr, - unsigned idx, - uint64_t b) + unsigned index, + uint64_t bytes) { CallSite Call = CallSite(unwrap(Instr)); AttrBuilder B; - B.addDereferenceableAttr(b); + B.addDereferenceableAttr(bytes); Call.setAttributes( - Call.getAttributes().addAttributes(Call->getContext(), idx, + Call.getAttributes().addAttributes(Call->getContext(), index, AttributeSet::get(Call->getContext(), - idx, B))); + index, B))); } extern "C" void LLVMRustAddFunctionAttribute(LLVMValueRef Fn, unsigned index, - uint64_t Val) + LLVMAttributeRef attr) { Function *A = unwrap(Fn); - AttrBuilder B; - B.addRawValue(Val); + AttrBuilder B(unwrap(attr)); A->addAttributes(index, AttributeSet::get(A->getContext(), index, B)); } @@ -153,16 +200,6 @@ extern "C" void LLVMRustAddDereferenceableAttr(LLVMValueRef Fn, A->addAttributes(index, AttributeSet::get(A->getContext(), index, B)); } -extern "C" void LLVMRustAddFunctionAttrString(LLVMValueRef Fn, - unsigned index, - const char *Name) -{ - Function *F = unwrap(Fn); - AttrBuilder B; - B.addAttribute(Name); - F->addAttributes(index, AttributeSet::get(F->getContext(), index, B)); -} - extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn, unsigned index, const char *Name, @@ -175,31 +212,15 @@ extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn, extern "C" void LLVMRustRemoveFunctionAttributes(LLVMValueRef Fn, unsigned index, - uint64_t Val) + LLVMAttributeRef attr) { - Function *A = unwrap(Fn); - const AttributeSet PAL = A->getAttributes(); - AttrBuilder B(Val); + Function *F = unwrap(Fn); + const AttributeSet PAL = F->getAttributes(); + AttrBuilder B(unwrap(attr)); const AttributeSet PALnew = - PAL.removeAttributes(A->getContext(), index, - AttributeSet::get(A->getContext(), index, B)); - A->setAttributes(PALnew); -} - -extern "C" void LLVMRustRemoveFunctionAttrString(LLVMValueRef fn, - unsigned index, - const char *Name) -{ - Function *f = unwrap(fn); - LLVMContext &C = f->getContext(); - AttrBuilder B; - B.addAttribute(Name); - AttributeSet to_remove = AttributeSet::get(C, index, B); - - AttributeSet attrs = f->getAttributes(); - f->setAttributes(attrs.removeAttributes(f->getContext(), - index, - to_remove)); + PAL.removeAttributes(F->getContext(), index, + AttributeSet::get(F->getContext(), index, B)); + F->setAttributes(PALnew); } // enable fpmath flag UnsafeAlgebra @@ -1293,3 +1314,7 @@ extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) { extern "C" void LLVMRustSetLinkage(LLVMValueRef V, LLVMRustLinkage RustLinkage) { LLVMSetLinkage(V, from_rust(RustLinkage)); } + +extern "C" LLVMContextRef LLVMRustGetValueContext(LLVMValueRef V) { + return wrap(&unwrap(V)->getContext()); +} diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h index ffe94d1e22f2..346153d578c4 100644 --- a/src/rustllvm/rustllvm.h +++ b/src/rustllvm/rustllvm.h @@ -72,6 +72,28 @@ enum class LLVMRustResult { Failure }; +enum LLVMRustAttribute { + AlwaysInline = 0, + ByVal = 1, + Cold = 2, + InlineHint = 3, + MinSize = 4, + Naked = 5, + NoAlias = 6, + NoCapture = 7, + NoInline = 8, + NonNull = 9, + NoRedZone = 10, + NoReturn = 11, + NoUnwind = 12, + OptimizeForSize = 13, + ReadOnly = 14, + SExt = 15, + StructRet = 16, + UWTable = 17, + ZExt = 18, +}; + typedef struct OpaqueRustString *RustStringRef; typedef struct LLVMOpaqueTwine *LLVMTwineRef; typedef struct LLVMOpaqueDebugLoc *LLVMDebugLocRef; From c938007f90711d6acc8b55e15a5e3cf7cc147e91 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 17 Nov 2016 15:12:43 -0500 Subject: [PATCH 164/177] add test for hashing trait impls --- src/test/incremental/hashes/trait_impls.rs | 404 +++++++++++++++++++++ 1 file changed, 404 insertions(+) create mode 100644 src/test/incremental/hashes/trait_impls.rs diff --git a/src/test/incremental/hashes/trait_impls.rs b/src/test/incremental/hashes/trait_impls.rs new file mode 100644 index 000000000000..500aaf52324b --- /dev/null +++ b/src/test/incremental/hashes/trait_impls.rs @@ -0,0 +1,404 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// This test case tests the incremental compilation hash (ICH) implementation +// for let expressions. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph + + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![feature(specialization)] +#![crate_type="rlib"] + +struct Foo; + +// Change Method Name ----------------------------------------------------------- + +#[cfg(cfail1)] +pub trait ChangeMethodNameTrait { + fn method_name(); +} + +#[cfg(cfail1)] +impl ChangeMethodNameTrait for Foo { + fn method_name() { } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub trait ChangeMethodNameTrait { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method_name2(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl ChangeMethodNameTrait for Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method_name2() { } +} + +// Change Method Body ----------------------------------------------------------- +// +// This should affect the method itself, but not the trait. + +pub trait ChangeMethodBodyTrait { + fn method_name(); +} + +#[cfg(cfail1)] +impl ChangeMethodBodyTrait for Foo { + fn method_name() { } +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl ChangeMethodBodyTrait for Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method_name() { + () + } +} + +// Change Method Selfness ----------------------------------------------------------- + +#[cfg(cfail1)] +pub trait ChangeMethodSelfnessTrait { + fn method_name(); +} + +#[cfg(cfail1)] +impl ChangeMethodSelfnessTrait for Foo { + fn method_name() { } +} + +#[cfg(not(cfail1))] +pub trait ChangeMethodSelfnessTrait { + fn method_name(&self); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl ChangeMethodSelfnessTrait for Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method_name(&self) { + () + } +} + +// Change Method Selfness ----------------------------------------------------------- + +#[cfg(cfail1)] +pub trait RemoveMethodSelfnessTrait { + fn method_name(&self); +} + +#[cfg(cfail1)] +impl RemoveMethodSelfnessTrait for Foo { + fn method_name(&self) { } +} + +#[cfg(not(cfail1))] +pub trait RemoveMethodSelfnessTrait { + fn method_name(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl RemoveMethodSelfnessTrait for Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method_name() { + () + } +} + +// Change Method Selfmutness ----------------------------------------------------------- + +#[cfg(cfail1)] +pub trait ChangeMethodSelfmutnessTrait { + fn method_name(&self); +} + +#[cfg(cfail1)] +impl ChangeMethodSelfmutnessTrait for Foo { + fn method_name(&self) { } +} + +#[cfg(not(cfail1))] +pub trait ChangeMethodSelfmutnessTrait { + fn method_name(&mut self); +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl ChangeMethodSelfmutnessTrait for Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method_name(&mut self) { + () + } +} + +// Change item kind ----------------------------------------------------------- + +#[cfg(cfail1)] +pub trait ChangeItemKindTrait { + fn name(); +} + +#[cfg(cfail1)] +impl ChangeItemKindTrait for Foo { + fn name() { } +} + +#[cfg(not(cfail1))] +pub trait ChangeItemKindTrait { + type name; +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl ChangeItemKindTrait for Foo { + type name = (); +} + +// Remove item ----------------------------------------------------------- + +#[cfg(cfail1)] +pub trait RemoveItemTrait { + type TypeName; + fn method_name(); +} + +#[cfg(cfail1)] +impl RemoveItemTrait for Foo { + type TypeName = (); + fn method_name() { } +} + +#[cfg(not(cfail1))] +pub trait RemoveItemTrait { + type TypeName; +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl RemoveItemTrait for Foo { + type TypeName = (); +} + +// Add item ----------------------------------------------------------- + +#[cfg(cfail1)] +pub trait AddItemTrait { + type TypeName; +} + +#[cfg(cfail1)] +impl AddItemTrait for Foo { + type TypeName = (); +} + +#[cfg(not(cfail1))] +pub trait AddItemTrait { + type TypeName; + fn method_name(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl AddItemTrait for Foo { + type TypeName = (); + fn method_name() { } +} + +// Change has-value ----------------------------------------------------------- + +#[cfg(cfail1)] +pub trait ChangeHasValueTrait { + fn method_name(); +} + +#[cfg(cfail1)] +impl ChangeHasValueTrait for Foo { + fn method_name() { } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub trait ChangeHasValueTrait { + fn method_name() { } +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl ChangeHasValueTrait for Foo { + fn method_name() { } +} + +// Add default + +pub trait AddDefaultTrait { + fn method_name(); +} + +#[cfg(cfail1)] +impl AddDefaultTrait for Foo { + fn method_name() { } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl AddDefaultTrait for Foo { + default fn method_name() { } +} + +// Remove default + +pub trait RemoveDefaultTrait { + fn method_name(); +} + +#[cfg(cfail1)] +impl RemoveDefaultTrait for Foo { + default fn method_name() { } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl RemoveDefaultTrait for Foo { + fn method_name() { } +} + +// Add arguments + +#[cfg(cfail1)] +pub trait AddArgumentTrait { + fn method_name(&self); +} + +#[cfg(cfail1)] +impl AddArgumentTrait for Foo { + fn method_name(&self) { } +} + +#[cfg(not(cfail1))] +pub trait AddArgumentTrait { + fn method_name(&self, x: u32); +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl AddArgumentTrait for Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method_name(&self, _x: u32) { } +} + +// Change argument type + +#[cfg(cfail1)] +pub trait ChangeArgumentTypeTrait { + fn method_name(&self, x: u32); +} + +#[cfg(cfail1)] +impl ChangeArgumentTypeTrait for Foo { + fn method_name(&self, _x: u32) { } +} + +#[cfg(not(cfail1))] +pub trait ChangeArgumentTypeTrait { + fn method_name(&self, x: char); +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl ChangeArgumentTypeTrait for Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method_name(&self, _x: char) { } +} + From 04886f2c983cc06f595578e3d35b92fd44400210 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 18 Nov 2016 00:03:10 +0000 Subject: [PATCH 165/177] Fix bug in loading proc macro dependencies. --- src/librustc_metadata/creader.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 4298bb47fea6..5384535024e5 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -318,11 +318,11 @@ impl<'a> CrateLoader<'a> { name: &str, hash: Option<&Svh>, span: Span, - kind: PathKind, + path_kind: PathKind, mut dep_kind: DepKind) -> (CrateNum, Rc) { info!("resolving crate `extern crate {} as {}`", name, ident); - let result = if let Some(cnum) = self.existing_match(name, hash, kind) { + let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) { LoadResult::Previous(cnum) } else { info!("falling back to a load"); @@ -332,7 +332,7 @@ impl<'a> CrateLoader<'a> { ident: ident, crate_name: name, hash: hash.map(|a| &*a), - filesearch: self.sess.target_filesearch(kind), + filesearch: self.sess.target_filesearch(path_kind), target: &self.sess.target.target, triple: &self.sess.opts.target_triple, root: root, @@ -350,7 +350,7 @@ impl<'a> CrateLoader<'a> { let mut proc_macro_locator = locator::Context { target: &self.sess.host, triple: config::host_triple(), - filesearch: self.sess.host_filesearch(PathKind::Crate), + filesearch: self.sess.host_filesearch(path_kind), rejected_via_hash: vec![], rejected_via_triple: vec![], rejected_via_kind: vec![], From 8a949dfea2c26d55aad036cf2b4000a2d45f5159 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 15 Nov 2016 17:03:27 +1300 Subject: [PATCH 166/177] save-analysis: handle << and >> operators inside [] in types Fixes #37700 --- src/librustc_save_analysis/span_utils.rs | 56 ++++++++++++++++++------ src/test/run-make/save-analysis/foo.rs | 6 +++ 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index 031b9a6a5aa5..9ec764b82f86 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -177,25 +177,44 @@ impl<'a> SpanUtils<'a> { } // Return the span for the last ident before a `<` and outside any - // brackets, or the last span. + // angle brackets, or the last span. pub fn sub_span_for_type_name(&self, span: Span) -> Option { let mut toks = self.retokenise_span(span); let mut prev = toks.real_token(); let mut result = None; + + // We keep track of the following two counts - the depth of nesting of + // angle brackets, and the depth of nesting of square brackets. For the + // angle bracket count, we only count tokens which occur outside of any + // square brackets (i.e. bracket_count == 0). The intutition here is + // that we want to count angle brackets in the type, but not any which + // could be in expression context (because these could mean 'less than', + // etc.). + let mut angle_count = 0; let mut bracket_count = 0; loop { let next = toks.real_token(); - if (next.tok == token::Lt || next.tok == token::Colon) && bracket_count == 0 && + if (next.tok == token::Lt || next.tok == token::Colon) && + angle_count == 0 && + bracket_count == 0 && prev.tok.is_ident() { result = Some(prev.sp); } + if bracket_count == 0 { + angle_count += match prev.tok { + token::Lt => 1, + token::Gt => -1, + token::BinOp(token::Shl) => 2, + token::BinOp(token::Shr) => -2, + _ => 0, + }; + } + bracket_count += match prev.tok { - token::Lt => 1, - token::Gt => -1, - token::BinOp(token::Shl) => 2, - token::BinOp(token::Shr) => -2, + token::OpenDelim(token::Bracket) => 1, + token::CloseDelim(token::Bracket) => -1, _ => 0, }; @@ -204,7 +223,7 @@ impl<'a> SpanUtils<'a> { } prev = next; } - if bracket_count != 0 { + if angle_count != 0 || bracket_count != 0 { let loc = self.sess.codemap().lookup_char_pos(span.lo); span_bug!(span, "Mis-counted brackets when breaking path? Parsing '{}' \ @@ -213,7 +232,7 @@ impl<'a> SpanUtils<'a> { loc.file.name, loc.line); } - if result.is_none() && prev.tok.is_ident() && bracket_count == 0 { + if result.is_none() && prev.tok.is_ident() && angle_count == 0 { return self.make_sub_span(span, Some(prev.sp)); } self.make_sub_span(span, result) @@ -222,19 +241,20 @@ impl<'a> SpanUtils<'a> { // Reparse span and return an owned vector of sub spans of the first limit // identifier tokens in the given nesting level. // example with Foo, Bar> - // Nesting = 0: all idents outside of brackets: [Foo] - // Nesting = 1: idents within one level of brackets: [Bar, Bar] + // Nesting = 0: all idents outside of angle brackets: [Foo] + // Nesting = 1: idents within one level of angle brackets: [Bar, Bar] pub fn spans_with_brackets(&self, span: Span, nesting: isize, limit: isize) -> Vec { let mut result: Vec = vec![]; let mut toks = self.retokenise_span(span); // We keep track of how many brackets we're nested in + let mut angle_count: isize = 0; let mut bracket_count: isize = 0; let mut found_ufcs_sep = false; loop { let ts = toks.real_token(); if ts.tok == token::Eof { - if bracket_count != 0 { + if angle_count != 0 || bracket_count != 0 { if generated_code(span) { return vec![]; } @@ -252,6 +272,14 @@ impl<'a> SpanUtils<'a> { return result; } bracket_count += match ts.tok { + token::OpenDelim(token::Bracket) => 1, + token::CloseDelim(token::Bracket) => -1, + _ => 0, + }; + if bracket_count > 0 { + continue; + } + angle_count += match ts.tok { token::Lt => 1, token::Gt => -1, token::BinOp(token::Shl) => 2, @@ -269,11 +297,11 @@ impl<'a> SpanUtils<'a> { // path, trying to pull out the non-nested idents (e.g., avoiding 'a // in `>::C`). So we end up with a span for `B>::C` from // the start of the first ident to the end of the path. - if !found_ufcs_sep && bracket_count == -1 { + if !found_ufcs_sep && angle_count == -1 { found_ufcs_sep = true; - bracket_count += 1; + angle_count += 1; } - if ts.tok.is_ident() && bracket_count == nesting { + if ts.tok.is_ident() && angle_count == nesting { result.push(self.make_sub_span(span, Some(ts.sp)).unwrap()); } } diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs index e9ed897bf302..e8b69729af67 100644 --- a/src/test/run-make/save-analysis/foo.rs +++ b/src/test/run-make/save-analysis/foo.rs @@ -57,6 +57,12 @@ fn test_alias(i: Option<::Item>) { let y = x.1; } +// Issue #37700 +const LUT_BITS: usize = 3; +pub struct HuffmanTable { + ac_lut: Option<[(i16, u8); 1 << LUT_BITS]>, +} + struct TupStruct(isize, isize, Box); fn test_tup_struct(x: TupStruct) -> isize { From 8918ddf0ed7ed02546919b2a360543c0930d6486 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 18 Nov 2016 00:51:24 +0000 Subject: [PATCH 167/177] Add regression test. --- src/test/run-make/issue-37839/Makefile | 6 ++++++ src/test/run-make/issue-37839/a.rs | 13 +++++++++++++ src/test/run-make/issue-37839/b.rs | 12 ++++++++++++ src/test/run-make/issue-37839/c.rs | 12 ++++++++++++ 4 files changed, 43 insertions(+) create mode 100644 src/test/run-make/issue-37839/Makefile create mode 100644 src/test/run-make/issue-37839/a.rs create mode 100644 src/test/run-make/issue-37839/b.rs create mode 100644 src/test/run-make/issue-37839/c.rs diff --git a/src/test/run-make/issue-37839/Makefile b/src/test/run-make/issue-37839/Makefile new file mode 100644 index 000000000000..f17ce537fb81 --- /dev/null +++ b/src/test/run-make/issue-37839/Makefile @@ -0,0 +1,6 @@ +-include ../tools.mk + +all: + $(RUSTC) a.rs && $(RUSTC) b.rs + $(BARE_RUSTC) c.rs -L dependency=$(TMPDIR) --extern b=$(TMPDIR)/libb.rlib \ + --out-dir=$(TMPDIR) diff --git a/src/test/run-make/issue-37839/a.rs b/src/test/run-make/issue-37839/a.rs new file mode 100644 index 000000000000..3dff45388c75 --- /dev/null +++ b/src/test/run-make/issue-37839/a.rs @@ -0,0 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(proc_macro)] +#![allow(unused)] +#![crate_type = "proc-macro"] diff --git a/src/test/run-make/issue-37839/b.rs b/src/test/run-make/issue-37839/b.rs new file mode 100644 index 000000000000..82f48f6d8d66 --- /dev/null +++ b/src/test/run-make/issue-37839/b.rs @@ -0,0 +1,12 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "lib"] +#[macro_use] extern crate a; diff --git a/src/test/run-make/issue-37839/c.rs b/src/test/run-make/issue-37839/c.rs new file mode 100644 index 000000000000..85bece514279 --- /dev/null +++ b/src/test/run-make/issue-37839/c.rs @@ -0,0 +1,12 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "lib"] +extern crate b; From f3240377e6ebdff032e9275aee8dd461e9866cbb Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 17 Nov 2016 21:50:59 -0800 Subject: [PATCH 168/177] rustbuild: update the llvm link logic further There are now four static/shared scenarios that can happen for the supported LLVM versions: - 3.9+: By default use `llvm-config --link-static` - 3.9+ and `--enable-llvm-link-shared`: Use `--link-shared` instead. - 3.8: Use `llvm-config --shared-mode` and go with its answer. - 3.7: Just assume static, maintaining the status quo. --- src/librustc_llvm/build.rs | 58 +++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index eb4a1da484d1..6be3d1172dc2 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -17,6 +17,35 @@ use std::path::{PathBuf, Path}; use build_helper::output; +fn detect_llvm_link(llvm_config: &Path) -> (&'static str, Option<&'static str>) { + let mut version_cmd = Command::new(llvm_config); + version_cmd.arg("--version"); + let version_output = output(&mut version_cmd); + let mut parts = version_output.split('.').take(2) + .filter_map(|s| s.parse::().ok()); + if let (Some(major), Some(minor)) = (parts.next(), parts.next()) { + if major > 3 || (major == 3 && minor >= 9) { + // Force the link mode we want, preferring static by default, but + // possibly overridden by `configure --enable-llvm-link-shared`. + if env::var_os("LLVM_LINK_SHARED").is_some() { + return ("dylib", Some("--link-shared")); + } else { + return ("static", Some("--link-static")); + } + } else if major == 3 && minor == 8 { + // Find out LLVM's default linking mode. + let mut mode_cmd = Command::new(llvm_config); + mode_cmd.arg("--shared-mode"); + if output(&mut mode_cmd).trim() == "shared" { + return ("dylib", None); + } else { + return ("static", None); + } + } + } + ("static", None) +} + fn main() { println!("cargo:rustc-cfg=cargobuild"); @@ -123,14 +152,7 @@ fn main() { .cpp_link_stdlib(None) // we handle this below .compile("librustllvm.a"); - // Find out LLVM's default linking mode. - let mut cmd = Command::new(&llvm_config); - cmd.arg("--shared-mode"); - let mut llvm_kind = if output(&mut cmd).trim() == "shared" { - "dylib" - } else { - "static" - }; + let (llvm_kind, llvm_link_arg) = detect_llvm_link(&llvm_config); // Link in all LLVM libraries, if we're uwring the "wrong" llvm-config then // we don't pick up system libs because unfortunately they're for the host @@ -138,24 +160,8 @@ fn main() { let mut cmd = Command::new(&llvm_config); cmd.arg("--libs"); - // Force static linking with "--link-static" if available, or - // force "--link-shared" if the configuration requested it. - let llvm_link_shared = env::var_os("LLVM_LINK_SHARED").is_some(); - let mut version_cmd = Command::new(&llvm_config); - version_cmd.arg("--version"); - let version_output = output(&mut version_cmd); - let mut parts = version_output.split('.'); - if let (Some(major), Some(minor)) = (parts.next().and_then(|s| s.parse::().ok()), - parts.next().and_then(|s| s.parse::().ok())) { - if major > 3 || (major == 3 && minor >= 9) { - if llvm_link_shared { - cmd.arg("--link-shared"); - llvm_kind = "dylib"; - } else { - cmd.arg("--link-static"); - llvm_kind = "static"; - } - } + if let Some(link_arg) = llvm_link_arg { + cmd.arg(link_arg); } if !is_crossed { From 4fc02f689380b9f330d4aa92bcb833c60da92aad Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 16 Nov 2016 12:27:43 +0200 Subject: [PATCH 169/177] instantiate closures on demand this should fix compilation with `-C codegen-units=4` - tested locally with `RUSTFLAGS='-C codegen-units=4' ../x.py test` --- src/librustc_trans/common.rs | 5 +++++ src/librustc_trans/trans_item.rs | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index a0fac9cc6599..df70a6e81166 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -18,6 +18,7 @@ use llvm::{ValueRef, BasicBlockRef, BuilderRef, ContextRef, TypeKind}; use llvm::{True, False, Bool, OperandBundleDef}; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; +use rustc::hir::map::DefPathData; use rustc::infer::TransNormalize; use rustc::mir::Mir; use rustc::util::common::MemoizationMap; @@ -1100,3 +1101,7 @@ pub fn ty_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, _ => bug!("unexpected type {:?} to ty_fn_sig", ty) } } + +pub fn is_closure(tcx: TyCtxt, def_id: DefId) -> bool { + tcx.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr +} diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 94a68de7f867..7fa59127704d 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -18,6 +18,7 @@ use attributes; use base; use consts; use context::{CrateContext, SharedCrateContext}; +use common; use declare; use glue::DropGlueKind; use llvm; @@ -245,6 +246,7 @@ impl<'a, 'tcx> TransItem<'tcx> { TransItem::Fn(ref instance) => { !instance.def.is_local() || instance.substs.types().next().is_some() || + common::is_closure(tcx, instance.def) || attr::requests_inline(&tcx.get_attrs(instance.def)[..]) } TransItem::DropGlue(..) => true, From fb5ccf80fe83653018794562bfc105d6914384ae Mon Sep 17 00:00:00 2001 From: Josh Driver Date: Fri, 18 Nov 2016 21:01:19 +1030 Subject: [PATCH 170/177] Warn when a #[should_panic] test has an unexpected message --- src/libtest/lib.rs | 43 +++++++++++++------ .../run-fail/test-should-panic-bad-message.rs | 19 ++++++++ .../run-fail/test-should-panic-no-message.rs | 19 ++++++++ 3 files changed, 68 insertions(+), 13 deletions(-) create mode 100644 src/test/run-fail/test-should-panic-bad-message.rs create mode 100644 src/test/run-fail/test-should-panic-no-message.rs diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 95ae6eb2efe8..8749a64e5fdb 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -75,9 +75,9 @@ const TEST_WARN_TIMEOUT_S: u64 = 60; // to be used by rustc to compile tests in libtest pub mod test { pub use {Bencher, TestName, TestResult, TestDesc, TestDescAndFn, TestOpts, TrFailed, - TrIgnored, TrOk, Metric, MetricMap, StaticTestFn, StaticTestName, DynTestName, - DynTestFn, run_test, test_main, test_main_static, filter_tests, parse_opts, - StaticBenchFn, ShouldPanic}; + TrFailedMsg, TrIgnored, TrOk, Metric, MetricMap, StaticTestFn, StaticTestName, + DynTestName, DynTestFn, run_test, test_main, test_main_static, filter_tests, + parse_opts, StaticBenchFn, ShouldPanic}; } pub mod stats; @@ -473,6 +473,7 @@ pub struct BenchSamples { pub enum TestResult { TrOk, TrFailed, + TrFailedMsg(String), TrIgnored, TrMetrics(MetricMap), TrBench(BenchSamples), @@ -611,7 +612,7 @@ impl ConsoleTestState { pub fn write_result(&mut self, result: &TestResult) -> io::Result<()> { match *result { TrOk => self.write_ok(), - TrFailed => self.write_failed(), + TrFailed | TrFailedMsg(_) => self.write_failed(), TrIgnored => self.write_ignored(), TrMetrics(ref mm) => { self.write_metric()?; @@ -638,6 +639,7 @@ impl ConsoleTestState { match *result { TrOk => "ok".to_owned(), TrFailed => "failed".to_owned(), + TrFailedMsg(ref msg) => format!("failed: {}", msg), TrIgnored => "ignored".to_owned(), TrMetrics(ref mm) => mm.fmt_metrics(), TrBench(ref bs) => fmt_bench_samples(bs), @@ -773,6 +775,14 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec) -> io::Resu st.failed += 1; st.failures.push((test, stdout)); } + TrFailedMsg(msg) => { + st.failed += 1; + let mut stdout = stdout; + stdout.extend_from_slice( + format!("note: {}", msg).as_bytes() + ); + st.failures.push((test, stdout)); + } } Ok(()) } @@ -1270,12 +1280,16 @@ fn calc_result(desc: &TestDesc, task_result: Result<(), Box>) -> Tes match (&desc.should_panic, task_result) { (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TrOk, - (&ShouldPanic::YesWithMessage(msg), Err(ref err)) + (&ShouldPanic::YesWithMessage(msg), Err(ref err)) => if err.downcast_ref::() - .map(|e| &**e) - .or_else(|| err.downcast_ref::<&'static str>().map(|e| *e)) - .map(|e| e.contains(msg)) - .unwrap_or(false) => TrOk, + .map(|e| &**e) + .or_else(|| err.downcast_ref::<&'static str>().map(|e| *e)) + .map(|e| e.contains(msg)) + .unwrap_or(false) { + TrOk + } else { + TrFailedMsg(format!("Panic did not include expected string '{}'", msg)) + }, _ => TrFailed, } } @@ -1482,8 +1496,9 @@ pub mod bench { #[cfg(test)] mod tests { - use test::{TrFailed, TrIgnored, TrOk, filter_tests, parse_opts, TestDesc, TestDescAndFn, - TestOpts, run_test, MetricMap, StaticTestName, DynTestName, DynTestFn, ShouldPanic}; + use test::{TrFailed, TrFailedMsg, TrIgnored, TrOk, filter_tests, parse_opts, TestDesc, + TestDescAndFn, TestOpts, run_test, MetricMap, StaticTestName, DynTestName, + DynTestFn, ShouldPanic}; use std::sync::mpsc::channel; #[test] @@ -1565,18 +1580,20 @@ mod tests { fn f() { panic!("an error message"); } + let expected = "foobar"; + let failed_msg = "Panic did not include expected string"; let desc = TestDescAndFn { desc: TestDesc { name: StaticTestName("whatever"), ignore: false, - should_panic: ShouldPanic::YesWithMessage("foobar"), + should_panic: ShouldPanic::YesWithMessage(expected), }, testfn: DynTestFn(Box::new(move |()| f())), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); let (_, res, _) = rx.recv().unwrap(); - assert!(res == TrFailed); + assert!(res == TrFailedMsg(format!("{} '{}'", failed_msg, expected))); } #[test] diff --git a/src/test/run-fail/test-should-panic-bad-message.rs b/src/test/run-fail/test-should-panic-bad-message.rs new file mode 100644 index 000000000000..7186672b4049 --- /dev/null +++ b/src/test/run-fail/test-should-panic-bad-message.rs @@ -0,0 +1,19 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --test + +// error-pattern:panicked at 'bar' +// check-stdout +#[test] +#[should_panic(expected = "foo")] +pub fn test_bar() { + panic!("bar") +} diff --git a/src/test/run-fail/test-should-panic-no-message.rs b/src/test/run-fail/test-should-panic-no-message.rs new file mode 100644 index 000000000000..50dc2aed8e9d --- /dev/null +++ b/src/test/run-fail/test-should-panic-no-message.rs @@ -0,0 +1,19 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --test + +// error-pattern:panicked at 'explicit panic' +// check-stdout +#[test] +#[should_panic(expected = "foo")] +pub fn test_explicit() { + panic!() +} From fc2216cc1df73a6785a1cdc603902660c8501c4a Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Fri, 18 Nov 2016 11:31:44 +0100 Subject: [PATCH 171/177] update Cargo.lock --- src/Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Cargo.lock b/src/Cargo.lock index ee38a043b122..2d5207e5c6bc 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -543,6 +543,7 @@ dependencies = [ "rustc_back 0.0.0", "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", + "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_platform_intrinsics 0.0.0", "syntax 0.0.0", From d3b050c3084f12545a8c224f8d88813b25f46c80 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 18 Nov 2016 20:37:25 +0000 Subject: [PATCH 172/177] Don't build the lexer verifier during tidy Tidy is not the right place to do this. Tidy is for running lints. We should instead be running the lexer/grammar tests as part of the test suite. This may fix nightly breakage, but I don't know why. --- mk/tests.mk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mk/tests.mk b/mk/tests.mk index 9885d275e8b6..35ee7697a7a6 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -243,8 +243,7 @@ cleantestlibs: .PHONY: tidy tidy: $(HBIN0_H_$(CFG_BUILD))/tidy$(X_$(CFG_BUILD)) \ - $(SNAPSHOT_RUSTC_POST_CLEANUP) \ - check-build-lexer-verifier + $(SNAPSHOT_RUSTC_POST_CLEANUP) $(TARGET_RPATH_VAR0_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $< $(S)src $(HBIN0_H_$(CFG_BUILD))/tidy$(X_$(CFG_BUILD)): \ From 003b1699c0044aef757c9c32df13a529fd4c485b Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 15 Nov 2016 11:55:34 -0500 Subject: [PATCH 173/177] Add error message when not finding the ICH of a DepNode. --- src/librustc_incremental/calculate_svh/mod.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index c08519090d27..0339f4882725 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -88,7 +88,12 @@ impl<'a> ::std::ops::Index<&'a DepNode> for IncrementalHashesMap { type Output = Fingerprint; fn index(&self, index: &'a DepNode) -> &Fingerprint { - &self.hashes[index] + match self.hashes.get(index) { + Some(fingerprint) => fingerprint, + None => { + bug!("Could not find ICH for {:?}", index); + } + } } } From a5137afe8cddf2366045c8d3de23a17c5ac8dc25 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 15 Nov 2016 15:20:39 -0500 Subject: [PATCH 174/177] ICH: Hash MacroDefs in a mostly stable way. --- src/librustc_incremental/calculate_svh/mod.rs | 7 +- .../calculate_svh/svh_visitor.rs | 139 +++++++++++++++++- 2 files changed, 143 insertions(+), 3 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index 0339f4882725..f98e698a1c9d 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -46,6 +46,7 @@ use self::caching_codemap_view::CachingCodemapView; use self::hasher::IchHasher; use ich::Fingerprint; + mod def_path_hash; mod svh_visitor; mod caching_codemap_view; @@ -113,8 +114,12 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || { visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| visit::walk_crate(v, krate)); - // FIXME(#37713) if foreign items were item likes, could use ItemLikeVisitor krate.visit_all_item_likes(&mut visitor.as_deep_visitor()); + + for macro_def in krate.exported_macros.iter() { + visitor.calculate_node_id(macro_def.id, + |v| v.visit_macro_def(macro_def)); + } }); tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64); diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index fa2eff817eaa..e8608b187d84 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -24,6 +24,7 @@ use syntax::ast::{self, Name, NodeId}; use syntax::attr; use syntax::parse::token; use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos}; +use syntax::tokenstream; use rustc::hir; use rustc::hir::*; use rustc::hir::def::{Def, PathResolution}; @@ -769,9 +770,10 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has debug!("visit_macro_def: st={:?}", self.st); SawMacroDef.hash(self.st); hash_attrs!(self, ¯o_def.attrs); + for tt in ¯o_def.body { + self.hash_token_tree(tt); + } visit::walk_macro_def(self, macro_def) - // FIXME(mw): We should hash the body of the macro too but we don't - // have a stable way of doing so yet. } } @@ -941,4 +943,137 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { self.overflow_checks_enabled = true; } } + + fn hash_token_tree(&mut self, tt: &tokenstream::TokenTree) { + self.hash_discriminant(tt); + match *tt { + tokenstream::TokenTree::Token(span, ref token) => { + hash_span!(self, span); + self.hash_token(token); + } + tokenstream::TokenTree::Delimited(span, ref delimited) => { + hash_span!(self, span); + let tokenstream::Delimited { + ref delim, + open_span, + ref tts, + close_span, + } = **delimited; + + delim.hash(self.st); + hash_span!(self, open_span); + tts.len().hash(self.st); + for sub_tt in tts { + self.hash_token_tree(sub_tt); + } + hash_span!(self, close_span); + } + tokenstream::TokenTree::Sequence(span, ref sequence_repetition) => { + hash_span!(self, span); + let tokenstream::SequenceRepetition { + ref tts, + ref separator, + op, + num_captures, + } = **sequence_repetition; + + tts.len().hash(self.st); + for sub_tt in tts { + self.hash_token_tree(sub_tt); + } + self.hash_discriminant(separator); + if let Some(ref separator) = *separator { + self.hash_token(separator); + } + op.hash(self.st); + num_captures.hash(self.st); + } + } + } + + fn hash_token(&mut self, token: &token::Token) { + self.hash_discriminant(token); + match *token { + token::Token::Eq | + token::Token::Lt | + token::Token::Le | + token::Token::EqEq | + token::Token::Ne | + token::Token::Ge | + token::Token::Gt | + token::Token::AndAnd | + token::Token::OrOr | + token::Token::Not | + token::Token::Tilde | + token::Token::At | + token::Token::Dot | + token::Token::DotDot | + token::Token::DotDotDot | + token::Token::Comma | + token::Token::Semi | + token::Token::Colon | + token::Token::ModSep | + token::Token::RArrow | + token::Token::LArrow | + token::Token::FatArrow | + token::Token::Pound | + token::Token::Dollar | + token::Token::Question | + token::Token::Underscore | + token::Token::Whitespace | + token::Token::Comment | + token::Token::Eof => {} + + token::Token::BinOp(bin_op_token) | + token::Token::BinOpEq(bin_op_token) => bin_op_token.hash(self.st), + + token::Token::OpenDelim(delim_token) | + token::Token::CloseDelim(delim_token) => delim_token.hash(self.st), + + token::Token::Literal(ref lit, ref opt_name) => { + self.hash_discriminant(lit); + match *lit { + token::Lit::Byte(val) | + token::Lit::Char(val) | + token::Lit::Integer(val) | + token::Lit::Float(val) | + token::Lit::Str_(val) | + token::Lit::ByteStr(val) => val.as_str().hash(self.st), + token::Lit::StrRaw(val, n) | + token::Lit::ByteStrRaw(val, n) => { + val.as_str().hash(self.st); + n.hash(self.st); + } + }; + opt_name.map(ast::Name::as_str).hash(self.st); + } + + token::Token::Ident(ident) | + token::Token::Lifetime(ident) | + token::Token::SubstNt(ident) => ident.name.as_str().hash(self.st), + token::Token::MatchNt(ident1, ident2) => { + ident1.name.as_str().hash(self.st); + ident2.name.as_str().hash(self.st); + } + + token::Token::Interpolated(ref non_terminal) => { + // FIXME(mw): This could be implemented properly. It's just a + // lot of work, since we would need to hash the AST + // in a stable way, in addition to the HIR. + // Since this is hardly used anywhere, just emit a + // warning for now. + if self.tcx.sess.opts.debugging_opts.incremental.is_some() { + let msg = format!("Quasi-quoting might make incremental \ + compilation very inefficient: {:?}", + non_terminal); + self.tcx.sess.warn(&msg[..]); + } + + non_terminal.hash(self.st); + } + + token::Token::DocComment(val) | + token::Token::Shebang(val) => val.as_str().hash(self.st), + } + } } From e6b30bda495eaf927a3bca66580f13095585e496 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 15 Nov 2016 15:22:15 -0500 Subject: [PATCH 175/177] Remove outdated comment about SVH. --- src/librustc_incremental/calculate_svh/svh_visitor.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index e8608b187d84..faf4da55ee5d 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -8,11 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME (#14132): Even this SVH computation still has implementation -// artifacts: namely, the order of item declaration will affect the -// hash computation, but for many kinds of items the order of -// declaration should be irrelevant to the ABI. - use self::SawExprComponent::*; use self::SawAbiComponent::*; use self::SawItemComponent::*; From 52d250efabed644a15c797bfcc747a4113d2433d Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 15 Nov 2016 16:16:40 -0500 Subject: [PATCH 176/177] Add test case for exported macros vs incremental compilation. --- .../incr_comp_with_macro_export.rs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/compile-fail/incr_comp_with_macro_export.rs diff --git a/src/test/compile-fail/incr_comp_with_macro_export.rs b/src/test/compile-fail/incr_comp_with_macro_export.rs new file mode 100644 index 000000000000..eafef1723036 --- /dev/null +++ b/src/test/compile-fail/incr_comp_with_macro_export.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Zincremental=tmp/cfail-tests/incr_comp_with_macro_export +// must-compile-successfully + + +// This test case makes sure that we can compile with incremental compilation +// enabled when there are macros exported from this crate. (See #37756) + +#![crate_type="rlib"] + +#[macro_export] +macro_rules! some_macro { + ($e:expr) => ($e + 1) +} From c722a1eb9992ac76f5c3dd0aee36b8734d613f11 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 16 Nov 2016 10:18:46 -0500 Subject: [PATCH 177/177] Add span to warning about incr. comp. vs Token::Interpolated. --- src/librustc_incremental/calculate_svh/svh_visitor.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index faf4da55ee5d..a1ece48462b1 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -944,7 +944,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { match *tt { tokenstream::TokenTree::Token(span, ref token) => { hash_span!(self, span); - self.hash_token(token); + self.hash_token(token, span); } tokenstream::TokenTree::Delimited(span, ref delimited) => { hash_span!(self, span); @@ -978,7 +978,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { } self.hash_discriminant(separator); if let Some(ref separator) = *separator { - self.hash_token(separator); + self.hash_token(separator, span); } op.hash(self.st); num_captures.hash(self.st); @@ -986,7 +986,9 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { } } - fn hash_token(&mut self, token: &token::Token) { + fn hash_token(&mut self, + token: &token::Token, + error_reporting_span: Span) { self.hash_discriminant(token); match *token { token::Token::Eq | @@ -1061,7 +1063,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { let msg = format!("Quasi-quoting might make incremental \ compilation very inefficient: {:?}", non_terminal); - self.tcx.sess.warn(&msg[..]); + self.tcx.sess.span_warn(error_reporting_span, &msg[..]); } non_terminal.hash(self.st);

, city: &str) @@ -2070,7 +2070,7 @@ fn search> for row in rdr.decode::() { let row = try!(row); match row.population { - None => { } // skip it + None => { } // Skip it. Some(count) => if row.city == city { found.push(PopulationCount { city: row.city, diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 8709c3f4b7b1..c58fc47c2d36 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -277,7 +277,7 @@ extern { fn main() { unsafe { register_callback(callback); - trigger_callback(); // Triggers the callback + trigger_callback(); // Triggers the callback. } } ``` @@ -294,7 +294,7 @@ int32_t register_callback(rust_callback callback) { } void trigger_callback() { - cb(7); // Will call callback(7) in Rust + cb(7); // Will call callback(7) in Rust. } ``` @@ -320,13 +320,13 @@ Rust code: #[repr(C)] struct RustObject { a: i32, - // other members + // Other members... } extern "C" fn callback(target: *mut RustObject, a: i32) { println!("I'm called from C with value {0}", a); unsafe { - // Update the value in RustObject with the value received from the callback + // Update the value in RustObject with the value received from the callback: (*target).a = a; } } @@ -339,7 +339,7 @@ extern { } fn main() { - // Create the object that will be referenced in the callback + // Create the object that will be referenced in the callback: let mut rust_object = Box::new(RustObject { a: 5 }); unsafe { @@ -363,7 +363,7 @@ int32_t register_callback(void* callback_target, rust_callback callback) { } void trigger_callback() { - cb(cb_target, 7); // Will call callback(&rustObject, 7) in Rust + cb(cb_target, 7); // Will call callback(&rustObject, 7) in Rust. } ``` @@ -606,7 +606,7 @@ use libc::c_int; # #[cfg(hidden)] extern "C" { - /// Register the callback. + /// Registers the callback. fn register(cb: Option c_int>, c_int) -> c_int>); } # unsafe fn register(_: Option c_int>, diff --git a/src/doc/book/functions.md b/src/doc/book/functions.md index b040684d05f7..b453936fe00d 100644 --- a/src/doc/book/functions.md +++ b/src/doc/book/functions.md @@ -135,7 +135,7 @@ In Rust, however, using `let` to introduce a binding is _not_ an expression. The following will produce a compile-time error: ```rust,ignore -let x = (let y = 5); // expected identifier, found keyword `let` +let x = (let y = 5); // Expected identifier, found keyword `let`. ``` The compiler is telling us here that it was expecting to see the beginning of @@ -151,7 +151,7 @@ other returned value would be too surprising: ```rust let mut y = 5; -let x = (y = 6); // x has the value `()`, not `6` +let x = (y = 6); // `x` has the value `()`, not `6`. ``` The second kind of statement in Rust is the *expression statement*. Its @@ -183,7 +183,7 @@ But what about early returns? Rust does have a keyword for that, `return`: fn foo(x: i32) -> i32 { return x; - // we never run this code! + // We never run this code! x + 1 } ``` @@ -307,10 +307,10 @@ fn plus_one(i: i32) -> i32 { i + 1 } -// without type inference +// Without type inference: let f: fn(i32) -> i32 = plus_one; -// with type inference +// With type inference: let f = plus_one; ``` diff --git a/src/doc/book/generics.md b/src/doc/book/generics.md index 9ab601419cd7..eafad6a05fc3 100644 --- a/src/doc/book/generics.md +++ b/src/doc/book/generics.md @@ -78,7 +78,7 @@ We can write functions that take generic types with a similar syntax: ```rust fn takes_anything(x: T) { - // do something with x + // Do something with `x`. } ``` diff --git a/src/doc/book/guessing-game.md b/src/doc/book/guessing-game.md index e2a23979a819..c854b7c373d2 100644 --- a/src/doc/book/guessing-game.md +++ b/src/doc/book/guessing-game.md @@ -158,8 +158,8 @@ take a name on the left hand side of the assignment, it actually accepts a to use for now: ```rust -let foo = 5; // immutable. -let mut bar = 5; // mutable +let foo = 5; // `foo` is immutable. +let mut bar = 5; // `bar` is mutable. ``` [immutable]: mutability.html diff --git a/src/doc/book/inline-assembly.md b/src/doc/book/inline-assembly.md index 62e196a7ccdf..e531d5d7fc0f 100644 --- a/src/doc/book/inline-assembly.md +++ b/src/doc/book/inline-assembly.md @@ -34,7 +34,7 @@ fn foo() { } } -// other platforms +// Other platforms: #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] fn foo() { /* ... */ } @@ -130,7 +130,7 @@ stay valid. # #![feature(asm)] # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] # fn main() { unsafe { -// Put the value 0x200 in eax +// Put the value 0x200 in eax: asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax"); # } } # #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] diff --git a/src/doc/book/lang-items.md b/src/doc/book/lang-items.md index 9fb130845fb1..6a08c1b6bb46 100644 --- a/src/doc/book/lang-items.md +++ b/src/doc/book/lang-items.md @@ -32,7 +32,7 @@ pub struct Box(*mut T); unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { let p = libc::malloc(size as libc::size_t) as *mut u8; - // malloc failed + // Check if `malloc` failed: if p as usize == 0 { abort(); } diff --git a/src/doc/book/lifetimes.md b/src/doc/book/lifetimes.md index df1ee5a293c9..397263c69733 100644 --- a/src/doc/book/lifetimes.md +++ b/src/doc/book/lifetimes.md @@ -54,13 +54,13 @@ dangling pointer or ‘use after free’, when the resource is memory. A small example of such a situation would be: ```rust,compile_fail -let r; // Introduce reference: r +let r; // Introduce reference: `r`. { - let i = 1; // Introduce scoped value: i - r = &i; // Store reference of i in r -} // i goes out of scope and is dropped. + let i = 1; // Introduce scoped value: `i`. + r = &i; // Store reference of `i` in `r`. +} // `i` goes out of scope and is dropped. -println!("{}", r); // r still refers to i +println!("{}", r); // `r` still refers to `i`. ``` To fix this, we have to make sure that step four never happens after step @@ -81,9 +81,9 @@ let lang = "en"; let v; { - let p = format!("lang:{}=", lang); // -+ p goes into scope + let p = format!("lang:{}=", lang); // -+ `p` comes into scope. v = skip_prefix(line, p.as_str()); // | -} // -+ p goes out of scope +} // -+ `p` goes out of scope. println!("{}", v); ``` @@ -191,7 +191,7 @@ struct Foo<'a> { } fn main() { - let y = &5; // this is the same as `let _y = 5; let y = &_y;` + let y = &5; // This is the same as `let _y = 5; let y = &_y;`. let f = Foo { x: y }; println!("{}", f.x); @@ -233,7 +233,7 @@ impl<'a> Foo<'a> { } fn main() { - let y = &5; // this is the same as `let _y = 5; let y = &_y;` + let y = &5; // This is the same as `let _y = 5; let y = &_y;`. let f = Foo { x: y }; println!("x is: {}", f.x()); @@ -274,11 +274,11 @@ valid for. For example: ```rust fn main() { - let y = &5; // -+ y goes into scope + let y = &5; // -+ `y` comes into scope. // | - // stuff // | + // Stuff... // | // | -} // -+ y goes out of scope +} // -+ `y` goes out of scope. ``` Adding in our `Foo`: @@ -289,11 +289,12 @@ struct Foo<'a> { } fn main() { - let y = &5; // -+ y goes into scope - let f = Foo { x: y }; // -+ f goes into scope - // stuff // | + let y = &5; // -+ `y` comes into scope. + let f = Foo { x: y }; // -+ `f` comes into scope. // | -} // -+ f and y go out of scope + // Stuff... // | + // | +} // -+ `f` and `y` go out of scope. ``` Our `f` lives within the scope of `y`, so everything works. What if it didn’t? @@ -305,16 +306,16 @@ struct Foo<'a> { } fn main() { - let x; // -+ x goes into scope + let x; // -+ `x` comes into scope. // | { // | - let y = &5; // ---+ y goes into scope - let f = Foo { x: y }; // ---+ f goes into scope - x = &f.x; // | | error here - } // ---+ f and y go out of scope + let y = &5; // ---+ `y` comes into scope. + let f = Foo { x: y }; // ---+ `f` comes into scope. + x = &f.x; // | | This causes an error. + } // ---+ `f` and y go out of scope. // | println!("{}", x); // | -} // -+ x goes out of scope +} // -+ `x` goes out of scope. ``` Whew! As you can see here, the scopes of `f` and `y` are smaller than the scope diff --git a/src/doc/book/loops.md b/src/doc/book/loops.md index e4cb861d3b0f..688e8c552653 100644 --- a/src/doc/book/loops.md +++ b/src/doc/book/loops.md @@ -202,8 +202,8 @@ of the outer loops, you can use labels to specify which loop the `break` or ```rust 'outer: for x in 0..10 { 'inner: for y in 0..10 { - if x % 2 == 0 { continue 'outer; } // continues the loop over x - if y % 2 == 0 { continue 'inner; } // continues the loop over y + if x % 2 == 0 { continue 'outer; } // Continues the loop over `x`. + if y % 2 == 0 { continue 'inner; } // Continues the loop over `y`. println!("x: {}, y: {}", x, y); } } diff --git a/src/doc/book/macros.md b/src/doc/book/macros.md index 78fe07ec1be1..7f52b33948ee 100644 --- a/src/doc/book/macros.md +++ b/src/doc/book/macros.md @@ -533,33 +533,33 @@ An example: ```rust macro_rules! m1 { () => (()) } -// visible here: m1 +// Visible here: `m1`. mod foo { - // visible here: m1 + // Visible here: `m1`. #[macro_export] macro_rules! m2 { () => (()) } - // visible here: m1, m2 + // Visible here: `m1`, `m2`. } -// visible here: m1 +// Visible here: `m1`. macro_rules! m3 { () => (()) } -// visible here: m1, m3 +// Visible here: `m1`, `m3`. #[macro_use] mod bar { - // visible here: m1, m3 + // Visible here: `m1`, `m3`. macro_rules! m4 { () => (()) } - // visible here: m1, m3, m4 + // Visible here: `m1`, `m3`, `m4`. } -// visible here: m1, m3, m4 +// Visible here: `m1`, `m3`, `m4`. # fn main() { } ``` @@ -644,7 +644,7 @@ macro_rules! bct { (1, $p:tt, $($ps:tt),* ; $($ds:tt),*) => (bct!($($ps),*, 1, $p ; $($ds),*)); - // halt on empty data string + // Halt on empty data string: ( $($ps:tt),* ; ) => (()); } @@ -694,7 +694,7 @@ Like this: assert!(true); assert_eq!(5, 3 + 2); -// nope :( +// Nope :( assert!(5 < 3); assert_eq!(5, 3); diff --git a/src/doc/book/mutability.md b/src/doc/book/mutability.md index a0a49d55e105..18017cc4a5e5 100644 --- a/src/doc/book/mutability.md +++ b/src/doc/book/mutability.md @@ -6,7 +6,7 @@ status: ```rust,ignore let x = 5; -x = 6; // error! +x = 6; // Error! ``` We can introduce mutability with the `mut` keyword: @@ -14,7 +14,7 @@ We can introduce mutability with the `mut` keyword: ```rust let mut x = 5; -x = 6; // no problem! +x = 6; // No problem! ``` This is a mutable [variable binding][vb]. When a binding is mutable, it means @@ -136,7 +136,7 @@ some fields mutable and some immutable: ```rust,ignore struct Point { x: i32, - mut y: i32, // nope + mut y: i32, // Nope. } ``` @@ -154,7 +154,7 @@ a.x = 10; let b = Point { x: 5, y: 6}; -b.x = 10; // error: cannot assign to immutable field `b.x` +b.x = 10; // Error: cannot assign to immutable field `b.x`. ``` [struct]: structs.html diff --git a/src/doc/book/no-stdlib.md b/src/doc/book/no-stdlib.md index 2604ca8d4cab..a06de35c0ce6 100644 --- a/src/doc/book/no-stdlib.md +++ b/src/doc/book/no-stdlib.md @@ -41,10 +41,10 @@ in the same format as C: #![feature(start)] #![no_std] -// Pull in the system libc library for what crt0.o likely requires +// Pull in the system libc library for what crt0.o likely requires. extern crate libc; -// Entry point for this program +// Entry point for this program. #[start] fn start(_argc: isize, _argv: *const *const u8) -> isize { 0 @@ -84,10 +84,10 @@ compiler's name mangling too: #![no_std] #![no_main] -// Pull in the system libc library for what crt0.o likely requires +// Pull in the system libc library for what crt0.o likely requires. extern crate libc; -// Entry point for this program +// Entry point for this program. #[no_mangle] // ensure that this symbol is called `main` in the output pub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 { 0 diff --git a/src/doc/book/operators-and-overloading.md b/src/doc/book/operators-and-overloading.md index 424e2cda6157..78ff871046ef 100644 --- a/src/doc/book/operators-and-overloading.md +++ b/src/doc/book/operators-and-overloading.md @@ -69,7 +69,7 @@ impl Add for Point { type Output = f64; fn add(self, rhs: i32) -> f64 { - // add an i32 to a Point and get an f64 + // Add an i32 to a Point and get an f64. # 1.0 } } diff --git a/src/doc/book/ownership.md b/src/doc/book/ownership.md index a711397b211d..11eda399adc9 100644 --- a/src/doc/book/ownership.md +++ b/src/doc/book/ownership.md @@ -107,7 +107,7 @@ try to use something after we’ve passed it as an argument: ```rust,ignore fn take(v: Vec) { - // what happens here isn’t important. + // What happens here isn’t important. } let v = vec![1, 2, 3]; @@ -264,9 +264,9 @@ Of course, if we had to hand ownership back with every function we wrote: ```rust fn foo(v: Vec) -> Vec { - // do stuff with v + // Do stuff with `v`. - // hand back ownership + // Hand back ownership. v } ``` @@ -275,9 +275,9 @@ This would get very tedious. It gets worse the more things we want to take owner ```rust fn foo(v1: Vec, v2: Vec) -> (Vec, Vec, i32) { - // do stuff with v1 and v2 + // Do stuff with `v1` and `v2`. - // hand back ownership, and the result of our function + // Hand back ownership, and the result of our function. (v1, v2, 42) } diff --git a/src/doc/book/patterns.md b/src/doc/book/patterns.md index 910b13754767..b50fa01b8e2b 100644 --- a/src/doc/book/patterns.md +++ b/src/doc/book/patterns.md @@ -163,7 +163,7 @@ ignore parts of a larger structure: ```rust fn coordinate() -> (i32, i32, i32) { - // generate and return some sort of triple tuple + // Generate and return some sort of triple tuple. # (1, 2, 3) } @@ -182,7 +182,7 @@ let tuple: (u32, String) = (5, String::from("five")); // Here, tuple is moved, because the String moved: let (x, _s) = tuple; -// The next line would give "error: use of partially moved value: `tuple`" +// The next line would give "error: use of partially moved value: `tuple`". // println!("Tuple is: {:?}", tuple); // However, diff --git a/src/doc/book/primitive-types.md b/src/doc/book/primitive-types.md index ea0bdf29fcc4..c4169d64ccc6 100644 --- a/src/doc/book/primitive-types.md +++ b/src/doc/book/primitive-types.md @@ -54,9 +54,9 @@ bigger numbers. If a number literal has nothing to cause its type to be inferred, it defaults: ```rust -let x = 42; // x has type i32 +let x = 42; // `x` has type `i32`. -let y = 1.0; // y has type f64 +let y = 1.0; // `y` has type `f64`. ``` Here’s a list of the different numeric types, with links to their documentation @@ -177,8 +177,8 @@ length of the slice: ```rust let a = [0, 1, 2, 3, 4]; -let complete = &a[..]; // A slice containing all of the elements in a -let middle = &a[1..4]; // A slice of a: only the elements 1, 2, and 3 +let complete = &a[..]; // A slice containing all of the elements in `a`. +let middle = &a[1..4]; // A slice of `a`: only the elements `1`, `2`, and `3`. ``` Slices have type `&[T]`. We’ll talk about that `T` when we cover @@ -264,8 +264,8 @@ You can disambiguate a single-element tuple from a value in parentheses with a comma: ```rust -(0,); // single-element tuple -(0); // zero in parentheses +(0,); // A single-element tuple. +(0); // A zero in parentheses. ``` ## Tuple Indexing diff --git a/src/doc/book/raw-pointers.md b/src/doc/book/raw-pointers.md index ae100aec3b51..2386475d15ea 100644 --- a/src/doc/book/raw-pointers.md +++ b/src/doc/book/raw-pointers.md @@ -101,11 +101,11 @@ programmer *must* guarantee this. The recommended method for the conversion is: ```rust -// explicit cast +// Explicit cast: let i: u32 = 1; let p_imm: *const u32 = &i as *const u32; -// implicit coercion +// Implicit coercion: let mut m: u32 = 2; let p_mut: *mut u32 = &mut m; diff --git a/src/doc/book/references-and-borrowing.md b/src/doc/book/references-and-borrowing.md index 1e2f061b0674..6c9c4fa7dd4b 100644 --- a/src/doc/book/references-and-borrowing.md +++ b/src/doc/book/references-and-borrowing.md @@ -46,9 +46,9 @@ like this: ```rust fn foo(v1: Vec, v2: Vec) -> (Vec, Vec, i32) { - // do stuff with v1 and v2 + // Do stuff with `v1` and `v2`. - // hand back ownership, and the result of our function + // Hand back ownership, and the result of our function. (v1, v2, 42) } @@ -63,9 +63,9 @@ the first step: ```rust fn foo(v1: &Vec, v2: &Vec) -> i32 { - // do stuff with v1 and v2 + // Do stuff with `v1` and `v2`. - // return the answer + // Return the answer. 42 } @@ -74,7 +74,7 @@ let v2 = vec![1, 2, 3]; let answer = foo(&v1, &v2); -// we can use v1 and v2 here! +// We can use `v1` and `v2` here! ``` A more concrete example: @@ -88,10 +88,10 @@ fn main() { // Borrow two vectors and sum them. // This kind of borrowing does not allow mutation through the borrowed reference. fn foo(v1: &Vec, v2: &Vec) -> i32 { - // do stuff with v1 and v2 + // Do stuff with `v1` and `v2`. let s1 = sum_vec(v1); let s2 = sum_vec(v2); - // return the answer + // Return the answer. s1 + s2 } @@ -248,12 +248,12 @@ scopes look like this: fn main() { let mut x = 5; - let y = &mut x; // -+ &mut borrow of x starts here + let y = &mut x; // -+ &mut borrow of `x` starts here. // | *y += 1; // | // | - println!("{}", x); // -+ - try to borrow x here -} // -+ &mut borrow of x ends here + println!("{}", x); // -+ - Try to borrow `x` here. +} // -+ &mut borrow of `x` ends here. ``` @@ -265,11 +265,11 @@ So when we add the curly braces: let mut x = 5; { - let y = &mut x; // -+ &mut borrow starts here + let y = &mut x; // -+ &mut borrow starts here. *y += 1; // | -} // -+ ... and ends here +} // -+ ... and ends here. -println!("{}", x); // <- try to borrow x here +println!("{}", x); // <- Try to borrow `x` here. ``` There’s no problem. Our mutable borrow goes out of scope before we create an diff --git a/src/doc/book/strings.md b/src/doc/book/strings.md index 135778c38b50..6af15d876836 100644 --- a/src/doc/book/strings.md +++ b/src/doc/book/strings.md @@ -83,10 +83,10 @@ converted using `&*`. ```rust,no_run use std::net::TcpStream; -TcpStream::connect("192.168.0.1:3000"); // &str parameter +TcpStream::connect("192.168.0.1:3000"); // Parameter is of type &str. let addr_string = "192.168.0.1:3000".to_string(); -TcpStream::connect(&*addr_string); // convert addr_string to &str +TcpStream::connect(&*addr_string); // Convert `addr_string` to &str. ``` Viewing a `String` as a `&str` is cheap, but converting the `&str` to a @@ -138,7 +138,7 @@ You can get something similar to an index like this: ```rust # let hachiko = "忠犬ハチ公"; -let dog = hachiko.chars().nth(1); // kinda like hachiko[1] +let dog = hachiko.chars().nth(1); // Kinda like `hachiko[1]`. ``` This emphasizes that we have to walk from the beginning of the list of `chars`. diff --git a/src/doc/book/structs.md b/src/doc/book/structs.md index d6960b10b080..cfd00cf997e0 100644 --- a/src/doc/book/structs.md +++ b/src/doc/book/structs.md @@ -82,9 +82,9 @@ fn main() { point.x = 5; - let point = point; // now immutable + let point = point; // `point` is now immutable. - point.y = 6; // this causes an error + point.y = 6; // This causes an error. } ``` @@ -234,10 +234,10 @@ rather than positions. You can define a `struct` with no members at all: ```rust -struct Electron {} // use empty braces... -struct Proton; // ...or just a semicolon +struct Electron {} // Use empty braces... +struct Proton; // ...or just a semicolon. -// whether you declared the struct with braces or not, do the same when creating one +// Whether you declared the struct with braces or not, do the same when creating one. let x = Electron {}; let y = Proton; ``` diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index ed916fd798bb..0f48f5798644 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -299,7 +299,7 @@ fn it_works() { #[test] #[ignore] fn expensive_test() { - // code that takes an hour to run + // Code that takes an hour to run... } ``` diff --git a/src/doc/book/trait-objects.md b/src/doc/book/trait-objects.md index b1aee579aabc..a0396a75fa26 100644 --- a/src/doc/book/trait-objects.md +++ b/src/doc/book/trait-objects.md @@ -221,8 +221,8 @@ struct FooVtable { // u8: fn call_method_on_u8(x: *const ()) -> String { - // the compiler guarantees that this function is only called - // with `x` pointing to a u8 + // The compiler guarantees that this function is only called + // with `x` pointing to a u8. let byte: &u8 = unsafe { &*(x as *const u8) }; byte.method() @@ -233,7 +233,7 @@ static Foo_for_u8_vtable: FooVtable = FooVtable { size: 1, align: 1, - // cast to a function pointer + // Cast to a function pointer: method: call_method_on_u8 as fn(*const ()) -> String, }; @@ -241,8 +241,8 @@ static Foo_for_u8_vtable: FooVtable = FooVtable { // String: fn call_method_on_String(x: *const ()) -> String { - // the compiler guarantees that this function is only called - // with `x` pointing to a String + // The compiler guarantees that this function is only called + // with `x` pointing to a String. let string: &String = unsafe { &*(x as *const String) }; string.method() @@ -250,7 +250,7 @@ fn call_method_on_String(x: *const ()) -> String { static Foo_for_String_vtable: FooVtable = FooVtable { destructor: /* compiler magic */, - // values for a 64-bit computer, halve them for 32-bit ones + // Values for a 64-bit computer, halve them for 32-bit ones. size: 24, align: 8, @@ -278,17 +278,17 @@ let x: u8 = 1; // let b: &Foo = &a; let b = TraitObject { - // store the data + // Store the data: data: &a, - // store the methods + // Store the methods: vtable: &Foo_for_String_vtable }; // let y: &Foo = x; let y = TraitObject { - // store the data + // Store the data: data: &x, - // store the methods + // Store the methods: vtable: &Foo_for_u8_vtable }; diff --git a/src/doc/book/traits.md b/src/doc/book/traits.md index d1166e686c7b..4747869b65c7 100644 --- a/src/doc/book/traits.md +++ b/src/doc/book/traits.md @@ -270,9 +270,9 @@ won’t have its methods: ```rust,ignore let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt"); -let buf = b"whatever"; // byte string literal. buf: &[u8; 8] +let buf = b"whatever"; // buf: &[u8; 8], a byte string literal. let result = f.write(buf); -# result.unwrap(); // ignore the error +# result.unwrap(); // Ignore the error. ``` Here’s the error: @@ -291,7 +291,7 @@ use std::io::Write; let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt"); let buf = b"whatever"; let result = f.write(buf); -# result.unwrap(); // ignore the error +# result.unwrap(); // Ignore the error. ``` This will compile without error. @@ -413,14 +413,14 @@ impl ConvertTo for i32 { fn convert(&self) -> i64 { *self as i64 } } -// can be called with T == i32 +// Can be called with T == i32. fn normal>(x: &T) -> i64 { x.convert() } -// can be called with T == i64 +// Can be called with T == i64. fn inverse(x: i32) -> T - // this is using ConvertTo as if it were "ConvertTo" + // This is using ConvertTo as if it were "ConvertTo". where i32: ConvertTo { x.convert() } @@ -470,15 +470,15 @@ impl Foo for OverrideDefault { fn is_invalid(&self) -> bool { println!("Called OverrideDefault.is_invalid!"); - true // overrides the expected value of is_invalid() + true // Overrides the expected value of `is_invalid()`. } } let default = UseDefault; -assert!(!default.is_invalid()); // prints "Called UseDefault.is_valid." +assert!(!default.is_invalid()); // Prints "Called UseDefault.is_valid." let over = OverrideDefault; -assert!(over.is_invalid()); // prints "Called OverrideDefault.is_invalid!" +assert!(over.is_invalid()); // Prints "Called OverrideDefault.is_invalid!" ``` # Inheritance diff --git a/src/doc/book/unsafe.md b/src/doc/book/unsafe.md index 9cab586b82c4..a272afa70bb1 100644 --- a/src/doc/book/unsafe.md +++ b/src/doc/book/unsafe.md @@ -12,7 +12,7 @@ four contexts. The first one is to mark a function as unsafe: ```rust unsafe fn danger_will_robinson() { - // scary stuff + // Scary stuff... } ``` @@ -23,7 +23,7 @@ The second use of `unsafe` is an unsafe block: ```rust unsafe { - // scary stuff + // Scary stuff... } ``` diff --git a/src/doc/book/variable-bindings.md b/src/doc/book/variable-bindings.md index 03f17371de68..54316649c715 100644 --- a/src/doc/book/variable-bindings.md +++ b/src/doc/book/variable-bindings.md @@ -194,7 +194,7 @@ fn main() { let y: i32 = 3; println!("The value of x is {} and value of y is {}", x, y); } - println!("The value of x is {} and value of y is {}", x, y); // This won't work + println!("The value of x is {} and value of y is {}", x, y); // This won't work. } ``` @@ -207,7 +207,7 @@ Instead we get this error: $ cargo build Compiling hello v0.1.0 (file:///home/you/projects/hello_world) main.rs:7:62: 7:63 error: unresolved name `y`. Did you mean `x`? [E0425] -main.rs:7 println!("The value of x is {} and value of y is {}", x, y); // This won't work +main.rs:7 println!("The value of x is {} and value of y is {}", x, y); // This won't work. ^ note: in expansion of format_args! :2:25: 2:56 note: expansion site @@ -229,13 +229,13 @@ scope will override the previous binding. ```rust let x: i32 = 8; { - println!("{}", x); // Prints "8" + println!("{}", x); // Prints "8". let x = 12; - println!("{}", x); // Prints "12" + println!("{}", x); // Prints "12". } -println!("{}", x); // Prints "8" +println!("{}", x); // Prints "8". let x = 42; -println!("{}", x); // Prints "42" +println!("{}", x); // Prints "42". ``` Shadowing and mutable bindings may appear as two sides of the same coin, but @@ -249,8 +249,8 @@ by any means. ```rust let mut x: i32 = 1; x = 7; -let x = x; // x is now immutable and is bound to 7 +let x = x; // `x` is now immutable and is bound to `7`. let y = 4; -let y = "I can also be bound to text!"; // y is now of a different type +let y = "I can also be bound to text!"; // `y` is now of a different type. ``` diff --git a/src/doc/book/vectors.md b/src/doc/book/vectors.md index cb6781cdf28f..b948a54f44a5 100644 --- a/src/doc/book/vectors.md +++ b/src/doc/book/vectors.md @@ -17,7 +17,7 @@ situation, this is just convention.) There’s an alternate form of `vec!` for repeating an initial value: ```rust -let v = vec![0; 10]; // ten zeroes +let v = vec![0; 10]; // A vector of ten zeroes. ``` Vectors store their contents as contiguous arrays of `T` on the heap. This means @@ -46,10 +46,10 @@ let v = vec![1, 2, 3, 4, 5]; let i: usize = 0; let j: i32 = 0; -// works +// Works: v[i]; -// doesn’t +// Doesn’t: v[j]; ``` From d3574b8dc756c5bd5dd2d7b8053c0de15b902691 Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Sun, 13 Nov 2016 12:38:10 -0600 Subject: [PATCH 098/177] Make LLVM debuginfo option names consistent --- configure | 6 +++--- mk/llvm.mk | 2 +- src/bootstrap/config.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/configure b/configure index c6f818299ff0..d37ffce52af3 100755 --- a/configure +++ b/configure @@ -642,7 +642,7 @@ opt_nosave optimize-cxx 1 "build optimized C++ code" opt_nosave optimize-llvm 1 "build optimized LLVM" opt_nosave llvm-assertions 0 "build LLVM with assertions" opt_nosave debug-assertions 0 "build with debugging assertions" -opt_nosave llvm-debuginfo 0 "build LLVM with debugger metadata" +opt_nosave llvm-release-debuginfo 0 "build LLVM with debugger metadata" opt_nosave debuginfo 0 "build with debugger metadata" opt_nosave debuginfo-lines 0 "build with line number debugger metadata" opt_nosave debug-jemalloc 0 "build jemalloc with --enable-debug --enable-fill" @@ -779,7 +779,7 @@ if [ -n "$CFG_DISABLE_OPTIMIZE_CXX" ]; then putvar CFG_DISABLE_OPTIMIZE_CXX; fi if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then putvar CFG_DISABLE_OPTIMIZE_LLVM; fi if [ -n "$CFG_ENABLE_LLVM_ASSERTIONS" ]; then putvar CFG_ENABLE_LLVM_ASSERTIONS; fi if [ -n "$CFG_ENABLE_DEBUG_ASSERTIONS" ]; then putvar CFG_ENABLE_DEBUG_ASSERTIONS; fi -if [ -n "$CFG_ENABLE_LLVM_DEBUGINFO" ]; then putvar CFG_ENABLE_LLVM_DEBUGINFO; fi +if [ -n "$CFG_ENABLE_LLVM_RELEASE_DEBUGINFO" ]; then putvar CFG_ENABLE_LLVM_RELEASE_DEBUGINFO; fi if [ -n "$CFG_ENABLE_DEBUGINFO" ]; then putvar CFG_ENABLE_DEBUGINFO; fi if [ -n "$CFG_ENABLE_DEBUGINFO_LINES" ]; then putvar CFG_ENABLE_DEBUGINFO_LINES; fi if [ -n "$CFG_ENABLE_DEBUG_JEMALLOC" ]; then putvar CFG_ENABLE_DEBUG_JEMALLOC; fi @@ -1774,7 +1774,7 @@ do if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Debug" - elif [ -n "$CFG_ENABLE_LLVM_DEBUGINFO" ]; then + elif [ -n "$CFG_ENABLE_LLVM_RELEASE_DEBUGINFO" ]; then CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=RelWithDebInfo" else CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release" diff --git a/mk/llvm.mk b/mk/llvm.mk index 842f1bcee119..76367e6f3a62 100644 --- a/mk/llvm.mk +++ b/mk/llvm.mk @@ -21,7 +21,7 @@ endif ifdef CFG_DISABLE_OPTIMIZE_LLVM LLVM_BUILD_CONFIG_MODE := Debug -else ifdef CFG_ENABLE_LLVM_DEBUGINFO +else ifdef CFG_ENABLE_LLVM_RELEASE_DEBUGINFO LLVM_BUILD_CONFIG_MODE := RelWithDebInfo else LLVM_BUILD_CONFIG_MODE := Release diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index bea475fb07b2..945d482c2aac 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -339,7 +339,7 @@ impl Config { ("COMPILER_DOCS", self.compiler_docs), ("DOCS", self.docs), ("LLVM_ASSERTIONS", self.llvm_assertions), - ("LLVM_DEBUGINFO", self.llvm_release_debuginfo), + ("LLVM_RELEASE_DEBUGINFO", self.llvm_release_debuginfo), ("OPTIMIZE_LLVM", self.llvm_optimize), ("LLVM_VERSION_CHECK", self.llvm_version_check), ("LLVM_STATIC_STDCPP", self.llvm_static_stdcpp), From e4a9d834afacc55ff1c746f8a605908ab51b92bb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 14 Nov 2016 00:39:14 +0100 Subject: [PATCH 099/177] Uncomment some long error explanation --- src/librustc_const_eval/diagnostics.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs index db72057636a8..83b0d9dec6d9 100644 --- a/src/librustc_const_eval/diagnostics.rs +++ b/src/librustc_const_eval/diagnostics.rs @@ -40,7 +40,9 @@ Ensure the ordering of the match arm is correct and remove any superfluous arms. "##, -/*E0002: r##" +E0002: r##" +## Note: this error code is no longer emitted by the compiler. + This error indicates that an empty match expression is invalid because the type it is matching on is non-empty (there exist values of this type). In safe code it is impossible to create an instance of an empty type, so empty match @@ -68,10 +70,11 @@ fn foo(x: Option) { } } ``` -"##,*/ +"##, +E0003: r##" +## Note: this error code is no longer emitted by the compiler. -/*E0003: r##" Not-a-Number (NaN) values cannot be compared for equality and hence can never match the input to a match expression. So, the following will not compile: @@ -98,7 +101,6 @@ match number { } ``` "##, -*/ E0004: r##" This error indicates that the compiler cannot guarantee a matching pattern for From 30f75e396a82d9c84372d14708822d68f7cd36b3 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Sun, 13 Nov 2016 15:56:23 -0500 Subject: [PATCH 100/177] do not use deprecated text for unstable docs --- src/librustdoc/clean/mod.rs | 16 +++++++++------- src/librustdoc/html/render.rs | 13 +++++++++---- src/libsyntax/attr.rs | 3 --- src/test/rustdoc/issue-32374.rs | 10 ++++++++++ 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f4df28a14763..4d70c64634fb 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2890,7 +2890,8 @@ pub struct Stability { pub feature: String, pub since: String, pub deprecated_since: String, - pub reason: String, + pub deprecated_reason: String, + pub unstable_reason: String, pub issue: Option } @@ -2913,12 +2914,13 @@ impl Clean for attr::Stability { Some(attr::RustcDeprecation {ref since, ..}) => since.to_string(), _=> "".to_string(), }, - reason: { - match (&self.rustc_depr, &self.level) { - (&Some(ref depr), _) => depr.reason.to_string(), - (&None, &attr::Unstable {reason: Some(ref reason), ..}) => reason.to_string(), - _ => "".to_string(), - } + deprecated_reason: match self.rustc_depr { + Some(ref depr) => depr.reason.to_string(), + _ => "".to_string(), + }, + unstable_reason: match self.level { + attr::Unstable { reason: Some(ref reason), .. } => reason.to_string(), + _ => "".to_string(), }, issue: match self.level { attr::Unstable {issue, ..} => Some(issue), diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 5aed37edbd42..90f954aa86ab 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1878,8 +1878,8 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec Vec{}", text)) }; @@ -1909,7 +1909,12 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec{}", text)) }; } else if let Some(depr) = item.deprecation.as_ref() { diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 57a936bf9b0c..2977e340a3c0 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -789,9 +789,6 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, // Merge the deprecation info into the stability info if let Some(rustc_depr) = rustc_depr { if let Some(ref mut stab) = stab { - if let Unstable {reason: ref mut reason @ None, ..} = stab.level { - *reason = Some(rustc_depr.reason.clone()) - } stab.rustc_depr = Some(rustc_depr); } else { span_err!(diagnostic, item_sp, E0549, diff --git a/src/test/rustdoc/issue-32374.rs b/src/test/rustdoc/issue-32374.rs index 262a1ffce747..dea73317e5e3 100644 --- a/src/test/rustdoc/issue-32374.rs +++ b/src/test/rustdoc/issue-32374.rs @@ -20,6 +20,16 @@ // 'Deprecated since 1.0.0: text' // @has - 'test' // @has - '#32374' +// @matches issue_32374/struct.T.html '//*[@class="stab unstable"]' \ +// 'Unstable \(test #32374\)$' #[rustc_deprecated(since = "1.0.0", reason = "text")] #[unstable(feature = "test", issue = "32374")] pub struct T; + +// @has issue_32374/struct.U.html '//*[@class="stab deprecated"]' \ +// 'Deprecated since 1.0.0: deprecated' +// @has issue_32374/struct.U.html '//*[@class="stab unstable"]' \ +// 'Unstable (test #32374): unstable' +#[rustc_deprecated(since = "1.0.0", reason = "deprecated")] +#[unstable(feature = "test", issue = "32374", reason = "unstable")] +pub struct U; From 5b093ebab2595a50ccb47ff4ec854917aa1838fe Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 4 Nov 2016 17:37:42 -0400 Subject: [PATCH 101/177] Make names of types used in LLVM IR stable. Before this PR, type names could depend on the cratenum being used for a given crate and also on the source location of closures. Both are undesirable for incremental compilation where we cache LLVM IR and don't want it to depend on formatting or in which order crates are loaded. --- src/librustc_data_structures/base_n.rs | 64 ++++ src/librustc_data_structures/lib.rs | 1 + src/librustc_incremental/persist/fs.rs | 55 +--- src/librustc_trans/base.rs | 12 +- src/librustc_trans/collector.rs | 20 +- src/librustc_trans/context.rs | 7 +- src/librustc_trans/trans_item.rs | 389 +++++++++++++------------ src/librustc_trans/type_of.rs | 30 +- 8 files changed, 324 insertions(+), 254 deletions(-) create mode 100644 src/librustc_data_structures/base_n.rs diff --git a/src/librustc_data_structures/base_n.rs b/src/librustc_data_structures/base_n.rs new file mode 100644 index 000000000000..bf3e682f86f6 --- /dev/null +++ b/src/librustc_data_structures/base_n.rs @@ -0,0 +1,64 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// Convert unsigned integers into a string representation with some base. +/// Bases up to and including 36 can be used for case-insensitive things. + +use std::str; + +pub const MAX_BASE: u64 = 64; +const BASE_64: &'static [u8; MAX_BASE as usize] = + b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@$"; + +#[inline] +pub fn push_str(mut n: u64, base: u64, output: &mut String) { + debug_assert!(base >= 2 && base <= MAX_BASE); + let mut s = [0u8; 64]; + let mut index = 0; + + loop { + s[index] = BASE_64[(n % base) as usize]; + index += 1; + n /= base; + + if n == 0 { + break; + } + } + &mut s[0..index].reverse(); + output.push_str(str::from_utf8(&s[0..index]).unwrap()); +} + +#[inline] +pub fn encode(n: u64, base: u64) -> String { + let mut s = String::with_capacity(13); + push_str(n, base, &mut s); + s +} + +#[test] +fn test_encode() { + fn test(n: u64, base: u64) { + assert_eq!(Ok(n), u64::from_str_radix(&encode(n, base)[..], base as u32)); + } + + for base in 2..37 { + test(0, base); + test(1, base); + test(35, base); + test(36, base); + test(37, base); + test(u64::max_value(), base); + + for i in 0 .. 1_000 { + test(i * 983, base); + } + } +} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 2e4206d2ee1e..de13b9bf4be1 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -47,6 +47,7 @@ extern crate libc; pub mod array_vec; pub mod accumulate_vec; pub mod small_vec; +pub mod base_n; pub mod bitslice; pub mod blake2b; pub mod bitvec; diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index ca9c11920232..223200957cb7 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -119,7 +119,7 @@ use rustc::hir::svh::Svh; use rustc::session::Session; use rustc::ty::TyCtxt; use rustc::util::fs as fs_util; -use rustc_data_structures::flock; +use rustc_data_structures::{flock, base_n}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use std::ffi::OsString; @@ -135,6 +135,12 @@ const DEP_GRAPH_FILENAME: &'static str = "dep-graph.bin"; const WORK_PRODUCTS_FILENAME: &'static str = "work-products.bin"; const METADATA_HASHES_FILENAME: &'static str = "metadata.bin"; +// We encode integers using the following base, so they are shorter than decimal +// or hexadecimal numbers (we want short file and directory names). Since these +// numbers will be used in file names, we choose an encoding that is not +// case-sensitive (as opposed to base64, for example). +const INT_ENCODE_BASE: u64 = 36; + pub fn dep_graph_path(sess: &Session) -> PathBuf { in_incr_comp_dir_sess(sess, DEP_GRAPH_FILENAME) } @@ -327,7 +333,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Svh) { let mut new_sub_dir_name = String::from(&old_sub_dir_name[.. dash_indices[2] + 1]); // Append the svh - new_sub_dir_name.push_str(&encode_base_36(svh.as_u64())); + base_n::push_str(svh.as_u64(), INT_ENCODE_BASE, &mut new_sub_dir_name); // Create the full path let new_path = incr_comp_session_dir.parent().unwrap().join(new_sub_dir_name); @@ -433,7 +439,8 @@ fn generate_session_dir_path(crate_dir: &Path) -> PathBuf { let directory_name = format!("s-{}-{}-working", timestamp, - encode_base_36(random_number as u64)); + base_n::encode(random_number as u64, + INT_ENCODE_BASE)); debug!("generate_session_dir_path: directory_name = {}", directory_name); let directory_path = crate_dir.join(directory_name); debug!("generate_session_dir_path: directory_path = {}", directory_path.display()); @@ -562,27 +569,11 @@ fn extract_timestamp_from_session_dir(directory_name: &str) string_to_timestamp(&directory_name[dash_indices[0]+1 .. dash_indices[1]]) } -const BASE_36: &'static [u8] = b"0123456789abcdefghijklmnopqrstuvwxyz"; - -fn encode_base_36(mut n: u64) -> String { - let mut s = Vec::with_capacity(13); - loop { - s.push(BASE_36[(n % 36) as usize]); - n /= 36; - - if n == 0 { - break; - } - } - s.reverse(); - String::from_utf8(s).unwrap() -} - fn timestamp_to_string(timestamp: SystemTime) -> String { let duration = timestamp.duration_since(UNIX_EPOCH).unwrap(); let micros = duration.as_secs() * 1_000_000 + (duration.subsec_nanos() as u64) / 1000; - encode_base_36(micros) + base_n::encode(micros, INT_ENCODE_BASE) } fn string_to_timestamp(s: &str) -> Result { @@ -629,7 +620,7 @@ pub fn find_metadata_hashes_for(tcx: TyCtxt, cnum: CrateNum) -> Option }; let target_svh = tcx.sess.cstore.crate_hash(cnum); - let target_svh = encode_base_36(target_svh.as_u64()); + let target_svh = base_n::encode(target_svh.as_u64(), INT_ENCODE_BASE); let sub_dir = find_metadata_hashes_iter(&target_svh, dir_entries.filter_map(|e| { e.ok().map(|e| e.file_name().to_string_lossy().into_owned()) @@ -677,7 +668,9 @@ fn crate_path(sess: &Session, let mut hasher = DefaultHasher::new(); crate_disambiguator.hash(&mut hasher); - let crate_name = format!("{}-{}", crate_name, encode_base_36(hasher.finish())); + let crate_name = format!("{}-{}", + crate_name, + base_n::encode(hasher.finish(), INT_ENCODE_BASE)); incr_dir.join(crate_name) } @@ -1049,21 +1042,3 @@ fn test_find_metadata_hashes_iter() None ); } - -#[test] -fn test_encode_base_36() { - fn test(n: u64) { - assert_eq!(Ok(n), u64::from_str_radix(&encode_base_36(n)[..], 36)); - } - - test(0); - test(1); - test(35); - test(36); - test(37); - test(u64::max_value()); - - for i in 0 .. 1_000 { - test(i * 983); - } -} diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index c7cad6455bc3..0c0b7fbf4afe 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -74,7 +74,7 @@ use monomorphize::{self, Instance}; use partitioning::{self, PartitioningStrategy, CodegenUnit}; use symbol_map::SymbolMap; use symbol_names_test; -use trans_item::TransItem; +use trans_item::{TransItem, DefPathBasedNames}; use type_::Type; use type_of; use value::Value; @@ -1004,7 +1004,15 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { } pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) { - let _s = StatRecorder::new(ccx, ccx.tcx().item_path_str(instance.def)); + let _s = if ccx.sess().trans_stats() { + let mut instance_name = String::new(); + DefPathBasedNames::new(ccx.tcx(), true, true) + .push_def_path(instance.def, &mut instance_name); + Some(StatRecorder::new(ccx, instance_name)) + } else { + None + }; + // this is an info! to allow collecting monomorphization statistics // and to allow finding the last function before LLVM aborts from // release builds. diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 2728a666556e..0fc6436e63cd 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -213,7 +213,7 @@ use glue::{self, DropGlueKind}; use monomorphize::{self, Instance}; use util::nodemap::{FxHashSet, FxHashMap, DefIdMap}; -use trans_item::{TransItem, type_to_string, def_id_to_string}; +use trans_item::{TransItem, DefPathBasedNames}; #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] pub enum TransItemCollectionMode { @@ -1234,3 +1234,21 @@ fn visit_mir_and_promoted<'tcx, V: MirVisitor<'tcx>>(mut visitor: V, mir: &mir:: visitor.visit_mir(promoted); } } + +fn def_id_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> String { + let mut output = String::new(); + let printer = DefPathBasedNames::new(tcx, false, false); + printer.push_def_path(def_id, &mut output); + output +} + +fn type_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + ty: ty::Ty<'tcx>) + -> String { + let mut output = String::new(); + let printer = DefPathBasedNames::new(tcx, false, false); + printer.push_type_name(ty, &mut output); + output +} diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 3930bcbdd9ae..f7af2d6b855d 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -26,6 +26,7 @@ use monomorphize::Instance; use partitioning::CodegenUnit; use trans_item::TransItem; use type_::Type; +use rustc_data_structures::base_n; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; use session::config::NoDebugInfo; @@ -975,7 +976,11 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.local().local_gen_sym_counter.set(idx + 1); // Include a '.' character, so there can be no accidental conflicts with // user defined names - format!("{}.{}", prefix, idx) + let mut name = String::with_capacity(prefix.len() + 6); + name.push_str(prefix); + name.push_str("."); + base_n::push_str(idx as u64, base_n::MAX_BASE, &mut name); + name } } diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index c5a7dbbcf548..94a68de7f867 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -34,6 +34,7 @@ use type_of; use glue; use abi::{Abi, FnType}; use back::symbol_names; +use std::fmt::Write; #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] pub enum TransItem<'tcx> { @@ -307,7 +308,8 @@ impl<'a, 'tcx> TransItem<'tcx> { DropGlueKind::Ty(_) => s.push_str("drop-glue "), DropGlueKind::TyContents(_) => s.push_str("drop-glue-contents "), }; - push_unique_type_name(tcx, dg.ty(), &mut s); + let printer = DefPathBasedNames::new(tcx, false, false); + printer.push_type_name(dg.ty(), &mut s); s } TransItem::Fn(instance) => { @@ -326,7 +328,8 @@ impl<'a, 'tcx> TransItem<'tcx> { -> String { let mut result = String::with_capacity(32); result.push_str(prefix); - push_instance_as_string(tcx, instance, &mut result); + let printer = DefPathBasedNames::new(tcx, false, false); + printer.push_instance_as_string(instance, &mut result); result } } @@ -367,209 +370,219 @@ impl<'a, 'tcx> TransItem<'tcx> { /// Same as `unique_type_name()` but with the result pushed onto the given /// `output` parameter. -pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - t: Ty<'tcx>, - output: &mut String) { - match t.sty { - ty::TyBool => output.push_str("bool"), - ty::TyChar => output.push_str("char"), - ty::TyStr => output.push_str("str"), - ty::TyNever => output.push_str("!"), - ty::TyInt(ast::IntTy::Is) => output.push_str("isize"), - ty::TyInt(ast::IntTy::I8) => output.push_str("i8"), - ty::TyInt(ast::IntTy::I16) => output.push_str("i16"), - ty::TyInt(ast::IntTy::I32) => output.push_str("i32"), - ty::TyInt(ast::IntTy::I64) => output.push_str("i64"), - ty::TyUint(ast::UintTy::Us) => output.push_str("usize"), - ty::TyUint(ast::UintTy::U8) => output.push_str("u8"), - ty::TyUint(ast::UintTy::U16) => output.push_str("u16"), - ty::TyUint(ast::UintTy::U32) => output.push_str("u32"), - ty::TyUint(ast::UintTy::U64) => output.push_str("u64"), - ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"), - ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"), - ty::TyAdt(adt_def, substs) => { - push_item_name(tcx, adt_def.did, output); - push_type_params(tcx, substs, &[], output); - }, - ty::TyTuple(component_types) => { - output.push('('); - for &component_type in component_types { - push_unique_type_name(tcx, component_type, output); - output.push_str(", "); - } - if !component_types.is_empty() { - output.pop(); - output.pop(); - } - output.push(')'); - }, - ty::TyBox(inner_type) => { - output.push_str("Box<"); - push_unique_type_name(tcx, inner_type, output); - output.push('>'); - }, - ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => { - output.push('*'); - match mutbl { - hir::MutImmutable => output.push_str("const "), - hir::MutMutable => output.push_str("mut "), - } +pub struct DefPathBasedNames<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + omit_disambiguators: bool, + omit_local_crate_name: bool, +} - push_unique_type_name(tcx, inner_type, output); - }, - ty::TyRef(_, ty::TypeAndMut { ty: inner_type, mutbl }) => { - output.push('&'); - if mutbl == hir::MutMutable { - output.push_str("mut "); - } +impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, + omit_disambiguators: bool, + omit_local_crate_name: bool) + -> Self { + DefPathBasedNames { + tcx: tcx, + omit_disambiguators: omit_disambiguators, + omit_local_crate_name: omit_local_crate_name, + } + } - push_unique_type_name(tcx, inner_type, output); - }, - ty::TyArray(inner_type, len) => { - output.push('['); - push_unique_type_name(tcx, inner_type, output); - output.push_str(&format!("; {}", len)); - output.push(']'); - }, - ty::TySlice(inner_type) => { - output.push('['); - push_unique_type_name(tcx, inner_type, output); - output.push(']'); - }, - ty::TyTrait(ref trait_data) => { - push_item_name(tcx, trait_data.principal.def_id(), output); - push_type_params(tcx, - trait_data.principal.skip_binder().substs, - &trait_data.projection_bounds, - output); - }, - ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) | - ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => { - if unsafety == hir::Unsafety::Unsafe { - output.push_str("unsafe "); - } - - if abi != ::abi::Abi::Rust { - output.push_str("extern \""); - output.push_str(abi.name()); - output.push_str("\" "); - } - - output.push_str("fn("); - - let sig = tcx.erase_late_bound_regions_and_normalize(sig); - if !sig.inputs.is_empty() { - for ¶meter_type in &sig.inputs { - push_unique_type_name(tcx, parameter_type, output); + pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String) { + match t.sty { + ty::TyBool => output.push_str("bool"), + ty::TyChar => output.push_str("char"), + ty::TyStr => output.push_str("str"), + ty::TyNever => output.push_str("!"), + ty::TyInt(ast::IntTy::Is) => output.push_str("isize"), + ty::TyInt(ast::IntTy::I8) => output.push_str("i8"), + ty::TyInt(ast::IntTy::I16) => output.push_str("i16"), + ty::TyInt(ast::IntTy::I32) => output.push_str("i32"), + ty::TyInt(ast::IntTy::I64) => output.push_str("i64"), + ty::TyUint(ast::UintTy::Us) => output.push_str("usize"), + ty::TyUint(ast::UintTy::U8) => output.push_str("u8"), + ty::TyUint(ast::UintTy::U16) => output.push_str("u16"), + ty::TyUint(ast::UintTy::U32) => output.push_str("u32"), + ty::TyUint(ast::UintTy::U64) => output.push_str("u64"), + ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"), + ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"), + ty::TyAdt(adt_def, substs) => { + self.push_def_path(adt_def.did, output); + self.push_type_params(substs, &[], output); + }, + ty::TyTuple(component_types) => { + output.push('('); + for &component_type in component_types { + self.push_type_name(component_type, output); output.push_str(", "); } - output.pop(); - output.pop(); - } - - if sig.variadic { - if !sig.inputs.is_empty() { - output.push_str(", ..."); - } else { - output.push_str("..."); + if !component_types.is_empty() { + output.pop(); + output.pop(); + } + output.push(')'); + }, + ty::TyBox(inner_type) => { + output.push_str("Box<"); + self.push_type_name(inner_type, output); + output.push('>'); + }, + ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => { + output.push('*'); + match mutbl { + hir::MutImmutable => output.push_str("const "), + hir::MutMutable => output.push_str("mut "), } - } - output.push(')'); + self.push_type_name(inner_type, output); + }, + ty::TyRef(_, ty::TypeAndMut { ty: inner_type, mutbl }) => { + output.push('&'); + if mutbl == hir::MutMutable { + output.push_str("mut "); + } - if !sig.output.is_nil() { - output.push_str(" -> "); - push_unique_type_name(tcx, sig.output, output); + self.push_type_name(inner_type, output); + }, + ty::TyArray(inner_type, len) => { + output.push('['); + self.push_type_name(inner_type, output); + write!(output, "; {}", len).unwrap(); + output.push(']'); + }, + ty::TySlice(inner_type) => { + output.push('['); + self.push_type_name(inner_type, output); + output.push(']'); + }, + ty::TyTrait(ref trait_data) => { + self.push_def_path(trait_data.principal.def_id(), output); + self.push_type_params(trait_data.principal.skip_binder().substs, + &trait_data.projection_bounds, + output); + }, + ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) | + ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => { + if unsafety == hir::Unsafety::Unsafe { + output.push_str("unsafe "); + } + + if abi != ::abi::Abi::Rust { + output.push_str("extern \""); + output.push_str(abi.name()); + output.push_str("\" "); + } + + output.push_str("fn("); + + let ty::FnSig { + inputs: sig_inputs, + output: sig_output, + variadic: sig_variadic + } = self.tcx.erase_late_bound_regions_and_normalize(sig); + + if !sig_inputs.is_empty() { + for ¶meter_type in &sig_inputs { + self.push_type_name(parameter_type, output); + output.push_str(", "); + } + output.pop(); + output.pop(); + } + + if sig_variadic { + if !sig_inputs.is_empty() { + output.push_str(", ..."); + } else { + output.push_str("..."); + } + } + + output.push(')'); + + if !sig_output.is_nil() { + output.push_str(" -> "); + self.push_type_name(sig_output, output); + } + }, + ty::TyClosure(def_id, ref closure_substs) => { + self.push_def_path(def_id, output); + let generics = self.tcx.item_generics(self.tcx.closure_base_def_id(def_id)); + let substs = closure_substs.substs.truncate_to(self.tcx, generics); + self.push_type_params(substs, &[], output); + } + ty::TyError | + ty::TyInfer(_) | + ty::TyProjection(..) | + ty::TyParam(_) | + ty::TyAnon(..) => { + bug!("DefPathBasedNames: Trying to create type name for \ + unexpected type: {:?}", t); } - }, - ty::TyClosure(def_id, closure_substs) => { - push_item_name(tcx, def_id, output); - output.push_str("{"); - output.push_str(&format!("{}:{}", def_id.krate, def_id.index.as_usize())); - output.push_str("}"); - let generics = tcx.item_generics(tcx.closure_base_def_id(def_id)); - let substs = closure_substs.substs.truncate_to(tcx, generics); - push_type_params(tcx, substs, &[], output); - } - ty::TyError | - ty::TyInfer(_) | - ty::TyProjection(..) | - ty::TyParam(_) | - ty::TyAnon(..) => { - bug!("debuginfo: Trying to create type name for \ - unexpected type: {:?}", t); } } -} -fn push_item_name(tcx: TyCtxt, - def_id: DefId, - output: &mut String) { - let def_path = tcx.def_path(def_id); + pub fn push_def_path(&self, + def_id: DefId, + output: &mut String) { + let def_path = self.tcx.def_path(def_id); - // some_crate:: - output.push_str(&tcx.crate_name(def_path.krate)); - output.push_str("::"); + // some_crate:: + if !(self.omit_local_crate_name && def_id.is_local()) { + output.push_str(&self.tcx.crate_name(def_path.krate)); + output.push_str("::"); + } - // foo::bar::ItemName:: - for part in tcx.def_path(def_id).data { - output.push_str(&format!("{}[{}]::", - part.data.as_interned_str(), - part.disambiguator)); + // foo::bar::ItemName:: + for part in self.tcx.def_path(def_id).data { + if self.omit_disambiguators { + write!(output, "{}::", part.data.as_interned_str()).unwrap(); + } else { + write!(output, "{}[{}]::", + part.data.as_interned_str(), + part.disambiguator).unwrap(); + } + } + + // remove final "::" + output.pop(); + output.pop(); } - // remove final "::" - output.pop(); - output.pop(); -} + pub fn push_type_params(&self, + substs: &Substs<'tcx>, + projections: &[ty::PolyExistentialProjection<'tcx>], + output: &mut String) { + if substs.types().next().is_none() && projections.is_empty() { + return; + } -fn push_type_params<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - substs: &Substs<'tcx>, - projections: &[ty::PolyExistentialProjection<'tcx>], - output: &mut String) { - if substs.types().next().is_none() && projections.is_empty() { - return; + output.push('<'); + + for type_parameter in substs.types() { + self.push_type_name(type_parameter, output); + output.push_str(", "); + } + + for projection in projections { + let projection = projection.skip_binder(); + let name = &projection.item_name.as_str(); + output.push_str(name); + output.push_str("="); + self.push_type_name(projection.ty, output); + output.push_str(", "); + } + + output.pop(); + output.pop(); + + output.push('>'); } - output.push('<'); - - for type_parameter in substs.types() { - push_unique_type_name(tcx, type_parameter, output); - output.push_str(", "); + pub fn push_instance_as_string(&self, + instance: Instance<'tcx>, + output: &mut String) { + self.push_def_path(instance.def, output); + self.push_type_params(instance.substs, &[], output); } - - for projection in projections { - let projection = projection.skip_binder(); - let name = &projection.item_name.as_str(); - output.push_str(name); - output.push_str("="); - push_unique_type_name(tcx, projection.ty, output); - output.push_str(", "); - } - - output.pop(); - output.pop(); - - output.push('>'); -} - -fn push_instance_as_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - instance: Instance<'tcx>, - output: &mut String) { - push_item_name(tcx, instance.def, output); - push_type_params(tcx, instance.substs, &[], output); -} - -pub fn def_id_to_string(tcx: TyCtxt, def_id: DefId) -> String { - let mut output = String::new(); - push_item_name(tcx, def_id, &mut output); - output -} - -pub fn type_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: Ty<'tcx>) - -> String { - let mut output = String::new(); - push_unique_type_name(tcx, ty, &mut output); - output } diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index dc794d5946a6..16d4f97200cb 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -10,14 +10,12 @@ #![allow(non_camel_case_types)] -use rustc::hir::def_id::DefId; use abi::FnType; use adt; use common::*; use machine; use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::ty::subst::Substs; - +use trans_item::DefPathBasedNames; use type_::Type; use syntax::ast; @@ -282,12 +280,12 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> let n = t.simd_size(cx.tcx()) as u64; Type::vector(&llet, n) } - ty::TyAdt(def, substs) => { + ty::TyAdt(..) => { // Only create the named struct, but don't fill it in. We // fill it in *after* placing it into the type cache. This // avoids creating more than one copy of the enum when one // of the enum's variants refers to the enum itself. - let name = llvm_type_name(cx, def.did, substs); + let name = llvm_type_name(cx, t); adt::incomplete_type_of(cx, t, &name[..]) } @@ -319,21 +317,9 @@ pub fn align_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) layout.align(&cx.tcx().data_layout).abi() as machine::llalign } -fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - did: DefId, - substs: &Substs<'tcx>) - -> String { - let base = cx.tcx().item_path_str(did); - let strings: Vec = substs.types().map(|t| t.to_string()).collect(); - let tstr = if strings.is_empty() { - base - } else { - format!("{}<{}>", base, strings.join(", ")) - }; - - if did.is_local() { - tstr - } else { - format!("{}.{}", did.krate, tstr) - } +fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> String { + let mut name = String::with_capacity(32); + let printer = DefPathBasedNames::new(cx.tcx(), true, true); + printer.push_type_name(ty, &mut name); + name } From fd4ee0021e6df93f47ba779b15a2bfaf61ebe1e2 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 8 Nov 2016 13:23:57 -0500 Subject: [PATCH 102/177] Fix codegen test after change of llvm type naming scheme --- src/test/codegen/lifetime_start_end.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/codegen/lifetime_start_end.rs b/src/test/codegen/lifetime_start_end.rs index 81f6cf309da5..e3b35cf35525 100644 --- a/src/test/codegen/lifetime_start_end.rs +++ b/src/test/codegen/lifetime_start_end.rs @@ -27,16 +27,16 @@ pub fn test() { let b = &Some(a); &b; // keep variable in an alloca -// CHECK: [[S_b:%[0-9]+]] = bitcast %"2.std::option::Option"** %b to i8* +// CHECK: [[S_b:%[0-9]+]] = bitcast %"core::option::Option"** %b to i8* // CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S_b]]) -// CHECK: [[S__5:%[0-9]+]] = bitcast %"2.std::option::Option"* %_5 to i8* +// CHECK: [[S__5:%[0-9]+]] = bitcast %"core::option::Option"* %_5 to i8* // CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S__5]]) -// CHECK: [[E__5:%[0-9]+]] = bitcast %"2.std::option::Option"* %_5 to i8* +// CHECK: [[E__5:%[0-9]+]] = bitcast %"core::option::Option"* %_5 to i8* // CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E__5]]) -// CHECK: [[E_b:%[0-9]+]] = bitcast %"2.std::option::Option"** %b to i8* +// CHECK: [[E_b:%[0-9]+]] = bitcast %"core::option::Option"** %b to i8* // CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E_b]]) } From 790a2f9b00602f951e903ac8b21f69e91737225c Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 7 Nov 2016 13:33:21 -0500 Subject: [PATCH 103/177] Adapt accidentally fixed test case. --- src/test/incremental/change_private_fn_cc/struct_point.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/test/incremental/change_private_fn_cc/struct_point.rs b/src/test/incremental/change_private_fn_cc/struct_point.rs index d6d2b5436ff3..ded87dd27f41 100644 --- a/src/test/incremental/change_private_fn_cc/struct_point.rs +++ b/src/test/incremental/change_private_fn_cc/struct_point.rs @@ -23,10 +23,7 @@ #![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")] #![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")] #![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")] - -// FIXME(#37335) -- should be reused, but an errant Krate edge causes -// it to get translated (at least I *think* this is that same problem) -#![rustc_partition_translated(module="struct_point-fn_make_struct", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")] extern crate point; From 276f052a804888e5c1d321183199bf37a42a94c2 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 7 Nov 2016 14:40:52 -0500 Subject: [PATCH 104/177] Remove unused method CrateContext::rotate(). --- src/librustc_trans/context.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index f7af2d6b855d..7657fc7d1c8b 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -701,22 +701,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local_ccxs[self.index] } - /// Get a (possibly) different `CrateContext` from the same - /// `SharedCrateContext`. - pub fn rotate(&'b self) -> CrateContext<'b, 'tcx> { - let (_, index) = - self.local_ccxs - .iter() - .zip(0..self.local_ccxs.len()) - .min_by_key(|&(local_ccx, _idx)| local_ccx.n_llvm_insns.get()) - .unwrap(); - CrateContext { - shared: self.shared, - index: index, - local_ccxs: &self.local_ccxs[..], - } - } - /// Either iterate over only `self`, or iterate over all `CrateContext`s in /// the `SharedCrateContext`. The iterator produces `(ccx, is_origin)` /// pairs, where `is_origin` is `true` if `ccx` is `self` and `false` From f3a71d3e8be80af5e8112bd9ae40f3384ea1c759 Mon Sep 17 00:00:00 2001 From: Robin Stocker Date: Mon, 14 Nov 2016 12:57:19 +1100 Subject: [PATCH 105/177] Add semicolon to "perhaps add a `use` for one of them" help Similar to pull request #37430, this makes the message more copy-paste friendly and aligns it with other messages like: help: you can import it into scope: use foo::Bar; --- src/librustc_typeck/check/method/suggest.rs | 2 +- .../compile-fail/no-method-suggested-traits.rs | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 0cb8cf2a5888..d15795730a86 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -308,7 +308,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let limit = if candidates.len() == 5 { 5 } else { 4 }; for (i, trait_did) in candidates.iter().take(limit).enumerate() { - err.help(&format!("candidate #{}: `use {}`", + err.help(&format!("candidate #{}: `use {};`", i + 1, self.tcx.item_path_str(*trait_did))); } diff --git a/src/test/compile-fail/no-method-suggested-traits.rs b/src/test/compile-fail/no-method-suggested-traits.rs index 9ccc7cc75ad5..ea8796d38f93 100644 --- a/src/test/compile-fail/no-method-suggested-traits.rs +++ b/src/test/compile-fail/no-method-suggested-traits.rs @@ -34,31 +34,31 @@ fn main() { 1u32.method(); //~^ HELP following traits are implemented but not in scope, perhaps add a `use` for one of them //~^^ ERROR no method named - //~^^^ HELP `use foo::Bar` - //~^^^^ HELP `use no_method_suggested_traits::foo::PubPub` + //~^^^ HELP `use foo::Bar;` + //~^^^^ HELP `use no_method_suggested_traits::foo::PubPub;` std::rc::Rc::new(&mut Box::new(&1u32)).method(); //~^ HELP following traits are implemented but not in scope, perhaps add a `use` for one of them //~^^ ERROR no method named - //~^^^ HELP `use foo::Bar` - //~^^^^ HELP `use no_method_suggested_traits::foo::PubPub` + //~^^^ HELP `use foo::Bar;` + //~^^^^ HELP `use no_method_suggested_traits::foo::PubPub;` 'a'.method(); //~^ ERROR no method named //~^^ HELP the following trait is implemented but not in scope, perhaps add a `use` for it: - //~^^^ HELP `use foo::Bar` + //~^^^ HELP `use foo::Bar;` std::rc::Rc::new(&mut Box::new(&'a')).method(); //~^ ERROR no method named //~^^ HELP the following trait is implemented but not in scope, perhaps add a `use` for it: - //~^^^ HELP `use foo::Bar` + //~^^^ HELP `use foo::Bar;` 1i32.method(); //~^ ERROR no method named //~^^ HELP the following trait is implemented but not in scope, perhaps add a `use` for it: - //~^^^ HELP `use no_method_suggested_traits::foo::PubPub` + //~^^^ HELP `use no_method_suggested_traits::foo::PubPub;` std::rc::Rc::new(&mut Box::new(&1i32)).method(); //~^ ERROR no method named //~^^ HELP the following trait is implemented but not in scope, perhaps add a `use` for it: - //~^^^ HELP `use no_method_suggested_traits::foo::PubPub` + //~^^^ HELP `use no_method_suggested_traits::foo::PubPub;` Foo.method(); //~^ ERROR no method named From dc3859d73e77a34b1a61fd4f23d18651bf515b80 Mon Sep 17 00:00:00 2001 From: Liigo Date: Fri, 11 Nov 2016 15:36:49 +0800 Subject: [PATCH 106/177] rustdoc: add cli argument `--playground-url` --- src/librustdoc/html/render.rs | 6 ++---- src/librustdoc/lib.rs | 8 ++++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 5aed37edbd42..e6275c2091e2 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -469,10 +469,8 @@ pub fn run(mut krate: clean::Crate, clean::NameValue(ref x, ref s) if "html_playground_url" == *x => { markdown::PLAYGROUND.with(|slot| { - if slot.borrow().is_none() { - let name = krate.name.clone(); - *slot.borrow_mut() = Some((Some(name), s.clone())); - } + let name = krate.name.clone(); + *slot.borrow_mut() = Some((Some(name), s.clone())); }); } clean::NameValue(ref x, ref s) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index ee395e0616b8..3af7c20c1336 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -162,6 +162,10 @@ pub fn opts() -> Vec { unstable(optmulti("Z", "", "internal and debugging options (only on nightly build)", "FLAG")), stable(optopt("", "sysroot", "Override the system root", "PATH")), + stable(optopt("", "playground-url", + "URL to send code snippets to, may be reset by --markdown-playground-url \ + or `#![doc(html_playground_url=...)]`", + "URL")), ] } @@ -230,6 +234,10 @@ pub fn main_args(args: &[String]) -> isize { } }; + if let Some(playground) = matches.opt_str("playground-url") { + html::markdown::PLAYGROUND.with(|s| { *s.borrow_mut() = Some((None, playground)); }); + } + let test_args = matches.opt_strs("test-args"); let test_args: Vec = test_args.iter() .flat_map(|s| s.split_whitespace()) From d7755701ad62f2b0764f9c86b77d65e59b7c5e6f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 3 Nov 2016 14:22:57 +1100 Subject: [PATCH 107/177] Remove `scope_auxiliary`. This reduces the peak RSS for a cut-down version of the program in #36799 by 10%, from 951MB to 856MB. --- src/librustc_mir/build/block.rs | 2 +- src/librustc_mir/build/cfg.rs | 5 --- src/librustc_mir/build/mod.rs | 60 ++++++-------------------- src/librustc_mir/build/scope.rs | 25 ++--------- src/librustc_mir/mir_map.rs | 6 +-- src/librustc_mir/pretty.rs | 58 +++---------------------- src/librustc_mir/transform/dump_mir.rs | 3 +- 7 files changed, 30 insertions(+), 129 deletions(-) diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index b53f8c4da86f..2c7b47c76699 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -54,7 +54,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let tcx = this.hir.tcx(); // Enter the remainder scope, i.e. the bindings' destruction scope. - this.push_scope(remainder_scope, block); + this.push_scope(remainder_scope); let_extent_stack.push(remainder_scope); // Declare the bindings, which may create a visibility scope. diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 9f612175e5da..71e97e4bfe0d 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -40,11 +40,6 @@ impl<'tcx> CFG<'tcx> { self.block_data_mut(block).statements.push(statement); } - pub fn current_location(&mut self, block: BasicBlock) -> Location { - let index = self.block_data(block).statements.len(); - Location { block: block, statement_index: index } - } - pub fn push_assign(&mut self, block: BasicBlock, source_info: SourceInfo, diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index f43181d8a610..458a952543e4 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -36,13 +36,6 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// see the `scope` module for more details scopes: Vec>, - /// for each scope, a span of blocks that defines it; - /// we track these for use in region and borrow checking, - /// but these are liable to get out of date once optimization - /// begins. They are also hopefully temporary, and will be - /// no longer needed when we adopt graph-based regions. - scope_auxiliary: IndexVec, - /// the current set of loops; see the `scope` module for more /// details loop_scopes: Vec, @@ -82,30 +75,6 @@ impl Idx for ScopeId { } } -/// For each scope, we track the extent (from the HIR) and a -/// single-entry-multiple-exit subgraph that contains all the -/// statements/terminators within it. -/// -/// This information is separated out from the main `ScopeData` -/// because it is short-lived. First, the extent contains node-ids, -/// so it cannot be saved and re-loaded. Second, any optimization will mess up -/// the dominator/postdominator information. -/// -/// The intention is basically to use this information to do -/// regionck/borrowck and then throw it away once we are done. -pub struct ScopeAuxiliary { - /// extent of this scope from the MIR. - pub extent: CodeExtent, - - /// "entry point": dominator of all nodes in the scope - pub dom: Location, - - /// "exit points": mutual postdominators of all nodes in the scope - pub postdoms: Vec, -} - -pub type ScopeAuxiliaryVec = IndexVec; - /////////////////////////////////////////////////////////////////////////// /// The `BlockAnd` "monad" packages up the new basic block along with a /// produced value (sometimes just unit, of course). The `unpack!` @@ -158,7 +127,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, abi: Abi, return_ty: Ty<'gcx>, ast_body: &'gcx hir::Expr) - -> (Mir<'tcx>, ScopeAuxiliaryVec) + -> Mir<'tcx> where A: Iterator, Option<&'gcx hir::Pat>)> { let arguments: Vec<_> = arguments.collect(); @@ -221,15 +190,15 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, }).collect() }); - let (mut mir, aux) = builder.finish(upvar_decls, return_ty); + let mut mir = builder.finish(upvar_decls, return_ty); mir.spread_arg = spread_arg; - (mir, aux) + mir } pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, item_id: ast::NodeId, ast_expr: &'tcx hir::Expr) - -> (Mir<'tcx>, ScopeAuxiliaryVec) { + -> Mir<'tcx> { let tcx = hir.tcx(); let ty = tcx.tables().expr_ty_adjusted(ast_expr); let span = tcx.map.span(item_id); @@ -269,7 +238,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { scopes: vec![], visibility_scopes: IndexVec::new(), visibility_scope: ARGUMENT_VISIBILITY_SCOPE, - scope_auxiliary: IndexVec::new(), loop_scopes: vec![], local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty), 1), var_indices: NodeMap(), @@ -288,22 +256,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn finish(self, upvar_decls: Vec, return_ty: Ty<'tcx>) - -> (Mir<'tcx>, ScopeAuxiliaryVec) { + -> Mir<'tcx> { for (index, block) in self.cfg.basic_blocks.iter().enumerate() { if block.terminator.is_none() { span_bug!(self.fn_span, "no terminator on block {:?}", index); } } - (Mir::new(self.cfg.basic_blocks, - self.visibility_scopes, - IndexVec::new(), - return_ty, - self.local_decls, - self.arg_count, - upvar_decls, - self.fn_span - ), self.scope_auxiliary) + Mir::new(self.cfg.basic_blocks, + self.visibility_scopes, + IndexVec::new(), + return_ty, + self.local_decls, + self.arg_count, + upvar_decls, + self.fn_span + ) } fn args_and_body(&mut self, diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 4af87381c704..4d9b6c0e05a4 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -86,7 +86,7 @@ should go to. */ -use build::{BlockAnd, BlockAndExtension, Builder, CFG, ScopeAuxiliary, ScopeId}; +use build::{BlockAnd, BlockAndExtension, Builder, CFG}; use rustc::middle::region::{CodeExtent, CodeExtentData}; use rustc::middle::lang_items; use rustc::ty::subst::{Kind, Subst}; @@ -97,14 +97,10 @@ use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::fx::FxHashMap; pub struct Scope<'tcx> { - /// the scope-id within the scope_auxiliary - id: ScopeId, - /// The visibility scope this scope was created in. visibility_scope: VisibilityScope, - /// the extent of this scope within source code; also stored in - /// `ScopeAuxiliary`, but kept here for convenience + /// the extent of this scope within source code. extent: CodeExtent, /// Whether there's anything to do for the cleanup path, that is, @@ -276,7 +272,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd { debug!("in_scope(extent={:?}, block={:?})", extent, block); - self.push_scope(extent, block); + self.push_scope(extent); let rv = unpack!(block = f(self)); unpack!(block = self.pop_scope(extent, block)); debug!("in_scope: exiting extent={:?} block={:?}", extent, block); @@ -287,12 +283,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// scope and call `pop_scope` afterwards. Note that these two /// calls must be paired; using `in_scope` as a convenience /// wrapper maybe preferable. - pub fn push_scope(&mut self, extent: CodeExtent, entry: BasicBlock) { + pub fn push_scope(&mut self, extent: CodeExtent) { debug!("push_scope({:?})", extent); - let id = ScopeId::new(self.scope_auxiliary.len()); let vis_scope = self.visibility_scope; self.scopes.push(Scope { - id: id, visibility_scope: vis_scope, extent: extent, needs_cleanup: false, @@ -300,11 +294,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { free: None, cached_exits: FxHashMap() }); - self.scope_auxiliary.push(ScopeAuxiliary { - extent: extent, - dom: self.cfg.current_location(entry), - postdoms: vec![] - }); } /// Pops a scope, which should have extent `extent`, adding any @@ -325,9 +314,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { &self.scopes, block, self.arg_count)); - self.scope_auxiliary[scope.id] - .postdoms - .push(self.cfg.current_location(block)); block.unit() } @@ -375,9 +361,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.cfg.terminate(block, scope.source_info(span), free); block = next; } - self.scope_auxiliary[scope.id] - .postdoms - .push(self.cfg.current_location(block)); } } let scope = &self.scopes[len - scope_count]; diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index f22a2a7ac9c7..4a50585efe3b 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -103,11 +103,11 @@ impl<'a, 'gcx, 'tcx> BuildMir<'a, 'gcx> { impl<'a, 'gcx, 'tcx> CxBuilder<'a, 'gcx, 'tcx> { fn build(&'tcx mut self, f: F) - where F: for<'b> FnOnce(Cx<'b, 'gcx, 'tcx>) -> (Mir<'tcx>, build::ScopeAuxiliaryVec) + where F: for<'b> FnOnce(Cx<'b, 'gcx, 'tcx>) -> Mir<'tcx> { let (src, def_id) = (self.src, self.def_id); self.infcx.enter(|infcx| { - let (mut mir, scope_auxiliary) = f(Cx::new(&infcx, src)); + let mut mir = f(Cx::new(&infcx, src)); // Convert the Mir to global types. let tcx = infcx.tcx.global_tcx(); @@ -120,7 +120,7 @@ impl<'a, 'gcx, 'tcx> CxBuilder<'a, 'gcx, 'tcx> { mem::transmute::>(mir) }; - pretty::dump_mir(tcx, "mir_map", &0, src, &mir, Some(&scope_auxiliary)); + pretty::dump_mir(tcx, "mir_map", &0, src, &mir); let mir = tcx.alloc_mir(mir); assert!(tcx.mir_map.borrow_mut().insert(def_id, mir).is_none()); diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index d6f514cfb913..e7188d536980 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use build::{ScopeAuxiliaryVec, ScopeId}; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::mir::*; @@ -43,8 +42,7 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pass_name: &str, disambiguator: &Display, src: MirSource, - mir: &Mir<'tcx>, - auxiliary: Option<&ScopeAuxiliaryVec>) { + mir: &Mir<'tcx>) { let filters = match tcx.sess.opts.debugging_opts.dump_mir { None => return, Some(ref filters) => filters, @@ -81,7 +79,7 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, writeln!(file, "// pass_name = {}", pass_name)?; writeln!(file, "// disambiguator = {}", disambiguator)?; writeln!(file, "")?; - write_mir_fn(tcx, src, mir, &mut file, auxiliary)?; + write_mir_fn(tcx, src, mir, &mut file)?; Ok(()) }); } @@ -106,52 +104,24 @@ pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>, let id = tcx.map.as_local_node_id(def_id).unwrap(); let src = MirSource::from_node(tcx, id); - write_mir_fn(tcx, src, mir, w, None)?; + write_mir_fn(tcx, src, mir, w)?; for (i, mir) in mir.promoted.iter_enumerated() { writeln!(w, "")?; - write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w, None)?; + write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w)?; } } Ok(()) } -enum Annotation { - EnterScope(ScopeId), - ExitScope(ScopeId), -} - -fn scope_entry_exit_annotations(auxiliary: Option<&ScopeAuxiliaryVec>) - -> FxHashMap> -{ - // compute scope/entry exit annotations - let mut annotations = FxHashMap(); - if let Some(auxiliary) = auxiliary { - for (scope_id, auxiliary) in auxiliary.iter_enumerated() { - annotations.entry(auxiliary.dom) - .or_insert(vec![]) - .push(Annotation::EnterScope(scope_id)); - - for &loc in &auxiliary.postdoms { - annotations.entry(loc) - .or_insert(vec![]) - .push(Annotation::ExitScope(scope_id)); - } - } - } - return annotations; -} - pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &Mir<'tcx>, - w: &mut Write, - auxiliary: Option<&ScopeAuxiliaryVec>) + w: &mut Write) -> io::Result<()> { - let annotations = scope_entry_exit_annotations(auxiliary); write_mir_intro(tcx, src, mir, w)?; for block in mir.basic_blocks().indices() { - write_basic_block(tcx, block, mir, w, &annotations)?; + write_basic_block(tcx, block, mir, w)?; if block.index() + 1 != mir.basic_blocks().len() { writeln!(w, "")?; } @@ -165,8 +135,7 @@ pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn write_basic_block(tcx: TyCtxt, block: BasicBlock, mir: &Mir, - w: &mut Write, - annotations: &FxHashMap>) + w: &mut Write) -> io::Result<()> { let data = &mir[block]; @@ -176,19 +145,6 @@ fn write_basic_block(tcx: TyCtxt, // List of statements in the middle. let mut current_location = Location { block: block, statement_index: 0 }; for statement in &data.statements { - if let Some(ref annotations) = annotations.get(¤t_location) { - for annotation in annotations.iter() { - match *annotation { - Annotation::EnterScope(id) => - writeln!(w, "{0}{0}// Enter Scope({1})", - INDENT, id.index())?, - Annotation::ExitScope(id) => - writeln!(w, "{0}{0}// Exit Scope({1})", - INDENT, id.index())?, - } - } - } - let indented_mir = format!("{0}{0}{1:?};", INDENT, statement); writeln!(w, "{0:1$} // {2}", indented_mir, diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index b8fd9fb12ab0..035f33de91aa 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -64,8 +64,7 @@ impl<'tcx> MirPassHook<'tcx> for DumpMir { is_after: is_after }, src, - mir, - None + mir ); } } From cf9ff2b59bf876650b1e13ab66078bfd22ac85ef Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 19 Oct 2016 18:21:27 +0300 Subject: [PATCH 108/177] Fix where clauses parsing Don't allow lifetimes without any bounds at all --- src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs | 2 +- src/libsyntax/parse/parser.rs | 2 +- .../parse-fail/where-clauses-no-bounds-or-predicates.rs | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs index f6260527039d..0694bbab66f1 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs @@ -88,7 +88,7 @@ pub trait MirWithFlowState<'tcx> { } impl<'a, 'tcx: 'a, BD> MirWithFlowState<'tcx> for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> - where 'a, 'tcx: 'a, BD: BitDenotation> + where 'tcx: 'a, BD: BitDenotation> { type BD = BD; fn node_id(&self) -> NodeId { self.node_id } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 61268d457ce4..e1de32de790c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4440,7 +4440,7 @@ impl<'a> Parser<'a> { let bounded_lifetime = self.parse_lifetime()?; - self.eat(&token::Colon); + self.expect(&token::Colon)?; let bounds = self.parse_lifetimes(token::BinOp(token::Plus))?; diff --git a/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs b/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs index 3ac71176342b..78d974540873 100644 --- a/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs +++ b/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error fn equal1(_: &T, _: &T) -> bool where { //~^ ERROR a `where` clause must have at least one predicate in it @@ -20,5 +20,8 @@ fn equal2(_: &T, _: &T) -> bool where T: { true } +fn foo<'a>() where 'a {} +//~^ ERROR expected `:`, found `{` + fn main() { } From 80ca1e1251b634b8b9831aa999f3f7435ccfdd16 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 14 Nov 2016 03:37:46 -0500 Subject: [PATCH 109/177] don't build an object file for emit=asm,llvm-ir --- src/librustc_driver/driver.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 48bf490d685b..2dd83f708235 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1056,7 +1056,11 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn phase_5_run_llvm_passes(sess: &Session, trans: &trans::CrateTranslation, outputs: &OutputFilenames) -> CompileResult { - if sess.opts.cg.no_integrated_as || sess.target.target.options.no_integrated_as { + if sess.opts.cg.no_integrated_as || + (sess.target.target.options.no_integrated_as && + (outputs.outputs.contains_key(&OutputType::Object) || + outputs.outputs.contains_key(&OutputType::Exe))) + { let output_types = OutputTypes::new(&[(OutputType::Assembly, None)]); time(sess.time_passes(), "LLVM passes", From d6689fdc616fd3e7af9946072cb0aaceb2bb26b9 Mon Sep 17 00:00:00 2001 From: Josh Driver Date: Sun, 13 Nov 2016 19:39:27 +1030 Subject: [PATCH 110/177] Add warnings when the #[should_panic] attribute is invalid --- src/libsyntax/test.rs | 44 ++++++++++++++++---- src/test/run-pass/test-should-panic-attr.rs | 46 +++++++++++++++++++++ 2 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 src/test/run-pass/test-should-panic-attr.rs diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 618878c1f798..59a7e75d1255 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -132,7 +132,7 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { path: self.cx.path.clone(), bench: is_bench_fn(&self.cx, &i), ignore: is_ignored(&i), - should_panic: should_panic(&i) + should_panic: should_panic(&i, &self.cx) }; self.cx.testfns.push(test); self.tests.push(i.ident); @@ -395,14 +395,44 @@ fn is_ignored(i: &ast::Item) -> bool { i.attrs.iter().any(|attr| attr.check_name("ignore")) } -fn should_panic(i: &ast::Item) -> ShouldPanic { +fn should_panic(i: &ast::Item, cx: &TestCtxt) -> ShouldPanic { match i.attrs.iter().find(|attr| attr.check_name("should_panic")) { Some(attr) => { - let msg = attr.meta_item_list() - .and_then(|list| list.iter().find(|mi| mi.check_name("expected"))) - .and_then(|li| li.meta_item()) - .and_then(|mi| mi.value_str()); - ShouldPanic::Yes(msg) + let sd = cx.span_diagnostic; + if attr.is_value_str() { + sd.struct_span_warn( + attr.span(), + "attribute must be of the form: \ + `#[should_panic]` or \ + `#[should_panic(expected = \"error message\")]`" + ).note("Errors in this attribute were erroneously allowed \ + and will become a hard error in a future release.") + .emit(); + return ShouldPanic::Yes(None); + } + match attr.meta_item_list() { + // Handle #[should_panic] + None => ShouldPanic::Yes(None), + // Handle #[should_panic(expected = "foo")] + Some(list) => { + let msg = list.iter() + .find(|mi| mi.check_name("expected")) + .and_then(|mi| mi.meta_item()) + .and_then(|mi| mi.value_str()); + if list.len() != 1 || msg.is_none() { + sd.struct_span_warn( + attr.span(), + "argument must be of the form: \ + `expected = \"error message\"`" + ).note("Errors in this attribute were erroneously \ + allowed and will become a hard error in a \ + future release.").emit(); + ShouldPanic::Yes(None) + } else { + ShouldPanic::Yes(msg) + } + }, + } } None => ShouldPanic::No, } diff --git a/src/test/run-pass/test-should-panic-attr.rs b/src/test/run-pass/test-should-panic-attr.rs new file mode 100644 index 000000000000..2d068872a4d3 --- /dev/null +++ b/src/test/run-pass/test-should-panic-attr.rs @@ -0,0 +1,46 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --test + +#[test] +#[should_panic = "foo"] +//~^ WARN: attribute must be of the form: +fn test1() { + panic!(); +} + +#[test] +#[should_panic(expected)] +//~^ WARN: argument must be of the form: +fn test2() { + panic!(); +} + +#[test] +#[should_panic(expect)] +//~^ WARN: argument must be of the form: +fn test3() { + panic!(); +} + +#[test] +#[should_panic(expected(foo, bar))] +//~^ WARN: argument must be of the form: +fn test4() { + panic!(); +} + +#[test] +#[should_panic(expected = "foo", bar)] +//~^ WARN: argument must be of the form: +fn test5() { + panic!(); +} From 67df9b9ac62ec1ec2e50289842a8842cf1a263f8 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Mon, 14 Nov 2016 13:52:43 +0000 Subject: [PATCH 111/177] Add sections about concurrency and stdout/err capture to the Testing chapter of the book. --- src/doc/book/testing.md | 43 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index ed916fd798bb..3b6d77032f13 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -586,3 +586,46 @@ you add more examples. We haven’t covered all of the details with writing documentation tests. For more, please see the [Documentation chapter](documentation.html). + +# Testing and concurrency + +One thing that is important to note when writing tests are run concurrently +using threads (by default the number of threads is equal to the number of CPUs +on the machine). For this reason you should take care that your tests are +written in such a way as to not depend on each-other, or on any shared +state. "Share state" can also include the environment, such as the current +working directory, or environment variables. + +If this is an issue it is possible to control this concurrency, either by +setting the environment variable `RUST_TEST_THREADS`, or by passing the argument +`--test-threads` to the tests: + +```bash +$ RUST_TEST_THREADS=1 cargo test # Run tests with no concurrency +... +$ cargo test -- --test-threads=1 # Same as above +... +``` + +# Test output + +By default Rust's test library captures and discards output to standard +out/error, e.g. output from `println!()`. This too can be controlled using the +environment or a switch: + + +```bash +$ RUST_TEST_NOCAPTURE=1 cargo test # Preserve stdout/stderr +... +$ cargo test -- --nocapture # Same as above +... +``` + +However a better method avoiding capture is to use logging rather than raw +output. Rust has a [standard logging API][log], which provides a frontend to +multiple loggin implementations. This can be used in conjunction with the +default [env_logger] to output any debugging information in a manner that can be +controlled at runtime. + +[log]: https://crates.io/crates/log +[env_logger]: https://crates.io/crates/env_logger From b9e17fa58ad9413355903d1a1a8cde5b11a9d436 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Mon, 14 Nov 2016 14:21:35 +0000 Subject: [PATCH 112/177] Typo in new section --- src/doc/book/testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index 3b6d77032f13..8ec482fa5851 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -593,7 +593,7 @@ One thing that is important to note when writing tests are run concurrently using threads (by default the number of threads is equal to the number of CPUs on the machine). For this reason you should take care that your tests are written in such a way as to not depend on each-other, or on any shared -state. "Share state" can also include the environment, such as the current +state. "Shared state" can also include the environment, such as the current working directory, or environment variables. If this is an issue it is possible to control this concurrency, either by From 5f626138a0a4848704b291bdba4d2c445fcffa3b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 14 Nov 2016 08:04:39 -0800 Subject: [PATCH 113/177] rustbuild: Allow configuration of python interpreter Add a configuration key to `config.toml`, read it from `./configure`, and add auto-detection if none of those were specified. Closes #35760 --- src/bootstrap/check.rs | 6 ++---- src/bootstrap/config.rs | 7 +++++++ src/bootstrap/config.toml.example | 12 +++++++++++- src/bootstrap/dist.rs | 4 ++-- src/bootstrap/lib.rs | 5 +++++ src/bootstrap/sanity.rs | 12 +++++++++++- 6 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index f27f9641036c..ac6be2a870b0 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -130,9 +130,7 @@ pub fn compiletest(build: &Build, build.test_helpers_out(target).display())); cmd.arg("--target-rustcflags").arg(targetflags.join(" ")); - // FIXME: CFG_PYTHON should probably be detected more robustly elsewhere - let python_default = "python"; - cmd.arg("--docck-python").arg(python_default); + cmd.arg("--docck-python").arg(build.python()); if build.config.build.ends_with("apple-darwin") { // Force /usr/bin/python on OSX for LLDB tests because we're loading the @@ -140,7 +138,7 @@ pub fn compiletest(build: &Build, // (namely not Homebrew-installed python) cmd.arg("--lldb-python").arg("/usr/bin/python"); } else { - cmd.arg("--lldb-python").arg(python_default); + cmd.arg("--lldb-python").arg(build.python()); } if let Some(ref gdb) = build.config.gdb { diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 50c703a73540..2ac06707bb11 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -90,6 +90,7 @@ pub struct Config { pub codegen_tests: bool, pub nodejs: Option, pub gdb: Option, + pub python: Option, } /// Per-target configuration stored in the global configuration structure. @@ -130,6 +131,7 @@ struct Build { gdb: Option, vendor: Option, nodejs: Option, + python: Option, } /// TOML representation of how the LLVM build is configured. @@ -237,6 +239,7 @@ impl Config { config.cargo = build.cargo.map(PathBuf::from); config.nodejs = build.nodejs.map(PathBuf::from); config.gdb = build.gdb.map(PathBuf::from); + config.python = build.python.map(PathBuf::from); set(&mut config.compiler_docs, build.compiler_docs); set(&mut config.docs, build.docs); set(&mut config.submodules, build.submodules); @@ -465,6 +468,10 @@ impl Config { self.rustc = Some(push_exe_path(path.clone(), &["bin", "rustc"])); self.cargo = Some(push_exe_path(path, &["bin", "cargo"])); } + "CFG_PYTHON" if value.len() > 0 => { + let path = parse_configure_path(value); + self.python = Some(path); + } _ => {} } } diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 1388dab303a4..b6774b3af20a 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -82,9 +82,19 @@ # Indicate whether submodules are managed and updated automatically. #submodules = true -# The path to (or name of) the GDB executable to use +# The path to (or name of) the GDB executable to use. This is only used for +# executing the debuginfo test suite. #gdb = "gdb" +# The node.js executable to use. Note that this is only used for the emscripten +# target when running tests, otherwise this can be omitted. +#nodejs = "node" + +# Python interpreter to use for various tasks throughout the build, notably +# rustdoc tests, the lldb python interpreter, and some dist bits and pieces. +# Note that Python 2 is currently required. +#python = "python2.7" + # Indicate whether the vendored sources are used for Rust dependencies or not #vendor = false diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 8676f5cc4a1e..d603455122eb 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -99,7 +99,7 @@ pub fn mingw(build: &Build, host: &str) { // (which is what we want). // // FIXME: this script should be rewritten into Rust - let mut cmd = Command::new("python"); + let mut cmd = Command::new(build.python()); cmd.arg(build.src.join("src/etc/make-win-dist.py")) .arg(tmpdir(build)) .arg(&image) @@ -159,7 +159,7 @@ pub fn rustc(build: &Build, stage: u32, host: &str) { // // FIXME: this script should be rewritten into Rust if host.contains("pc-windows-gnu") { - let mut cmd = Command::new("python"); + let mut cmd = Command::new(build.python()); cmd.arg(build.src.join("src/etc/make-win-dist.py")) .arg(&image) .arg(tmpdir(build)) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index e6b88ea58c9b..828e82d38321 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -774,6 +774,11 @@ impl Build { .or(self.config.musl_root.as_ref()) .map(|p| &**p) } + + /// Path to the python interpreter to use + fn python(&self) -> &Path { + self.config.python.as_ref().unwrap() + } } impl<'a> Compiler<'a> { diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index a541ba0b2f3f..47efa6952177 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -79,7 +79,17 @@ pub fn check(build: &mut Build) { break } - need_cmd("python".as_ref()); + if build.config.python.is_none() { + build.config.python = have_cmd("python2.7".as_ref()); + } + if build.config.python.is_none() { + build.config.python = have_cmd("python2".as_ref()); + } + if build.config.python.is_none() { + need_cmd("python".as_ref()); + build.config.python = Some("python".into()); + } + need_cmd(build.config.python.as_ref().unwrap().as_ref()); if let Some(ref s) = build.config.nodejs { From 5a76fe4225f735a3a6e8574954b327157461423c Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Mon, 14 Nov 2016 16:43:25 +0000 Subject: [PATCH 114/177] Remove thread-per-CPU bit as it may not be accurate. --- src/doc/book/testing.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index 8ec482fa5851..3faa4b09c1fc 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -590,11 +590,10 @@ please see the [Documentation chapter](documentation.html). # Testing and concurrency One thing that is important to note when writing tests are run concurrently -using threads (by default the number of threads is equal to the number of CPUs -on the machine). For this reason you should take care that your tests are -written in such a way as to not depend on each-other, or on any shared -state. "Shared state" can also include the environment, such as the current -working directory, or environment variables. +using threads. For this reason you should take care that your tests are written +in such a way as to not depend on each-other, or on any shared state. "Shared +state" can also include the environment, such as the current working directory, +or environment variables. If this is an issue it is possible to control this concurrency, either by setting the environment variable `RUST_TEST_THREADS`, or by passing the argument @@ -623,7 +622,7 @@ $ cargo test -- --nocapture # Same as above However a better method avoiding capture is to use logging rather than raw output. Rust has a [standard logging API][log], which provides a frontend to -multiple loggin implementations. This can be used in conjunction with the +multiple logging implementations. This can be used in conjunction with the default [env_logger] to output any debugging information in a manner that can be controlled at runtime. From 321602452311bbfdb8feb7db339cef93d436a9d4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 14 Nov 2016 09:23:17 -0800 Subject: [PATCH 115/177] test: Move missing-items to a ui test This test is failing on nightly for unknown reasons, and my best guess is a difference in grep versions which is interpreting symbols differently. For now let's just move this to a ui test and hope it fixes nightlies. --- src/test/run-make/missing-items/Makefile | 10 ---------- .../missing-items/auxiliary}/m1.rs | 8 ++++---- src/test/{run-make => ui}/missing-items/m2.rs | 4 +++- src/test/ui/missing-items/m2.stderr | 14 ++++++++++++++ 4 files changed, 21 insertions(+), 15 deletions(-) delete mode 100644 src/test/run-make/missing-items/Makefile rename src/test/{run-make/missing-items => ui/missing-items/auxiliary}/m1.rs (82%) rename src/test/{run-make => ui}/missing-items/m2.rs (95%) create mode 100644 src/test/ui/missing-items/m2.stderr diff --git a/src/test/run-make/missing-items/Makefile b/src/test/run-make/missing-items/Makefile deleted file mode 100644 index bcc9cdf2d652..000000000000 --- a/src/test/run-make/missing-items/Makefile +++ /dev/null @@ -1,10 +0,0 @@ --include ../tools.mk - -all: - $(RUSTC) m1.rs -C prefer-dynamic - $(RUSTC) m2.rs 2>&1 | grep "error\[E0046\]: not all trait items implemented, missing: .*" - $(RUSTC) m2.rs 2>&1 | grep " --> m2.rs:18:1" - $(RUSTC) m2.rs 2>&1 | grep " | ^ missing .CONSTANT., .Type., .method. in implementation" - $(RUSTC) m2.rs 2>&1 | grep " = note: .CONSTANT. from trait: .const CONSTANT: u32;." - $(RUSTC) m2.rs 2>&1 | grep " = note: .Type. from trait: .type Type;." - $(RUSTC) m2.rs 2>&1 | grep " = note: .method. from trait: .fn(&Self, std::string::String) -> ::Type." diff --git a/src/test/run-make/missing-items/m1.rs b/src/test/ui/missing-items/auxiliary/m1.rs similarity index 82% rename from src/test/run-make/missing-items/m1.rs rename to src/test/ui/missing-items/auxiliary/m1.rs index 060c7a9571b7..f8389692267e 100644 --- a/src/test/run-make/missing-items/m1.rs +++ b/src/test/ui/missing-items/auxiliary/m1.rs @@ -9,9 +9,9 @@ // except according to those terms. #![feature(associated_consts)] -#![crate_type = "dylib"] + pub trait X { - const CONSTANT: u32; - type Type; - fn method(&self, s: String) -> Self::Type; + const CONSTANT: u32; + type Type; + fn method(&self, s: String) -> Self::Type; } diff --git a/src/test/run-make/missing-items/m2.rs b/src/test/ui/missing-items/m2.rs similarity index 95% rename from src/test/run-make/missing-items/m2.rs rename to src/test/ui/missing-items/m2.rs index 7055673acc9a..fc09039640b9 100644 --- a/src/test/run-make/missing-items/m2.rs +++ b/src/test/ui/missing-items/m2.rs @@ -8,8 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// aux-build:m1.rs + #![feature(associated_consts)] -#![crate_type = "dylib"] + extern crate m1; struct X { diff --git a/src/test/ui/missing-items/m2.stderr b/src/test/ui/missing-items/m2.stderr new file mode 100644 index 000000000000..caeb9ff415cd --- /dev/null +++ b/src/test/ui/missing-items/m2.stderr @@ -0,0 +1,14 @@ +error: main function not found + +error[E0046]: not all trait items implemented, missing: `CONSTANT`, `Type`, `method` + --> $DIR/m2.rs:20:1 + | +20 | impl m1::X for X { + | ^ missing `CONSTANT`, `Type`, `method` in implementation + | + = note: `CONSTANT` from trait: `const CONSTANT: u32;` + = note: `Type` from trait: `type Type;` + = note: `method` from trait: `fn(&Self, std::string::String) -> ::Type` + +error: aborting due to previous error + From 8e70a50a8a1c2d4bc9f02b27634c6d71952bf03f Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Mon, 14 Nov 2016 12:35:37 -0500 Subject: [PATCH 116/177] add test for #37765 --- src/test/run-pass/path-lookahead.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/run-pass/path-lookahead.rs diff --git a/src/test/run-pass/path-lookahead.rs b/src/test/run-pass/path-lookahead.rs new file mode 100644 index 000000000000..017259af190f --- /dev/null +++ b/src/test/run-pass/path-lookahead.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Parser test for #37765 + +fn with_parens(arg: T) -> String { //~WARN dead_code + return (::to_string(&arg)); //~WARN unused_parens +} + +fn no_parens(arg: T) -> String { //~WARN dead_code + return ::to_string(&arg); +} + +fn main() { + +} From 6fe7786db6d44449127600cf69838cb246db810b Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Mon, 14 Nov 2016 18:24:47 +0000 Subject: [PATCH 117/177] rustdoc: Fix some local inlining issues * Only inline public items when inlining glob imports. * Never inline while in a private module or a child of a private module. * Never inline impls. This allowed the removal of a workaround in the rendering code. --- src/librustdoc/html/render.rs | 52 ++++------- src/librustdoc/visit_ast.rs | 88 ++++++++++++------- .../inline_local/glob-extern-no-defaults.rs | 35 ++++++++ src/test/rustdoc/inline_local/glob-extern.rs | 31 +++++++ .../inline_local/glob-private-no-defaults.rs | 58 ++++++++++++ src/test/rustdoc/inline_local/glob-private.rs | 49 +++++++++++ 6 files changed, 244 insertions(+), 69 deletions(-) create mode 100644 src/test/rustdoc/inline_local/glob-extern-no-defaults.rs create mode 100644 src/test/rustdoc/inline_local/glob-extern.rs create mode 100644 src/test/rustdoc/inline_local/glob-private-no-defaults.rs create mode 100644 src/test/rustdoc/inline_local/glob-private.rs diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 93827a01038f..956b7fa19cb3 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -257,8 +257,6 @@ pub struct Cache { parent_stack: Vec, parent_is_trait_impl: bool, search_index: Vec, - seen_modules: FxHashSet, - seen_mod: bool, stripped_mod: bool, deref_trait_did: Option, deref_mut_trait_did: Option, @@ -520,8 +518,6 @@ pub fn run(mut krate: clean::Crate, parent_is_trait_impl: false, extern_locations: FxHashMap(), primitive_locations: FxHashMap(), - seen_modules: FxHashSet(), - seen_mod: false, stripped_mod: false, access_levels: krate.access_levels.clone(), orphan_impl_items: Vec::new(), @@ -977,37 +973,26 @@ impl DocFolder for Cache { _ => self.stripped_mod, }; - // Inlining can cause us to visit the same item multiple times. - // (i.e. relevant for gathering impls and implementors) - let orig_seen_mod = if item.is_mod() { - let seen_this = self.seen_mod || !self.seen_modules.insert(item.def_id); - mem::replace(&mut self.seen_mod, seen_this) - } else { - self.seen_mod - }; - // Register any generics to their corresponding string. This is used // when pretty-printing types if let Some(generics) = item.inner.generics() { self.generics(generics); } - if !self.seen_mod { - // Propagate a trait methods' documentation to all implementors of the - // trait - if let clean::TraitItem(ref t) = item.inner { - self.traits.insert(item.def_id, t.clone()); - } + // Propagate a trait methods' documentation to all implementors of the + // trait + if let clean::TraitItem(ref t) = item.inner { + self.traits.entry(item.def_id).or_insert_with(|| t.clone()); + } - // Collect all the implementors of traits. - if let clean::ImplItem(ref i) = item.inner { - if let Some(did) = i.trait_.def_id() { - self.implementors.entry(did).or_insert(vec![]).push(Implementor { - def_id: item.def_id, - stability: item.stability.clone(), - impl_: i.clone(), - }); - } + // Collect all the implementors of traits. + if let clean::ImplItem(ref i) = item.inner { + if let Some(did) = i.trait_.def_id() { + self.implementors.entry(did).or_insert(vec![]).push(Implementor { + def_id: item.def_id, + stability: item.stability.clone(), + impl_: i.clone(), + }); } } @@ -1186,12 +1171,10 @@ impl DocFolder for Cache { } else { unreachable!() }; - if !self.seen_mod { - if let Some(did) = did { - self.impls.entry(did).or_insert(vec![]).push(Impl { - impl_item: item, - }); - } + if let Some(did) = did { + self.impls.entry(did).or_insert(vec![]).push(Impl { + impl_item: item, + }); } None } else { @@ -1201,7 +1184,6 @@ impl DocFolder for Cache { if pushed { self.stack.pop().unwrap(); } if parent_pushed { self.parent_stack.pop().unwrap(); } - self.seen_mod = orig_seen_mod; self.stripped_mod = orig_stripped_mod; self.parent_is_trait_impl = orig_parent_is_trait_impl; ret diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index d0407162793e..d9155e10e17b 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -44,7 +44,9 @@ pub struct RustdocVisitor<'a, 'tcx: 'a> { pub attrs: hir::HirVec, pub cx: &'a core::DocContext<'a, 'tcx>, view_item_stack: FxHashSet, - inlining_from_glob: bool, + inlining: bool, + /// Is the current module and all of its parents public? + inside_public_path: bool, } impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { @@ -57,7 +59,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: hir::HirVec::new(), cx: cx, view_item_stack: stack, - inlining_from_glob: false, + inlining: false, + inside_public_path: true, } } @@ -189,10 +192,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { om.stab = self.stability(id); om.depr = self.deprecation(id); om.id = id; + // Keep track of if there were any private modules in the path. + let orig_inside_public_path = self.inside_public_path; + self.inside_public_path &= vis == hir::Public; for i in &m.item_ids { let item = self.cx.map.expect_item(i.id); self.visit_item(item, None, &mut om); } + self.inside_public_path = orig_inside_public_path; if let Some(exports) = self.cx.export_map.get(&id) { for export in exports { if let Def::Macro(def_id) = export.def { @@ -336,8 +343,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let ret = match tcx.map.get(def_node_id) { hir_map::NodeItem(it) => { + let prev = mem::replace(&mut self.inlining, true); if glob { - let prev = mem::replace(&mut self.inlining_from_glob, true); match it.node { hir::ItemMod(ref m) => { for i in &m.item_ids { @@ -348,10 +355,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { hir::ItemEnum(..) => {} _ => { panic!("glob not mapped to a module or enum"); } } - self.inlining_from_glob = prev; } else { self.visit_item(it, renamed, om); } + self.inlining = prev; true } _ => false, @@ -365,6 +372,19 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { debug!("Visiting item {:?}", item); let name = renamed.unwrap_or(item.name); match item.node { + hir::ItemForeignMod(ref fm) => { + // If inlining we only want to include public functions. + om.foreigns.push(if self.inlining { + hir::ForeignMod { + abi: fm.abi, + items: fm.items.iter().filter(|i| i.vis == hir::Public).cloned().collect(), + } + } else { + fm.clone() + }); + } + // If we're inlining, skip private items. + _ if self.inlining && item.vis != hir::Public => {} hir::ItemExternCrate(ref p) => { let cstore = &self.cx.sess().cstore; om.extern_crates.push(ExternCrate { @@ -379,7 +399,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } hir::ItemUse(ref vpath) => { let node = vpath.node.clone(); - let node = if item.vis == hir::Public { + // If there was a private module in the current path then don't bother inlining + // anything as it will probably be stripped anyway. + let node = if item.vis == hir::Public && self.inside_public_path { let please_inline = item.attrs.iter().any(|item| { match item.meta_item_list() { Some(list) if item.check_name("doc") => { @@ -479,43 +501,41 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { }; om.traits.push(t); }, + hir::ItemImpl(unsafety, polarity, ref gen, ref tr, ref ty, ref items) => { - let i = Impl { - unsafety: unsafety, - polarity: polarity, - generics: gen.clone(), - trait_: tr.clone(), - for_: ty.clone(), - items: items.clone(), - attrs: item.attrs.clone(), - id: item.id, - whence: item.span, - vis: item.vis.clone(), - stab: self.stability(item.id), - depr: self.deprecation(item.id), - }; - // Don't duplicate impls when inlining glob imports, we'll pick - // them up regardless of where they're located. - if !self.inlining_from_glob { + // Don't duplicate impls when inlining, we'll pick them up + // regardless of where they're located. + if !self.inlining { + let i = Impl { + unsafety: unsafety, + polarity: polarity, + generics: gen.clone(), + trait_: tr.clone(), + for_: ty.clone(), + items: items.clone(), + attrs: item.attrs.clone(), + id: item.id, + whence: item.span, + vis: item.vis.clone(), + stab: self.stability(item.id), + depr: self.deprecation(item.id), + }; om.impls.push(i); } }, hir::ItemDefaultImpl(unsafety, ref trait_ref) => { - let i = DefaultImpl { - unsafety: unsafety, - trait_: trait_ref.clone(), - id: item.id, - attrs: item.attrs.clone(), - whence: item.span, - }; - // see comment above about ItemImpl - if !self.inlining_from_glob { + // See comment above about ItemImpl. + if !self.inlining { + let i = DefaultImpl { + unsafety: unsafety, + trait_: trait_ref.clone(), + id: item.id, + attrs: item.attrs.clone(), + whence: item.span, + }; om.def_traits.push(i); } } - hir::ItemForeignMod(ref fm) => { - om.foreigns.push(fm.clone()); - } } } diff --git a/src/test/rustdoc/inline_local/glob-extern-no-defaults.rs b/src/test/rustdoc/inline_local/glob-extern-no-defaults.rs new file mode 100644 index 000000000000..fd2fdd7b8d32 --- /dev/null +++ b/src/test/rustdoc/inline_local/glob-extern-no-defaults.rs @@ -0,0 +1,35 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --no-defaults + +#![crate_name = "foo"] + +mod mod1 { + extern { + pub fn public_fn(); + fn private_fn(); + } +} + +pub use mod1::*; + +// @has foo/index.html +// @has - "mod1" +// @has - "public_fn" +// @!has - "private_fn" +// @has foo/fn.public_fn.html +// @!has foo/fn.private_fn.html + +// @has foo/mod1/index.html +// @has - "public_fn" +// @has - "private_fn" +// @has foo/mod1/fn.public_fn.html +// @has foo/mod1/fn.private_fn.html diff --git a/src/test/rustdoc/inline_local/glob-extern.rs b/src/test/rustdoc/inline_local/glob-extern.rs new file mode 100644 index 000000000000..cf899d7728c9 --- /dev/null +++ b/src/test/rustdoc/inline_local/glob-extern.rs @@ -0,0 +1,31 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +mod mod1 { + extern { + pub fn public_fn(); + fn private_fn(); + } +} + +pub use mod1::*; + +// @has foo/index.html +// @!has - "mod1" +// @has - "public_fn" +// @!has - "private_fn" +// @has foo/fn.public_fn.html +// @!has foo/fn.private_fn.html + +// @!has foo/mod1/index.html +// @has foo/mod1/fn.public_fn.html +// @!has foo/mod1/fn.private_fn.html diff --git a/src/test/rustdoc/inline_local/glob-private-no-defaults.rs b/src/test/rustdoc/inline_local/glob-private-no-defaults.rs new file mode 100644 index 000000000000..420b60f2aca9 --- /dev/null +++ b/src/test/rustdoc/inline_local/glob-private-no-defaults.rs @@ -0,0 +1,58 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --no-defaults + +#![crate_name = "foo"] + +mod mod1 { + mod mod2 { + pub struct Mod2Public; + struct Mod2Private; + } + pub use self::mod2::*; + + pub struct Mod1Public; + struct Mod1Private; +} +pub use mod1::*; + +// @has foo/index.html +// @has - "mod1" +// @has - "Mod1Public" +// @!has - "Mod1Private" +// @!has - "mod2" +// @has - "Mod2Public" +// @!has - "Mod2Private" +// @has foo/struct.Mod1Public.html +// @!has foo/struct.Mod1Private.html +// @has foo/struct.Mod2Public.html +// @!has foo/struct.Mod2Private.html + +// @has foo/mod1/index.html +// @has - "mod2" +// @has - "Mod1Public" +// @has - "Mod1Private" +// @!has - "Mod2Public" +// @!has - "Mod2Private" +// @has foo/mod1/struct.Mod1Public.html +// @has foo/mod1/struct.Mod1Private.html +// @!has foo/mod1/struct.Mod2Public.html +// @!has foo/mod1/struct.Mod2Private.html + +// @has foo/mod1/mod2/index.html +// @has - "Mod2Public" +// @has - "Mod2Private" +// @has foo/mod1/mod2/struct.Mod2Public.html +// @has foo/mod1/mod2/struct.Mod2Private.html + +// @!has foo/mod2/index.html +// @!has foo/mod2/struct.Mod2Public.html +// @!has foo/mod2/struct.Mod2Private.html diff --git a/src/test/rustdoc/inline_local/glob-private.rs b/src/test/rustdoc/inline_local/glob-private.rs new file mode 100644 index 000000000000..b5e256dfdce9 --- /dev/null +++ b/src/test/rustdoc/inline_local/glob-private.rs @@ -0,0 +1,49 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +mod mod1 { + mod mod2 { + pub struct Mod2Public; + struct Mod2Private; + } + pub use self::mod2::*; + + pub struct Mod1Public; + struct Mod1Private; +} +pub use mod1::*; + +// @has foo/index.html +// @!has - "mod1" +// @has - "Mod1Public" +// @!has - "Mod1Private" +// @!has - "mod2" +// @has - "Mod2Public" +// @!has - "Mod2Private" +// @has foo/struct.Mod1Public.html +// @!has foo/struct.Mod1Private.html +// @has foo/struct.Mod2Public.html +// @!has foo/struct.Mod2Private.html + +// @!has foo/mod1/index.html +// @has foo/mod1/struct.Mod1Public.html +// @!has foo/mod1/struct.Mod1Private.html +// @!has foo/mod1/struct.Mod2Public.html +// @!has foo/mod1/struct.Mod2Private.html + +// @!has foo/mod1/mod2/index.html +// @has foo/mod1/mod2/struct.Mod2Public.html +// @!has foo/mod1/mod2/struct.Mod2Private.html + +// @!has foo/mod2/index.html +// @!has foo/mod2/struct.Mod2Public.html +// @!has foo/mod2/struct.Mod2Private.html From 7cd8a497cce5f85670fb5736e9064f22c0f4da99 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 14 Nov 2016 12:50:38 -0800 Subject: [PATCH 118/177] rustbuild: Tweak default rule inclusion If a rule is flagged with `default(true)` then the pseudo-rule `default:foo` will include that. If a rule is also flagged with `.host(true)`, however, then the rule shouldn't be included for targets that aren't in the host array. This adds a filter to ensure we don't pull in host rules for targets by accident. --- src/bootstrap/step.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 190a4cc67f92..56be2ccb235a 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -565,7 +565,8 @@ impl<'a> Rules<'a> { for dep in rule.deps.iter() { let dep = dep(&self.sbuild.name(rule.name)); if self.rules.contains_key(&dep.name) || dep.name.starts_with("default:") { - continue } + continue + } panic!("\ invalid rule dependency graph detected, was a rule added and maybe typo'd? @@ -686,8 +687,9 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? "dist" => Kind::Dist, kind => panic!("unknown kind: `{}`", kind), }; + let host = self.build.config.host.iter().any(|h| h == dep.target); let rules = self.rules.values().filter(|r| r.default); - for rule in rules.filter(|r| r.kind == kind) { + for rule in rules.filter(|r| r.kind == kind && (!r.host || host)) { self.fill(dep.name(rule.name), order, added); } } else { From af1aa1bccf8029a1db1aaddfc6b8c54ea3dff927 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Mon, 14 Nov 2016 15:51:15 -0500 Subject: [PATCH 119/177] Update top-level path doc examples to show results. --- src/libstd/path.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 281e2f17ae61..95c8af664254 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -25,11 +25,18 @@ //! //! ```rust //! use std::path::Path; +//! use std::ffi::OsStr; //! //! let path = Path::new("/tmp/foo/bar.txt"); -//! let file = path.file_name(); +//! +//! let parent = path.parent(); +//! assert_eq!(parent, Some(Path::new("/tmp/foo"))); +//! +//! let file_stem = path.file_stem(); +//! assert_eq!(file_stem, Some(OsStr::new("bar"))); +//! //! let extension = path.extension(); -//! let parent_dir = path.parent(); +//! assert_eq!(extension, Some(OsStr::new("txt"))); //! ``` //! //! To build or modify paths, use `PathBuf`: @@ -1319,13 +1326,19 @@ impl AsRef for PathBuf { /// /// ``` /// use std::path::Path; +/// use std::ffi::OsStr; /// /// let path = Path::new("/tmp/foo/bar.txt"); -/// let file = path.file_name(); -/// let extension = path.extension(); -/// let parent_dir = path.parent(); -/// ``` /// +/// let parent = path.parent(); +/// assert_eq!(parent, Some(Path::new("/tmp/foo"))); +/// +/// let file_stem = path.file_stem(); +/// assert_eq!(file_stem, Some(OsStr::new("bar"))); +/// +/// let extension = path.extension(); +/// assert_eq!(extension, Some(OsStr::new("txt"))); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Path { inner: OsStr, From 19c1a47713bfba32ded7d8c32ceb36423fe44e35 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 7 Nov 2016 13:25:06 -0500 Subject: [PATCH 120/177] remove TypeOrigin and use ObligationCause instead In general having all these different structs for "origins" is not great, since equating types can cause obligations and vice-versa. I think we should gradually collapse these things. We almost certainly also need to invest a big more energy into the `error_reporting` code to rationalize it: this PR does kind of the minimal effort in that direction. --- src/librustc/infer/combine.rs | 2 +- src/librustc/infer/error_reporting.rs | 75 ++++++-- src/librustc/infer/higher_ranked/mod.rs | 14 +- src/librustc/infer/mod.rs | 181 ++++---------------- src/librustc/infer/sub.rs | 1 + src/librustc/traits/coherence.rs | 10 +- src/librustc/traits/error_reporting.rs | 24 ++- src/librustc/traits/fulfill.rs | 2 +- src/librustc/traits/mod.rs | 30 ++++ src/librustc/traits/project.rs | 15 +- src/librustc/traits/select.rs | 29 ++-- src/librustc/traits/specialize/mod.rs | 8 +- src/librustc/traits/structural_impls.rs | 46 +++++ src/librustc_driver/test.rs | 7 +- src/librustc_mir/transform/type_check.rs | 18 +- src/librustc_typeck/check/_match.rs | 18 +- src/librustc_typeck/check/coercion.rs | 27 +-- src/librustc_typeck/check/compare_method.rs | 68 ++++---- src/librustc_typeck/check/demand.rs | 21 +-- src/librustc_typeck/check/dropck.rs | 6 +- src/librustc_typeck/check/intrinsic.rs | 6 +- src/librustc_typeck/check/method/confirm.rs | 4 +- src/librustc_typeck/check/method/probe.rs | 8 +- src/librustc_typeck/check/mod.rs | 81 +++++---- src/librustc_typeck/check/regionck.rs | 5 +- src/librustc_typeck/check/wfcheck.rs | 13 +- src/librustc_typeck/coherence/mod.rs | 10 +- src/librustc_typeck/lib.rs | 14 +- 28 files changed, 389 insertions(+), 354 deletions(-) diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 641273d2b762..5d33d6e6d2e7 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -274,7 +274,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { { let mut generalize = Generalizer { infcx: self.infcx, - span: self.trace.origin.span(), + span: self.trace.cause.span, for_vid: for_vid, make_region_vars: make_region_vars, cycle_detected: false diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index d8a7ce72f50d..58caac4034e3 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -80,8 +80,9 @@ use hir::print as pprust; use lint; use hir::def::Def; use hir::def_id::DefId; -use infer::{self, TypeOrigin}; +use infer; use middle::region; +use traits::{ObligationCause, ObligationCauseCode}; use ty::{self, TyCtxt, TypeFoldable}; use ty::{Region, ReFree}; use ty::error::TypeError; @@ -524,10 +525,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn note_error_origin(&self, err: &mut DiagnosticBuilder<'tcx>, - origin: &TypeOrigin) + cause: &ObligationCause<'tcx>) { - match origin { - &TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source { + match cause.code { + ObligationCauseCode::MatchExpressionArm { arm_span, source } => match source { hir::MatchSource::IfLetDesugar {..} => { err.span_note(arm_span, "`if let` arm with an incompatible type"); } @@ -541,7 +542,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn note_type_err(&self, diag: &mut DiagnosticBuilder<'tcx>, - origin: TypeOrigin, + cause: &ObligationCause<'tcx>, secondary_span: Option<(Span, String)>, values: Option>, terr: &TypeError<'tcx>) @@ -558,7 +559,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } }; - let span = origin.span(); + let span = cause.span; if let Some((expected, found)) = expected_found { let is_simple_error = if let &TypeError::Sorts(ref values) = terr { @@ -588,7 +589,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { diag.span_label(sp, &msg); } - self.note_error_origin(diag, &origin); + self.note_error_origin(diag, &cause); self.check_and_note_conflicting_crates(diag, terr, span); self.tcx.note_and_explain_type_err(diag, terr, span); } @@ -598,17 +599,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { terr: &TypeError<'tcx>) -> DiagnosticBuilder<'tcx> { - let span = trace.origin.span(); - let failure_str = trace.origin.as_failure_str(); - let mut diag = match trace.origin { - TypeOrigin::IfExpressionWithNoElse(_) => { + let span = trace.cause.span; + let failure_str = trace.cause.as_failure_str(); + let mut diag = match trace.cause.code { + ObligationCauseCode::IfExpressionWithNoElse => { struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str) }, _ => { struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str) }, }; - self.note_type_err(&mut diag, trace.origin, None, Some(trace.values), terr); + self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr); diag } @@ -1695,18 +1696,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if let Some((expected, found)) = self.values_str(&trace.values) { // FIXME: do we want a "the" here? err.span_note( - trace.origin.span(), + trace.cause.span, &format!("...so that {} (expected {}, found {})", - trace.origin.as_requirement_str(), expected, found)); + trace.cause.as_requirement_str(), expected, found)); } else { // FIXME: this really should be handled at some earlier stage. Our // handling of region checking when type errors are present is // *terrible*. err.span_note( - trace.origin.span(), + trace.cause.span, &format!("...so that {}", - trace.origin.as_requirement_str())); + trace.cause.as_requirement_str())); } } infer::Reborrow(span) => { @@ -1961,3 +1962,45 @@ fn name_to_dummy_lifetime(name: ast::Name) -> hir::Lifetime { span: syntax_pos::DUMMY_SP, name: name } } + +impl<'tcx> ObligationCause<'tcx> { + fn as_failure_str(&self) -> &'static str { + use traits::ObligationCauseCode::*; + match self.code { + CompareImplMethodObligation { .. } => "method not compatible with trait", + MatchExpressionArm { source, .. } => match source { + hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types", + _ => "match arms have incompatible types", + }, + IfExpression => "if and else have incompatible types", + IfExpressionWithNoElse => "if may be missing an else clause", + EquatePredicate => "equality predicate not satisfied", + MainFunctionType => "main function has wrong type", + StartFunctionType => "start function has wrong type", + IntrinsicType => "intrinsic has wrong type", + MethodReceiver => "mismatched method receiver", + _ => "mismatched types", + } + } + + fn as_requirement_str(&self) -> &'static str { + use traits::ObligationCauseCode::*; + match self.code { + CompareImplMethodObligation { .. } => "method type is compatible with trait", + ExprAssignable => "expression is assignable", + MatchExpressionArm { source, .. } => match source { + hir::MatchSource::IfLetDesugar{..} => "`if let` arms have compatible types", + _ => "match arms have compatible types", + }, + IfExpression => "if and else have compatible types", + IfExpressionWithNoElse => "if missing an else returns ()", + EquatePredicate => "equality where clause is satisfied", + MainFunctionType => "`main` function has the correct type", + StartFunctionType => "`start` function has the correct type", + IntrinsicType => "intrinsic has the correct type", + MethodReceiver => "method receiver has the correct type", + _ => "types are compatible", + } + } +} + diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 737ce8bdf681..08e522f5fd6e 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -58,7 +58,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // Start a snapshot so we can examine "all bindings that were // created as part of this type comparison". return self.infcx.commit_if_ok(|snapshot| { - let span = self.trace.origin.span(); + let span = self.trace.cause.span; // First, we instantiate each bound region in the subtype with a fresh // region variable. @@ -230,7 +230,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // created as part of this type comparison". return self.infcx.commit_if_ok(|snapshot| { // Instantiate each bound region with a fresh region variable. - let span = self.trace.origin.span(); + let span = self.trace.cause.span; let (a_with_fresh, a_map) = self.infcx.replace_late_bound_regions_with_fresh_var( span, HigherRankedType, a); @@ -247,7 +247,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // Generalize the regions appearing in result0 if possible let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot); - let span = self.trace.origin.span(); + let span = self.trace.cause.span; let result1 = fold_regions_in( self.tcx(), @@ -325,10 +325,10 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // Instantiate each bound region with a fresh region variable. let (a_with_fresh, a_map) = self.infcx.replace_late_bound_regions_with_fresh_var( - self.trace.origin.span(), HigherRankedType, a); + self.trace.cause.span, HigherRankedType, a); let (b_with_fresh, b_map) = self.infcx.replace_late_bound_regions_with_fresh_var( - self.trace.origin.span(), HigherRankedType, b); + self.trace.cause.span, HigherRankedType, b); let a_vars = var_ids(self, &a_map); let b_vars = var_ids(self, &b_map); @@ -341,7 +341,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // Generalize the regions appearing in result0 if possible let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot); - let span = self.trace.origin.span(); + let span = self.trace.cause.span; let result1 = fold_regions_in( self.tcx(), @@ -463,7 +463,7 @@ fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>, ty::ReVar(r) => { r } _ => { span_bug!( - fields.trace.origin.span(), + fields.trace.cause.span, "found non-region-vid: {:?}", r); } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 2d4b36ec1876..6ae104d79122 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -32,7 +32,7 @@ use ty::{self, Ty, TyCtxt}; use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use ty::relate::{Relate, RelateResult, TypeRelation}; -use traits::{self, PredicateObligations, Reveal}; +use traits::{self, ObligationCause, PredicateObligations, Reveal}; use rustc_data_structures::unify::{self, UnificationTable}; use std::cell::{Cell, RefCell, Ref, RefMut}; use std::fmt; @@ -173,89 +173,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// region that each late-bound region was replaced with. pub type SkolemizationMap<'tcx> = FxHashMap; -/// Why did we require that the two types be related? -/// -/// See `error_reporting.rs` for more details -#[derive(Clone, Copy, Debug)] -pub enum TypeOrigin { - // Not yet categorized in a better way - Misc(Span), - - // Checking that method of impl is compatible with trait - MethodCompatCheck(Span), - - // Checking that this expression can be assigned where it needs to be - ExprAssignable(Span), - - // Relating trait type parameters to those found in impl etc - RelateOutputImplTypes(Span), - - // Computing common supertype in the arms of a match expression - MatchExpressionArm(Span, Span, hir::MatchSource), - - // Computing common supertype in an if expression - IfExpression(Span), - - // Computing common supertype of an if expression with no else counter-part - IfExpressionWithNoElse(Span), - - // `where a == b` - EquatePredicate(Span), - - // `main` has wrong type - MainFunctionType(Span), - - // `start` has wrong type - StartFunctionType(Span), - - // intrinsic has wrong type - IntrinsicType(Span), - - // method receiver - MethodReceiver(Span), -} - -impl TypeOrigin { - fn as_failure_str(&self) -> &'static str { - match self { - &TypeOrigin::Misc(_) | - &TypeOrigin::RelateOutputImplTypes(_) | - &TypeOrigin::ExprAssignable(_) => "mismatched types", - &TypeOrigin::MethodCompatCheck(_) => "method not compatible with trait", - &TypeOrigin::MatchExpressionArm(.., source) => match source { - hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types", - _ => "match arms have incompatible types", - }, - &TypeOrigin::IfExpression(_) => "if and else have incompatible types", - &TypeOrigin::IfExpressionWithNoElse(_) => "if may be missing an else clause", - &TypeOrigin::EquatePredicate(_) => "equality predicate not satisfied", - &TypeOrigin::MainFunctionType(_) => "main function has wrong type", - &TypeOrigin::StartFunctionType(_) => "start function has wrong type", - &TypeOrigin::IntrinsicType(_) => "intrinsic has wrong type", - &TypeOrigin::MethodReceiver(_) => "mismatched method receiver", - } - } - - fn as_requirement_str(&self) -> &'static str { - match self { - &TypeOrigin::Misc(_) => "types are compatible", - &TypeOrigin::MethodCompatCheck(_) => "method type is compatible with trait", - &TypeOrigin::ExprAssignable(_) => "expression is assignable", - &TypeOrigin::RelateOutputImplTypes(_) => { - "trait type parameters matches those specified on the impl" - } - &TypeOrigin::MatchExpressionArm(..) => "match arms have compatible types", - &TypeOrigin::IfExpression(_) => "if and else have compatible types", - &TypeOrigin::IfExpressionWithNoElse(_) => "if missing an else returns ()", - &TypeOrigin::EquatePredicate(_) => "equality where clause is satisfied", - &TypeOrigin::MainFunctionType(_) => "`main` function has the correct type", - &TypeOrigin::StartFunctionType(_) => "`start` function has the correct type", - &TypeOrigin::IntrinsicType(_) => "intrinsic has the correct type", - &TypeOrigin::MethodReceiver(_) => "method receiver has the correct type", - } - } -} - /// See `error_reporting.rs` for more details #[derive(Clone, Debug)] pub enum ValuePairs<'tcx> { @@ -270,7 +187,7 @@ pub enum ValuePairs<'tcx> { /// See `error_reporting.rs` for more details. #[derive(Clone)] pub struct TypeTrace<'tcx> { - origin: TypeOrigin, + cause: ObligationCause<'tcx>, values: ValuePairs<'tcx>, } @@ -1006,14 +923,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn sub_types(&self, a_is_expected: bool, - origin: TypeOrigin, + cause: &ObligationCause<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, ()> { debug!("sub_types({:?} <: {:?})", a, b); self.commit_if_ok(|_| { - let trace = TypeTrace::types(origin, a_is_expected, a, b); + let trace = TypeTrace::types(cause, a_is_expected, a, b); self.sub(a_is_expected, trace, &a, &b).map(|ok| ok.unit()) }) } @@ -1024,7 +941,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> UnitResult<'tcx> { self.probe(|_| { - let origin = TypeOrigin::Misc(syntax_pos::DUMMY_SP); + let origin = &ObligationCause::dummy(); let trace = TypeTrace::types(origin, true, a, b); self.sub(true, trace, &a, &b).map(|InferOk { obligations, .. }| { // FIXME(#32730) propagate obligations @@ -1035,20 +952,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn eq_types(&self, a_is_expected: bool, - origin: TypeOrigin, + cause: &ObligationCause<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, ()> { self.commit_if_ok(|_| { - let trace = TypeTrace::types(origin, a_is_expected, a, b); + let trace = TypeTrace::types(cause, a_is_expected, a, b); self.equate(a_is_expected, trace, &a, &b).map(|ok| ok.unit()) }) } pub fn eq_trait_refs(&self, a_is_expected: bool, - origin: TypeOrigin, + cause: &ObligationCause<'tcx>, a: ty::TraitRef<'tcx>, b: ty::TraitRef<'tcx>) -> InferResult<'tcx, ()> @@ -1056,7 +973,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { debug!("eq_trait_refs({:?} = {:?})", a, b); self.commit_if_ok(|_| { let trace = TypeTrace { - origin: origin, + cause: cause.clone(), values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)) }; self.equate(a_is_expected, trace, &a, &b).map(|ok| ok.unit()) @@ -1065,22 +982,22 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn eq_impl_headers(&self, a_is_expected: bool, - origin: TypeOrigin, + cause: &ObligationCause<'tcx>, a: &ty::ImplHeader<'tcx>, b: &ty::ImplHeader<'tcx>) -> InferResult<'tcx, ()> { debug!("eq_impl_header({:?} = {:?})", a, b); match (a.trait_ref, b.trait_ref) { - (Some(a_ref), Some(b_ref)) => self.eq_trait_refs(a_is_expected, origin, a_ref, b_ref), - (None, None) => self.eq_types(a_is_expected, origin, a.self_ty, b.self_ty), + (Some(a_ref), Some(b_ref)) => self.eq_trait_refs(a_is_expected, cause, a_ref, b_ref), + (None, None) => self.eq_types(a_is_expected, cause, a.self_ty, b.self_ty), _ => bug!("mk_eq_impl_headers given mismatched impl kinds"), } } pub fn sub_poly_trait_refs(&self, a_is_expected: bool, - origin: TypeOrigin, + cause: ObligationCause<'tcx>, a: ty::PolyTraitRef<'tcx>, b: ty::PolyTraitRef<'tcx>) -> InferResult<'tcx, ()> @@ -1088,7 +1005,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { debug!("sub_poly_trait_refs({:?} <: {:?})", a, b); self.commit_if_ok(|_| { let trace = TypeTrace { - origin: origin, + cause: cause, values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b)) }; self.sub(a_is_expected, trace, &a, &b).map(|ok| ok.unit()) @@ -1104,16 +1021,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn equality_predicate(&self, - span: Span, + cause: &ObligationCause<'tcx>, predicate: &ty::PolyEquatePredicate<'tcx>) -> InferResult<'tcx, ()> { self.commit_if_ok(|snapshot| { let (ty::EquatePredicate(a, b), skol_map) = self.skolemize_late_bound_regions(predicate, snapshot); - let origin = TypeOrigin::EquatePredicate(span); - let eqty_ok = self.eq_types(false, origin, a, b)?; - self.leak_check(false, span, &skol_map, snapshot)?; + let cause_span = cause.span; + let eqty_ok = self.eq_types(false, cause, a, b)?; + self.leak_check(false, cause_span, &skol_map, snapshot)?; self.pop_skolemized(skol_map, snapshot); Ok(eqty_ok.unit()) }) @@ -1443,26 +1360,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn report_mismatched_types(&self, - origin: TypeOrigin, + cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, err: TypeError<'tcx>) { - let trace = TypeTrace { - origin: origin, - values: Types(ExpectedFound { - expected: expected, - found: actual - }) - }; + let trace = TypeTrace::types(cause, true, expected, actual); self.report_and_explain_type_error(trace, &err).emit(); } pub fn report_conflicting_default_types(&self, span: Span, + body_id: ast::NodeId, expected: type_variable::Default<'tcx>, actual: type_variable::Default<'tcx>) { let trace = TypeTrace { - origin: TypeOrigin::Misc(span), + cause: ObligationCause::misc(span, body_id), values: Types(ExpectedFound { expected: expected.ty, found: actual.ty @@ -1507,15 +1419,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// See `higher_ranked_match` in `higher_ranked/mod.rs` for more /// details. pub fn match_poly_projection_predicate(&self, - origin: TypeOrigin, + cause: ObligationCause<'tcx>, match_a: ty::PolyProjectionPredicate<'tcx>, match_b: ty::TraitRef<'tcx>) -> InferResult<'tcx, HrMatchResult>> { - let span = origin.span(); + let span = cause.span; let match_trait_ref = match_a.skip_binder().projection_ty.trait_ref; let trace = TypeTrace { - origin: origin, + cause: cause, values: TraitRefs(ExpectedFound::new(true, match_trait_ref, match_b)) }; @@ -1664,23 +1576,23 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> { pub fn span(&self) -> Span { - self.origin.span() + self.cause.span } - pub fn types(origin: TypeOrigin, + pub fn types(cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Ty<'tcx>, b: Ty<'tcx>) -> TypeTrace<'tcx> { TypeTrace { - origin: origin, + cause: cause.clone(), values: Types(ExpectedFound::new(a_is_expected, a, b)) } } pub fn dummy(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> TypeTrace<'tcx> { TypeTrace { - origin: TypeOrigin::Misc(syntax_pos::DUMMY_SP), + cause: ObligationCause::dummy(), values: Types(ExpectedFound { expected: tcx.types.err, found: tcx.types.err, @@ -1691,26 +1603,7 @@ impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> { impl<'tcx> fmt::Debug for TypeTrace<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "TypeTrace({:?})", self.origin) - } -} - -impl TypeOrigin { - pub fn span(&self) -> Span { - match *self { - TypeOrigin::MethodCompatCheck(span) => span, - TypeOrigin::ExprAssignable(span) => span, - TypeOrigin::Misc(span) => span, - TypeOrigin::RelateOutputImplTypes(span) => span, - TypeOrigin::MatchExpressionArm(match_span, ..) => match_span, - TypeOrigin::IfExpression(span) => span, - TypeOrigin::IfExpressionWithNoElse(span) => span, - TypeOrigin::EquatePredicate(span) => span, - TypeOrigin::MainFunctionType(span) => span, - TypeOrigin::StartFunctionType(span) => span, - TypeOrigin::IntrinsicType(span) => span, - TypeOrigin::MethodReceiver(span) => span, - } + write!(f, "TypeTrace({:?})", self.cause) } } @@ -1787,16 +1680,6 @@ impl RegionVariableOrigin { } } -impl<'tcx> TypeFoldable<'tcx> for TypeOrigin { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self { - self.clone() - } - - fn super_visit_with>(&self, _visitor: &mut V) -> bool { - false - } -} - impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match *self { @@ -1824,12 +1707,12 @@ impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> { impl<'tcx> TypeFoldable<'tcx> for TypeTrace<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { TypeTrace { - origin: self.origin.fold_with(folder), + cause: self.cause.fold_with(folder), values: self.values.fold_with(folder) } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.origin.visit_with(visitor) || self.values.visit_with(visitor) + self.cause.visit_with(visitor) || self.values.visit_with(visitor) } } diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index 159de2faced5..5664777772f7 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -111,6 +111,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> -> RelateResult<'tcx, &'tcx ty::Region> { debug!("{}.regions({:?}, {:?}) self.cause={:?}", self.tag(), a, b, self.fields.cause); + // FIXME -- we have more fine-grained information available // from the "cause" field, we could perhaps give more tailored // error messages. diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 1ccd048cedca..2e06e83f8489 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -14,8 +14,8 @@ use super::{SelectionContext, Obligation, ObligationCause}; use hir::def_id::{DefId, LOCAL_CRATE}; use ty::{self, Ty, TyCtxt}; -use infer::{InferCtxt, InferOk, TypeOrigin}; -use syntax_pos::DUMMY_SP; + +use infer::{InferCtxt, InferOk}; #[derive(Copy, Clone)] struct InferIsLocal(bool); @@ -55,8 +55,10 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, debug!("overlap: b_impl_header={:?}", b_impl_header); // Do `a` and `b` unify? If not, no overlap. - match selcx.infcx().eq_impl_headers(true, TypeOrigin::Misc(DUMMY_SP), &a_impl_header, - &b_impl_header) { + match selcx.infcx().eq_impl_headers(true, + &ObligationCause::dummy(), + &a_impl_header, + &b_impl_header) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 7e70fdb92e68..e0a397ad28fb 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -26,7 +26,7 @@ use super::{ use fmt_macros::{Parser, Piece, Position}; use hir::def_id::DefId; -use infer::{self, InferCtxt, TypeOrigin}; +use infer::{self, InferCtxt}; use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::error::ExpectedFound; @@ -100,7 +100,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } self.probe(|_| { - let origin = TypeOrigin::Misc(obligation.cause.span); let err_buf; let mut err = &error.err; let mut values = None; @@ -121,9 +120,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { obligation.cause.clone(), 0 ); - let origin = TypeOrigin::Misc(obligation.cause.span); if let Err(error) = self.eq_types( - false, origin, + false, &obligation.cause, data.ty, normalized.value ) { values = Some(infer::ValuePairs::Types(ExpectedFound { @@ -136,10 +134,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } let mut diag = struct_span_err!( - self.tcx.sess, origin.span(), E0271, + self.tcx.sess, obligation.cause.span, E0271, "type mismatch resolving `{}`", predicate ); - self.note_type_err(&mut diag, origin, None, values, err); + self.note_type_err(&mut diag, &obligation.cause, None, values, err); self.note_obligation_cause(&mut diag, obligation); diag.emit(); }); @@ -529,7 +527,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::Predicate::Equate(ref predicate) => { let predicate = self.resolve_type_vars_if_possible(predicate); - let err = self.equality_predicate(span, + let err = self.equality_predicate(&obligation.cause, &predicate).err().unwrap(); struct_span_err!(self.tcx.sess, span, E0278, "the requirement `{}` is not satisfied (`{}`)", @@ -851,7 +849,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { let tcx = self.tcx; match *cause_code { - ObligationCauseCode::MiscObligation => { } + ObligationCauseCode::ExprAssignable | + ObligationCauseCode::MatchExpressionArm { .. } | + ObligationCauseCode::IfExpression | + ObligationCauseCode::IfExpressionWithNoElse | + ObligationCauseCode::EquatePredicate | + ObligationCauseCode::MainFunctionType | + ObligationCauseCode::StartFunctionType | + ObligationCauseCode::IntrinsicType | + ObligationCauseCode::MethodReceiver | + ObligationCauseCode::MiscObligation => { + } ObligationCauseCode::SliceOrArrayElem => { err.note("slice and array elements must have `Sized` type"); } diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index b4592a03bcd1..535156e61e94 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -519,7 +519,7 @@ fn process_predicate<'a, 'gcx, 'tcx>( } ty::Predicate::Equate(ref binder) => { - match selcx.infcx().equality_predicate(obligation.cause.span, binder) { + match selcx.infcx().equality_predicate(&obligation.cause, binder) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index eba24bfd2c9e..a5fdaed97125 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -15,6 +15,7 @@ pub use self::FulfillmentErrorCode::*; pub use self::Vtable::*; pub use self::ObligationCauseCode::*; +use hir; use hir::def_id::DefId; use middle::free_region::FreeRegionMap; use ty::subst::Substs; @@ -148,6 +149,35 @@ pub enum ObligationCauseCode<'tcx> { trait_item_def_id: DefId, lint_id: Option, }, + + // Checking that this expression can be assigned where it needs to be + // FIXME(eddyb) #11161 is the original Expr required? + ExprAssignable, + + // Computing common supertype in the arms of a match expression + MatchExpressionArm { arm_span: Span, + source: hir::MatchSource }, + + // Computing common supertype in an if expression + IfExpression, + + // Computing common supertype of an if expression with no else counter-part + IfExpressionWithNoElse, + + // `where a == b` + EquatePredicate, + + // `main` has wrong type + MainFunctionType, + + // `start` has wrong type + StartFunctionType, + + // intrinsic has wrong type + IntrinsicType, + + // method receiver + MethodReceiver, } #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index f1b69feb545e..6ab7a1fbfb8a 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -24,7 +24,7 @@ use super::VtableImplData; use super::util; use hir::def_id::DefId; -use infer::{InferOk, TypeOrigin}; +use infer::InferOk; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; use syntax::parse::token; use syntax::ast; @@ -209,8 +209,7 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>( obligations); let infcx = selcx.infcx(); - let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); - match infcx.eq_types(true, origin, normalized_ty, obligation.predicate.ty) { + match infcx.eq_types(true, &obligation.cause, normalized_ty, obligation.predicate.ty) { Ok(InferOk { obligations: inferred_obligations, .. }) => { // FIXME(#32730) once obligations are generated in inference, drop this assertion assert!(inferred_obligations.is_empty()); @@ -840,13 +839,12 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>( let same_name = data.item_name() == obligation.predicate.item_name; let is_match = same_name && infcx.probe(|_| { - let origin = TypeOrigin::Misc(obligation.cause.span); let data_poly_trait_ref = data.to_poly_trait_ref(); let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); infcx.sub_poly_trait_refs(false, - origin, + obligation.cause.clone(), data_poly_trait_ref, obligation_poly_trait_ref) // FIXME(#32730) once obligations are propagated from unification in @@ -1153,12 +1151,11 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>( // select those with a relevant trait-ref let mut env_predicates = env_predicates.filter(|data| { - let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); let data_poly_trait_ref = data.to_poly_trait_ref(); let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); selcx.infcx().probe(|_| { selcx.infcx().sub_poly_trait_refs(false, - origin, + obligation.cause.clone(), data_poly_trait_ref, obligation_poly_trait_ref).is_ok() }) @@ -1265,9 +1262,9 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>( -> Progress<'tcx> { let infcx = selcx.infcx(); - let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); + let cause = obligation.cause.clone(); let trait_ref = obligation.predicate.trait_ref; - match infcx.match_poly_projection_predicate(origin, poly_projection, trait_ref) { + match infcx.match_poly_projection_predicate(cause, poly_projection, trait_ref) { Ok(InferOk { value: ty_match, obligations }) => { // FIXME(#32730) once obligations are generated in inference, drop this assertion assert!(obligations.is_empty()); diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 6f6534cb2064..6c75fb6a246e 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -35,7 +35,7 @@ use super::util; use hir::def_id::DefId; use infer; -use infer::{InferCtxt, InferOk, TypeFreshener, TypeOrigin}; +use infer::{InferCtxt, InferOk, TypeFreshener}; use ty::subst::{Kind, Subst, Substs}; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use traits; @@ -521,7 +521,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::Predicate::Equate(ref p) => { // does this code ever run? - match self.infcx.equality_predicate(obligation.cause.span, p) { + match self.infcx.equality_predicate(&obligation.cause, p) { Ok(InferOk { obligations, .. }) => { self.inferred_obligations.extend(obligations); EvaluatedToOk @@ -1247,9 +1247,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { -> bool { assert!(!skol_trait_ref.has_escaping_regions()); - let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); + let cause = obligation.cause.clone(); match self.infcx.sub_poly_trait_refs(false, - origin, + cause, trait_bound.clone(), ty::Binder(skol_trait_ref.clone())) { Ok(InferOk { obligations, .. }) => { @@ -2439,16 +2439,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// selection of the impl. Therefore, if there is a mismatch, we /// report an error to the user. fn confirm_poly_trait_refs(&mut self, - obligation_cause: ObligationCause, + obligation_cause: ObligationCause<'tcx>, obligation_trait_ref: ty::PolyTraitRef<'tcx>, expected_trait_ref: ty::PolyTraitRef<'tcx>) -> Result<(), SelectionError<'tcx>> { - let origin = TypeOrigin::RelateOutputImplTypes(obligation_cause.span); - let obligation_trait_ref = obligation_trait_ref.clone(); self.infcx.sub_poly_trait_refs(false, - origin, + obligation_cause.clone(), expected_trait_ref.clone(), obligation_trait_ref.clone()) .map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations)) @@ -2482,9 +2480,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { builtin_bounds: data_b.builtin_bounds, projection_bounds: data_a.projection_bounds.clone(), }); - let origin = TypeOrigin::Misc(obligation.cause.span); let InferOk { obligations, .. } = - self.infcx.sub_types(false, origin, new_trait, target) + self.infcx.sub_types(false, &obligation.cause, new_trait, target) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); @@ -2553,9 +2550,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // [T; n] -> [T]. (&ty::TyArray(a, _), &ty::TySlice(b)) => { - let origin = TypeOrigin::Misc(obligation.cause.span); let InferOk { obligations, .. } = - self.infcx.sub_types(false, origin, a, b) + self.infcx.sub_types(false, &obligation.cause, a, b) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); } @@ -2617,9 +2613,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } }); let new_struct = tcx.mk_adt(def, tcx.mk_substs(params)); - let origin = TypeOrigin::Misc(obligation.cause.span); let InferOk { obligations, .. } = - self.infcx.sub_types(false, origin, new_struct, target) + self.infcx.sub_types(false, &obligation.cause, new_struct, target) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); @@ -2705,10 +2700,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { impl_trait_ref, skol_obligation_trait_ref); - let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); let InferOk { obligations, .. } = self.infcx.eq_trait_refs(false, - origin, + &obligation.cause, impl_trait_ref.value.clone(), skol_obligation_trait_ref) .map_err(|e| { @@ -2780,9 +2774,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation, poly_trait_ref); - let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); self.infcx.sub_poly_trait_refs(false, - origin, + obligation.cause.clone(), poly_trait_ref, obligation.predicate.to_poly_trait_ref()) .map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations)) diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 91c40a5cc851..870494363c85 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -22,7 +22,7 @@ use super::util::impl_trait_ref_and_oblig; use rustc_data_structures::fx::FxHashMap; use hir::def_id::DefId; -use infer::{InferCtxt, InferOk, TypeOrigin}; +use infer::{InferCtxt, InferOk}; use middle::region; use ty::subst::{Subst, Substs}; use traits::{self, Reveal, ObligationCause}; @@ -223,8 +223,10 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, target_substs); // do the impls unify? If not, no specialization. - match infcx.eq_trait_refs(true, TypeOrigin::Misc(DUMMY_SP), source_trait_ref, - target_trait_ref) { + match infcx.eq_trait_refs(true, + &ObligationCause::dummy(), + source_trait_ref, + target_trait_ref) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()) diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index d33e8b5675f5..d03ba5b0a31f 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -213,6 +213,34 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { lint_id: lint_id, }) } + super::ExprAssignable => { + Some(super::ExprAssignable) + } + super::MatchExpressionArm { arm_span, source } => { + Some(super::MatchExpressionArm { arm_span: arm_span, + source: source }) + } + super::IfExpression => { + Some(super::IfExpression) + } + super::IfExpressionWithNoElse => { + Some(super::IfExpressionWithNoElse) + } + super::EquatePredicate => { + Some(super::EquatePredicate) + } + super::MainFunctionType => { + Some(super::MainFunctionType) + } + super::StartFunctionType => { + Some(super::StartFunctionType) + } + super::IntrinsicType => { + Some(super::IntrinsicType) + } + super::MethodReceiver => { + Some(super::MethodReceiver) + } } } } @@ -461,6 +489,15 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> { impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match *self { + super::ExprAssignable | + super::MatchExpressionArm { arm_span: _, source: _ } | + super::IfExpression | + super::IfExpressionWithNoElse | + super::EquatePredicate | + super::MainFunctionType | + super::StartFunctionType | + super::IntrinsicType | + super::MethodReceiver | super::MiscObligation | super::SliceOrArrayElem | super::TupleElem | @@ -497,6 +534,15 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { fn super_visit_with>(&self, visitor: &mut V) -> bool { match *self { + super::ExprAssignable | + super::MatchExpressionArm { arm_span: _, source: _ } | + super::IfExpression | + super::IfExpressionWithNoElse | + super::EquatePredicate | + super::MainFunctionType | + super::StartFunctionType | + super::IntrinsicType | + super::MethodReceiver | super::MiscObligation | super::SliceOrArrayElem | super::TupleElem | diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 8dc21550148c..782c74c8c78c 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -21,9 +21,9 @@ use rustc::middle::region::CodeExtentData; use rustc::middle::resolve_lifetime; use rustc::middle::stability; use rustc::ty::subst::{Kind, Subst}; -use rustc::traits::Reveal; +use rustc::traits::{ObligationCause, Reveal}; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc::infer::{self, InferOk, InferResult, TypeOrigin}; +use rustc::infer::{self, InferOk, InferResult}; use rustc_metadata::cstore::CStore; use rustc::hir::map as hir_map; use rustc::session::{self, config}; @@ -36,7 +36,6 @@ use errors::emitter::Emitter; use errors::{Level, DiagnosticBuilder}; use syntax::parse::token; use syntax::feature_gate::UnstableFeatures; -use syntax_pos::DUMMY_SP; use rustc::hir; @@ -245,7 +244,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { } pub fn make_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - match self.infcx.sub_types(true, TypeOrigin::Misc(DUMMY_SP), a, b) { + match self.infcx.sub_types(true, &ObligationCause::dummy(), a, b) { Ok(_) => true, Err(ref e) => panic!("Encountered error: {}", e), } diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 79bb14b7336c..78912f607faa 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -306,22 +306,28 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, fulfillment_cx: traits::FulfillmentContext<'tcx>, - last_span: Span + last_span: Span, + body_id: ast::NodeId, } impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { - fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self { + fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, body_id: ast::NodeId) -> Self { TypeChecker { infcx: infcx, fulfillment_cx: traits::FulfillmentContext::new(), - last_span: DUMMY_SP + last_span: DUMMY_SP, + body_id: body_id, } } + fn misc(&self, span: Span) -> traits::ObligationCause<'tcx> { + traits::ObligationCause::misc(span, self.body_id) + } + fn sub_types(&self, span: Span, sup: Ty<'tcx>, sub: Ty<'tcx>) -> infer::UnitResult<'tcx> { - self.infcx.sub_types(false, infer::TypeOrigin::Misc(span), sup, sub) + self.infcx.sub_types(false, &self.misc(span), sup, sub) // FIXME(#32730) propagate obligations .map(|InferOk { obligations, .. }| assert!(obligations.is_empty())) } @@ -329,7 +335,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fn eq_types(&self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>) -> infer::UnitResult<'tcx> { - self.infcx.eq_types(false, infer::TypeOrigin::Misc(span), a, b) + self.infcx.eq_types(false, &self.misc(span), a, b) // FIXME(#32730) propagate obligations .map(|InferOk { obligations, .. }| assert!(obligations.is_empty())) } @@ -715,7 +721,7 @@ impl<'tcx> MirPass<'tcx> for TypeckMir { } let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id()); tcx.infer_ctxt(None, Some(param_env), Reveal::NotSpecializable).enter(|infcx| { - let mut checker = TypeChecker::new(&infcx); + let mut checker = TypeChecker::new(&infcx, src.item_id()); { let mut verifier = TypeVerifier::new(&mut checker, mir); verifier.visit_mir(mir); diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index ca630624cdb3..d57a27ddc761 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -11,7 +11,8 @@ use rustc::hir::{self, PatKind}; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; -use rustc::infer::{self, InferOk, TypeOrigin}; +use rustc::infer::{self, InferOk}; +use rustc::traits::ObligationCauseCode; use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference}; use check::{FnCtxt, Expectation, Diverges}; use util::nodemap::FxHashMap; @@ -450,14 +451,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => false }; - let origin = if is_if_let_fallback { - TypeOrigin::IfExpressionWithNoElse(expr.span) + let cause = if is_if_let_fallback { + self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse) } else { - TypeOrigin::MatchExpressionArm(expr.span, arm.body.span, match_src) + self.cause(expr.span, ObligationCauseCode::MatchExpressionArm { + arm_span: arm.body.span, + source: match_src + }) }; let result = if is_if_let_fallback { - self.eq_types(true, origin, arm_ty, result_ty) + self.eq_types(true, &cause, arm_ty, result_ty) .map(|InferOk { obligations, .. }| { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); @@ -468,7 +472,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.try_coerce(&arm.body, arm_ty, coerce_first) } else { let prev_arms = || arms[..i].iter().map(|arm| &*arm.body); - self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body, arm_ty) + self.try_find_coercion_lub(&cause, prev_arms, result_ty, &arm.body, arm_ty) }; result_ty = match result { @@ -479,7 +483,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { (result_ty, arm_ty) }; - self.report_mismatched_types(origin, expected, found, e); + self.report_mismatched_types(&cause, expected, found, e); self.tcx.types.err } }; diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 16493412d690..7a7ea760c038 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -63,8 +63,8 @@ use check::FnCtxt; use rustc::hir; -use rustc::infer::{Coercion, InferOk, TypeOrigin, TypeTrace}; -use rustc::traits::{self, ObligationCause}; +use rustc::infer::{Coercion, InferOk, TypeTrace}; +use rustc::traits::{self, ObligationCause, ObligationCauseCode}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty}; use rustc::ty::fold::TypeFoldable; @@ -78,7 +78,7 @@ use std::ops::Deref; struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - origin: TypeOrigin, + cause: ObligationCause<'tcx>, use_lub: bool, unsizing_obligations: RefCell>>, } @@ -104,10 +104,10 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, } impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { - fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, origin: TypeOrigin) -> Self { + fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, cause: ObligationCause<'tcx>) -> Self { Coerce { fcx: fcx, - origin: origin, + cause: cause, use_lub: false, unsizing_obligations: RefCell::new(vec![]), } @@ -115,7 +115,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { self.commit_if_ok(|_| { - let trace = TypeTrace::types(self.origin, false, a, b); + let trace = TypeTrace::types(&self.cause, false, a, b); if self.use_lub { self.lub(false, trace, &a, &b) .map(|InferOk { value, obligations }| { @@ -238,7 +238,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { _ => return self.unify_and_identity(a, b), }; - let span = self.origin.span(); + let span = self.cause.span; let mut first_error = None; let mut r_borrow_var = None; @@ -430,7 +430,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { (&ty::TyRef(_, mt_a), &ty::TyRef(_, mt_b)) => { coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?; - let coercion = Coercion(self.origin.span()); + let coercion = Coercion(self.cause.span); let r_borrow = self.next_region_var(coercion); (mt_a.ty, Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl))) } @@ -449,7 +449,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let mut leftover_predicates = vec![]; // Create an obligation for `Source: CoerceUnsized`. - let cause = ObligationCause::misc(self.origin.span(), self.body_id); + let cause = ObligationCause::misc(self.cause.span, self.body_id); queue.push_back(self.tcx .predicate_for_trait_def(cause, coerce_unsized_did, 0, source, &[target])); @@ -635,7 +635,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let source = self.resolve_type_vars_with_obligations(expr_ty); debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); - let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span)); + let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable); + let mut coerce = Coerce::new(self, cause); self.commit_if_ok(|_| { let adjustment = apply(&mut coerce, &|| Some(expr), source, target)?; if !adjustment.is_identity() { @@ -655,7 +656,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// tries to unify the types, potentially inserting coercions on any of the /// provided expressions and returns their LUB (aka "common supertype"). pub fn try_find_coercion_lub<'b, E, I>(&self, - origin: TypeOrigin, + cause: &ObligationCause<'tcx>, exprs: E, prev_ty: Ty<'tcx>, new: &'b hir::Expr, @@ -669,7 +670,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let new_ty = self.resolve_type_vars_with_obligations(new_ty); debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty); - let trace = TypeTrace::types(origin, true, prev_ty, new_ty); + let trace = TypeTrace::types(cause, true, prev_ty, new_ty); // Special-case that coercion alone cannot handle: // Two function item types of differing IDs or Substs. @@ -715,7 +716,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => {} } - let mut coerce = Coerce::new(self, origin); + let mut coerce = Coerce::new(self, cause.clone()); coerce.use_lub = true; // First try to coerce the new expression to the type of the previous ones, diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 54a0ef071ce4..075567c79492 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -9,10 +9,10 @@ // except according to those terms. use rustc::hir; -use rustc::infer::{self, InferOk, TypeOrigin}; +use rustc::infer::{self, InferOk}; use rustc::middle::free_region::FreeRegionMap; use rustc::ty; -use rustc::traits::{self, Reveal}; +use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use rustc::ty::error::{ExpectedFound, TypeError}; use rustc::ty::subst::{Subst, Substs}; use rustc::hir::{ImplItemKind, TraitItem_, Ty_}; @@ -95,6 +95,17 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let trait_to_impl_substs = impl_trait_ref.substs; + let cause = ObligationCause { + span: impl_m_span, + body_id: impl_m_body_id, + code: ObligationCauseCode::CompareImplMethodObligation { + item_name: impl_m.name, + impl_item_def_id: impl_m.def_id, + trait_item_def_id: trait_m.def_id, + lint_id: if !old_broken_mode { Some(impl_m_body_id) } else { None }, + }, + }; + // This code is best explained by example. Consider a trait: // // trait Trait<'t,T> { @@ -235,20 +246,9 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let traits::Normalized { value: predicate, .. } = traits::normalize(&mut selcx, normalize_cause.clone(), &predicate); - let cause = traits::ObligationCause { - span: impl_m_span, - body_id: impl_m_body_id, - code: traits::ObligationCauseCode::CompareImplMethodObligation { - item_name: impl_m.name, - impl_item_def_id: impl_m.def_id, - trait_item_def_id: trait_m.def_id, - lint_id: if !old_broken_mode { Some(impl_m_body_id) } else { None }, - }, - }; - fulfillment_cx.borrow_mut().register_predicate_obligation( &infcx, - traits::Obligation::new(cause, predicate)); + traits::Obligation::new(cause.clone(), predicate)); } // We now need to check that the signature of the impl method is @@ -266,7 +266,6 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Compute skolemized form of impl and trait method tys. let tcx = infcx.tcx; - let origin = TypeOrigin::MethodCompatCheck(impl_m_span); let m_fty = |method: &ty::AssociatedItem| { match tcx.item_type(method.def_id).sty { @@ -315,7 +314,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("compare_impl_method: trait_fty={:?}", trait_fty); - let sub_result = infcx.sub_types(false, origin, impl_fty, trait_fty) + let sub_result = infcx.sub_types(false, &cause, impl_fty, trait_fty) .map(|InferOk { obligations, .. }| { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); @@ -328,22 +327,25 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let (impl_err_span, trait_err_span) = extract_spans_for_error_reporting(&infcx, &terr, - origin, + &cause, impl_m, impl_sig, trait_m, trait_sig); - let origin = TypeOrigin::MethodCompatCheck(impl_err_span); + let cause = ObligationCause { + span: impl_err_span, + ..cause.clone() + }; let mut diag = struct_span_err!(tcx.sess, - origin.span(), + cause.span, E0053, "method `{}` has an incompatible type for trait", trait_m.name); infcx.note_type_err(&mut diag, - origin, + &cause, trait_err_span.map(|sp| (sp, format!("type in trait"))), Some(infer::ValuePairs::Types(ExpectedFound { expected: trait_fty, @@ -429,7 +431,7 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, terr: &TypeError, - origin: TypeOrigin, + cause: &ObligationCause<'tcx>, impl_m: &ty::AssociatedItem, impl_sig: ty::FnSig<'tcx>, trait_m: &ty::AssociatedItem, @@ -478,9 +480,9 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a } } }) - .unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id))) + .unwrap_or((cause.span, tcx.map.span_if_local(trait_m.def_id))) } else { - (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + (cause.span, tcx.map.span_if_local(trait_m.def_id)) } } TypeError::Sorts(ExpectedFound { .. }) => { @@ -499,25 +501,25 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a .zip(impl_m_iter) .zip(trait_m_iter) .filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| { - match infcx.sub_types(true, origin, trait_arg_ty, impl_arg_ty) { + match infcx.sub_types(true, &cause, trait_arg_ty, impl_arg_ty) { Ok(_) => None, Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span))), } }) .next() .unwrap_or_else(|| { - if infcx.sub_types(false, origin, impl_sig.output, trait_sig.output) + if infcx.sub_types(false, &cause, impl_sig.output, trait_sig.output) .is_err() { (impl_m_output.span(), Some(trait_m_output.span())) } else { - (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + (cause.span, tcx.map.span_if_local(trait_m.def_id)) } }) } else { - (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + (cause.span, tcx.map.span_if_local(trait_m.def_id)) } } - _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id)), + _ => (cause.span, tcx.map.span_if_local(trait_m.def_id)), } } @@ -787,7 +789,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Compute skolemized form of impl and trait const tys. let impl_ty = tcx.item_type(impl_c.def_id).subst(tcx, impl_to_skol_substs); let trait_ty = tcx.item_type(trait_c.def_id).subst(tcx, trait_to_skol_substs); - let mut origin = TypeOrigin::Misc(impl_c_span); + let mut cause = ObligationCause::misc(impl_c_span, impl_c_node_id); let err = infcx.commit_if_ok(|_| { // There is no "body" here, so just pass dummy id. @@ -807,7 +809,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("compare_const_impl: trait_ty={:?}", trait_ty); - infcx.sub_types(false, origin, impl_ty, trait_ty) + infcx.sub_types(false, &cause, impl_ty, trait_ty) .map(|InferOk { obligations, .. }| { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()) @@ -821,12 +823,12 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Locate the Span containing just the type of the offending impl match tcx.map.expect_impl_item(impl_c_node_id).node { - ImplItemKind::Const(ref ty, _) => origin = TypeOrigin::Misc(ty.span), + ImplItemKind::Const(ref ty, _) => cause.span = ty.span, _ => bug!("{:?} is not a impl const", impl_c), } let mut diag = struct_span_err!(tcx.sess, - origin.span(), + cause.span, E0326, "implemented const `{}` has an incompatible type for \ trait", @@ -840,7 +842,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }; infcx.note_type_err(&mut diag, - origin, + &cause, Some((trait_c_span, format!("type in trait"))), Some(infer::ValuePairs::Types(ExpectedFound { expected: trait_ty, diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index d622bc7f751d..8a0f1478a736 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -11,7 +11,8 @@ use check::FnCtxt; use rustc::ty::Ty; -use rustc::infer::{InferOk, TypeOrigin}; +use rustc::infer::{InferOk}; +use rustc::traits::ObligationCause; use syntax_pos::Span; use rustc::hir; @@ -20,34 +21,34 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Requires that the two types unify, and prints an error message if // they don't. pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - let origin = TypeOrigin::Misc(sp); - match self.sub_types(false, origin, actual, expected) { + let cause = self.misc(sp); + match self.sub_types(false, &cause, actual, expected) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); }, Err(e) => { - self.report_mismatched_types(origin, expected, actual, e); + self.report_mismatched_types(&cause, expected, actual, e); } } } pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - self.demand_eqtype_with_origin(TypeOrigin::Misc(sp), expected, actual); + self.demand_eqtype_with_origin(&self.misc(sp), expected, actual); } pub fn demand_eqtype_with_origin(&self, - origin: TypeOrigin, + cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>) { - match self.eq_types(false, origin, actual, expected) { + match self.eq_types(false, cause, actual, expected) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); }, Err(e) => { - self.report_mismatched_types(origin, expected, actual, e); + self.report_mismatched_types(cause, expected, actual, e); } } } @@ -56,9 +57,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) { let expected = self.resolve_type_vars_with_obligations(expected); if let Err(e) = self.try_coerce(expr, checked_ty, expected) { - let origin = TypeOrigin::Misc(expr.span); + let cause = self.misc(expr.span); let expr_ty = self.resolve_type_vars_with_obligations(checked_ty); - self.report_mismatched_types(origin, expected, expr_ty, e); + self.report_mismatched_types(&cause, expected, expr_ty, e); } } } diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 09e1f6592c17..8868d1e54f4b 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -17,7 +17,7 @@ use rustc::infer::{self, InferOk}; use middle::region; use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, AdtKind, Ty, TyCtxt}; -use rustc::traits::{self, Reveal}; +use rustc::traits::{self, ObligationCause, Reveal}; use util::nodemap::FxHashSet; use syntax::ast; @@ -93,8 +93,8 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did); let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs); - match infcx.eq_types(true, infer::TypeOrigin::Misc(drop_impl_span), - named_type, fresh_impl_self_ty) { + let cause = &ObligationCause::misc(drop_impl_span, drop_impl_node_id); + match infcx.eq_types(true, cause, named_type, fresh_impl_self_ty) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index ac6343cae1c8..77106b8b0c3a 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -12,7 +12,7 @@ //! intrinsics that the compiler exposes. use intrinsics; -use rustc::infer::TypeOrigin; +use rustc::traits::{ObligationCause, ObligationCauseCode}; use rustc::ty::subst::Substs; use rustc::ty::FnSig; use rustc::ty::{self, Ty}; @@ -63,7 +63,9 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, .emit(); } else { require_same_types(ccx, - TypeOrigin::IntrinsicType(it.span), + &ObligationCause::new(it.span, + it.id, + ObligationCauseCode::IntrinsicType), tcx.item_type(def_id), fty); } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 0b6f7794e9fe..f9e1db141c8b 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -17,7 +17,7 @@ use rustc::traits; use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::fold::TypeFoldable; -use rustc::infer::{self, InferOk, TypeOrigin}; +use rustc::infer::{self, InferOk}; use syntax_pos::Span; use rustc::hir; @@ -330,7 +330,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { } fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) { - match self.sub_types(false, TypeOrigin::Misc(self.span), self_ty, method_self_ty) { + match self.sub_types(false, &self.misc(self.span), self_ty, method_self_ty) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 481923c25978..71696c0abea9 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -17,12 +17,12 @@ use check::FnCtxt; use hir::def_id::DefId; use hir::def::Def; use rustc::ty::subst::{Subst, Substs}; -use rustc::traits; +use rustc::traits::{self, ObligationCause}; use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable}; -use rustc::infer::{InferOk, TypeOrigin}; +use rustc::infer::InferOk; use rustc::util::nodemap::FxHashSet; use syntax::ast; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::Span; use rustc::hir; use std::mem; use std::ops::Deref; @@ -1032,7 +1032,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.probe(|_| { // First check that the self type can be related. match self.sub_types(false, - TypeOrigin::Misc(DUMMY_SP), + &ObligationCause::dummy(), self_ty, probe.xform_self_ty) { Ok(InferOk { obligations, .. }) => { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a95b3f4a973b..76cd3c4a1eb7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -87,9 +87,9 @@ use hir::def::{Def, CtorKind, PathResolution}; use hir::def_id::{DefId, LOCAL_CRATE}; use hir::pat_util; use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin, - TypeOrigin, TypeTrace, type_variable}; + TypeTrace, type_variable}; use rustc::ty::subst::{Kind, Subst, Substs}; -use rustc::traits::{self, Reveal}; +use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use rustc::ty::{ParamTy, ParameterEnvironment}; use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue}; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, Visibility}; @@ -1521,6 +1521,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + pub fn cause(&self, + span: Span, + code: ObligationCauseCode<'tcx>) + -> ObligationCause<'tcx> { + ObligationCause::new(span, self.body_id, code) + } + + pub fn misc(&self, span: Span) -> ObligationCause<'tcx> { + self.cause(span, ObligationCauseCode::MiscObligation) + } + /// Resolves type variables in `ty` if possible. Unlike the infcx /// version (resolve_type_vars_if_possible), this version will /// also select obligations if it seems useful, in an effort @@ -2096,8 +2107,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(default) = default_map.get(ty) { let default = default.clone(); match self.eq_types(false, - TypeOrigin::Misc(default.origin_span), - ty, default.ty) { + &self.misc(default.origin_span), + ty, + default.ty) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()) @@ -2146,6 +2158,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.report_conflicting_default_types( first_default.origin_span, + self.body_id, first_default, second_default) } @@ -2194,8 +2207,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(default) = default_map.get(ty) { let default = default.clone(); match self.eq_types(false, - TypeOrigin::Misc(default.origin_span), - ty, default.ty) { + &self.misc(default.origin_span), + ty, + default.ty) { // FIXME(#32730) propagate obligations Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()), Err(_) => { @@ -2765,8 +2779,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // return type (likely containing type variables if the function // is polymorphic) and the expected return type. // No argument expectations are produced if unification fails. - let origin = TypeOrigin::Misc(call_span); - let ures = self.sub_types(false, origin, formal_ret, ret_ty); + let origin = self.misc(call_span); + let ures = self.sub_types(false, &origin, formal_ret, ret_ty); // FIXME(#15760) can't use try! here, FromError doesn't default // to identity so the resulting type is not constrained. match ures { @@ -2852,16 +2866,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.diverges.set(Diverges::Maybe); let unit = self.tcx.mk_nil(); - let (origin, expected, found, result) = + let (cause, expected_ty, found_ty, result); if let Some(else_expr) = opt_else_expr { let else_ty = self.check_expr_with_expectation(else_expr, expected); let else_diverges = self.diverges.get(); + cause = self.cause(sp, ObligationCauseCode::IfExpression); // Only try to coerce-unify if we have a then expression // to assign coercions to, otherwise it's () or diverging. - let origin = TypeOrigin::IfExpression(sp); - let result = if let Some(ref then) = then_blk.expr { - let res = self.try_find_coercion_lub(origin, || Some(&**then), + expected_ty = then_ty; + found_ty = else_ty; + result = if let Some(ref then) = then_blk.expr { + let res = self.try_find_coercion_lub(&cause, || Some(&**then), then_ty, else_expr, else_ty); // In case we did perform an adjustment, we have to update @@ -2876,7 +2892,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { res } else { self.commit_if_ok(|_| { - let trace = TypeTrace::types(origin, true, then_ty, else_ty); + let trace = TypeTrace::types(&cause, true, then_ty, else_ty); self.lub(true, trace, &then_ty, &else_ty) .map(|InferOk { value, obligations }| { // FIXME(#32730) propagate obligations @@ -2888,21 +2904,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // We won't diverge unless both branches do (or the condition does). self.diverges.set(cond_diverges | then_diverges & else_diverges); - - (origin, then_ty, else_ty, result) } else { // If the condition is false we can't diverge. self.diverges.set(cond_diverges); - let origin = TypeOrigin::IfExpressionWithNoElse(sp); - (origin, unit, then_ty, - self.eq_types(true, origin, unit, then_ty) - .map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - unit - })) - }; + cause = self.cause(sp, ObligationCauseCode::IfExpressionWithNoElse); + expected_ty = unit; + found_ty = then_ty; + result = self.eq_types(true, &cause, unit, then_ty) + .map(|InferOk { obligations, .. }| { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + unit + }); + } match result { Ok(ty) => { @@ -2913,7 +2928,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } Err(e) => { - self.report_mismatched_types(origin, expected, found, e); + self.report_mismatched_types(&cause, expected_ty, found_ty, e); self.tcx.types.err } } @@ -3565,7 +3580,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_expr_coercable_to_type(&e, self.ret_ty); } else { let eq_result = self.eq_types(false, - TypeOrigin::Misc(expr.span), + &self.misc(expr.span), self.ret_ty, tcx.mk_nil()) // FIXME(#32730) propagate obligations @@ -3695,20 +3710,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for (i, e) in args.iter().enumerate() { let e_ty = self.check_expr_with_hint(e, coerce_to); - let origin = TypeOrigin::Misc(e.span); + let cause = self.misc(e.span); // Special-case the first element, as it has no "previous expressions". let result = if i == 0 { self.try_coerce(e, e_ty, coerce_to) } else { let prev_elems = || args[..i].iter().map(|e| &**e); - self.try_find_coercion_lub(origin, prev_elems, unified, e, e_ty) + self.try_find_coercion_lub(&cause, prev_elems, unified, e, e_ty) }; match result { Ok(ty) => unified = ty, Err(e) => { - self.report_mismatched_types(origin, unified, e_ty, e); + self.report_mismatched_types(&cause, unified, e_ty, e); } } } @@ -4064,9 +4079,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // We're not diverging and there's an expected type, which, // in case it's not `()`, could result in an error higher-up. // We have a chance to error here early and be more helpful. - let origin = TypeOrigin::Misc(blk.span); - let trace = TypeTrace::types(origin, false, ty, ety); - match self.sub_types(false, origin, ty, ety) { + let cause = self.misc(blk.span); + let trace = TypeTrace::types(&cause, false, ty, ety); + match self.sub_types(false, &cause, ty, ety) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); @@ -4367,7 +4382,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ty = self.tcx.item_type(impl_def_id); let impl_ty = self.instantiate_type_scheme(span, &substs, &ty); - match self.sub_types(false, TypeOrigin::Misc(span), self_ty, impl_ty) { + match self.sub_types(false, &self.misc(span), self_ty, impl_ty) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index e019c4c76148..e41c149b178c 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -91,7 +91,7 @@ use middle::region::{self, CodeExtent}; use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, Ty, MethodCall, TypeFoldable}; -use rustc::infer::{self, GenericKind, InferOk, SubregionOrigin, TypeOrigin, VerifyBound}; +use rustc::infer::{self, GenericKind, InferOk, SubregionOrigin, VerifyBound}; use hir::pat_util; use rustc::ty::adjustment; use rustc::ty::wf::ImpliedBound; @@ -1762,7 +1762,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { outlives); // check whether this predicate applies to our current projection - match self.eq_types(false, TypeOrigin::Misc(span), ty, outlives.0) { + let cause = self.fcx.misc(span); + match self.eq_types(false, &cause, ty, outlives.0) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 066b3d4be088..41bea1874162 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -15,8 +15,7 @@ use CrateCtxt; use hir::def_id::DefId; use middle::region::{CodeExtent}; -use rustc::infer::TypeOrigin; -use rustc::traits; +use rustc::traits::{self, ObligationCauseCode}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::util::nodemap::{FxHashSet, FxHashMap}; @@ -29,7 +28,7 @@ use rustc::hir; pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> { ccx: &'ccx CrateCtxt<'ccx, 'tcx>, - code: traits::ObligationCauseCode<'tcx>, + code: ObligationCauseCode<'tcx>, } /// Helper type of a temporary returned by .for_item(...). @@ -37,7 +36,7 @@ pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> { /// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(FnCtxt<'b, 'gcx, 'tcx>). struct CheckWfFcxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { inherited: super::InheritedBuilder<'a, 'gcx, 'tcx>, - code: traits::ObligationCauseCode<'gcx>, + code: ObligationCauseCode<'gcx>, id: ast::NodeId, span: Span } @@ -67,7 +66,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { -> CheckTypeWellFormedVisitor<'ccx, 'gcx> { CheckTypeWellFormedVisitor { ccx: ccx, - code: traits::ObligationCauseCode::MiscObligation + code: ObligationCauseCode::MiscObligation } } @@ -515,8 +514,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty); - let origin = TypeOrigin::MethodReceiver(span); - fcx.demand_eqtype_with_origin(origin, rcvr_ty, self_arg_ty); + let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver); + fcx.demand_eqtype_with_origin(&cause, rcvr_ty, self_arg_ty); } fn check_variances_for_type_defn(&self, diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 586330582646..7c860bc5aecb 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -19,7 +19,7 @@ use hir::def_id::DefId; use middle::lang_items::UnsizeTraitLangItem; use rustc::ty::subst::Subst; use rustc::ty::{self, TyCtxt, TypeFoldable}; -use rustc::traits::{self, Reveal}; +use rustc::traits::{self, ObligationCause, Reveal}; use rustc::ty::ParameterEnvironment; use rustc::ty::{Ty, TyBool, TyChar, TyError}; use rustc::ty::{TyParam, TyRawPtr}; @@ -30,7 +30,7 @@ use rustc::ty::{TyProjection, TyAnon}; use rustc::ty::util::CopyImplementationError; use middle::free_region::FreeRegionMap; use CrateCtxt; -use rustc::infer::{self, InferCtxt, TypeOrigin}; +use rustc::infer::{self, InferCtxt}; use syntax_pos::Span; use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; @@ -344,12 +344,12 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { target); tcx.infer_ctxt(None, Some(param_env), Reveal::ExactMatch).enter(|infcx| { - let origin = TypeOrigin::Misc(span); + let cause = ObligationCause::misc(span, impl_node_id); let check_mutbl = |mt_a: ty::TypeAndMut<'gcx>, mt_b: ty::TypeAndMut<'gcx>, mk_ptr: &Fn(Ty<'gcx>) -> Ty<'gcx>| { if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) { - infcx.report_mismatched_types(origin, + infcx.report_mismatched_types(&cause, mk_ptr(mt_b.ty), target, ty::error::TypeError::Mutability); @@ -397,7 +397,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { } // Ignore fields that aren't significantly changed - if let Ok(ok) = infcx.sub_types(false, origin, b, a) { + if let Ok(ok) = infcx.sub_types(false, &cause, b, a) { if ok.obligations.is_empty() { return None; } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 2c12959dbdde..76f8254cb0fe 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -106,10 +106,10 @@ pub use rustc::util; use dep_graph::DepNode; use hir::map as hir_map; -use rustc::infer::{InferOk, TypeOrigin}; +use rustc::infer::InferOk; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::traits::{self, Reveal}; +use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use session::{config, CompileResult}; use util::common::time; @@ -172,19 +172,19 @@ fn require_c_abi_if_variadic(tcx: TyCtxt, } fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - origin: TypeOrigin, + cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>) -> bool { ccx.tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| { - match infcx.eq_types(false, origin.clone(), expected, actual) { + match infcx.eq_types(false, &cause, expected, actual) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); true } Err(err) => { - infcx.report_mismatched_types(origin, expected, actual, err); + infcx.report_mismatched_types(cause, expected, actual, err); false } } @@ -231,7 +231,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt, require_same_types( ccx, - TypeOrigin::MainFunctionType(main_span), + &ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType), se_ty, main_t); } @@ -286,7 +286,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt, require_same_types( ccx, - TypeOrigin::StartFunctionType(start_span), + &ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType), se_ty, start_t); } From 48dc6e26ca2ccb72a241ea42af509c4dcf3636fb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 24 Aug 2016 18:09:46 -0400 Subject: [PATCH 121/177] register `infer-ok` obligations properly Or at least, more properly. I think I left one or two FIXMEs still in there. cc #32730 --- src/librustc/infer/sub.rs | 3 +- src/librustc/traits/fulfill.rs | 6 +- src/librustc/traits/project.rs | 17 ++---- src/librustc/traits/select.rs | 3 - src/librustc_mir/transform/type_check.rs | 41 +++++++------ src/librustc_typeck/check/_match.rs | 7 +-- src/librustc_typeck/check/coercion.rs | 33 ++-------- src/librustc_typeck/check/compare_method.rs | 9 +-- src/librustc_typeck/check/demand.rs | 10 ++- src/librustc_typeck/check/method/confirm.rs | 5 +- src/librustc_typeck/check/method/probe.rs | 4 +- src/librustc_typeck/check/mod.rs | 67 ++++++++++----------- src/librustc_typeck/check/regionck.rs | 7 +-- 13 files changed, 91 insertions(+), 121 deletions(-) diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index 5664777772f7..dae30ea97c80 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::combine::CombineFields; use super::SubregionOrigin; +use super::combine::CombineFields; use super::type_variable::{SubtypeOf, SupertypeOf}; use ty::{self, Ty, TyCtxt}; @@ -117,6 +117,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> // error messages. let origin = SubregionOrigin::Subtype(self.fields.trace.clone()); self.fields.infcx.region_vars.make_subregion(origin, a, b); + Ok(a) } diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 535156e61e94..f406580286da 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -520,10 +520,8 @@ fn process_predicate<'a, 'gcx, 'tcx>( ty::Predicate::Equate(ref binder) => { match selcx.infcx().equality_predicate(&obligation.cause, binder) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - Ok(Some(Vec::new())) + Ok(InferOk { obligations, value: () }) => { + Ok(Some(obligations)) }, Err(_) => Err(CodeSelectionError(Unimplemented)), } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 6ab7a1fbfb8a..986e4192f889 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -210,9 +210,7 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>( let infcx = selcx.infcx(); match infcx.eq_types(true, &obligation.cause, normalized_ty, obligation.predicate.ty) { - Ok(InferOk { obligations: inferred_obligations, .. }) => { - // FIXME(#32730) once obligations are generated in inference, drop this assertion - assert!(inferred_obligations.is_empty()); + Ok(InferOk { obligations: inferred_obligations, value: () }) => { obligations.extend(inferred_obligations); Ok(Some(obligations)) }, @@ -847,9 +845,10 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>( obligation.cause.clone(), data_poly_trait_ref, obligation_poly_trait_ref) - // FIXME(#32730) once obligations are propagated from unification in - // inference, drop this assertion - .map(|InferOk { obligations, .. }| assert!(obligations.is_empty())) + .map(|InferOk { obligations: _, value: () }| { + // FIXME(#32730) -- do we need to take obligations + // into account in any way? At the moment, no. + }) .is_ok() }); @@ -1184,12 +1183,10 @@ fn confirm_fn_pointer_candidate<'cx, 'gcx, 'tcx>( fn_pointer_vtable: VtableFnPointerData<'tcx, PredicateObligation<'tcx>>) -> Progress<'tcx> { - // FIXME(#32730) drop this assertion once obligations are propagated from inference (fn pointer - // vtable nested obligations ONLY come from unification in inference) - assert!(fn_pointer_vtable.nested.is_empty()); let fn_type = selcx.infcx().shallow_resolve(fn_pointer_vtable.fn_ty); let sig = fn_type.fn_sig(); confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes) + .with_addl_obligations(fn_pointer_vtable.nested) } fn confirm_closure_candidate<'cx, 'gcx, 'tcx>( @@ -1266,8 +1263,6 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>( let trait_ref = obligation.predicate.trait_ref; match infcx.match_poly_projection_predicate(cause, poly_projection, trait_ref) { Ok(InferOk { value: ty_match, obligations }) => { - // FIXME(#32730) once obligations are generated in inference, drop this assertion - assert!(obligations.is_empty()); Progress { ty: ty_match.value, obligations: obligations, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 6c75fb6a246e..c25e7ee344f6 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -418,9 +418,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { None => Ok(None), Some(candidate) => { let mut candidate = self.confirm_candidate(obligation, candidate)?; - // FIXME(#32730) remove this assertion once inferred obligations are propagated - // from inference - assert!(self.inferred_obligations.len() == 0); let inferred_obligations = (*self.inferred_obligations).into_iter().cloned(); candidate.nested_obligations_mut().extend(inferred_obligations); Ok(Some(candidate)) diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 78912f607faa..0ceed274b6da 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -324,20 +324,25 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { traits::ObligationCause::misc(span, self.body_id) } - fn sub_types(&self, span: Span, sup: Ty<'tcx>, sub: Ty<'tcx>) - -> infer::UnitResult<'tcx> - { - self.infcx.sub_types(false, &self.misc(span), sup, sub) - // FIXME(#32730) propagate obligations - .map(|InferOk { obligations, .. }| assert!(obligations.is_empty())) + pub fn register_infer_ok_obligations(&mut self, infer_ok: InferOk<'tcx, T>) -> T { + for obligation in infer_ok.obligations { + self.fulfillment_cx.register_predicate_obligation(self.infcx, obligation); + } + infer_ok.value } - fn eq_types(&self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>) + fn sub_types(&mut self, sup: Ty<'tcx>, sub: Ty<'tcx>) + -> infer::UnitResult<'tcx> + { + self.infcx.sub_types(false, &self.misc(self.last_span), sup, sub) + .map(|ok| self.register_infer_ok_obligations(ok)) + } + + fn eq_types(&mut self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>) -> infer::UnitResult<'tcx> { self.infcx.eq_types(false, &self.misc(span), a, b) - // FIXME(#32730) propagate obligations - .map(|InferOk { obligations, .. }| assert!(obligations.is_empty())) + .map(|ok| self.register_infer_ok_obligations(ok)) } fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { @@ -352,7 +357,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let lv_ty = lv.ty(mir, tcx).to_ty(tcx); let rv_ty = rv.ty(mir, tcx); if let Some(rv_ty) = rv_ty { - if let Err(terr) = self.sub_types(self.last_span, rv_ty, lv_ty) { + if let Err(terr) = self.sub_types(rv_ty, lv_ty) { span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}", lv_ty, rv_ty, terr); } @@ -413,7 +418,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } => { let lv_ty = location.ty(mir, tcx).to_ty(tcx); let rv_ty = value.ty(mir, tcx); - if let Err(terr) = self.sub_types(self.last_span, rv_ty, lv_ty) { + if let Err(terr) = self.sub_types(rv_ty, lv_ty) { span_mirbug!(self, term, "bad DropAndReplace ({:?} = {:?}): {:?}", lv_ty, rv_ty, terr); } @@ -430,7 +435,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => { let discr_ty = discr.ty(mir, tcx).to_ty(tcx); - if let Err(terr) = self.sub_types(self.last_span, discr_ty, switch_ty) { + if let Err(terr) = self.sub_types(discr_ty, switch_ty) { span_mirbug!(self, term, "bad SwitchInt ({:?} on {:?}): {:?}", switch_ty, discr_ty, terr); } @@ -492,7 +497,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn check_call_dest(&self, + fn check_call_dest(&mut self, mir: &Mir<'tcx>, term: &Terminator<'tcx>, sig: &ty::FnSig<'tcx>, @@ -501,7 +506,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { match *destination { Some((ref dest, _)) => { let dest_ty = dest.ty(mir, tcx).to_ty(tcx); - if let Err(terr) = self.sub_types(self.last_span, sig.output, dest_ty) { + if let Err(terr) = self.sub_types(sig.output, dest_ty) { span_mirbug!(self, term, "call dest mismatch ({:?} <- {:?}): {:?}", dest_ty, sig.output, terr); @@ -516,7 +521,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn check_call_inputs(&self, + fn check_call_inputs(&mut self, mir: &Mir<'tcx>, term: &Terminator<'tcx>, sig: &ty::FnSig<'tcx>, @@ -529,7 +534,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } for (n, (fn_arg, op_arg)) in sig.inputs.iter().zip(args).enumerate() { let op_arg_ty = op_arg.ty(mir, self.tcx()); - if let Err(terr) = self.sub_types(self.last_span, op_arg_ty, fn_arg) { + if let Err(terr) = self.sub_types(op_arg_ty, fn_arg) { span_mirbug!(self, term, "bad arg #{:?} ({:?} <- {:?}): {:?}", n, fn_arg, op_arg_ty, terr); } @@ -547,7 +552,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn check_box_free_inputs(&self, + fn check_box_free_inputs(&mut self, mir: &Mir<'tcx>, term: &Terminator<'tcx>, sig: &ty::FnSig<'tcx>, @@ -584,7 +589,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } }; - if let Err(terr) = self.sub_types(self.last_span, arg_ty, pointee_ty) { + if let Err(terr) = self.sub_types(arg_ty, pointee_ty) { span_mirbug!(self, term, "bad box_free arg ({:?} <- {:?}): {:?}", pointee_ty, arg_ty, terr); } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index d57a27ddc761..556d1f84fccd 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -11,7 +11,7 @@ use rustc::hir::{self, PatKind}; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; -use rustc::infer::{self, InferOk}; +use rustc::infer; use rustc::traits::ObligationCauseCode; use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference}; use check::{FnCtxt, Expectation, Diverges}; @@ -462,9 +462,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let result = if is_if_let_fallback { self.eq_types(true, &cause, arm_ty, result_ty) - .map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + .map(|infer_ok| { + self.register_infer_ok_obligations(infer_ok); arm_ty }) } else if i == 0 { diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 7a7ea760c038..718c273785ae 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -118,16 +118,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let trace = TypeTrace::types(&self.cause, false, a, b); if self.use_lub { self.lub(false, trace, &a, &b) - .map(|InferOk { value, obligations }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - value - }) + .map(|ok| self.register_infer_ok_obligations(ok)) } else { self.sub(false, trace, &a, &b) .map(|InferOk { value, obligations }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + self.fcx.register_predicates(obligations); value }) } @@ -678,21 +673,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (&ty::TyFnDef(a_def_id, a_substs, a_fty), &ty::TyFnDef(b_def_id, b_substs, b_fty)) => { // The signature must always match. let fty = self.lub(true, trace.clone(), &a_fty, &b_fty) - .map(|InferOk { value, obligations }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - value - })?; + .map(|ok| self.register_infer_ok_obligations(ok))?; if a_def_id == b_def_id { // Same function, maybe the parameters match. let substs = self.commit_if_ok(|_| { self.lub(true, trace.clone(), &a_substs, &b_substs) - .map(|InferOk { value, obligations }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - value - }) + .map(|ok| self.register_infer_ok_obligations(ok)) }); if let Ok(substs) = substs { @@ -761,11 +748,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if !noop { return self.commit_if_ok(|_| { self.lub(true, trace.clone(), &prev_ty, &new_ty) - .map(|InferOk { value, obligations }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - value - }) + .map(|ok| self.register_infer_ok_obligations(ok)) }); } } @@ -778,11 +761,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { self.commit_if_ok(|_| { self.lub(true, trace, &prev_ty, &new_ty) - .map(|InferOk { value, obligations }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - value - }) + .map(|ok| self.register_infer_ok_obligations(ok)) }) } } diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 075567c79492..2602ff05badd 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -810,10 +810,11 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("compare_const_impl: trait_ty={:?}", trait_ty); infcx.sub_types(false, &cause, impl_ty, trait_ty) - .map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()) - }) + .map(|InferOk { obligations, value: () }| { + for obligation in obligations { + fulfillment_cx.register_predicate_obligation(&infcx, obligation); + } + }) }); if let Err(terr) = err { diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 8a0f1478a736..ef1c08bdab54 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -23,9 +23,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { let cause = self.misc(sp); match self.sub_types(false, &cause, actual, expected) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + Ok(InferOk { obligations, value: () }) => { + self.register_predicates(obligations); }, Err(e) => { self.report_mismatched_types(&cause, expected, actual, e); @@ -43,9 +42,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { actual: Ty<'tcx>) { match self.eq_types(false, cause, actual, expected) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + Ok(InferOk { obligations, value: () }) => { + self.register_predicates(obligations); }, Err(e) => { self.report_mismatched_types(cause, expected, actual, e); diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index f9e1db141c8b..54e93978b798 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -331,9 +331,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) { match self.sub_types(false, &self.misc(self.span), self_ty, method_self_ty) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + Ok(InferOk { obligations, value: () }) => { + self.register_predicates(obligations); } Err(_) => { span_bug!(self.span, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 71696c0abea9..545d4e788524 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -16,10 +16,10 @@ use super::suggest; use check::FnCtxt; use hir::def_id::DefId; use hir::def::Def; +use rustc::infer::InferOk; use rustc::ty::subst::{Subst, Substs}; use rustc::traits::{self, ObligationCause}; use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable}; -use rustc::infer::InferOk; use rustc::util::nodemap::FxHashSet; use syntax::ast; use syntax_pos::Span; @@ -1035,7 +1035,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { &ObligationCause::dummy(), self_ty, probe.xform_self_ty) { - Ok(InferOk { obligations, .. }) => { + Ok(InferOk { obligations, value: () }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 76cd3c4a1eb7..8e9dfe54f013 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1797,6 +1797,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .register_predicate_obligation(self, obligation); } + pub fn register_predicates(&self, + obligations: Vec>) + { + for obligation in obligations { + self.register_predicate(obligation); + } + } + + pub fn register_infer_ok_obligations(&self, infer_ok: InferOk<'tcx, T>) -> T { + self.register_predicates(infer_ok.obligations); + infer_ok.value + } + pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> { let t = AstConv::ast_ty_to_ty(self, self, ast_t); self.register_wf_obligation(t, ast_t.span, traits::MiscObligation); @@ -2110,13 +2123,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &self.misc(default.origin_span), ty, default.ty) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()) - }, - Err(_) => { - conflicts.push((*ty, default)); - } + Ok(ok) => self.register_infer_ok_obligations(ok), + Err(_) => conflicts.push((*ty, default)), } } } @@ -2210,8 +2218,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &self.misc(default.origin_span), ty, default.ty) { - // FIXME(#32730) propagate obligations - Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()), + Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { result = Some(default); } @@ -2784,8 +2791,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // FIXME(#15760) can't use try! here, FromError doesn't default // to identity so the resulting type is not constrained. match ures { - // FIXME(#32730) propagate obligations - Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()), + Ok(ok) => self.register_infer_ok_obligations(ok), Err(e) => return Err(e), } @@ -2894,11 +2900,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.commit_if_ok(|_| { let trace = TypeTrace::types(&cause, true, then_ty, else_ty); self.lub(true, trace, &then_ty, &else_ty) - .map(|InferOk { value, obligations }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - value - }) + .map(|ok| self.register_infer_ok_obligations(ok)) }) }; @@ -2912,9 +2914,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expected_ty = unit; found_ty = then_ty; result = self.eq_types(true, &cause, unit, then_ty) - .map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + .map(|ok| { + self.register_infer_ok_obligations(ok); unit }); } @@ -3579,17 +3580,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(ref e) = *expr_opt { self.check_expr_coercable_to_type(&e, self.ret_ty); } else { - let eq_result = self.eq_types(false, - &self.misc(expr.span), - self.ret_ty, - tcx.mk_nil()) - // FIXME(#32730) propagate obligations - .map(|InferOk { obligations, .. }| assert!(obligations.is_empty())); - if eq_result.is_err() { - struct_span_err!(tcx.sess, expr.span, E0069, - "`return;` in a function whose return type is not `()`") - .span_label(expr.span, &format!("return type is not ()")) - .emit(); + match self.eq_types(false, + &self.misc(expr.span), + self.ret_ty, + tcx.mk_nil()) + { + Ok(ok) => self.register_infer_ok_obligations(ok), + Err(_) => { + struct_span_err!(tcx.sess, expr.span, E0069, + "`return;` in a function whose return type is not `()`") + .span_label(expr.span, &format!("return type is not ()")) + .emit(); + } } } tcx.types.never @@ -4383,10 +4385,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let impl_ty = self.instantiate_type_scheme(span, &substs, &ty); match self.sub_types(false, &self.misc(span), self_ty, impl_ty) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - } + Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { span_bug!(span, "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?", diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index e41c149b178c..a280001d5e99 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -91,7 +91,7 @@ use middle::region::{self, CodeExtent}; use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, Ty, MethodCall, TypeFoldable}; -use rustc::infer::{self, GenericKind, InferOk, SubregionOrigin, VerifyBound}; +use rustc::infer::{self, GenericKind, SubregionOrigin, VerifyBound}; use hir::pat_util; use rustc::ty::adjustment; use rustc::ty::wf::ImpliedBound; @@ -1764,9 +1764,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // check whether this predicate applies to our current projection let cause = self.fcx.misc(span); match self.eq_types(false, &cause, ty, outlives.0) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + Ok(ok) => { + self.register_infer_ok_obligations(ok); Ok(outlives.1) } Err(_) => { Err(()) } From 88dfb885ea478fa6ffeeba5ecb6b6931bafcc2a1 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 16 Nov 2016 06:10:34 +0000 Subject: [PATCH 122/177] Improve proc macro def ids. --- src/librustc_metadata/cstore_impl.rs | 2 +- src/librustc_metadata/decoder.rs | 39 +++++++++++++++++++++------- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 83de8acdb605..fba56da2bfb2 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -356,7 +356,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn load_macro(&self, id: DefId, sess: &Session) -> LoadedMacro { let data = self.get_crate_data(id.krate); if let Some(ref proc_macros) = data.proc_macros { - return LoadedMacro::ProcMacro(proc_macros[id.index.as_usize()].1.clone()); + return LoadedMacro::ProcMacro(proc_macros[id.index.as_usize() - 1].1.clone()); } let (name, def) = data.get_macro(id.index); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index ba85544326f8..edd9dd052bb6 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -23,7 +23,7 @@ use rustc::hir::intravisit::IdRange; use rustc::middle::cstore::{DepKind, InlinedItem, LinkagePreference}; use rustc::hir::def::{self, Def, CtorKind}; -use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; +use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc::middle::lang_items; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; @@ -513,7 +513,14 @@ impl<'a, 'tcx> CrateMetadata { } pub fn get_def(&self, index: DefIndex) -> Option { - self.entry(index).kind.to_def(self.local_def_id(index)) + if self.proc_macros.is_some() { + Some(match index { + CRATE_DEF_INDEX => Def::Mod(self.local_def_id(index)), + _ => Def::Macro(self.local_def_id(index)), + }) + } else { + self.entry(index).kind.to_def(self.local_def_id(index)) + } } pub fn get_trait_def(&self, @@ -643,15 +650,24 @@ impl<'a, 'tcx> CrateMetadata { } pub fn get_stability(&self, id: DefIndex) -> Option { - self.entry(id).stability.map(|stab| stab.decode(self)) + match self.proc_macros { + Some(_) if id != CRATE_DEF_INDEX => None, + _ => self.entry(id).stability.map(|stab| stab.decode(self)), + } } pub fn get_deprecation(&self, id: DefIndex) -> Option { - self.entry(id).deprecation.map(|depr| depr.decode(self)) + match self.proc_macros { + Some(_) if id != CRATE_DEF_INDEX => None, + _ => self.entry(id).deprecation.map(|depr| depr.decode(self)), + } } pub fn get_visibility(&self, id: DefIndex) -> ty::Visibility { - self.entry(id).visibility + match self.proc_macros { + Some(_) => ty::Visibility::Public, + _ => self.entry(id).visibility, + } } fn get_impl_data(&self, id: DefIndex) -> ImplData<'tcx> { @@ -692,11 +708,11 @@ impl<'a, 'tcx> CrateMetadata { where F: FnMut(def::Export) { if let Some(ref proc_macros) = self.proc_macros { - for (id, &(name, _)) in proc_macros.iter().enumerate() { - callback(def::Export { - name: name, - def: Def::Macro(DefId { krate: self.cnum, index: DefIndex::new(id), }), - }) + if id == CRATE_DEF_INDEX { + for (id, &(name, _)) in proc_macros.iter().enumerate() { + let def = Def::Macro(DefId { krate: self.cnum, index: DefIndex::new(id + 1) }); + callback(def::Export { name: name, def: def }); + } } return } @@ -894,6 +910,9 @@ impl<'a, 'tcx> CrateMetadata { } pub fn get_item_attrs(&self, node_id: DefIndex) -> Vec { + if self.proc_macros.is_some() && node_id != CRATE_DEF_INDEX { + return Vec::new(); + } // The attributes for a tuple struct are attached to the definition, not the ctor; // we assume that someone passing in a tuple struct ctor is actually wanting to // look at the definition From 06242ff15d2b510689a99c33aa2495da11a75fad Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 31 Oct 2016 16:40:13 -0700 Subject: [PATCH 123/177] rustc: Implement #[link(cfg(..))] and crt-static This commit is an implementation of [RFC 1721] which adds a new target feature to the compiler, `crt-static`, which can be used to select how the C runtime for a target is linked. Most targets dynamically linke the C runtime by default with the notable exception of some of the musl targets. [RFC 1721]: https://github.com/rust-lang/rfcs/blob/master/text/1721-crt-static.md This commit first adds the new target-feature, `crt-static`. If enabled, then the `cfg(target_feature = "crt-static")` will be available. Targets like musl will have this enabled by default. This feature can be controlled through the standard target-feature interface, `-C target-feature=+crt-static` or `-C target-feature=-crt-static`. Next this adds an gated and unstable `#[link(cfg(..))]` feature to enable the `crt-static` semantics we want with libc. The exact behavior of this attribute is a little squishy, but it's intended to be a forever-unstable implementation detail of the liblibc crate. Specifically the `#[link(cfg(..))]` annotation means that the `#[link]` directive is only active in a compilation unit if that `cfg` value is satisfied. For example when compiling an rlib, these directives are just encoded and ignored for dylibs, and all staticlibs are continued to be put into the rlib as usual. When placing that rlib into a staticlib, executable, or dylib, however, the `cfg` is evaluated *as if it were defined in the final artifact* and the library is decided to be linked or not. Essentially, what'll happen is: * On MSVC with `-C target-feature=-crt-static`, the `msvcrt.lib` library will be linked to. * On MSVC with `-C target-feature=+crt-static`, the `libcmt.lib` library will be linked to. * On musl with `-C target-feature=-crt-static`, the object files in liblibc.rlib are removed and `-lc` is passed instead. * On musl with `-C target-feature=+crt-static`, the object files in liblibc.rlib are used and `-lc` is not passed. This commit does **not** include an update to the liblibc module to implement these changes. I plan to do that just after the 1.14.0 beta release is cut to ensure we get ample time to test this feature. cc #37406 --- src/liblibc | 2 +- src/librustc/middle/cstore.rs | 17 +- src/librustc_back/target/linux_musl_base.rs | 4 +- src/librustc_back/target/mod.rs | 6 + src/librustc_driver/target_features.rs | 29 ++++ src/librustc_metadata/creader.rs | 49 ++++-- src/librustc_metadata/cstore.rs | 12 +- src/librustc_metadata/cstore_impl.rs | 6 +- src/librustc_metadata/decoder.rs | 4 +- src/librustc_metadata/encoder.rs | 11 +- src/librustc_metadata/schema.rs | 4 +- src/librustc_trans/back/archive.rs | 27 ++- src/librustc_trans/back/link.rs | 154 +++++++++++++----- src/librustc_trans/back/write.rs | 11 +- src/libsyntax/feature_gate.rs | 3 + src/test/compile-fail/crt-static-gated.rs | 14 ++ src/test/compile-fail/link-cfg-gated.rs | 15 ++ src/test/run-make/link-cfg/Makefile | 22 +++ .../run-make/link-cfg/dep-with-staticlib.rs | 18 ++ src/test/run-make/link-cfg/dep.rs | 18 ++ src/test/run-make/link-cfg/no-deps.rs | 30 ++++ src/test/run-make/link-cfg/return1.c | 16 ++ src/test/run-make/link-cfg/return2.c | 16 ++ src/test/run-make/link-cfg/return3.c | 16 ++ src/test/run-make/link-cfg/with-deps.rs | 24 +++ .../run-make/link-cfg/with-staticlib-deps.rs | 24 +++ .../link-cfg-works-transitive-dylib.rs | 14 ++ .../link-cfg-works-transitive-rlib.rs | 17 ++ src/test/run-pass/crt-static-off-works.rs | 17 ++ src/test/run-pass/crt-static-on-works.rs | 16 ++ src/test/run-pass/link-cfg-works.rs | 23 +++ 31 files changed, 547 insertions(+), 92 deletions(-) create mode 100644 src/test/compile-fail/crt-static-gated.rs create mode 100644 src/test/compile-fail/link-cfg-gated.rs create mode 100644 src/test/run-make/link-cfg/Makefile create mode 100644 src/test/run-make/link-cfg/dep-with-staticlib.rs create mode 100644 src/test/run-make/link-cfg/dep.rs create mode 100644 src/test/run-make/link-cfg/no-deps.rs create mode 100644 src/test/run-make/link-cfg/return1.c create mode 100644 src/test/run-make/link-cfg/return2.c create mode 100644 src/test/run-make/link-cfg/return3.c create mode 100644 src/test/run-make/link-cfg/with-deps.rs create mode 100644 src/test/run-make/link-cfg/with-staticlib-deps.rs create mode 100644 src/test/run-pass/auxiliary/link-cfg-works-transitive-dylib.rs create mode 100644 src/test/run-pass/auxiliary/link-cfg-works-transitive-rlib.rs create mode 100644 src/test/run-pass/crt-static-off-works.rs create mode 100644 src/test/run-pass/crt-static-on-works.rs create mode 100644 src/test/run-pass/link-cfg-works.rs diff --git a/src/liblibc b/src/liblibc index 7d9b71f0971f..6e8c1b490ccb 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 7d9b71f0971f8fa196d864d7071f216a59036d6e +Subproject commit 6e8c1b490ccbe5e84d248bab883515bc85394b5f diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 3583ccdb97ba..f61978271e7f 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -89,6 +89,13 @@ pub enum NativeLibraryKind { NativeUnknown, // default way to specify a dynamic library } +#[derive(Clone, Hash, RustcEncodable, RustcDecodable)] +pub struct NativeLibrary { + pub kind: NativeLibraryKind, + pub name: String, + pub cfg: Option>, +} + /// The data we save and restore about an inlined item or method. This is not /// part of the AST that we parse from a file, but it becomes part of the tree /// that we trans. @@ -204,7 +211,7 @@ pub trait CrateStore<'tcx> { fn crate_hash(&self, cnum: CrateNum) -> Svh; fn crate_disambiguator(&self, cnum: CrateNum) -> InternedString; fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option; - fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)>; + fn native_libraries(&self, cnum: CrateNum) -> Vec; fn reachable_ids(&self, cnum: CrateNum) -> Vec; fn is_no_builtins(&self, cnum: CrateNum) -> bool; @@ -231,7 +238,7 @@ pub trait CrateStore<'tcx> { // This is basically a 1-based range of ints, which is a little // silly - I may fix that. fn crates(&self) -> Vec; - fn used_libraries(&self) -> Vec<(String, NativeLibraryKind)>; + fn used_libraries(&self) -> Vec; fn used_link_args(&self) -> Vec; // utility functions @@ -377,7 +384,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { -> InternedString { bug!("crate_disambiguator") } fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option { bug!("plugin_registrar_fn") } - fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)> + fn native_libraries(&self, cnum: CrateNum) -> Vec { bug!("native_libraries") } fn reachable_ids(&self, cnum: CrateNum) -> Vec { bug!("reachable_ids") } fn is_no_builtins(&self, cnum: CrateNum) -> bool { bug!("is_no_builtins") } @@ -412,7 +419,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // This is basically a 1-based range of ints, which is a little // silly - I may fix that. fn crates(&self) -> Vec { vec![] } - fn used_libraries(&self) -> Vec<(String, NativeLibraryKind)> { vec![] } + fn used_libraries(&self) -> Vec { + vec![] + } fn used_link_args(&self) -> Vec { vec![] } // utility functions diff --git a/src/librustc_back/target/linux_musl_base.rs b/src/librustc_back/target/linux_musl_base.rs index d55907aeedfb..18cca425a32c 100644 --- a/src/librustc_back/target/linux_musl_base.rs +++ b/src/librustc_back/target/linux_musl_base.rs @@ -16,7 +16,6 @@ pub fn opts() -> TargetOptions { // Make sure that the linker/gcc really don't pull in anything, including // default objects, libs, etc. base.pre_link_args.push("-nostdlib".to_string()); - base.pre_link_args.push("-static".to_string()); // At least when this was tested, the linker would not add the // `GNU_EH_FRAME` program header to executables generated, which is required @@ -67,5 +66,8 @@ pub fn opts() -> TargetOptions { base.has_rpath = false; base.position_independent_executables = false; + // These targets statically link libc by default + base.crt_static_default = true; + base } diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index cc04582b19e2..f195ccb3f429 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -373,6 +373,9 @@ pub struct TargetOptions { /// A blacklist of ABIs unsupported by the current target. Note that generic /// ABIs are considered to be supported on all platforms and cannot be blacklisted. pub abi_blacklist: Vec, + + /// Whether or not the CRT is statically linked by default. + pub crt_static_default: bool, } impl Default for TargetOptions { @@ -425,6 +428,7 @@ impl Default for TargetOptions { max_atomic_width: None, panic_strategy: PanicStrategy::Unwind, abi_blacklist: vec![], + crt_static_default: false, } } } @@ -585,6 +589,7 @@ impl Target { key!(no_integrated_as, bool); key!(max_atomic_width, Option); try!(key!(panic_strategy, PanicStrategy)); + key!(crt_static_default, bool); if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) { for name in array.iter().filter_map(|abi| abi.as_string()) { @@ -745,6 +750,7 @@ impl ToJson for Target { target_option_val!(no_integrated_as); target_option_val!(max_atomic_width); target_option_val!(panic_strategy); + target_option_val!(crt_static_default); if default.abi_blacklist != self.options.abi_blacklist { d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter() diff --git a/src/librustc_driver/target_features.rs b/src/librustc_driver/target_features.rs index ba51947a3330..57a9edc5c586 100644 --- a/src/librustc_driver/target_features.rs +++ b/src/librustc_driver/target_features.rs @@ -12,6 +12,7 @@ use syntax::{ast, attr}; use llvm::LLVMRustHasFeature; use rustc::session::Session; use rustc_trans::back::write::create_target_machine; +use syntax::feature_gate::UnstableFeatures; use syntax::parse::token::InternedString; use syntax::parse::token::intern_and_get_ident as intern; use libc::c_char; @@ -47,4 +48,32 @@ pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) { cfg.push(attr::mk_name_value_item_str(tf.clone(), intern(&feat[..feat.len() - 1]))) } } + + let requested_features = sess.opts.cg.target_feature.split(','); + let unstable_options = sess.opts.debugging_opts.unstable_options; + let is_nightly = UnstableFeatures::from_environment().is_nightly_build(); + let found_negative = requested_features.clone().any(|r| r == "-crt-static"); + let found_positive = requested_features.clone().any(|r| r == "+crt-static"); + + // If the target we're compiling for requests a static crt by default, + // then see if the `-crt-static` feature was passed to disable that. + // Otherwise if we don't have a static crt by default then see if the + // `+crt-static` feature was passed. + let crt_static = if sess.target.target.options.crt_static_default { + !found_negative + } else { + found_positive + }; + + // If we switched from the default then that's only allowed on nightly, so + // gate that here. + if (found_positive || found_negative) && (!is_nightly || !unstable_options) { + sess.fatal("specifying the `crt-static` target feature is only allowed \ + on the nightly channel with `-Z unstable-options` passed \ + as well"); + } + + if crt_static { + cfg.push(attr::mk_name_value_item_str(tf.clone(), intern("crt-static"))); + } } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 75944122f5c1..4298bb47fea6 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -23,6 +23,7 @@ use rustc::session::search_paths::PathKind; use rustc::middle; use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate}; use rustc::util::nodemap::{FxHashMap, FxHashSet}; +use rustc::middle::cstore::NativeLibrary; use rustc::hir::map::Definitions; use std::cell::{RefCell, Cell}; @@ -35,6 +36,7 @@ use syntax::ast; use syntax::abi::Abi; use syntax::attr; use syntax::ext::base::SyntaxExtension; +use syntax::feature_gate::{self, GateIssue}; use syntax::parse::token::{InternedString, intern}; use syntax_pos::{Span, DUMMY_SP}; use log; @@ -77,9 +79,8 @@ struct ExternCrateInfo { fn register_native_lib(sess: &Session, cstore: &CStore, span: Option, - name: String, - kind: cstore::NativeLibraryKind) { - if name.is_empty() { + lib: NativeLibrary) { + if lib.name.is_empty() { match span { Some(span) => { struct_span_err!(sess, span, E0454, @@ -94,17 +95,21 @@ fn register_native_lib(sess: &Session, return } let is_osx = sess.target.target.options.is_like_osx; - if kind == cstore::NativeFramework && !is_osx { + if lib.kind == cstore::NativeFramework && !is_osx { let msg = "native frameworks are only available on OSX targets"; match span { - Some(span) => { - span_err!(sess, span, E0455, - "{}", msg) - } + Some(span) => span_err!(sess, span, E0455, "{}", msg), None => sess.err(msg), } } - cstore.add_used_library(name, kind); + if lib.cfg.is_some() && !sess.features.borrow().link_cfg { + feature_gate::emit_feature_err(&sess.parse_sess, + "link_cfg", + span.unwrap(), + GateIssue::Language, + "is feature gated"); + } + cstore.add_used_library(lib); } // Extra info about a crate loaded for plugins or exported macros. @@ -635,9 +640,9 @@ impl<'a> CrateLoader<'a> { fn register_statically_included_foreign_items(&mut self) { let libs = self.cstore.get_used_libraries(); - for (lib, list) in self.foreign_item_map.iter() { - let is_static = libs.borrow().iter().any(|&(ref name, kind)| { - lib == name && kind == cstore::NativeStatic + for (foreign_lib, list) in self.foreign_item_map.iter() { + let is_static = libs.borrow().iter().any(|lib| { + *foreign_lib == lib.name && lib.kind == cstore::NativeStatic }); if is_static { for id in list { @@ -898,7 +903,18 @@ impl<'a> CrateLoader<'a> { InternedString::new("foo") } }; - register_native_lib(self.sess, self.cstore, Some(m.span), n.to_string(), kind); + let cfg = items.iter().find(|k| { + k.check_name("cfg") + }).and_then(|a| a.meta_item_list()); + let cfg = cfg.map(|list| { + list[0].meta_item().unwrap().clone() + }); + let lib = NativeLibrary { + name: n.to_string(), + kind: kind, + cfg: cfg, + }; + register_native_lib(self.sess, self.cstore, Some(m.span), lib); } // Finally, process the #[linked_from = "..."] attribute @@ -924,7 +940,12 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { } for &(ref name, kind) in &self.sess.opts.libs { - register_native_lib(self.sess, self.cstore, None, name.clone(), kind); + let lib = NativeLibrary { + name: name.clone(), + kind: kind, + cfg: None, + }; + register_native_lib(self.sess, self.cstore, None, lib); } self.register_statically_included_foreign_items(); } diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 8c95e4aec0a0..37853b7473a6 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -31,7 +31,7 @@ use syntax::{ast, attr}; use syntax::ext::base::SyntaxExtension; use syntax_pos; -pub use rustc::middle::cstore::{NativeLibraryKind, LinkagePreference}; +pub use rustc::middle::cstore::{NativeLibrary, LinkagePreference}; pub use rustc::middle::cstore::{NativeStatic, NativeFramework, NativeUnknown}; pub use rustc::middle::cstore::{CrateSource, LinkMeta}; @@ -97,7 +97,7 @@ pub struct CStore { metas: RefCell>>, /// Map from NodeId's of local extern crate statements to crate numbers extern_mod_crate_map: RefCell>, - used_libraries: RefCell>, + used_libraries: RefCell>, used_link_args: RefCell>, statically_included_foreign_items: RefCell, pub inlined_item_cache: RefCell>>, @@ -212,12 +212,12 @@ impl CStore { libs } - pub fn add_used_library(&self, lib: String, kind: NativeLibraryKind) { - assert!(!lib.is_empty()); - self.used_libraries.borrow_mut().push((lib, kind)); + pub fn add_used_library(&self, lib: NativeLibrary) { + assert!(!lib.name.is_empty()); + self.used_libraries.borrow_mut().push(lib); } - pub fn get_used_libraries<'a>(&'a self) -> &'a RefCell> { + pub fn get_used_libraries(&self) -> &RefCell> { &self.used_libraries } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 83de8acdb605..5419f9955e44 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -14,7 +14,7 @@ use locator; use schema; use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, DepKind, ExternCrate}; -use rustc::middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference, LoadedMacro}; +use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro}; use rustc::hir::def::{self, Def}; use rustc::middle::lang_items; use rustc::session::Session; @@ -295,7 +295,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { }) } - fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)> + fn native_libraries(&self, cnum: CrateNum) -> Vec { self.get_crate_data(cnum).get_native_libraries() } @@ -524,7 +524,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { result } - fn used_libraries(&self) -> Vec<(String, NativeLibraryKind)> + fn used_libraries(&self) -> Vec { self.get_used_libraries().borrow().clone() } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index ba85544326f8..6ffe53345332 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -11,7 +11,7 @@ // Decoding metadata from a single crate's metadata use astencode::decode_inlined_item; -use cstore::{self, CrateMetadata, MetadataBlob, NativeLibraryKind}; +use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary}; use index::Index; use schema::*; @@ -980,7 +980,7 @@ impl<'a, 'tcx> CrateMetadata { } - pub fn get_native_libraries(&self) -> Vec<(NativeLibraryKind, String)> { + pub fn get_native_libraries(&self) -> Vec { self.root.native_libraries.decode(self).collect() } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 778a9d185e14..823c50e1e5fd 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -13,7 +13,7 @@ use index::Index; use schema::*; use rustc::middle::cstore::{InlinedItemRef, LinkMeta}; -use rustc::middle::cstore::{LinkagePreference, NativeLibraryKind}; +use rustc::middle::cstore::{LinkagePreference, NativeLibrary}; use rustc::hir::def; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId}; use rustc::middle::dependency_format::Linkage; @@ -1134,14 +1134,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy_seq_ref(&tcx.lang_items.missing)) } - fn encode_native_libraries(&mut self) -> LazySeq<(NativeLibraryKind, String)> { + fn encode_native_libraries(&mut self) -> LazySeq { let used_libraries = self.tcx.sess.cstore.used_libraries(); - self.lazy_seq(used_libraries.into_iter().filter_map(|(lib, kind)| { - match kind { - cstore::NativeStatic => None, // these libraries are not propagated - cstore::NativeFramework | cstore::NativeUnknown => Some((kind, lib)), - } - })) + self.lazy_seq(used_libraries) } fn encode_codemap(&mut self) -> LazySeq { diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index d7a5f7ad7154..5292a4a7c376 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -14,7 +14,7 @@ use index; use rustc::hir; use rustc::hir::def::{self, CtorKind}; use rustc::hir::def_id::{DefIndex, DefId}; -use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibraryKind}; +use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary}; use rustc::middle::lang_items; use rustc::mir; use rustc::ty::{self, Ty}; @@ -175,7 +175,7 @@ pub struct CrateRoot { pub dylib_dependency_formats: LazySeq>, pub lang_items: LazySeq<(DefIndex, usize)>, pub lang_items_missing: LazySeq, - pub native_libraries: LazySeq<(NativeLibraryKind, String)>, + pub native_libraries: LazySeq, pub codemap: LazySeq, pub impls: LazySeq, pub reachable_ids: LazySeq, diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_trans/back/archive.rs index e063209799f1..df8dd7750ae0 100644 --- a/src/librustc_trans/back/archive.rs +++ b/src/librustc_trans/back/archive.rs @@ -145,8 +145,11 @@ impl<'a> ArchiveBuilder<'a> { /// /// This ignores adding the bytecode from the rlib, and if LTO is enabled /// then the object file also isn't added. - pub fn add_rlib(&mut self, rlib: &Path, name: &str, lto: bool) - -> io::Result<()> { + pub fn add_rlib(&mut self, + rlib: &Path, + name: &str, + lto: bool, + skip_objects: bool) -> io::Result<()> { // Ignoring obj file starting with the crate name // as simple comparison is not enough - there // might be also an extra name suffix @@ -159,9 +162,23 @@ impl<'a> ArchiveBuilder<'a> { self.config.sess.cstore.metadata_filename().to_owned(); self.add_archive(rlib, move |fname: &str| { - let skip_obj = lto && fname.starts_with(&obj_start) - && fname.ends_with(".o"); - skip_obj || fname.ends_with(bc_ext) || fname == metadata_filename + if fname.ends_with(bc_ext) || fname == metadata_filename { + return true + } + + // Don't include Rust objects if LTO is enabled + if lto && fname.starts_with(&obj_start) && fname.ends_with(".o") { + return true + } + + // Otherwise if this is *not* a rust object and we're skipping + // objects then skip this file + if skip_objects && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) { + return true + } + + // ok, don't skip this + return false }) } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index ad8e0c1ee59f..95d63311ee6e 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -19,7 +19,7 @@ use session::config::{OutputFilenames, Input, OutputType}; use session::filesearch; use session::search_paths::PathKind; use session::Session; -use middle::cstore::{self, LinkMeta}; +use middle::cstore::{self, LinkMeta, NativeLibrary}; use middle::cstore::{LinkagePreference, NativeLibraryKind}; use middle::dependency_format::Linkage; use CrateTranslation; @@ -43,6 +43,7 @@ use std::process::Command; use std::str; use flate; use syntax::ast; +use syntax::attr; use syntax_pos::Span; // RLIB LLVM-BYTECODE OBJECT LAYOUT @@ -406,12 +407,29 @@ fn link_rlib<'a>(sess: &'a Session, ab.add_file(obj); } - for (l, kind) in sess.cstore.used_libraries() { - match kind { - NativeLibraryKind::NativeStatic => ab.add_native_library(&l), + // Note that in this loop we are ignoring the value of `lib.cfg`. That is, + // we may not be configured to actually include a static library if we're + // adding it here. That's because later when we consume this rlib we'll + // decide whether we actually needed the static library or not. + // + // To do this "correctly" we'd need to keep track of which libraries added + // which object files to the archive. We don't do that here, however. The + // #[link(cfg(..))] feature is unstable, though, and only intended to get + // liblibc working. In that sense the check below just indicates that if + // there are any libraries we want to omit object files for at link time we + // just exclude all custom object files. + // + // Eventually if we want to stabilize or flesh out the #[link(cfg(..))] + // feature then we'll need to figure out how to record what objects were + // loaded from the libraries found here and then encode that into the + // metadata of the rlib we're generating somehow. + for lib in sess.cstore.used_libraries() { + match lib.kind { + NativeLibraryKind::NativeStatic => {} NativeLibraryKind::NativeFramework | - NativeLibraryKind::NativeUnknown => {} + NativeLibraryKind::NativeUnknown => continue, } + ab.add_native_library(&lib.name); } // After adding all files to the archive, we need to update the @@ -578,10 +596,28 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path, each_linked_rlib(sess, &mut |cnum, path| { let name = sess.cstore.crate_name(cnum); - ab.add_rlib(path, &name, sess.lto()).unwrap(); - let native_libs = sess.cstore.native_libraries(cnum); - all_native_libs.extend(native_libs); + + // Here when we include the rlib into our staticlib we need to make a + // decision whether to include the extra object files along the way. + // These extra object files come from statically included native + // libraries, but they may be cfg'd away with #[link(cfg(..))]. + // + // This unstable feature, though, only needs liblibc to work. The only + // use case there is where musl is statically included in liblibc.rlib, + // so if we don't want the included version we just need to skip it. As + // a result the logic here is that if *any* linked library is cfg'd away + // we just skip all object files. + // + // Clearly this is not sufficient for a general purpose feature, and + // we'd want to read from the library's metadata to determine which + // object files come from where and selectively skip them. + let skip_object_files = native_libs.iter().any(|lib| { + lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) + }); + ab.add_rlib(path, &name, sess.lto(), skip_object_files).unwrap(); + + all_native_libs.extend(sess.cstore.native_libraries(cnum)); }); ab.update_symbols(); @@ -594,13 +630,14 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path, platforms, and so may need to be preserved"); } - for &(kind, ref lib) in &all_native_libs { - let name = match kind { - NativeLibraryKind::NativeStatic => "static library", + for lib in all_native_libs.iter().filter(|l| relevant_lib(sess, l)) { + let name = match lib.kind { NativeLibraryKind::NativeUnknown => "library", NativeLibraryKind::NativeFramework => "framework", + // These are included, no need to print them + NativeLibraryKind::NativeStatic => continue, }; - sess.note_without_error(&format!("{}: {}", name, *lib)); + sess.note_without_error(&format!("{}: {}", name, lib.name)); } } @@ -876,14 +913,12 @@ fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) { } }); - let libs = sess.cstore.used_libraries(); - - let staticlibs = libs.iter().filter_map(|&(ref l, kind)| { - if kind == NativeLibraryKind::NativeStatic {Some(l)} else {None} - }); - let others = libs.iter().filter(|&&(_, kind)| { - kind != NativeLibraryKind::NativeStatic + let pair = sess.cstore.used_libraries().into_iter().filter(|l| { + relevant_lib(sess, l) + }).partition(|lib| { + lib.kind == NativeLibraryKind::NativeStatic }); + let (staticlibs, others): (Vec<_>, Vec<_>) = pair; // Some platforms take hints about whether a library is static or dynamic. // For those that support this, we ensure we pass the option if the library @@ -899,15 +934,15 @@ fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) { // don't otherwise explicitly reference them. This can occur for // libraries which are just providing bindings, libraries with generic // functions, etc. - cmd.link_whole_staticlib(l, &search_path); + cmd.link_whole_staticlib(&l.name, &search_path); } cmd.hint_dynamic(); - for &(ref l, kind) in others { - match kind { - NativeLibraryKind::NativeUnknown => cmd.link_dylib(l), - NativeLibraryKind::NativeFramework => cmd.link_framework(l), + for lib in others { + match lib.kind { + NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name), + NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name), NativeLibraryKind::NativeStatic => bug!(), } } @@ -1017,7 +1052,16 @@ fn add_upstream_rust_crates(cmd: &mut Linker, cnum: CrateNum) { let src = sess.cstore.used_crate_source(cnum); let cratepath = &src.rlib.unwrap().0; - if !sess.lto() && crate_type != config::CrateTypeDylib { + + // See the comment above in `link_staticlib` and `link_rlib` for why if + // there's a static library that's not relevant we skip all object + // files. + let native_libs = sess.cstore.native_libraries(cnum); + let skip_native = native_libs.iter().any(|lib| { + lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) + }); + + if !sess.lto() && crate_type != config::CrateTypeDylib && !skip_native { cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath)); return } @@ -1029,33 +1073,42 @@ fn add_upstream_rust_crates(cmd: &mut Linker, time(sess.time_passes(), &format!("altering {}.rlib", name), || { let cfg = archive_config(sess, &dst, Some(cratepath)); let mut archive = ArchiveBuilder::new(cfg); - archive.remove_file(sess.cstore.metadata_filename()); archive.update_symbols(); let mut any_objects = false; for f in archive.src_files() { - if f.ends_with("bytecode.deflate") { + if f.ends_with("bytecode.deflate") || + f == sess.cstore.metadata_filename() { archive.remove_file(&f); continue } + let canonical = f.replace("-", "_"); let canonical_name = name.replace("-", "_"); + let is_rust_object = + canonical.starts_with(&canonical_name) && { + let num = &f[name.len()..f.len() - 2]; + num.len() > 0 && num[1..].parse::().is_ok() + }; + + // If we've been requested to skip all native object files + // (those not generated by the rust compiler) then we can skip + // this file. See above for why we may want to do this. + let skip_because_cfg_say_so = skip_native && !is_rust_object; + // If we're performing LTO and this is a rust-generated object // file, then we don't need the object file as it's part of the // LTO module. Note that `#![no_builtins]` is excluded from LTO, // though, so we let that object file slide. - if sess.lto() && - !sess.cstore.is_no_builtins(cnum) && - canonical.starts_with(&canonical_name) && - canonical.ends_with(".o") { - let num = &f[name.len()..f.len() - 2]; - if num.len() > 0 && num[1..].parse::().is_ok() { - archive.remove_file(&f); - continue - } + let skip_because_lto = sess.lto() && is_rust_object && + !sess.cstore.is_no_builtins(cnum); + + if skip_because_cfg_say_so || skip_because_lto { + archive.remove_file(&f); + } else { + any_objects = true; } - any_objects = true; } if !any_objects { @@ -1127,15 +1180,26 @@ fn add_upstream_native_libraries(cmd: &mut Linker, sess: &Session) { // the paths. let crates = sess.cstore.used_crates(LinkagePreference::RequireStatic); for (cnum, _) in crates { - let libs = sess.cstore.native_libraries(cnum); - for &(kind, ref lib) in &libs { - match kind { - NativeLibraryKind::NativeUnknown => cmd.link_dylib(lib), - NativeLibraryKind::NativeFramework => cmd.link_framework(lib), - NativeLibraryKind::NativeStatic => { - bug!("statics shouldn't be propagated"); - } + for lib in sess.cstore.native_libraries(cnum) { + if !relevant_lib(sess, &lib) { + continue + } + match lib.kind { + NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name), + NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name), + + // ignore statically included native libraries here as we've + // already included them when we included the rust library + // previously + NativeLibraryKind::NativeStatic => {} } } } } + +fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool { + match lib.cfg { + Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None), + None => true, + } +} diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 9012914deeb0..01eea08c50bc 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -147,7 +147,16 @@ impl Emitter for SharedEmitter { // arise as some of intrinsics are converted into function calls // and nobody provides implementations those functions fn target_feature(sess: &Session) -> String { - format!("{},{}", sess.target.target.options.features, sess.opts.cg.target_feature) + let rustc_features = [ + "crt-static", + ]; + let requested_features = sess.opts.cg.target_feature.split(','); + let llvm_features = requested_features.filter(|f| { + !rustc_features.iter().any(|s| f.contains(s)) + }); + format!("{},{}", + sess.target.target.options.features, + llvm_features.collect::>().join(",")) } fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9116b392f178..27f720b76099 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -311,6 +311,9 @@ declare_features! ( // Allows using `Self` and associated types in struct expressions and patterns. (active, more_struct_aliases, "1.14.0", Some(37544)), + + // Allows #[link(..., cfg(..))] + (active, link_cfg, "1.14.0", Some(37406)), ); declare_features! ( diff --git a/src/test/compile-fail/crt-static-gated.rs b/src/test/compile-fail/crt-static-gated.rs new file mode 100644 index 000000000000..6c7c60b653a2 --- /dev/null +++ b/src/test/compile-fail/crt-static-gated.rs @@ -0,0 +1,14 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C target-feature=+crt-static +// error-pattern: specifying the `crt-static` target feature is only allowed + +fn main() {} diff --git a/src/test/compile-fail/link-cfg-gated.rs b/src/test/compile-fail/link-cfg-gated.rs new file mode 100644 index 000000000000..27918a27caf5 --- /dev/null +++ b/src/test/compile-fail/link-cfg-gated.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[link(name = "foo", cfg(foo))] +//~^ ERROR: is feature gated +extern {} + +fn main() {} diff --git a/src/test/run-make/link-cfg/Makefile b/src/test/run-make/link-cfg/Makefile new file mode 100644 index 000000000000..4abc0caa6986 --- /dev/null +++ b/src/test/run-make/link-cfg/Makefile @@ -0,0 +1,22 @@ +-include ../tools.mk + +all: $(call DYLIB,return1) $(call DYLIB,return2) $(call NATIVE_STATICLIB,return3) + ls $(TMPDIR) + $(RUSTC) --print cfg --target x86_64-unknown-linux-musl | grep crt-static + + $(RUSTC) no-deps.rs --cfg foo + $(call RUN,no-deps) + $(RUSTC) no-deps.rs --cfg bar + $(call RUN,no-deps) + + $(RUSTC) dep.rs + $(RUSTC) with-deps.rs --cfg foo + $(call RUN,with-deps) + $(RUSTC) with-deps.rs --cfg bar + $(call RUN,with-deps) + + $(RUSTC) dep-with-staticlib.rs + $(RUSTC) with-staticlib-deps.rs --cfg foo + $(call RUN,with-staticlib-deps) + $(RUSTC) with-staticlib-deps.rs --cfg bar + $(call RUN,with-staticlib-deps) diff --git a/src/test/run-make/link-cfg/dep-with-staticlib.rs b/src/test/run-make/link-cfg/dep-with-staticlib.rs new file mode 100644 index 000000000000..ecc2365ddb06 --- /dev/null +++ b/src/test/run-make/link-cfg/dep-with-staticlib.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(link_cfg)] +#![crate_type = "rlib"] + +#[link(name = "return1", cfg(foo))] +#[link(name = "return3", kind = "static", cfg(bar))] +extern { + pub fn my_function() -> i32; +} diff --git a/src/test/run-make/link-cfg/dep.rs b/src/test/run-make/link-cfg/dep.rs new file mode 100644 index 000000000000..7da879c2bfa2 --- /dev/null +++ b/src/test/run-make/link-cfg/dep.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(link_cfg)] +#![crate_type = "rlib"] + +#[link(name = "return1", cfg(foo))] +#[link(name = "return2", cfg(bar))] +extern { + pub fn my_function() -> i32; +} diff --git a/src/test/run-make/link-cfg/no-deps.rs b/src/test/run-make/link-cfg/no-deps.rs new file mode 100644 index 000000000000..6b1141067440 --- /dev/null +++ b/src/test/run-make/link-cfg/no-deps.rs @@ -0,0 +1,30 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(link_cfg)] + +#[link(name = "return1", cfg(foo))] +#[link(name = "return2", cfg(bar))] +extern { + fn my_function() -> i32; +} + +fn main() { + unsafe { + let v = my_function(); + if cfg!(foo) { + assert_eq!(v, 1); + } else if cfg!(bar) { + assert_eq!(v, 2); + } else { + panic!("unknown"); + } + } +} diff --git a/src/test/run-make/link-cfg/return1.c b/src/test/run-make/link-cfg/return1.c new file mode 100644 index 000000000000..a2a3d051dd14 --- /dev/null +++ b/src/test/run-make/link-cfg/return1.c @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int my_function() { + return 1; +} diff --git a/src/test/run-make/link-cfg/return2.c b/src/test/run-make/link-cfg/return2.c new file mode 100644 index 000000000000..d6ddcccf2fb7 --- /dev/null +++ b/src/test/run-make/link-cfg/return2.c @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int my_function() { + return 2; +} diff --git a/src/test/run-make/link-cfg/return3.c b/src/test/run-make/link-cfg/return3.c new file mode 100644 index 000000000000..6a3b695f2081 --- /dev/null +++ b/src/test/run-make/link-cfg/return3.c @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int my_function() { + return 3; +} diff --git a/src/test/run-make/link-cfg/with-deps.rs b/src/test/run-make/link-cfg/with-deps.rs new file mode 100644 index 000000000000..799555c500a1 --- /dev/null +++ b/src/test/run-make/link-cfg/with-deps.rs @@ -0,0 +1,24 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate dep; + +fn main() { + unsafe { + let v = dep::my_function(); + if cfg!(foo) { + assert_eq!(v, 1); + } else if cfg!(bar) { + assert_eq!(v, 2); + } else { + panic!("unknown"); + } + } +} diff --git a/src/test/run-make/link-cfg/with-staticlib-deps.rs b/src/test/run-make/link-cfg/with-staticlib-deps.rs new file mode 100644 index 000000000000..33a9c7720e26 --- /dev/null +++ b/src/test/run-make/link-cfg/with-staticlib-deps.rs @@ -0,0 +1,24 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate dep_with_staticlib; + +fn main() { + unsafe { + let v = dep_with_staticlib::my_function(); + if cfg!(foo) { + assert_eq!(v, 1); + } else if cfg!(bar) { + assert_eq!(v, 3); + } else { + panic!("unknown"); + } + } +} diff --git a/src/test/run-pass/auxiliary/link-cfg-works-transitive-dylib.rs b/src/test/run-pass/auxiliary/link-cfg-works-transitive-dylib.rs new file mode 100644 index 000000000000..d41fd490f58e --- /dev/null +++ b/src/test/run-pass/auxiliary/link-cfg-works-transitive-dylib.rs @@ -0,0 +1,14 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(link_cfg)] + +#[link(name = "foo", cfg(foo))] +extern {} diff --git a/src/test/run-pass/auxiliary/link-cfg-works-transitive-rlib.rs b/src/test/run-pass/auxiliary/link-cfg-works-transitive-rlib.rs new file mode 100644 index 000000000000..9f096c351fbe --- /dev/null +++ b/src/test/run-pass/auxiliary/link-cfg-works-transitive-rlib.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![feature(link_cfg)] +#![crate_type = "rlib"] + +#[link(name = "foo", cfg(foo))] +extern {} diff --git a/src/test/run-pass/crt-static-off-works.rs b/src/test/run-pass/crt-static-off-works.rs new file mode 100644 index 000000000000..c94c877c12c6 --- /dev/null +++ b/src/test/run-pass/crt-static-off-works.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C target-feature=-crt-static -Z unstable-options +// ignore-musl - requires changing the linker which is hard + +#![feature(cfg_target_feature)] + +#[cfg(not(target_feature = "crt-static"))] +fn main() {} diff --git a/src/test/run-pass/crt-static-on-works.rs b/src/test/run-pass/crt-static-on-works.rs new file mode 100644 index 000000000000..ae8e5f629704 --- /dev/null +++ b/src/test/run-pass/crt-static-on-works.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C target-feature=+crt-static -Z unstable-options + +#![feature(cfg_target_feature)] + +#[cfg(target_feature = "crt-static")] +fn main() {} diff --git a/src/test/run-pass/link-cfg-works.rs b/src/test/run-pass/link-cfg-works.rs new file mode 100644 index 000000000000..7db948c7daa9 --- /dev/null +++ b/src/test/run-pass/link-cfg-works.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:link-cfg-works-transitive-rlib.rs +// aux-build:link-cfg-works-transitive-dylib.rs + +#![feature(link_cfg)] + +extern crate link_cfg_works_transitive_rlib; +extern crate link_cfg_works_transitive_dylib; + +#[link(name = "foo", cfg(foo))] +extern {} + +fn main() {} + From 8e4097f6a843ec6d333627459ca54e4656d42335 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 16 Nov 2016 11:56:18 -0500 Subject: [PATCH 124/177] ICH: Add test case for type alias definitions --- src/test/incremental/hashes/type_defs.rs | 249 +++++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 src/test/incremental/hashes/type_defs.rs diff --git a/src/test/incremental/hashes/type_defs.rs b/src/test/incremental/hashes/type_defs.rs new file mode 100644 index 000000000000..35fb583cd4ed --- /dev/null +++ b/src/test/incremental/hashes/type_defs.rs @@ -0,0 +1,249 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// This test case tests the incremental compilation hash (ICH) implementation +// for `type` definitions. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// We also test the ICH for `type` definitions exported in metadata. Same as +// above, we want to make sure that the change between rev1 and rev2 also +// results in a change of the ICH for the enum's metadata, and that it stays +// the same between rev2 and rev3. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![crate_type="rlib"] + + +// Change type (primitive) ----------------------------------------------------- +#[cfg(cfail1)] +type ChangePrimitiveType = i32; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type ChangePrimitiveType = i64; + + + +// Change mutability ----------------------------------------------------------- +#[cfg(cfail1)] +type ChangeMutability = &'static i32; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type ChangeMutability = &'static mut i32; + + + +// Change mutability ----------------------------------------------------------- +#[cfg(cfail1)] +type ChangeLifetime<'a> = (&'static i32, &'a i32); + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type ChangeLifetime<'a> = (&'a i32, &'a i32); + + + +// Change type (struct) ----------------------------------------------------------- +struct Struct1; +struct Struct2; + +#[cfg(cfail1)] +type ChangeTypeStruct = Struct1; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type ChangeTypeStruct = Struct2; + + + +// Change type (tuple) --------------------------------------------------------- +#[cfg(cfail1)] +type ChangeTypeTuple = (u32, u64); + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type ChangeTypeTuple = (u32, i64); + + + +// Change type (enum) ---------------------------------------------------------- +enum Enum1 { + Var1, + Var2, +} +enum Enum2 { + Var1, + Var2, +} + +#[cfg(cfail1)] +type ChangeTypeEnum = Enum1; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type ChangeTypeEnum = Enum2; + + + +// Add tuple field ------------------------------------------------------------- +#[cfg(cfail1)] +type AddTupleField = (i32, i64); + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type AddTupleField = (i32, i64, i16); + + + +// Change nested tuple field --------------------------------------------------- +#[cfg(cfail1)] +type ChangeNestedTupleField = (i32, (i64, i16)); + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type ChangeNestedTupleField = (i32, (i64, i8)); + + + +// Add type param -------------------------------------------------------------- +#[cfg(cfail1)] +type AddTypeParam = (T1, T1); + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type AddTypeParam = (T1, T2); + + + +// Add type param bound -------------------------------------------------------- +#[cfg(cfail1)] +type AddTypeParamBound = (T1, u32); + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type AddTypeParamBound = (T1, u32); + + + +// Add type param bound in where clause ---------------------------------------- +#[cfg(cfail1)] +type AddTypeParamBoundWhereClause where T1: Clone = (T1, u32); + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type AddTypeParamBoundWhereClause where T1: Clone+Copy = (T1, u32); + + + +// Add lifetime param ---------------------------------------------------------- +#[cfg(cfail1)] +type AddLifetimeParam<'a> = (&'a u32, &'a u32); + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type AddLifetimeParam<'a, 'b> = (&'a u32, &'b u32); + + + +// Add lifetime param bound ---------------------------------------------------- +#[cfg(cfail1)] +type AddLifetimeParamBound<'a, 'b> = (&'a u32, &'b u32); + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type AddLifetimeParamBound<'a, 'b: 'a> = (&'a u32, &'b u32); + + + +// Add lifetime param bound in where clause ------------------------------------ +#[cfg(cfail1)] +type AddLifetimeParamBoundWhereClause<'a, 'b, 'c> +where 'b: 'a + = (&'a u32, &'b u32, &'c u32); + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type AddLifetimeParamBoundWhereClause<'a, 'b, 'c> +where 'b: 'a, + 'c: 'a + = (&'a u32, &'b u32, &'c u32); + + + +// Change Trait Bound Indirectly ----------------------------------------------- +trait ReferencedTrait1 {} +trait ReferencedTrait2 {} + +mod change_trait_bound_indirectly { + #[cfg(cfail1)] + use super::ReferencedTrait1 as Trait; + #[cfg(not(cfail1))] + use super::ReferencedTrait2 as Trait; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + type ChangeTraitBoundIndirectly = (T, u32); +} + + + +// Change Trait Bound Indirectly In Where Clause ------------------------------- +mod change_trait_bound_indirectly_in_where_clause { + #[cfg(cfail1)] + use super::ReferencedTrait1 as Trait; + #[cfg(not(cfail1))] + use super::ReferencedTrait2 as Trait; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + type ChangeTraitBoundIndirectly where T : Trait = (T, u32); +} From 36fbf8c53cd37498e5eaadf02740e2aac87f6118 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 2 Nov 2016 18:22:59 -0400 Subject: [PATCH 125/177] refactor Visitor into ItemLikeVisitor and intravisit::Visitor There are now three patterns (shallow, deep, and nested visit). These are described in detail on the docs in `itemlikevisit::ItemLikeVisitor`. --- src/librustc/dep_graph/mod.rs | 2 +- src/librustc/dep_graph/visit.rs | 17 ++-- src/librustc/hir/intravisit.rs | 28 +++++-- src/librustc/hir/itemlikevisit.rs | 79 +++++++++++++++++++ src/librustc/hir/mod.rs | 5 +- src/librustc/middle/dead.rs | 5 +- src/librustc/middle/effect.rs | 2 +- src/librustc/middle/entry.rs | 6 +- src/librustc/middle/intrinsicck.rs | 2 +- src/librustc/middle/lang_items.rs | 6 +- src/librustc/middle/liveness.rs | 2 +- src/librustc/middle/reachable.rs | 5 +- src/librustc/middle/region.rs | 2 +- src/librustc/middle/resolve_lifetime.rs | 17 +++- src/librustc/middle/weak_lang_items.rs | 2 +- src/librustc/ty/mod.rs | 12 +-- src/librustc_borrowck/borrowck/mod.rs | 2 +- src/librustc_const_eval/check_match.rs | 3 +- src/librustc_driver/derive_registrar.rs | 6 +- src/librustc_incremental/assert_dep_graph.rs | 6 +- src/librustc_incremental/calculate_svh/mod.rs | 6 +- .../persist/dirty_clean.rs | 10 +-- src/librustc_metadata/encoder.rs | 7 +- src/librustc_mir/mir_map.rs | 4 +- src/librustc_passes/consts.rs | 14 ++-- src/librustc_passes/loops.rs | 4 +- src/librustc_passes/rvalues.rs | 6 +- src/librustc_passes/static_recursion.rs | 3 +- src/librustc_plugin/build.rs | 6 +- src/librustc_privacy/lib.rs | 5 +- src/librustc_trans/collector.rs | 16 ++-- src/librustc_trans/symbol_names_test.rs | 3 +- src/librustc_typeck/check/method/suggest.rs | 6 +- src/librustc_typeck/check/mod.rs | 10 ++- src/librustc_typeck/check_unused.rs | 6 +- src/librustc_typeck/coherence/mod.rs | 9 ++- src/librustc_typeck/coherence/orphan.rs | 6 +- src/librustc_typeck/coherence/overlap.rs | 6 +- src/librustc_typeck/coherence/unsafety.rs | 8 +- src/librustc_typeck/collect.rs | 7 +- src/librustc_typeck/variance/constraints.rs | 8 +- src/librustc_typeck/variance/terms.rs | 6 +- 42 files changed, 239 insertions(+), 126 deletions(-) create mode 100644 src/librustc/hir/itemlikevisit.rs diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 9c00e95c17e0..e365cea6d0e5 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -25,5 +25,5 @@ pub use self::dep_node::WorkProductId; pub use self::graph::DepGraph; pub use self::graph::WorkProduct; pub use self::query::DepGraphQuery; -pub use self::visit::visit_all_items_in_krate; +pub use self::visit::visit_all_item_likes_in_krate; pub use self::raii::DepTask; diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs index d085c24036ce..30de5e5288ab 100644 --- a/src/librustc/dep_graph/visit.rs +++ b/src/librustc/dep_graph/visit.rs @@ -10,22 +10,21 @@ use hir; use hir::def_id::DefId; -use hir::intravisit::Visitor; +use hir::itemlikevisit::ItemLikeVisitor; use ty::TyCtxt; use super::dep_node::DepNode; - /// Visit all the items in the krate in some order. When visiting a /// particular item, first create a dep-node by calling `dep_node_fn` /// and push that onto the dep-graph stack of tasks, and also create a /// read edge from the corresponding AST node. This is used in /// compiler passes to automatically record the item that they are /// working on. -pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - mut dep_node_fn: F, - visitor: &mut V) - where F: FnMut(DefId) -> DepNode, V: Visitor<'tcx> +pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + mut dep_node_fn: F, + visitor: &mut V) + where F: FnMut(DefId) -> DepNode, V: ItemLikeVisitor<'tcx> { struct TrackingVisitor<'visit, 'tcx: 'visit, F: 'visit, V: 'visit> { tcx: TyCtxt<'visit, 'tcx, 'tcx>, @@ -33,8 +32,8 @@ pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, visitor: &'visit mut V } - impl<'visit, 'tcx, F, V> Visitor<'tcx> for TrackingVisitor<'visit, 'tcx, F, V> - where F: FnMut(DefId) -> DepNode, V: Visitor<'tcx> + impl<'visit, 'tcx, F, V> ItemLikeVisitor<'tcx> for TrackingVisitor<'visit, 'tcx, F, V> + where F: FnMut(DefId) -> DepNode, V: ItemLikeVisitor<'tcx> { fn visit_item(&mut self, i: &'tcx hir::Item) { let item_def_id = self.tcx.map.local_def_id(i.id); @@ -54,5 +53,5 @@ pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, dep_node_fn: &mut dep_node_fn, visitor: visitor }; - krate.visit_all_items(&mut tracking_visitor) + krate.visit_all_item_likes(&mut tracking_visitor) } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 9932e5fe6862..2fc27e0cea09 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -8,7 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! HIR walker. Each overridden visit method has full control over what +//! HIR walker for walking the contents of nodes. +//! +//! **For an overview of the visitor strategy, see the docs on the +//! `super::itemlikevisit::ItemLikeVisitor` trait.** +//! +//! If you have decided to use this visitor, here are some general +//! notes on how to do it: +//! +//! Each overridden visit method has full control over what //! happens with its node, it can do its own traversal of the node's children, //! call `intravisit::walk_*` to apply the default traversal algorithm, or prevent //! deeper traversal by doing nothing. @@ -30,6 +38,7 @@ use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute}; use syntax::codemap::Spanned; use syntax_pos::Span; use hir::*; +use super::itemlikevisit::DeepVisitor; use std::cmp; use std::u32; @@ -78,10 +87,9 @@ pub trait Visitor<'v> : Sized { /// Invoked when a nested item is encountered. By default, does /// nothing. If you want a deep walk, you need to override to - /// fetch the item contents. But most of the time, it is easier - /// (and better) to invoke `Crate::visit_all_items`, which visits - /// all items in the crate in some order (but doesn't respect - /// nesting). + /// fetch the item contents. But most of the time, it is easier to + /// use either the "shallow" or "deep" visit patterns described on + /// `itemlikevisit::ItemLikeVisitor`. #[allow(unused_variables)] fn visit_nested_item(&mut self, id: ItemId) { } @@ -92,6 +100,16 @@ pub trait Visitor<'v> : Sized { walk_item(self, i) } + /// When invoking `visit_all_item_likes()`, you need to supply an + /// item-like visitor. This method converts a "intra-visit" + /// visitor into an item-like visitor that walks the entire tree. + /// If you use this, you probably don't want to process the + /// contents of nested item-like things, since the outer loop will + /// visit them as well. + fn as_deep_visitor<'s>(&'s mut self) -> DeepVisitor<'s, Self> { + DeepVisitor::new(self) + } + /////////////////////////////////////////////////////////////////////////// fn visit_id(&mut self, _node_id: NodeId) { diff --git a/src/librustc/hir/itemlikevisit.rs b/src/librustc/hir/itemlikevisit.rs new file mode 100644 index 000000000000..6da47015d7dc --- /dev/null +++ b/src/librustc/hir/itemlikevisit.rs @@ -0,0 +1,79 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::Item; +use super::intravisit::Visitor; + +/// The "item-like visitor" visitor defines only the top-level methods +/// that can be invoked by `Crate::visit_all_item_likes()`. Whether +/// this trait is the right one to implement will depend on the +/// overall pattern you need. Here are the three available patterns, +/// in roughly the order of desirability: +/// +/// 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR. +/// - Example: find all items with a `#[foo]` attribute on them. +/// - How: Implement `ItemLikeVisitor` and call `tcx.visit_all_item_likes_in_krate()`. +/// - Pro: Efficient; just walks the lists of item-like things, not the nodes themselves. +/// - Pro: Integrates well into dependency tracking. +/// - Con: Don't get information about nesting +/// - Con: Don't have methods for specific bits of HIR, like "on +/// every expr, do this". +/// 2. **Deep visit**: Want to scan for specific kinds of HIR nodes within +/// an item, but don't care about how item-like things are nested +/// within one another. +/// - Example: Examine each expression to look for its type and do some check or other. +/// - How: Implement `intravisit::Visitor` and use +/// `tcx.visit_all_item_likes_in_krate(visitor.as_deep_visitor())`. Within +/// your `intravisit::Visitor` impl, implement methods like +/// `visit_expr()`; don't forget to invoke +/// `intravisit::walk_visit_expr()` to keep walking the subparts. +/// - Pro: Visitor methods for any kind of HIR node, not just item-like things. +/// - Pro: Integrates well into dependency tracking. +/// - Con: Don't get information about nesting between items +/// 3. **Nested visit**: Want to visit the whole HIR and you care about the nesting between +/// item-like things. +/// - Example: Lifetime resolution, which wants to bring lifetimes declared on the +/// impl into scope while visiting the impl-items, and then back out again. +/// - How: Implement `intravisit::Visitor` and override the `visit_nested_foo()` foo methods +/// as needed. Walk your crate with `intravisit::walk_crate()` invoked on `tcx.map.krate()`. +/// - Pro: Visitor methods for any kind of HIR node, not just item-like things. +/// - Pro: Preserves nesting information +/// - Con: Does not integrate well into dependency tracking. +/// +/// Note: the methods of `ItemLikeVisitor` intentionally have no +/// defaults, so that as we expand the list of item-like things, we +/// revisit the various visitors to see if they need to change. This +/// is harder to do with `intravisit::Visitor`, so when you add a new +/// `visit_nested_foo()` method, it is recommended that you search for +/// existing `fn visit_nested` methods to see where changes are +/// needed. +pub trait ItemLikeVisitor<'hir> { + fn visit_item(&mut self, item: &'hir Item); +} + +pub struct DeepVisitor<'v, V: 'v> { + visitor: &'v mut V, +} + +impl<'v, 'hir, V> DeepVisitor<'v, V> + where V: Visitor<'hir> + 'v +{ + pub fn new(base: &'v mut V) -> Self { + DeepVisitor { visitor: base } + } +} + +impl<'v, 'hir, V> ItemLikeVisitor<'hir> for DeepVisitor<'v, V> + where V: Visitor<'hir> +{ + fn visit_item(&mut self, item: &'hir Item) { + self.visitor.visit_item(item); + } +} diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 6b5b8101a146..4716a09ad35a 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -68,6 +68,7 @@ pub mod check_attr; pub mod def; pub mod def_id; pub mod intravisit; +pub mod itemlikevisit; pub mod lowering; pub mod map; pub mod pat_util; @@ -438,8 +439,8 @@ impl Crate { /// follows lexical scoping rules -- then you want a different /// approach. You should override `visit_nested_item` in your /// visitor and then call `intravisit::walk_crate` instead. - pub fn visit_all_items<'hir, V>(&'hir self, visitor: &mut V) - where V: intravisit::Visitor<'hir> + pub fn visit_all_item_likes<'hir, V>(&'hir self, visitor: &mut V) + where V: itemlikevisit::ItemLikeVisitor<'hir> { for (_, item) in &self.items { visitor.visit_item(item); diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 94667b398b08..2667943bea93 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -16,6 +16,7 @@ use dep_graph::DepNode; use hir::map as ast_map; use hir::{self, pat_util, PatKind}; use hir::intravisit::{self, Visitor}; +use hir::itemlikevisit::ItemLikeVisitor; use middle::privacy; use ty::{self, TyCtxt}; @@ -333,7 +334,7 @@ struct LifeSeeder { worklist: Vec } -impl<'v> Visitor<'v> for LifeSeeder { +impl<'v> ItemLikeVisitor<'v> for LifeSeeder { fn visit_item(&mut self, item: &hir::Item) { let allow_dead_code = has_allow_dead_code_or_lang_attr(&item.attrs); if allow_dead_code { @@ -388,7 +389,7 @@ fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut life_seeder = LifeSeeder { worklist: worklist }; - krate.visit_all_items(&mut life_seeder); + krate.visit_all_item_likes(&mut life_seeder); return life_seeder.worklist; } diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 5634e2012c97..25fe407271bc 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -235,5 +235,5 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { unsafe_context: UnsafeContext::new(SafeContext), }; - tcx.map.krate().visit_all_items(&mut visitor); + tcx.map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); } diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index 11bde922f47f..e5112749c0ee 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -18,7 +18,7 @@ use syntax::attr; use syntax::entry::EntryPointType; use syntax_pos::Span; use hir::{Item, ItemFn}; -use hir::intravisit::Visitor; +use hir::itemlikevisit::ItemLikeVisitor; struct EntryContext<'a, 'tcx: 'a> { session: &'a Session, @@ -39,7 +39,7 @@ struct EntryContext<'a, 'tcx: 'a> { non_main_fns: Vec<(NodeId, Span)> , } -impl<'a, 'tcx> Visitor<'tcx> for EntryContext<'a, 'tcx> { +impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx Item) { let def_id = self.map.local_def_id(item.id); let def_key = self.map.def_key(def_id); @@ -74,7 +74,7 @@ pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map) { non_main_fns: Vec::new(), }; - ast_map.krate().visit_all_items(&mut ctxt); + ast_map.krate().visit_all_item_likes(&mut ctxt); configure_main(&mut ctxt); } diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 0f9748a16f46..cf08b59312d5 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -26,7 +26,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut visitor = ItemVisitor { tcx: tcx }; - tcx.visit_all_items_in_krate(DepNode::IntrinsicCheck, &mut visitor); + tcx.visit_all_item_likes_in_krate(DepNode::IntrinsicCheck, &mut visitor.as_deep_visitor()); } struct ItemVisitor<'a, 'tcx: 'a> { diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 3e7de79246b6..6fe8442474a9 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -31,7 +31,7 @@ use util::nodemap::FxHashMap; use syntax::ast; use syntax::parse::token::InternedString; -use hir::intravisit::Visitor; +use hir::itemlikevisit::ItemLikeVisitor; use hir; // The actual lang items defined come at the end of this file in one handy table. @@ -149,7 +149,7 @@ struct LanguageItemCollector<'a, 'tcx: 'a> { item_refs: FxHashMap<&'static str, usize>, } -impl<'a, 'v, 'tcx> Visitor<'v> for LanguageItemCollector<'a, 'tcx> { +impl<'a, 'v, 'tcx> ItemLikeVisitor<'v> for LanguageItemCollector<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { if let Some(value) = extract(&item.attrs) { let item_index = self.item_refs.get(&value[..]).cloned(); @@ -219,7 +219,7 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> { } pub fn collect_local_language_items(&mut self, krate: &hir::Crate) { - krate.visit_all_items(self); + krate.visit_all_item_likes(self); } pub fn collect_external_language_items(&mut self) { diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index f472205b732d..d381188d56b5 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -196,7 +196,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IrMaps<'a, 'tcx> { pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _task = tcx.dep_graph.in_task(DepNode::Liveness); - tcx.map.krate().visit_all_items(&mut IrMaps::new(tcx)); + tcx.map.krate().visit_all_item_likes(&mut IrMaps::new(tcx).as_deep_visitor()); tcx.sess.abort_if_errors(); } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 7868e700f270..848f4218d884 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -29,6 +29,7 @@ use syntax::ast; use syntax::attr; use hir; use hir::intravisit::Visitor; +use hir::itemlikevisit::ItemLikeVisitor; use hir::intravisit; // Returns true if the given set of generics implies that the item it's @@ -324,7 +325,7 @@ struct CollectPrivateImplItemsVisitor<'a> { worklist: &'a mut Vec, } -impl<'a, 'v> Visitor<'v> for CollectPrivateImplItemsVisitor<'a> { +impl<'a, 'v> ItemLikeVisitor<'v> for CollectPrivateImplItemsVisitor<'a> { fn visit_item(&mut self, item: &hir::Item) { // We need only trait impls here, not inherent impls, and only non-exported ones if let hir::ItemImpl(.., Some(_), _, ref impl_items) = item.node { @@ -364,7 +365,7 @@ pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, access_levels: access_levels, worklist: &mut reachable_context.worklist, }; - tcx.map.krate().visit_all_items(&mut collect_private_impl_items); + tcx.map.krate().visit_all_item_likes(&mut collect_private_impl_items); } // Step 2: Mark all symbols that the symbols on the worklist touch. diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 34a6a547d944..5f9a6b283c6a 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1235,7 +1235,7 @@ pub fn resolve_crate(sess: &Session, map: &ast_map::Map) -> RegionMaps { }, terminating_scopes: NodeSet() }; - krate.visit_all_items(&mut visitor); + krate.visit_all_item_likes(&mut visitor.as_deep_visitor()); } return maps; } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 292d9592ceb0..c342342d73b7 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -119,7 +119,7 @@ pub fn krate(sess: &Session, late_bound: NodeMap(), }; sess.track_errors(|| { - krate.visit_all_items(&mut LifetimeContext { + intravisit::walk_crate(&mut LifetimeContext { sess: sess, hir_map: hir_map, map: &mut map, @@ -127,14 +127,23 @@ pub fn krate(sess: &Session, def_map: def_map, trait_ref_hack: false, labels_in_fn: vec![], - }); + }, krate); })?; Ok(map) } impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { + // Override the nested functions -- lifetimes follow lexical scope, + // so it's convenient to walk the tree in lexical order. + + fn visit_nested_item(&mut self, id: hir::ItemId) { + let item = self.hir_map.expect_item(id.id); + self.visit_item(item) + } + fn visit_item(&mut self, item: &hir::Item) { - assert!(self.labels_in_fn.is_empty()); + // Save labels for nested items. + let saved_labels_in_fn = replace(&mut self.labels_in_fn, vec![]); // Items always introduce a new root scope self.with(RootScope, |_, this| { @@ -175,7 +184,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { }); // Done traversing the item; remove any labels it created - self.labels_in_fn.truncate(0); + self.labels_in_fn = saved_labels_in_fn; } fn visit_foreign_item(&mut self, item: &hir::ForeignItem) { diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 2c08e17f8f1a..12d32bf31b13 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -50,7 +50,7 @@ pub fn check_crate(krate: &hir::Crate, { let mut cx = Context { sess: sess, items: items }; - krate.visit_all_items(&mut cx); + krate.visit_all_item_likes(&mut cx.as_deep_visitor()); } verify(sess, items); } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 1de54f49a552..c6fff94438fc 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -50,7 +50,7 @@ use syntax_pos::{DUMMY_SP, Span}; use rustc_const_math::ConstInt; use hir; -use hir::intravisit::Visitor; +use hir::itemlikevisit::ItemLikeVisitor; pub use self::sty::{Binder, DebruijnIndex}; pub use self::sty::{BuiltinBound, BuiltinBounds}; @@ -2695,12 +2695,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_region(ty::ReScope(self.region_maps.node_extent(id))) } - pub fn visit_all_items_in_krate(self, - dep_node_fn: F, - visitor: &mut V) - where F: FnMut(DefId) -> DepNode, V: Visitor<'gcx> + pub fn visit_all_item_likes_in_krate(self, + dep_node_fn: F, + visitor: &mut V) + where F: FnMut(DefId) -> DepNode, V: ItemLikeVisitor<'gcx> { - dep_graph::visit_all_items_in_krate(self.global_tcx(), dep_node_fn, visitor); + dep_graph::visit_all_item_likes_in_krate(self.global_tcx(), dep_node_fn, visitor); } /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err` diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 237656087922..5e54e333bb90 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -110,7 +110,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { } }; - tcx.visit_all_items_in_krate(DepNode::BorrowCheck, &mut bccx); + tcx.visit_all_item_likes_in_krate(DepNode::BorrowCheck, &mut bccx.as_deep_visitor()); if tcx.sess.borrowck_stats() { println!("--- borrowck stats ---"); diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index e0e8a2159192..f63a27e0d756 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -78,7 +78,8 @@ impl<'a, 'v, 'tcx> Visitor<'v> for OuterVisitor<'a, 'tcx> { } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.visit_all_items_in_krate(DepNode::MatchCheck, &mut OuterVisitor { tcx: tcx }); + tcx.visit_all_item_likes_in_krate(DepNode::MatchCheck, + &mut OuterVisitor { tcx: tcx }.as_deep_visitor()); tcx.sess.abort_if_errors(); } diff --git a/src/librustc_driver/derive_registrar.rs b/src/librustc_driver/derive_registrar.rs index ea7621e16e7b..605193a0434b 100644 --- a/src/librustc_driver/derive_registrar.rs +++ b/src/librustc_driver/derive_registrar.rs @@ -9,7 +9,7 @@ // except according to those terms. use rustc::dep_graph::DepNode; -use rustc::hir::intravisit::Visitor; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::map::Map; use rustc::hir; use syntax::ast; @@ -20,7 +20,7 @@ pub fn find(hir_map: &Map) -> Option { let krate = hir_map.krate(); let mut finder = Finder { registrar: None }; - krate.visit_all_items(&mut finder); + krate.visit_all_item_likes(&mut finder); finder.registrar } @@ -28,7 +28,7 @@ struct Finder { registrar: Option, } -impl<'v> Visitor<'v> for Finder { +impl<'v> ItemLikeVisitor<'v> for Finder { fn visit_item(&mut self, item: &hir::Item) { if attr::contains_name(&item.attrs, "rustc_derive_registrar") { self.registrar = Some(item.id); diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 37477da755c9..84489c2e8c67 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -51,7 +51,7 @@ use rustc::ty::TyCtxt; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::{Direction, INCOMING, OUTGOING, NodeIndex}; use rustc::hir; -use rustc::hir::intravisit::Visitor; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use graphviz::IntoCow; use std::env; use std::fs::File; @@ -81,7 +81,7 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { if_this_changed: vec![], then_this_would_need: vec![] }; visitor.process_attrs(ast::CRATE_NODE_ID, &tcx.map.krate().attrs); - tcx.map.krate().visit_all_items(&mut visitor); + tcx.map.krate().visit_all_item_likes(&mut visitor); (visitor.if_this_changed, visitor.then_this_would_need) }; @@ -167,7 +167,7 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for IfThisChanged<'a, 'tcx> { +impl<'a, 'tcx> ItemLikeVisitor<'tcx> for IfThisChanged<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { self.process_attrs(item.id, &item.attrs); } diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index 58a215299741..5697441b6676 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -34,6 +34,7 @@ use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::intravisit as visit; +use rustc::hir::intravisit::Visitor; use rustc::ty::TyCtxt; use rustc_data_structures::fx::FxHashMap; use rustc::util::common::record_time; @@ -107,7 +108,8 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || { visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| visit::walk_crate(v, krate)); - krate.visit_all_items(&mut visitor); + // FIXME(#37713) if foreign items were item likes, could use ItemLikeVisitor + krate.visit_all_item_likes(&mut visitor.as_deep_visitor()); }); tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64); @@ -199,7 +201,7 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { } -impl<'a, 'tcx> visit::Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { self.calculate_node_id(item.id, |v| v.visit_item(item)); visit::walk_item(self, item); diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 69b9be12de46..f6b7abd2ef12 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -45,7 +45,7 @@ use super::load::DirtyNodes; use rustc::dep_graph::{DepGraphQuery, DepNode}; use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::hir::intravisit::Visitor; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use syntax::ast::{self, Attribute, NestedMetaItem}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use syntax::parse::token::InternedString; @@ -74,7 +74,7 @@ pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let query = tcx.dep_graph.query(); debug!("query-nodes: {:?}", query.nodes()); let krate = tcx.map.krate(); - krate.visit_all_items(&mut DirtyCleanVisitor { + krate.visit_all_item_likes(&mut DirtyCleanVisitor { tcx: tcx, query: &query, dirty_inputs: dirty_inputs, @@ -169,7 +169,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> { +impl<'a, 'tcx> ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { let def_id = self.tcx.map.local_def_id(item.id); for attr in self.tcx.get_attrs(def_id).iter() { @@ -195,7 +195,7 @@ pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.dep_graph.with_ignore(||{ let krate = tcx.map.krate(); - krate.visit_all_items(&mut DirtyCleanMetadataVisitor { + krate.visit_all_item_likes(&mut DirtyCleanMetadataVisitor { tcx: tcx, prev_metadata_hashes: prev_metadata_hashes, current_metadata_hashes: current_metadata_hashes, @@ -209,7 +209,7 @@ pub struct DirtyCleanMetadataVisitor<'a, 'tcx:'a, 'm> { current_metadata_hashes: &'m FxHashMap, } -impl<'a, 'tcx, 'm> Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { +impl<'a, 'tcx, 'm> ItemLikeVisitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { fn visit_item(&mut self, item: &'tcx hir::Item) { let def_id = self.tcx.map.local_def_id(item.id); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 778a9d185e14..bbffe88316b3 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -38,6 +38,7 @@ use syntax; use syntax_pos; use rustc::hir::{self, PatKind}; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::intravisit::Visitor; use rustc::hir::intravisit; @@ -1074,7 +1075,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { EncodeContext::encode_info_for_mod, FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public))); let mut visitor = EncodeVisitor { index: index }; - krate.visit_all_items(&mut visitor); + krate.visit_all_item_likes(&mut visitor.as_deep_visitor()); for macro_def in &krate.exported_macros { visitor.visit_macro_def(macro_def); } @@ -1164,7 +1165,7 @@ struct ImplVisitor<'a, 'tcx: 'a> { impls: FxHashMap>, } -impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> { +impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { if let hir::ItemImpl(..) = item.node { let impl_id = self.tcx.map.local_def_id(item.id); @@ -1185,7 +1186,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { tcx: self.tcx, impls: FxHashMap(), }; - self.tcx.map.krate().visit_all_items(&mut visitor); + self.tcx.map.krate().visit_all_item_likes(&mut visitor); let all_impls: Vec<_> = visitor.impls .into_iter() diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 4a50585efe3b..992c0e9b5fc8 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -38,9 +38,9 @@ use syntax_pos::Span; use std::mem; pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.visit_all_items_in_krate(DepNode::Mir, &mut BuildMir { + tcx.visit_all_item_likes_in_krate(DepNode::Mir, &mut BuildMir { tcx: tcx - }); + }.as_deep_visitor()); } /// A pass to lift all the types and substitutions in a Mir diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 02a0b3ab28d6..5df8accd8cef 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -644,13 +644,13 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.visit_all_items_in_krate(DepNode::CheckConst, - &mut CheckCrateVisitor { - tcx: tcx, - mode: Mode::Var, - qualif: ConstQualif::NOT_CONST, - rvalue_borrows: NodeMap(), - }); + tcx.visit_all_item_likes_in_krate(DepNode::CheckConst, + &mut CheckCrateVisitor { + tcx: tcx, + mode: Mode::Var, + qualif: ConstQualif::NOT_CONST, + rvalue_borrows: NodeMap(), + }.as_deep_visitor()); tcx.sess.abort_if_errors(); } diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index e58cd8938193..adcb7842ee1f 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -33,10 +33,10 @@ struct CheckLoopVisitor<'a> { pub fn check_crate(sess: &Session, map: &Map) { let _task = map.dep_graph.in_task(DepNode::CheckLoops); let krate = map.krate(); - krate.visit_all_items(&mut CheckLoopVisitor { + krate.visit_all_item_likes(&mut CheckLoopVisitor { sess: sess, cx: Normal, - }); + }.as_deep_visitor()); } impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> { diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs index d55ce4c35638..7386be2528c9 100644 --- a/src/librustc_passes/rvalues.rs +++ b/src/librustc_passes/rvalues.rs @@ -18,20 +18,20 @@ use rustc::ty::{self, TyCtxt, ParameterEnvironment}; use rustc::traits::Reveal; use rustc::hir; -use rustc::hir::intravisit; +use rustc::hir::intravisit::{self, Visitor}; use syntax::ast; use syntax_pos::Span; pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut rvcx = RvalueContext { tcx: tcx }; - tcx.visit_all_items_in_krate(DepNode::RvalueCheck, &mut rvcx); + tcx.visit_all_item_likes_in_krate(DepNode::RvalueCheck, &mut rvcx.as_deep_visitor()); } struct RvalueContext<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, } -impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> { +impl<'a, 'tcx, 'v> Visitor<'v> for RvalueContext<'a, 'tcx> { fn visit_fn(&mut self, fk: intravisit::FnKind<'v>, fd: &'v hir::FnDecl, diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs index 0e0f8a845673..5f76f865c4ac 100644 --- a/src/librustc_passes/static_recursion.rs +++ b/src/librustc_passes/static_recursion.rs @@ -100,7 +100,8 @@ pub fn check_crate<'ast>(sess: &Session, discriminant_map: RefCell::new(NodeMap()), }; sess.track_errors(|| { - ast_map.krate().visit_all_items(&mut visitor); + // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like + ast_map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); }) } diff --git a/src/librustc_plugin/build.rs b/src/librustc_plugin/build.rs index ff3038c3d117..0464a93ef717 100644 --- a/src/librustc_plugin/build.rs +++ b/src/librustc_plugin/build.rs @@ -16,14 +16,14 @@ use errors; use syntax_pos::Span; use rustc::dep_graph::DepNode; use rustc::hir::map::Map; -use rustc::hir::intravisit::Visitor; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir; struct RegistrarFinder { registrars: Vec<(ast::NodeId, Span)> , } -impl<'v> Visitor<'v> for RegistrarFinder { +impl<'v> ItemLikeVisitor<'v> for RegistrarFinder { fn visit_item(&mut self, item: &hir::Item) { if let hir::ItemFn(..) = item.node { if attr::contains_name(&item.attrs, @@ -42,7 +42,7 @@ pub fn find_plugin_registrar(diagnostic: &errors::Handler, let krate = hir_map.krate(); let mut finder = RegistrarFinder { registrars: Vec::new() }; - krate.visit_all_items(&mut finder); + krate.visit_all_item_likes(&mut finder); match finder.registrars.len() { 0 => None, diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index dc7399e22890..d9c1cfd9fdba 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -31,6 +31,7 @@ use rustc::hir::{self, PatKind}; use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{self, Visitor}; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc::lint; use rustc::middle::privacy::{AccessLevel, AccessLevels}; @@ -1039,7 +1040,7 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> { } } -impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> { +impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { let min = |vis1: ty::Visibility, vis2| { if vis1.is_at_least(vis2, &self.tcx.map) { vis2 } else { vis1 } @@ -1161,7 +1162,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: tcx, old_error_set: &visitor.old_error_set, }; - krate.visit_all_items(&mut visitor); + krate.visit_all_item_likes(&mut visitor); } visitor.access_levels diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 0fc6436e63cd..d744d2a6db37 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -189,7 +189,7 @@ //! regardless of whether it is actually needed or not. use rustc::hir; -use rustc::hir::intravisit as hir_visit; +use rustc::hir::intravisit::{self, Visitor}; use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; @@ -306,10 +306,9 @@ fn collect_roots<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, scx: scx, mode: mode, output: &mut roots, - enclosing_item: None, }; - scx.tcx().map.krate().visit_all_items(&mut visitor); + scx.tcx().map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); } roots @@ -1030,14 +1029,10 @@ struct RootCollector<'b, 'a: 'b, 'tcx: 'a + 'b> { scx: &'b SharedCrateContext<'a, 'tcx>, mode: TransItemCollectionMode, output: &'b mut Vec>, - enclosing_item: Option<&'tcx hir::Item>, } -impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { +impl<'b, 'a, 'v> Visitor<'v> for RootCollector<'b, 'a, 'v> { fn visit_item(&mut self, item: &'v hir::Item) { - let old_enclosing_item = self.enclosing_item; - self.enclosing_item = Some(item); - match item.node { hir::ItemExternCrate(..) | hir::ItemUse(..) | @@ -1095,8 +1090,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { } } - hir_visit::walk_item(self, item); - self.enclosing_item = old_enclosing_item; + intravisit::walk_item(self, item) } fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) { @@ -1132,7 +1126,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { _ => { /* Nothing to do here */ } } - hir_visit::walk_impl_item(self, ii) + intravisit::walk_impl_item(self, ii) } } diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs index 25c30151ad45..aa23a1817227 100644 --- a/src/librustc_trans/symbol_names_test.rs +++ b/src/librustc_trans/symbol_names_test.rs @@ -35,7 +35,8 @@ pub fn report_symbol_names(scx: &SharedCrateContext) { let _ignore = tcx.dep_graph.in_ignore(); let mut visitor = SymbolNamesTest { scx: scx }; - tcx.map.krate().visit_all_items(&mut visitor); + // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like + tcx.map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); } struct SymbolNamesTest<'a, 'tcx:'a> { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 0cb8cf2a5888..35f419bbf739 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -439,7 +439,7 @@ impl Ord for TraitInfo { /// Retrieve all traits in this crate and any dependent crates. pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { if ccx.all_traits.borrow().is_none() { - use rustc::hir::intravisit; + use rustc::hir::itemlikevisit; let mut traits = vec![]; @@ -450,7 +450,7 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { map: &'a hir_map::Map<'tcx>, traits: &'a mut AllTraitsVec, } - impl<'v, 'a, 'tcx> intravisit::Visitor<'v> for Visitor<'a, 'tcx> { + impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'v hir::Item) { match i.node { hir::ItemTrait(..) => { @@ -461,7 +461,7 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { } } } - ccx.tcx.map.krate().visit_all_items(&mut Visitor { + ccx.tcx.map.krate().visit_all_item_likes(&mut Visitor { map: &ccx.tcx.map, traits: &mut traits, }); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a95b3f4a973b..7cf773688e6d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -121,6 +121,7 @@ use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::{self, BytePos, Span}; use rustc::hir::intravisit::{self, Visitor}; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::{self, PatKind}; use rustc::hir::print as pprust; use rustc_back::slice; @@ -525,7 +526,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> { +impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> { fn visit_item(&mut self, i: &'tcx hir::Item) { check_item_body(self.ccx, i); } @@ -534,21 +535,22 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> { pub fn check_wf_new(ccx: &CrateCtxt) -> CompileResult { ccx.tcx.sess.track_errors(|| { let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(ccx); - ccx.tcx.visit_all_items_in_krate(DepNode::WfCheck, &mut visit); + ccx.tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut visit.as_deep_visitor()); }) } pub fn check_item_types(ccx: &CrateCtxt) -> CompileResult { ccx.tcx.sess.track_errors(|| { let mut visit = CheckItemTypesVisitor { ccx: ccx }; - ccx.tcx.visit_all_items_in_krate(DepNode::TypeckItemType, &mut visit); + ccx.tcx.visit_all_item_likes_in_krate(DepNode::TypeckItemType, + &mut visit.as_deep_visitor()); }) } pub fn check_item_bodies(ccx: &CrateCtxt) -> CompileResult { ccx.tcx.sess.track_errors(|| { let mut visit = CheckItemBodiesVisitor { ccx: ccx }; - ccx.tcx.visit_all_items_in_krate(DepNode::TypeckItemBody, &mut visit); + ccx.tcx.visit_all_item_likes_in_krate(DepNode::TypeckItemBody, &mut visit); // Process deferred obligations, now that all functions // bodies have been fully inferred. diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index 7e41a672bf32..d9411070e2e8 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -16,7 +16,7 @@ use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; use rustc::hir; -use rustc::hir::intravisit::Visitor; +use rustc::hir::itemlikevisit::ItemLikeVisitor; struct UnusedTraitImportVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -40,7 +40,7 @@ impl<'a, 'tcx> UnusedTraitImportVisitor<'a, 'tcx> { } } -impl<'a, 'tcx, 'v> Visitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> { +impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { if item.vis == hir::Public || item.span == DUMMY_SP { return; @@ -63,5 +63,5 @@ impl<'a, 'tcx, 'v> Visitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> { pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _task = tcx.dep_graph.in_task(DepNode::UnusedTraitCheck); let mut visitor = UnusedTraitImportVisitor { tcx: tcx }; - tcx.map.krate().visit_all_items(&mut visitor); + tcx.map.krate().visit_all_item_likes(&mut visitor); } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 586330582646..e8b0044ed20c 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -34,7 +34,7 @@ use rustc::infer::{self, InferCtxt, TypeOrigin}; use syntax_pos::Span; use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; -use rustc::hir::intravisit; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::{Item, ItemImpl}; use rustc::hir; @@ -51,7 +51,7 @@ struct CoherenceCheckVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { cc: &'a CoherenceChecker<'a, 'gcx, 'tcx>, } -impl<'a, 'gcx, 'tcx, 'v> intravisit::Visitor<'v> for CoherenceCheckVisitor<'a, 'gcx, 'tcx> { +impl<'a, 'gcx, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCheckVisitor<'a, 'gcx, 'tcx> { fn visit_item(&mut self, item: &Item) { if let ItemImpl(..) = item.node { self.cc.check_implementation(item) @@ -87,8 +87,9 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { // Check implementations and traits. This populates the tables // containing the inherent methods and extension methods. It also // builds up the trait inheritance table. - self.crate_context.tcx.visit_all_items_in_krate(DepNode::CoherenceCheckImpl, - &mut CoherenceCheckVisitor { cc: self }); + self.crate_context.tcx.visit_all_item_likes_in_krate( + DepNode::CoherenceCheckImpl, + &mut CoherenceCheckVisitor { cc: self }); // Populate the table of destructors. It might seem a bit strange to // do this here, but it's actually the most convenient place, since diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 371c182030e2..d5a7726aa142 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -17,12 +17,12 @@ use rustc::ty::{self, TyCtxt}; use syntax::ast; use syntax_pos::Span; use rustc::dep_graph::DepNode; -use rustc::hir::intravisit; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir; pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut orphan = OrphanChecker { tcx: tcx }; - tcx.visit_all_items_in_krate(DepNode::CoherenceOrphanCheck, &mut orphan); + tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOrphanCheck, &mut orphan); } struct OrphanChecker<'cx, 'tcx: 'cx> { @@ -380,7 +380,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { } } -impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OrphanChecker<'cx, 'tcx> { +impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { self.check_item(item); } diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index b5aba512a66b..fb17255ccbc6 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -18,7 +18,7 @@ use rustc::ty::{self, TyCtxt}; use syntax::ast; use rustc::dep_graph::DepNode; use rustc::hir; -use rustc::hir::intravisit; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use util::nodemap::DefIdMap; use lint; @@ -30,7 +30,7 @@ pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // this secondary walk specifically checks for some other cases, // like defaulted traits, for which additional overlap rules exist - tcx.visit_all_items_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap); + tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap); } struct OverlapChecker<'cx, 'tcx: 'cx> { @@ -97,7 +97,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { } } -impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { +impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &'v hir::Item) { match item.node { hir::ItemEnum(..) | diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index cca6c8843067..dd9d3e0d5b7e 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -12,12 +12,12 @@ //! crate or pertains to a type defined in this crate. use rustc::ty::TyCtxt; -use rustc::hir::intravisit; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::{self, Unsafety}; pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let mut orphan = UnsafetyChecker { tcx: tcx }; - tcx.map.krate().visit_all_items(&mut orphan); + let mut unsafety = UnsafetyChecker { tcx: tcx }; + tcx.map.krate().visit_all_item_likes(&mut unsafety); } struct UnsafetyChecker<'cx, 'tcx: 'cx> { @@ -94,7 +94,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { } } -impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> { +impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for UnsafetyChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &'v hir::Item) { match item.node { hir::ItemDefaultImpl(unsafety, _) => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 816243b3eab4..52669ccc8425 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -83,7 +83,8 @@ use syntax::{abi, ast, attr}; use syntax::parse::token::{self, keywords}; use syntax_pos::Span; -use rustc::hir::{self, intravisit, map as hir_map, print as pprust}; +use rustc::hir::{self, map as hir_map, print as pprust}; +use rustc::hir::intravisit::{self, Visitor}; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; @@ -92,7 +93,7 @@ use rustc::hir::def_id::DefId; pub fn collect_item_types(ccx: &CrateCtxt) { let mut visitor = CollectItemTypesVisitor { ccx: ccx }; - ccx.tcx.visit_all_items_in_krate(DepNode::CollectItem, &mut visitor); + ccx.tcx.visit_all_item_likes_in_krate(DepNode::CollectItem, &mut visitor.as_deep_visitor()); } /////////////////////////////////////////////////////////////////////////// @@ -128,7 +129,7 @@ struct CollectItemTypesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> } -impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> { +impl<'a, 'tcx, 'v> Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { convert_item(self.ccx, item); intravisit::walk_item(self, item); diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 10fca644ec16..2c045bc88a26 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -22,7 +22,7 @@ use rustc::ty::maps::ItemVariances; use rustc::hir::map as hir_map; use syntax::ast; use rustc::hir; -use rustc::hir::intravisit::Visitor; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use super::terms::*; use super::terms::VarianceTerm::*; @@ -65,13 +65,13 @@ pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>) }; // See README.md for a discussion on dep-graph management. - tcx.visit_all_items_in_krate(|def_id| ItemVariances::to_dep_node(&def_id), - &mut constraint_cx); + tcx.visit_all_item_likes_in_krate(|def_id| ItemVariances::to_dep_node(&def_id), + &mut constraint_cx); constraint_cx } -impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> { +impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { let tcx = self.terms_cx.tcx; let did = tcx.map.local_def_id(item.id); diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index f6732f36e355..c40adb5f428e 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -27,7 +27,7 @@ use std::fmt; use std::rc::Rc; use syntax::ast; use rustc::hir; -use rustc::hir::intravisit::Visitor; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use util::nodemap::NodeMap; use self::VarianceTerm::*; @@ -109,7 +109,7 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx> }; // See README.md for a discussion on dep-graph management. - tcx.visit_all_items_in_krate(|def_id| ItemVariances::to_dep_node(&def_id), &mut terms_cx); + tcx.visit_all_item_likes_in_krate(|def_id| ItemVariances::to_dep_node(&def_id), &mut terms_cx); terms_cx } @@ -227,7 +227,7 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { } } -impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> { +impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { debug!("add_inferreds for item {}", self.tcx.map.node_to_string(item.id)); From b889259e2b42479584343eb3674b7a3de1870e5b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 2 Nov 2016 18:25:31 -0400 Subject: [PATCH 126/177] separate impl-items from the impl in the HIR This commit does not change how the incremental accounting is done, so changes (or accessses) to an impl-item are still tagged to the enclosing impl. This commits adds the "main guts" of this change. It does not build on its own. --- src/librustc/dep_graph/visit.rs | 12 ++++++++++++ src/librustc/hir/intravisit.rs | 18 +++++++++++++++--- src/librustc/hir/itemlikevisit.rs | 2 +- src/librustc/hir/lowering.rs | 22 ++++++++++++++++++---- src/librustc/hir/map/mod.rs | 9 +++++++++ src/librustc/hir/mod.rs | 20 +++++++++++++++++++- src/librustc/hir/print.rs | 14 ++++++++++++-- 7 files changed, 86 insertions(+), 11 deletions(-) diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs index 30de5e5288ab..6d89bbba54ec 100644 --- a/src/librustc/dep_graph/visit.rs +++ b/src/librustc/dep_graph/visit.rs @@ -45,6 +45,18 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx> self.visitor.visit_item(i); debug!("Ended task {:?}", task_id); } + + fn visit_impl_item(&mut self, i: &'tcx hir::ImplItem) { + // TODO -- use the def-id of the impl for now + let impl_def_id = self.tcx.map.get_parent_did(i.id); + let task_id = (self.dep_node_fn)(impl_def_id); + let _task = self.tcx.dep_graph.in_task(task_id.clone()); + debug!("Started task {:?}", task_id); + assert!(!self.tcx.map.is_inlined_def_id(impl_def_id)); + self.tcx.dep_graph.read(DepNode::Hir(impl_def_id)); + self.visitor.visit_impl_item(i); + debug!("Ended task {:?}", task_id); + } } let krate = tcx.dep_graph.with_ignore(|| tcx.map.krate()); diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 2fc27e0cea09..5a193a0ac942 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -94,7 +94,17 @@ pub trait Visitor<'v> : Sized { fn visit_nested_item(&mut self, id: ItemId) { } - /// Visit the top-level item and (optionally) nested items. See + /// Invoked when a nested impl item is encountered. By default, does + /// nothing. If you want a deep walk, you need to override to + /// fetch the item contents. But most of the time, it is easier + /// (and better) to invoke `Crate::visit_all_item_likes`, which visits + /// all items in the crate in some order (but doesn't respect + /// nesting). + #[allow(unused_variables)] + fn visit_nested_impl_item(&mut self, id: ImplItemId) { + } + + /// Visit the top-level item and (optionally) nested items / impl items. See /// `visit_nested_item` for details. fn visit_item(&mut self, i: &'v Item) { walk_item(self, i) @@ -359,12 +369,14 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_id(item.id); visitor.visit_trait_ref(trait_ref) } - ItemImpl(.., ref type_parameters, ref opt_trait_reference, ref typ, ref impl_items) => { + ItemImpl(.., ref type_parameters, ref opt_trait_reference, ref typ, ref impl_item_ids) => { visitor.visit_id(item.id); visitor.visit_generics(type_parameters); walk_list!(visitor, visit_trait_ref, opt_trait_reference); visitor.visit_ty(typ); - walk_list!(visitor, visit_impl_item, impl_items); + for &impl_item_id in impl_item_ids { + visitor.visit_nested_impl_item(impl_item_id); + } } ItemStruct(ref struct_definition, ref generics) | ItemUnion(ref struct_definition, ref generics) => { diff --git a/src/librustc/hir/itemlikevisit.rs b/src/librustc/hir/itemlikevisit.rs index 6da47015d7dc..22b566044288 100644 --- a/src/librustc/hir/itemlikevisit.rs +++ b/src/librustc/hir/itemlikevisit.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::Item; +use super::{Item, ImplItem}; use super::intravisit::Visitor; /// The "item-like visitor" visitor defines only the top-level methods diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index b985298e47cc..0731c35ff163 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -105,6 +105,7 @@ impl<'a> LoweringContext<'a> { fn lower_crate(&mut self, c: &Crate) -> hir::Crate { struct ItemLowerer<'lcx, 'interner: 'lcx> { items: BTreeMap, + impl_items: BTreeMap, lctx: &'lcx mut LoweringContext<'interner>, } @@ -113,12 +114,20 @@ impl<'a> LoweringContext<'a> { self.items.insert(item.id, self.lctx.lower_item(item)); visit::walk_item(self, item); } + + fn visit_impl_item(&mut self, item: &ImplItem) { + let id = self.lctx.lower_impl_item_id(item); + self.impl_items.insert(id, self.lctx.lower_impl_item(item)); + visit::walk_impl_item(self, item); + } } - let items = { - let mut item_lowerer = ItemLowerer { items: BTreeMap::new(), lctx: self }; + let (items, impl_items) = { + let mut item_lowerer = ItemLowerer { items: BTreeMap::new(), + impl_items: BTreeMap::new(), + lctx: self }; visit::walk_crate(&mut item_lowerer, c); - item_lowerer.items + (item_lowerer.items, item_lowerer.impl_items) }; hir::Crate { @@ -127,6 +136,7 @@ impl<'a> LoweringContext<'a> { span: c.span, exported_macros: c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect(), items: items, + impl_items: impl_items, } } @@ -631,7 +641,7 @@ impl<'a> LoweringContext<'a> { } ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => { let new_impl_items = impl_items.iter() - .map(|item| self.lower_impl_item(item)) + .map(|item| self.lower_impl_item_id(item)) .collect(); let ifce = ifce.as_ref().map(|trait_ref| self.lower_trait_ref(trait_ref)); hir::ItemImpl(self.lower_unsafety(unsafety), @@ -707,6 +717,10 @@ impl<'a> LoweringContext<'a> { }) } + fn lower_impl_item_id(&mut self, i: &ImplItem) -> hir::ImplItemId { + hir::ImplItemId { id: i.id } + } + fn lower_mod(&mut self, m: &Mod) -> hir::Mod { hir::Mod { inner: m.inner, diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 39114ec4238e..c629ec66ca4d 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -378,6 +378,15 @@ impl<'ast> Map<'ast> { self.forest.krate() } + pub fn impl_item(&self, id: ImplItemId) -> &'ast ImplItem { + // TODO right now this triggers a read of the whole impl + self.read(id.id); + + // NB: intentionally bypass `self.forest.krate()` so that we + // do not trigger a read of the whole krate here + self.forest.krate.impl_item(id) + } + /// Get the attributes on the krate. This is preferable to /// invoking `krate.attrs` because it registers a tighter /// dep-graph access. diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 4716a09ad35a..c9892135b1d3 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -424,6 +424,8 @@ pub struct Crate { // detected, which in turn can make compile-fail tests yield // slightly different results. pub items: BTreeMap, + + pub impl_items: BTreeMap, } impl Crate { @@ -431,6 +433,10 @@ impl Crate { &self.items[&id] } + pub fn impl_item(&self, id: ImplItemId) -> &ImplItem { + &self.impl_items[&id] + } + /// Visits all items in the crate in some determinstic (but /// unspecified) order. If you just need to process every item, /// but don't care about nesting, this method is the best choice. @@ -445,6 +451,10 @@ impl Crate { for (_, item) in &self.items { visitor.visit_item(item); } + + for (_, impl_item) in &self.impl_items { + visitor.visit_impl_item(impl_item); + } } } @@ -1042,6 +1052,14 @@ pub enum TraitItem_ { TypeTraitItem(TyParamBounds, Option>), } +// The bodies for items are stored "out of line", in a separate +// hashmap in the `Crate`. Here we just record the node-id of the item +// so it can fetched later. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct ImplItemId { + pub id: NodeId, +} + /// Represents anything within an `impl` block #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct ImplItem { @@ -1528,7 +1546,7 @@ pub enum Item_ { Generics, Option, // (optional) trait this impl implements P, // self - HirVec), + HirVec), } impl Item_ { diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 2c4ffb853c1f..ed274b5a23ef 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -808,8 +808,8 @@ impl<'a> State<'a> { space(&mut self.s)?; self.bopen()?; self.print_inner_attributes(&item.attrs)?; - for impl_item in impl_items { - self.print_impl_item(impl_item)?; + for &impl_item in impl_items { + self.print_impl_item_id(impl_item)?; } self.bclose(item.span)?; } @@ -1020,6 +1020,16 @@ impl<'a> State<'a> { self.ann.post(self, NodeSubItem(ti.id)) } + pub fn print_impl_item_id(&mut self, item_id: hir::ImplItemId) -> io::Result<()> { + if let Some(krate) = self.krate { + // skip nested items if krate context was not provided + let item = &krate.impl_item(item_id); + self.print_impl_item(item) + } else { + Ok(()) + } + } + pub fn print_impl_item(&mut self, ii: &hir::ImplItem) -> io::Result<()> { self.ann.pre(self, NodeSubItem(ii.id))?; self.hardbreak_if_not_bol()?; From 27acb5ca11cea8c48030f440772111805dbb9520 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 16 Nov 2016 19:56:01 +0100 Subject: [PATCH 127/177] Add missing urls and improve internal doc representation --- src/libstd/net/ip.rs | 24 +++++++++++++++++++----- src/libstd/net/tcp.rs | 3 ++- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 49080680fac6..e85c95198c74 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -176,8 +176,9 @@ impl Ipv4Addr { /// Returns true for the special 'unspecified' address (0.0.0.0). /// /// This property is defined in _UNIX Network Programming, Second Edition_, - /// W. Richard Stevens, p. 891; see also [ip7] - /// [ip7][http://man7.org/linux/man-pages/man7/ip.7.html] + /// W. Richard Stevens, p. 891; see also [ip7]. + /// + /// [ip7]: (http://man7.org/linux/man-pages/man7/ip.7.html) #[stable(feature = "ip_shared", since = "1.12.0")] pub fn is_unspecified(&self) -> bool { self.inner.s_addr == 0 @@ -186,6 +187,7 @@ impl Ipv4Addr { /// Returns true if this is a loopback address (127.0.0.0/8). /// /// This property is defined by [RFC 1122]. + /// /// [RFC 1122]: https://tools.ietf.org/html/rfc1122 #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_loopback(&self) -> bool { @@ -195,11 +197,12 @@ impl Ipv4Addr { /// Returns true if this is a private address. /// /// The private address ranges are defined in [RFC 1918] and include: - /// [RFC 1918]: https://tools.ietf.org/html/rfc1918 /// /// - 10.0.0.0/8 /// - 172.16.0.0/12 /// - 192.168.0.0/16 + /// + /// [RFC 1918]: https://tools.ietf.org/html/rfc1918 #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_private(&self) -> bool { match (self.octets()[0], self.octets()[1]) { @@ -213,6 +216,7 @@ impl Ipv4Addr { /// Returns true if the address is link-local (169.254.0.0/16). /// /// This property is defined by [RFC 3927]. + /// /// [RFC 3927]: https://tools.ietf.org/html/rfc3927 #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_link_local(&self) -> bool { @@ -221,7 +225,6 @@ impl Ipv4Addr { /// Returns true if the address appears to be globally routable. /// See [iana-ipv4-special-registry][ipv4-sr]. - /// [ipv4-sr]: http://goo.gl/RaZ7lg /// /// The following return false: /// @@ -231,6 +234,8 @@ impl Ipv4Addr { /// - the broadcast address (255.255.255.255/32) /// - test addresses used for documentation (192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24) /// - the unspecified address (0.0.0.0) + /// + /// [ipv4-sr]: http://goo.gl/RaZ7lg pub fn is_global(&self) -> bool { !self.is_private() && !self.is_loopback() && !self.is_link_local() && !self.is_broadcast() && !self.is_documentation() && !self.is_unspecified() @@ -240,6 +245,7 @@ impl Ipv4Addr { /// /// Multicast addresses have a most significant octet between 224 and 239, /// and is defined by [RFC 5771]. + /// /// [RFC 5771]: https://tools.ietf.org/html/rfc5771 #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_multicast(&self) -> bool { @@ -249,6 +255,7 @@ impl Ipv4Addr { /// Returns true if this is a broadcast address (255.255.255.255). /// /// A broadcast address has all octets set to 255 as defined in [RFC 919]. + /// /// [RFC 919]: https://tools.ietf.org/html/rfc919 #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_broadcast(&self) -> bool { @@ -259,11 +266,12 @@ impl Ipv4Addr { /// Returns true if this address is in a range designated for documentation. /// /// This is defined in [RFC 5737]: - /// [RFC 5737]: https://tools.ietf.org/html/rfc5737 /// /// - 192.0.2.0/24 (TEST-NET-1) /// - 198.51.100.0/24 (TEST-NET-2) /// - 203.0.113.0/24 (TEST-NET-3) + /// + /// [RFC 5737]: https://tools.ietf.org/html/rfc5737 #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_documentation(&self) -> bool { match(self.octets()[0], self.octets()[1], self.octets()[2], self.octets()[3]) { @@ -425,6 +433,7 @@ impl Ipv6Addr { /// Returns true for the special 'unspecified' address (::). /// /// This property is defined in [RFC 4291]. + /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_unspecified(&self) -> bool { @@ -434,6 +443,7 @@ impl Ipv6Addr { /// Returns true if this is a loopback address (::1). /// /// This property is defined in [RFC 4291]. + /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_loopback(&self) -> bool { @@ -458,6 +468,7 @@ impl Ipv6Addr { /// Returns true if this is a unique local address (fc00::/7). /// /// This property is defined in [RFC 4193]. + /// /// [RFC 4193]: https://tools.ietf.org/html/rfc4193 pub fn is_unique_local(&self) -> bool { (self.segments()[0] & 0xfe00) == 0xfc00 @@ -466,6 +477,7 @@ impl Ipv6Addr { /// Returns true if the address is unicast and link-local (fe80::/10). /// /// This property is defined in [RFC 4291]. + /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 pub fn is_unicast_link_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfe80 @@ -481,6 +493,7 @@ impl Ipv6Addr { /// (2001:db8::/32). /// /// This property is defined in [RFC 3849]. + /// /// [RFC 3849]: https://tools.ietf.org/html/rfc3849 pub fn is_documentation(&self) -> bool { (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) @@ -524,6 +537,7 @@ impl Ipv6Addr { /// Returns true if this is a multicast address (ff00::/8). /// /// This property is defined by [RFC 4291]. + /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_multicast(&self) -> bool { diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 0e7c5b06713f..159aa997b272 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -67,11 +67,12 @@ pub struct TcpListener(net_imp::TcpListener); /// An infinite iterator over the connections from a `TcpListener`. /// -/// This iterator will infinitely yield `Some` of the accepted connections. It +/// This iterator will infinitely yield [`Some`] of the accepted connections. It /// is equivalent to calling `accept` in a loop. /// /// This `struct` is created by the [`incoming`] method on [`TcpListener`]. /// +/// [`Some`]: ../../std/option/enum.Option.html#variant.Some /// [`incoming`]: struct.TcpListener.html#method.incoming /// [`TcpListener`]: struct.TcpListener.html #[stable(feature = "rust1", since = "1.0.0")] From 3fd67eba87fc4bd634af34d170d7683397aeca3a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 4 Nov 2016 18:20:15 -0400 Subject: [PATCH 128/177] fallout from separating impl-items from impls Basically adding `visit_impl_item` in various places and so forth. --- src/librustc/hir/itemlikevisit.rs | 5 ++ src/librustc/hir/map/collector.rs | 4 + src/librustc/lint/context.rs | 9 +- src/librustc/middle/dead.rs | 30 +++++-- src/librustc/middle/entry.rs | 6 +- src/librustc/middle/lang_items.rs | 4 + src/librustc/middle/reachable.rs | 4 + src/librustc/middle/resolve_lifetime.rs | 5 ++ src/librustc/middle/stability.rs | 23 +++-- src/librustc_driver/derive_registrar.rs | 4 + src/librustc_incremental/assert_dep_graph.rs | 4 + .../calculate_svh/svh_visitor.rs | 6 ++ .../persist/dirty_clean.rs | 6 ++ src/librustc_metadata/encoder.rs | 4 + src/librustc_mir/transform/qualify_consts.rs | 8 +- src/librustc_passes/loops.rs | 4 + src/librustc_plugin/build.rs | 3 + src/librustc_privacy/lib.rs | 84 +++++++++++++------ src/librustc_trans/collector.rs | 18 ++-- src/librustc_typeck/check/method/suggest.rs | 3 + src/librustc_typeck/check/mod.rs | 19 +++-- src/librustc_typeck/check_unused.rs | 3 + src/librustc_typeck/coherence/mod.rs | 3 + src/librustc_typeck/coherence/orphan.rs | 4 + src/librustc_typeck/coherence/overlap.rs | 3 + src/librustc_typeck/coherence/unsafety.rs | 3 + src/librustc_typeck/collect.rs | 23 +++-- src/librustc_typeck/variance/constraints.rs | 3 + src/librustc_typeck/variance/terms.rs | 3 + src/librustdoc/visit_ast.rs | 5 +- 30 files changed, 233 insertions(+), 70 deletions(-) diff --git a/src/librustc/hir/itemlikevisit.rs b/src/librustc/hir/itemlikevisit.rs index 22b566044288..1e373441e9e8 100644 --- a/src/librustc/hir/itemlikevisit.rs +++ b/src/librustc/hir/itemlikevisit.rs @@ -56,6 +56,7 @@ use super::intravisit::Visitor; /// needed. pub trait ItemLikeVisitor<'hir> { fn visit_item(&mut self, item: &'hir Item); + fn visit_impl_item(&mut self, impl_item: &'hir ImplItem); } pub struct DeepVisitor<'v, V: 'v> { @@ -76,4 +77,8 @@ impl<'v, 'hir, V> ItemLikeVisitor<'hir> for DeepVisitor<'v, V> fn visit_item(&mut self, item: &'hir Item) { self.visitor.visit_item(item); } + + fn visit_impl_item(&mut self, impl_item: &'hir ImplItem) { + self.visitor.visit_impl_item(impl_item); + } } diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 04fcf7e84508..eafb7949da38 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -99,6 +99,10 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { } } + fn visit_nested_impl_item(&mut self, item_id: ImplItemId) { + self.visit_impl_item(self.krate.impl_item(item_id)) + } + fn visit_item(&mut self, i: &'ast Item) { debug!("visit_item: {:?}", i); diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 50c581057407..78049663afeb 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -797,8 +797,13 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { /// items in the context of the outer item, so enable /// deep-walking. fn visit_nested_item(&mut self, item: hir::ItemId) { - let tcx = self.tcx; - self.visit_item(tcx.map.expect_item(item.id)) + let item = self.tcx.map.expect_item(item.id); + self.visit_item(item) + } + + fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { + let impl_item = self.tcx.map.impl_item(item_id); + self.visit_impl_item(impl_item) } fn visit_item(&mut self, it: &hir::Item) { diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 2667943bea93..57abf0bdc427 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -330,11 +330,12 @@ fn has_allow_dead_code_or_lang_attr(attrs: &[ast::Attribute]) -> bool { // or // 2) We are not sure to be live or not // * Implementation of a trait method -struct LifeSeeder { - worklist: Vec +struct LifeSeeder<'k> { + worklist: Vec, + krate: &'k hir::Crate, } -impl<'v> ItemLikeVisitor<'v> for LifeSeeder { +impl<'v, 'k> ItemLikeVisitor<'v> for LifeSeeder<'k> { fn visit_item(&mut self, item: &hir::Item) { let allow_dead_code = has_allow_dead_code_or_lang_attr(&item.attrs); if allow_dead_code { @@ -358,17 +359,22 @@ impl<'v> ItemLikeVisitor<'v> for LifeSeeder { } } } - hir::ItemImpl(.., ref opt_trait, _, ref impl_items) => { - for impl_item in impl_items { + hir::ItemImpl(.., ref opt_trait, _, ref impl_item_ids) => { + for &impl_item_id in impl_item_ids { + let impl_item = self.krate.impl_item(impl_item_id); if opt_trait.is_some() || has_allow_dead_code_or_lang_attr(&impl_item.attrs) { - self.worklist.push(impl_item.id); + self.worklist.push(impl_item_id.id); } } } _ => () } } + + fn visit_impl_item(&mut self, _item: &hir::ImplItem) { + // ignore: we are handling this in `visit_item` above + } } fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -387,7 +393,8 @@ fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Seed implemented trait items let mut life_seeder = LifeSeeder { - worklist: worklist + worklist: worklist, + krate: krate, }; krate.visit_all_item_likes(&mut life_seeder); @@ -510,8 +517,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { /// an error. We could do this also by checking the parents, but /// this is how the code is setup and it seems harmless enough. fn visit_nested_item(&mut self, item: hir::ItemId) { - let tcx = self.tcx; - self.visit_item(tcx.map.expect_item(item.id)) + let item = self.tcx.map.expect_item(item.id); + self.visit_item(item) + } + + fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { + let impl_item = self.tcx.map.impl_item(item_id); + self.visit_impl_item(impl_item) } fn visit_item(&mut self, item: &hir::Item) { diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index e5112749c0ee..9dd54457a349 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -17,7 +17,7 @@ use syntax::ast::NodeId; use syntax::attr; use syntax::entry::EntryPointType; use syntax_pos::Span; -use hir::{Item, ItemFn}; +use hir::{Item, ItemFn, ImplItem}; use hir::itemlikevisit::ItemLikeVisitor; struct EntryContext<'a, 'tcx: 'a> { @@ -46,6 +46,10 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> { let at_root = def_key.parent == Some(CRATE_DEF_INDEX); find_item(item, self, at_root); } + + fn visit_impl_item(&mut self, _impl_item: &'tcx ImplItem) { + // entry fn is never an impl item + } } pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map) { diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 6fe8442474a9..9b4b1396669a 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -164,6 +164,10 @@ impl<'a, 'v, 'tcx> ItemLikeVisitor<'v> for LanguageItemCollector<'a, 'tcx> { } } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + // at present, lang items are always items, not impl items + } } impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> { diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 848f4218d884..0a45f895d7df 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -336,6 +336,10 @@ impl<'a, 'v> ItemLikeVisitor<'v> for CollectPrivateImplItemsVisitor<'a> { } } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + // processed in visit_item above + } } pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index c342342d73b7..68d2cceda847 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -141,6 +141,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { self.visit_item(item) } + fn visit_nested_impl_item(&mut self, id: hir::ImplItemId) { + let impl_item = self.hir_map.impl_item(id); + self.visit_impl_item(impl_item) + } + fn visit_item(&mut self, item: &hir::Item) { // Save labels for nested items. let saved_labels_in_fn = replace(&mut self.labels_in_fn, vec![]); diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index d79833998d6c..f8d58c5f2d91 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -239,8 +239,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> { /// nested items in the context of the outer item, so enable /// deep-walking. fn visit_nested_item(&mut self, item: hir::ItemId) { - let tcx = self.tcx; - self.visit_item(tcx.map.expect_item(item.id)) + let item = self.tcx.map.expect_item(item.id); + self.visit_item(item) + } + + fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { + let impl_item = self.tcx.map.impl_item(item_id); + self.visit_impl_item(impl_item) } fn visit_item(&mut self, i: &Item) { @@ -449,8 +454,13 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> { /// nested items in the context of the outer item, so enable /// deep-walking. fn visit_nested_item(&mut self, item: hir::ItemId) { - let tcx = self.tcx; - self.visit_item(tcx.map.expect_item(item.id)) + let item = self.tcx.map.expect_item(item.id); + self.visit_item(item) + } + + fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { + let impl_item = self.tcx.map.impl_item(item_id); + self.visit_impl_item(impl_item) } fn visit_item(&mut self, item: &hir::Item) { @@ -527,9 +537,10 @@ pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // For implementations of traits, check the stability of each item // individually as it's possible to have a stable trait with unstable // items. - hir::ItemImpl(.., Some(ref t), _, ref impl_items) => { + hir::ItemImpl(.., Some(ref t), _, ref impl_item_ids) => { let trait_did = tcx.expect_def(t.ref_id).def_id(); - for impl_item in impl_items { + for &impl_item_id in impl_item_ids { + let impl_item = tcx.map.impl_item(impl_item_id); let item = tcx.associated_items(trait_did) .find(|item| item.name == impl_item.name).unwrap(); if warn_about_defns { diff --git a/src/librustc_driver/derive_registrar.rs b/src/librustc_driver/derive_registrar.rs index 605193a0434b..4db620b2bec3 100644 --- a/src/librustc_driver/derive_registrar.rs +++ b/src/librustc_driver/derive_registrar.rs @@ -34,4 +34,8 @@ impl<'v> ItemLikeVisitor<'v> for Finder { self.registrar = Some(item.id); } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } + diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 84489c2e8c67..d66e0f6aba35 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -171,6 +171,10 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for IfThisChanged<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { self.process_attrs(item.id, &item.attrs); } + + fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) { + // handled in `visit_item` above + } } fn check_paths<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 0b0dd596784e..3060e237fc13 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -503,6 +503,12 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has // Each item is hashed independently; ignore nested items. } + fn visit_nested_impl_item(&mut self, impl_item_id: ImplItemId) { + // For now, we hash impl items as part of the containing impl. + let impl_item = self.tcx.map.impl_item(impl_item_id); + self.visit_impl_item(impl_item); + } + fn visit_variant_data(&mut self, s: &'tcx VariantData, name: Name, diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index f6b7abd2ef12..0cd1c88fb877 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -184,6 +184,9 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> { } } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -225,6 +228,9 @@ impl<'a, 'tcx, 'm> ItemLikeVisitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, } } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } impl<'a, 'tcx, 'm> DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index bbffe88316b3..2d96eeb8f201 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1177,6 +1177,10 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'a, 'tcx> { } } } + + fn visit_impl_item(&mut self, _impl_item: &'v hir::ImplItem) { + // handled in `visit_item` above + } } impl<'a, 'tcx> EncodeContext<'a, 'tcx> { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index b33a7060e375..21bebb2562a1 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -277,8 +277,12 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { .and_then(|impl_node_id| self.tcx.map.find(impl_node_id)) .map(|node| { if let hir_map::NodeItem(item) = node { - if let hir::ItemImpl(_, _, _, _, _, ref methods) = item.node { - span = methods.first().map(|method| method.span); + if let hir::ItemImpl(_, _, _, _, _, ref impl_item_ids) = item.node { + span = impl_item_ids.first() + .map(|&impl_item_id| { + self.tcx.map.impl_item(impl_item_id) + .span + }); } } }); diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index adcb7842ee1f..724100e02237 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -44,6 +44,10 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> { self.with_context(Normal, |v| intravisit::walk_item(v, i)); } + fn visit_impl_item(&mut self, i: &hir::ImplItem) { + self.with_context(Normal, |v| intravisit::walk_impl_item(v, i)); + } + fn visit_expr(&mut self, e: &hir::Expr) { match e.node { hir::ExprWhile(ref e, ref b, _) => { diff --git a/src/librustc_plugin/build.rs b/src/librustc_plugin/build.rs index 0464a93ef717..75046f6aeb87 100644 --- a/src/librustc_plugin/build.rs +++ b/src/librustc_plugin/build.rs @@ -32,6 +32,9 @@ impl<'v> ItemLikeVisitor<'v> for RegistrarFinder { } } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } /// Find the function marked with `#[plugin_registrar]`, if any. diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index d9c1cfd9fdba..3fd1ed935165 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -124,6 +124,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { self.visit_item(tcx.map.expect_item(item.id)) } + fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { + let impl_item = self.tcx.map.impl_item(item_id); + self.visit_impl_item(impl_item) + } + fn visit_item(&mut self, item: &hir::Item) { let inherited_item_level = match item.node { // Impls inherit level from their types and traits @@ -159,15 +164,17 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { } } } - hir::ItemImpl(.., None, _, ref impl_items) => { - for impl_item in impl_items { + hir::ItemImpl(.., None, _, ref impl_item_ids) => { + for &impl_item_id in impl_item_ids { + let impl_item = self.tcx.map.impl_item(impl_item_id); if impl_item.vis == hir::Public { self.update(impl_item.id, item_level); } } } - hir::ItemImpl(.., Some(_), _, ref impl_items) => { - for impl_item in impl_items { + hir::ItemImpl(.., Some(_), _, ref impl_item_ids) => { + for &impl_item_id in impl_item_ids { + let impl_item = self.tcx.map.impl_item(impl_item_id); self.update(impl_item.id, item_level); } } @@ -250,11 +257,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { // The interface is empty hir::ItemDefaultImpl(..) => {} // Visit everything except for private impl items - hir::ItemImpl(.., ref generics, None, _, ref impl_items) => { + hir::ItemImpl(.., ref generics, None, _, ref impl_item_ids) => { if item_level.is_some() { self.reach().visit_generics(generics); - for impl_item in impl_items { - if self.get(impl_item.id).is_some() { + for &impl_item_id in impl_item_ids { + if self.get(impl_item_id.id).is_some() { + let impl_item = self.tcx.map.impl_item(impl_item_id); self.reach().visit_impl_item(impl_item); } } @@ -319,6 +327,12 @@ impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { } impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { + fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { + // when we visit an impl, its methods and items are part of its "interface" + let impl_item = self.ev.tcx.map.impl_item(item_id); + self.visit_impl_item(impl_item) + } + fn visit_ty(&mut self, ty: &hir::Ty) { if let hir::TyPath(_, ref path) = ty.node { let def = self.ev.tcx.expect_def(ty.id); @@ -421,6 +435,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { self.visit_item(tcx.map.expect_item(item.id)) } + fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { + let impl_item = self.tcx.map.impl_item(item_id); + self.visit_impl_item(impl_item) + } + fn visit_item(&mut self, item: &hir::Item) { let orig_curitem = replace(&mut self.curitem, item.id); intravisit::walk_item(self, item); @@ -625,6 +644,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> self.visit_item(tcx.map.expect_item(item.id)) } + fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { + let impl_item = self.tcx.map.impl_item(item_id); + self.visit_impl_item(impl_item) + } + fn visit_item(&mut self, item: &hir::Item) { match item.node { // contents of a private mod can be reexported, so we need @@ -650,7 +674,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> // (i.e. we could just return here to not check them at // all, or some worse estimation of whether an impl is // publicly visible). - hir::ItemImpl(.., ref g, ref trait_ref, ref self_, ref impl_items) => { + hir::ItemImpl(.., ref g, ref trait_ref, ref self_, ref impl_item_ids) => { // `impl [... for] Private` is never visible. let self_contains_private; // impl [... for] Public<...>, but not `impl [... for] @@ -695,16 +719,17 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> // are private (because `T` won't be visible externally). let trait_or_some_public_method = trait_ref.is_some() || - impl_items.iter() - .any(|impl_item| { - match impl_item.node { - hir::ImplItemKind::Const(..) | - hir::ImplItemKind::Method(..) => { - self.access_levels.is_reachable(impl_item.id) - } - hir::ImplItemKind::Type(_) => false, - } - }); + impl_item_ids.iter() + .any(|&impl_item_id| { + let impl_item = self.tcx.map.impl_item(impl_item_id); + match impl_item.node { + hir::ImplItemKind::Const(..) | + hir::ImplItemKind::Method(..) => { + self.access_levels.is_reachable(impl_item.id) + } + hir::ImplItemKind::Type(_) => false, + } + }); if !self_contains_private && not_private_trait && @@ -714,12 +739,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> match *trait_ref { None => { - for impl_item in impl_items { + for &impl_item_id in impl_item_ids { // This is where we choose whether to walk down // further into the impl to check its items. We // should only walk into public items so that we // don't erroneously report errors for private // types in private items. + let impl_item = self.tcx.map.impl_item(impl_item_id); match impl_item.node { hir::ImplItemKind::Const(..) | hir::ImplItemKind::Method(..) @@ -751,7 +777,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> intravisit::walk_path(self, &tr.path); // Those in 3. are warned with this call. - for impl_item in impl_items { + for &impl_item_id in impl_item_ids { + let impl_item = self.tcx.map.impl_item(impl_item_id); if let hir::ImplItemKind::Type(ref ty) = impl_item.node { self.visit_ty(ty); } @@ -762,7 +789,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> // impl Public { ... }. Any public static // methods will be visible as `Public::foo`. let mut found_pub_static = false; - for impl_item in impl_items { + for &impl_item_id in impl_item_ids { + let impl_item = self.tcx.map.impl_item(impl_item_id); match impl_item.node { hir::ImplItemKind::Const(..) => { if self.item_is_public(&impl_item.id, &impl_item.vis) { @@ -1086,12 +1114,13 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for PrivateItemsInPublicInterfacesVisitor hir::ItemDefaultImpl(..) => {} // An inherent impl is public when its type is public // Subitems of inherent impls have their own publicity - hir::ItemImpl(.., ref generics, None, ref ty, ref impl_items) => { + hir::ItemImpl(.., ref generics, None, ref ty, ref impl_item_ids) => { let ty_vis = self.ty_visibility(ty); check.required_visibility = ty_vis; check.visit_generics(generics); - for impl_item in impl_items { + for &impl_item_id in impl_item_ids { + let impl_item = self.tcx.map.impl_item(impl_item_id); let impl_item_vis = ty::Visibility::from_hir(&impl_item.vis, item.id, self.tcx); check.required_visibility = min(impl_item_vis, ty_vis); @@ -1100,16 +1129,21 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for PrivateItemsInPublicInterfacesVisitor } // A trait impl is public when both its type and its trait are public // Subitems of trait impls have inherited publicity - hir::ItemImpl(.., ref generics, Some(ref trait_ref), ref ty, ref impl_items) => { + hir::ItemImpl(.., ref generics, Some(ref trait_ref), ref ty, ref impl_item_ids) => { let vis = min(self.ty_visibility(ty), self.trait_ref_visibility(trait_ref)); check.required_visibility = vis; check.visit_generics(generics); - for impl_item in impl_items { + for &impl_item_id in impl_item_ids { + let impl_item = self.tcx.map.impl_item(impl_item_id); check.visit_impl_item(impl_item); } } } } + + fn visit_impl_item(&mut self, _impl_item: &'v hir::ImplItem) { + // handled in `visit_item` above + } } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index d744d2a6db37..8245b0cf7f53 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -189,7 +189,7 @@ //! regardless of whether it is actually needed or not. use rustc::hir; -use rustc::hir::intravisit::{self, Visitor}; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; @@ -308,7 +308,7 @@ fn collect_roots<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, output: &mut roots, }; - scx.tcx().map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); + scx.tcx().map.krate().visit_all_item_likes(&mut visitor); } roots @@ -1031,7 +1031,7 @@ struct RootCollector<'b, 'a: 'b, 'tcx: 'a + 'b> { output: &'b mut Vec>, } -impl<'b, 'a, 'v> Visitor<'v> for RootCollector<'b, 'a, 'v> { +impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { fn visit_item(&mut self, item: &'v hir::Item) { match item.node { hir::ItemExternCrate(..) | @@ -1089,8 +1089,6 @@ impl<'b, 'a, 'v> Visitor<'v> for RootCollector<'b, 'a, 'v> { } } } - - intravisit::walk_item(self, item) } fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) { @@ -1125,8 +1123,6 @@ impl<'b, 'a, 'v> Visitor<'v> for RootCollector<'b, 'a, 'v> { } _ => { /* Nothing to do here */ } } - - intravisit::walk_impl_item(self, ii) } } @@ -1151,9 +1147,11 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) { let callee_substs = tcx.erase_regions(&trait_ref.substs); - let overridden_methods: FxHashSet<_> = items.iter() - .map(|item| item.name) - .collect(); + let overridden_methods: FxHashSet<_> = + items.iter() + .map(|&id| tcx.map.impl_item(id)) + .map(|item| item.name) + .collect(); for method in tcx.provided_trait_methods(trait_ref.def_id) { if overridden_methods.contains(&method.name) { continue; diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 35f419bbf739..6093e45e5a21 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -460,6 +460,9 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { _ => {} } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } ccx.tcx.map.krate().visit_all_item_likes(&mut Visitor { map: &ccx.tcx.map, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7cf773688e6d..e8ebc2eee63d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -530,6 +530,10 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> { fn visit_item(&mut self, i: &'tcx hir::Item) { check_item_body(self.ccx, i); } + + fn visit_impl_item(&mut self, _item: &'tcx hir::ImplItem) { + // done as part of `visit_item` above + } } pub fn check_wf_new(ccx: &CrateCtxt) -> CompileResult { @@ -811,7 +815,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { it.id); } hir::ItemFn(..) => {} // entirely within check_item_body - hir::ItemImpl(.., ref impl_items) => { + hir::ItemImpl(.., ref impl_item_ids) => { debug!("ItemImpl {} with id {}", it.name, it.id); let impl_def_id = ccx.tcx.map.local_def_id(it.id); if let Some(impl_trait_ref) = ccx.tcx.impl_trait_ref(impl_def_id) { @@ -819,7 +823,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { it.span, impl_def_id, impl_trait_ref, - impl_items); + impl_item_ids); let trait_def_id = impl_trait_ref.def_id; check_on_unimplemented(ccx, trait_def_id, it); } @@ -881,10 +885,11 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { hir::ItemFn(ref decl, .., ref body) => { check_bare_fn(ccx, &decl, &body, it.id, it.span); } - hir::ItemImpl(.., ref impl_items) => { + hir::ItemImpl(.., ref impl_item_ids) => { debug!("ItemImpl {} with id {}", it.name, it.id); - for impl_item in impl_items { + for &impl_item_id in impl_item_ids { + let impl_item = ccx.tcx.map.impl_item(impl_item_id); match impl_item.node { hir::ImplItemKind::Const(_, ref expr) => { check_const(ccx, &expr, impl_item.id) @@ -1021,7 +1026,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_span: Span, impl_id: DefId, impl_trait_ref: ty::TraitRef<'tcx>, - impl_items: &[hir::ImplItem]) { + impl_item_ids: &[hir::ImplItemId]) { // If the trait reference itself is erroneous (so the compilation is going // to fail), skip checking the items here -- the `impl_item` table in `tcx` // isn't populated for such impls. @@ -1032,9 +1037,11 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let trait_def = tcx.lookup_trait_def(impl_trait_ref.def_id); let mut overridden_associated_type = None; + let impl_items = || impl_item_ids.iter().map(|&id| ccx.tcx.map.impl_item(id)); + // Check existing impl methods to see if they are both present in trait // and compatible with trait signature - for impl_item in impl_items { + for impl_item in impl_items() { let ty_impl_item = tcx.associated_item(tcx.map.local_def_id(impl_item.id)); let ty_trait_item = tcx.associated_items(impl_trait_ref.def_id) .find(|ac| ac.name == ty_impl_item.name); diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index d9411070e2e8..b4a10c52270e 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -58,6 +58,9 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> { } } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index e8b0044ed20c..31bd7b0f19b3 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -57,6 +57,9 @@ impl<'a, 'gcx, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCheckVisitor<'a, 'gcx, self.cc.check_implementation(item) } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index d5a7726aa142..a507077bef77 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -384,4 +384,8 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { self.check_item(item); } + + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index fb17255ccbc6..c66a76ebba02 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -199,4 +199,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> { _ => {} } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index dd9d3e0d5b7e..6d5de8f25065 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -106,4 +106,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for UnsafetyChecker<'cx, 'tcx> { _ => {} } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 52669ccc8425..658a655c2dec 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -149,6 +149,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> { } intravisit::walk_ty(self, ty); } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + // handled in `visit_item` above; we may want to break this out later + } } /////////////////////////////////////////////////////////////////////////// @@ -727,7 +731,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { ref generics, ref opt_trait_ref, ref selfty, - ref impl_items) => { + ref impl_item_ids) => { // Create generics from the generics specified in the impl head. debug!("convert: ast_generics={:?}", generics); let def_id = ccx.tcx.map.local_def_id(it.id); @@ -757,7 +761,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { let mut seen_type_items = FxHashMap(); let mut seen_value_items = FxHashMap(); - for impl_item in impl_items { + for &impl_item_id in impl_item_ids { + let impl_item = tcx.map.impl_item(impl_item_id); let seen_items = match impl_item.node { hir::ImplItemKind::Type(_) => &mut seen_type_items, _ => &mut seen_value_items, @@ -790,7 +795,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } // Convert all the associated types. - for impl_item in impl_items { + for &impl_item_id in impl_item_ids { + let impl_item = tcx.map.impl_item(impl_item_id); if let hir::ImplItemKind::Type(ref ty) = impl_item.node { let type_def_id = ccx.tcx.map.local_def_id(impl_item.id); generics_of_def_id(ccx, type_def_id); @@ -806,7 +812,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } } - for impl_item in impl_items { + for &impl_item_id in impl_item_ids { + let impl_item = tcx.map.impl_item(impl_item_id); if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { convert_method(ccx, ImplContainer(def_id), impl_item.id, sig, selfty, @@ -814,7 +821,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } } - enforce_impl_lifetimes_are_constrained(ccx, generics, def_id, impl_items); + enforce_impl_lifetimes_are_constrained(ccx, generics, def_id, impl_item_ids); }, hir::ItemTrait(.., ref trait_items) => { let trait_def = trait_def_of_item(ccx, it); @@ -2103,7 +2110,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ast_generics: &hir::Generics, impl_def_id: DefId, - impl_items: &[hir::ImplItem]) + impl_item_ids: &[hir::ImplItemId]) { // Every lifetime used in an associated type must be constrained. let impl_ty = ccx.tcx.item_type(impl_def_id); @@ -2118,8 +2125,8 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ctp::identify_constrained_type_params( &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters); - let lifetimes_in_associated_types: FxHashSet<_> = impl_items.iter() - .map(|item| ccx.tcx.map.local_def_id(item.id)) + let lifetimes_in_associated_types: FxHashSet<_> = impl_item_ids.iter() + .map(|item_id| ccx.tcx.map.local_def_id(item_id.id)) .filter(|&def_id| { let item = ccx.tcx.associated_item(def_id); item.kind == ty::AssociatedKind::Type && item.has_value diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 2c045bc88a26..8a0c1c68322d 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -115,6 +115,9 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { hir::ItemDefaultImpl(..) => {} } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } /// Is `param_id` a lifetime according to `map`? diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index c40adb5f428e..0a3238480d90 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -257,4 +257,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { hir::ItemTy(..) => {} } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index d9155e10e17b..6587392e18ff 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -502,10 +502,13 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { om.traits.push(t); }, - hir::ItemImpl(unsafety, polarity, ref gen, ref tr, ref ty, ref items) => { + hir::ItemImpl(unsafety, polarity, ref gen, ref tr, ref ty, ref item_ids) => { // Don't duplicate impls when inlining, we'll pick them up // regardless of where they're located. if !self.inlining { + let items = item_ids.iter() + .map(|&id| self.cx.map.impl_item(id).clone()) + .collect(); let i = Impl { unsafety: unsafety, polarity: polarity, From eeb45c7591ae7c7e843a132fe937b97a7d670581 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 8 Nov 2016 11:16:39 -0500 Subject: [PATCH 129/177] make distinct Hir() nodes in the graph for impl items --- src/librustc/dep_graph/visit.rs | 9 ++++----- src/librustc/hir/map/mod.rs | 8 ++++++-- src/librustc_incremental/calculate_svh/mod.rs | 5 +++++ src/librustc_incremental/calculate_svh/svh_visitor.rs | 6 ++---- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs index 6d89bbba54ec..600732fc6f70 100644 --- a/src/librustc/dep_graph/visit.rs +++ b/src/librustc/dep_graph/visit.rs @@ -47,13 +47,12 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx> } fn visit_impl_item(&mut self, i: &'tcx hir::ImplItem) { - // TODO -- use the def-id of the impl for now - let impl_def_id = self.tcx.map.get_parent_did(i.id); - let task_id = (self.dep_node_fn)(impl_def_id); + let impl_item_def_id = self.tcx.map.local_def_id(i.id); + let task_id = (self.dep_node_fn)(impl_item_def_id); let _task = self.tcx.dep_graph.in_task(task_id.clone()); debug!("Started task {:?}", task_id); - assert!(!self.tcx.map.is_inlined_def_id(impl_def_id)); - self.tcx.dep_graph.read(DepNode::Hir(impl_def_id)); + assert!(!self.tcx.map.is_inlined_def_id(impl_item_def_id)); + self.tcx.dep_graph.read(DepNode::Hir(impl_item_def_id)); self.visitor.visit_impl_item(i); debug!("Ended task {:?}", task_id); } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index c629ec66ca4d..e684040a1735 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -254,9 +254,14 @@ impl<'ast> Map<'ast> { return DepNode::Hir(def_id); } + EntryImplItem(..) => { + let def_id = self.local_def_id(id); + assert!(!self.is_inlined_def_id(def_id)); + return DepNode::Hir(def_id); + } + EntryForeignItem(p, _) | EntryTraitItem(p, _) | - EntryImplItem(p, _) | EntryVariant(p, _) | EntryExpr(p, _) | EntryStmt(p, _) | @@ -379,7 +384,6 @@ impl<'ast> Map<'ast> { } pub fn impl_item(&self, id: ImplItemId) -> &'ast ImplItem { - // TODO right now this triggers a read of the whole impl self.read(id.id); // NB: intentionally bypass `self.forest.krate()` so that we diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index 5697441b6676..c08519090d27 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -207,6 +207,11 @@ impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> { visit::walk_item(self, item); } + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { + self.calculate_node_id(impl_item.id, |v| v.visit_impl_item(impl_item)); + visit::walk_impl_item(self, impl_item); + } + fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) { self.calculate_node_id(item.id, |v| v.visit_foreign_item(item)); visit::walk_foreign_item(self, item); diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 3060e237fc13..3af6ee35f9e5 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -503,10 +503,8 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has // Each item is hashed independently; ignore nested items. } - fn visit_nested_impl_item(&mut self, impl_item_id: ImplItemId) { - // For now, we hash impl items as part of the containing impl. - let impl_item = self.tcx.map.impl_item(impl_item_id); - self.visit_impl_item(impl_item); + fn visit_nested_impl_item(&mut self, _: ImplItemId) { + // Impl items are hashed independently; ignore nested impl items. } fn visit_variant_data(&mut self, From 7918299bf0aa96951f304ce84aa1b3c4b3a75cb9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 11 Nov 2016 10:02:10 -0500 Subject: [PATCH 130/177] fix dep-graph checking to account for implitems --- src/librustc_incremental/assert_dep_graph.rs | 4 ++-- src/test/compile-fail/dep-graph-type-alias.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index d66e0f6aba35..998cbae2cce1 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -172,8 +172,8 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for IfThisChanged<'a, 'tcx> { self.process_attrs(item.id, &item.attrs); } - fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) { - // handled in `visit_item` above + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { + self.process_attrs(impl_item.id, &impl_item.attrs); } } diff --git a/src/test/compile-fail/dep-graph-type-alias.rs b/src/test/compile-fail/dep-graph-type-alias.rs index 80cc9e71c7ab..2e33f11c04b4 100644 --- a/src/test/compile-fail/dep-graph-type-alias.rs +++ b/src/test/compile-fail/dep-graph-type-alias.rs @@ -42,8 +42,9 @@ trait Trait { struct SomeType; -#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK +#[rustc_then_this_would_need(ItemSignature)] //~ ERROR no path impl SomeType { + #[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK fn method(&self, _: TypeAlias) {} } From ae8cb22fb9f2fa753963504b9c6a4d9e333840ba Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 8 Nov 2016 13:23:59 -0500 Subject: [PATCH 131/177] factor out collection of impl-items into a distinct fn --- src/librustc_trans/callee.rs | 2 +- src/librustc_typeck/collect.rs | 79 +++++++++++++++++++--------------- 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index faf65f3f98b0..a7553ce4995e 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -605,7 +605,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Create a fn pointer with the substituted signature. tcx.mk_fn_ptr(fty) } - _ => bug!("expected fn item type, found {}", fn_ty) + _ => bug!("expected fn item type for {:?}, found {}", def_id, fn_ty) }; let llptrty = type_of::type_of(ccx, fn_ptr_ty); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 658a655c2dec..eb4775a29bf3 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -150,8 +150,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> { intravisit::walk_ty(self, ty); } - fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) { // handled in `visit_item` above; we may want to break this out later + intravisit::walk_impl_item(self, impl_item); } } @@ -782,43 +783,10 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { entry.insert(impl_item.span); } } - - if let hir::ImplItemKind::Const(ref ty, _) = impl_item.node { - let const_def_id = ccx.tcx.map.local_def_id(impl_item.id); - generics_of_def_id(ccx, const_def_id); - let ty = ccx.icx(&ty_predicates) - .to_ty(&ExplicitRscope, &ty); - tcx.item_types.borrow_mut().insert(const_def_id, ty); - convert_associated_const(ccx, ImplContainer(def_id), - impl_item.id, ty); - } - } - - // Convert all the associated types. - for &impl_item_id in impl_item_ids { - let impl_item = tcx.map.impl_item(impl_item_id); - if let hir::ImplItemKind::Type(ref ty) = impl_item.node { - let type_def_id = ccx.tcx.map.local_def_id(impl_item.id); - generics_of_def_id(ccx, type_def_id); - - if opt_trait_ref.is_none() { - span_err!(tcx.sess, impl_item.span, E0202, - "associated types are not allowed in inherent impls"); - } - - let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty); - - convert_associated_type(ccx, ImplContainer(def_id), impl_item.id, Some(typ)); - } } for &impl_item_id in impl_item_ids { - let impl_item = tcx.map.impl_item(impl_item_id); - if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { - convert_method(ccx, ImplContainer(def_id), - impl_item.id, sig, selfty, - &ty_predicates); - } + convert_impl_item(ccx, impl_item_id); } enforce_impl_lifetimes_are_constrained(ccx, generics, def_id, impl_item_ids); @@ -907,6 +875,47 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } } +fn convert_impl_item(ccx: &CrateCtxt, impl_item_id: hir::ImplItemId) { + let tcx = ccx.tcx; + let impl_item = tcx.map.impl_item(impl_item_id); + let impl_def_id = tcx.map.get_parent_did(impl_item_id.id); + let impl_predicates = tcx.item_predicates(impl_def_id); + let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); + let impl_self_ty = tcx.item_type(impl_def_id); + + match impl_item.node { + hir::ImplItemKind::Const(ref ty, _) => { + let const_def_id = ccx.tcx.map.local_def_id(impl_item.id); + generics_of_def_id(ccx, const_def_id); + let ty = ccx.icx(&impl_predicates) + .to_ty(&ExplicitRscope, &ty); + tcx.item_types.borrow_mut().insert(const_def_id, ty); + convert_associated_const(ccx, ImplContainer(impl_def_id), + impl_item.id, ty); + } + + hir::ImplItemKind::Type(ref ty) => { + let type_def_id = ccx.tcx.map.local_def_id(impl_item.id); + generics_of_def_id(ccx, type_def_id); + + if impl_trait_ref.is_none() { + span_err!(tcx.sess, impl_item.span, E0202, + "associated types are not allowed in inherent impls"); + } + + let typ = ccx.icx(&impl_predicates).to_ty(&ExplicitRscope, ty); + + convert_associated_type(ccx, ImplContainer(impl_def_id), impl_item.id, Some(typ)); + } + + hir::ImplItemKind::Method(ref sig, _) => { + convert_method(ccx, ImplContainer(impl_def_id), + impl_item.id, sig, impl_self_ty, + &impl_predicates); + } + } +} + fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ctor_id: ast::NodeId, variant: ty::VariantDef<'tcx>, From 4a4c61b2d2b99e2ae20ab5fcf7c1c59a9ac7d226 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 8 Nov 2016 19:23:09 -0500 Subject: [PATCH 132/177] move the impl-params-constrained check out of collect This helps with incr. comp. because otherwise the Collect(Impl) check winds up touching all of the impl items; since Collect(Impl) also produces the types for the impl header, this creates a polluted graph where the impl types depend on the impl items. --- src/librustc_typeck/Cargo.toml | 1 + .../check/impl_parameters_used.rs | 129 ++++++++++++++++++ src/librustc_typeck/check/mod.rs | 9 +- src/librustc_typeck/collect.rs | 119 ++-------------- .../constrained_type_params.rs | 12 ++ src/librustc_typeck/lib.rs | 1 + 6 files changed, 160 insertions(+), 111 deletions(-) create mode 100644 src/librustc_typeck/check/impl_parameters_used.rs diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index 720423371a83..f08d26373e50 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -18,6 +18,7 @@ rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } +rustc_data_structures = { path = "../librustc_data_structures" } rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } syntax_pos = { path = "../libsyntax_pos" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_typeck/check/impl_parameters_used.rs b/src/librustc_typeck/check/impl_parameters_used.rs new file mode 100644 index 000000000000..defdcc7906c3 --- /dev/null +++ b/src/librustc_typeck/check/impl_parameters_used.rs @@ -0,0 +1,129 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use constrained_type_params as ctp; +use rustc::hir; +use rustc::hir::def_id::DefId; +use rustc::ty; +use rustc::util::nodemap::FxHashSet; + +use syntax_pos::Span; + +use CrateCtxt; + +/// Checks that all the type/lifetime parameters on an impl also +/// appear in the trait ref or self-type (or are constrained by a +/// where-clause). These rules are needed to ensure that, given a +/// trait ref like `>`, we can derive the values of all +/// parameters on the impl (which is needed to make specialization +/// possible). +/// +/// However, in the case of lifetimes, we only enforce these rules if +/// the lifetime parameter is used in an associated type. This is a +/// concession to backwards compatibility; see comment at the end of +/// the fn for details. +/// +/// Example: +/// +/// ``` +/// impl Trait for Bar { ... } +/// ^ T does not appear in `Foo` or `Bar`, error! +/// +/// impl Trait> for Bar { ... } +/// ^ T appears in `Foo`, ok. +/// +/// impl Trait for Bar where Bar: Iterator { ... } +/// ^ T is bound to `::Item`, ok. +/// +/// impl<'a> Trait for Bar { } +/// ^ 'a is unused, but for back-compat we allow it +/// +/// impl<'a> Trait for Bar { type X = &'a i32; } +/// ^ 'a is unused and appears in assoc type, error +/// ``` +pub fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + impl_hir_generics: &hir::Generics, + impl_def_id: DefId, + impl_item_ids: &[hir::ImplItemId]) +{ + // Every lifetime used in an associated type must be constrained. + let impl_scheme = ccx.tcx.lookup_item_type(impl_def_id); + let impl_predicates = ccx.tcx.lookup_predicates(impl_def_id); + let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id); + + let mut input_parameters = ctp::parameters_for_impl(impl_scheme.ty, impl_trait_ref); + ctp::identify_constrained_type_params( + &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters); + + // Disallow ANY unconstrained type parameters. + for (ty_param, param) in impl_scheme.generics.types.iter().zip(&impl_hir_generics.ty_params) { + let param_ty = ty::ParamTy::for_def(ty_param); + if !input_parameters.contains(&ctp::Parameter::from(param_ty)) { + report_unused_parameter(ccx, param.span, "type", ¶m_ty.to_string()); + } + } + + // Disallow unconstrained lifetimes, but only if they appear in assoc types. + let lifetimes_in_associated_types: FxHashSet<_> = impl_item_ids.iter() + .map(|item_id| ccx.tcx.map.local_def_id(item_id.id)) + .filter(|&def_id| { + let item = ccx.tcx.associated_item(def_id); + item.kind == ty::AssociatedKind::Type && item.has_value + }) + .flat_map(|def_id| { + ctp::parameters_for(&ccx.tcx.lookup_item_type(def_id).ty, true) + }).collect(); + for (ty_lifetime, lifetime) in impl_scheme.generics.regions.iter() + .zip(&impl_hir_generics.lifetimes) + { + let param = ctp::Parameter::from(ty_lifetime.to_early_bound_region_data()); + + if + lifetimes_in_associated_types.contains(¶m) && // (*) + !input_parameters.contains(¶m) + { + report_unused_parameter(ccx, lifetime.lifetime.span, + "lifetime", &lifetime.lifetime.name.to_string()); + } + } + + // (*) This is a horrible concession to reality. I think it'd be + // better to just ban unconstrianed lifetimes outright, but in + // practice people do non-hygenic macros like: + // + // ``` + // macro_rules! __impl_slice_eq1 { + // ($Lhs: ty, $Rhs: ty, $Bound: ident) => { + // impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq { + // .... + // } + // } + // } + // ``` + // + // In a concession to backwards compatbility, we continue to + // permit those, so long as the lifetimes aren't used in + // associated types. I believe this is sound, because lifetimes + // used elsewhere are not projected back out. +} + +fn report_unused_parameter(ccx: &CrateCtxt, + span: Span, + kind: &str, + name: &str) +{ + struct_span_err!( + ccx.tcx.sess, span, E0207, + "the {} parameter `{}` is not constrained by the \ + impl trait, self type, or predicates", + kind, name) + .span_label(span, &format!("unconstrained {} parameter", kind)) + .emit(); +} diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e8ebc2eee63d..12a1cc8279fd 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -143,6 +143,7 @@ mod closure; mod callee; mod compare_method; mod intrinsic; +mod impl_parameters_used; mod op; /// closures defined within the function. For example: @@ -815,7 +816,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { it.id); } hir::ItemFn(..) => {} // entirely within check_item_body - hir::ItemImpl(.., ref impl_item_ids) => { + hir::ItemImpl(_, _, ref hir_generics, _, _, ref impl_item_ids) => { debug!("ItemImpl {} with id {}", it.name, it.id); let impl_def_id = ccx.tcx.map.local_def_id(it.id); if let Some(impl_trait_ref) = ccx.tcx.impl_trait_ref(impl_def_id) { @@ -827,6 +828,12 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { let trait_def_id = impl_trait_ref.def_id; check_on_unimplemented(ccx, trait_def_id, it); } + + impl_parameters_used::enforce_impl_params_are_constrained(ccx, + hir_generics, + impl_def_id, + impl_item_ids); + } hir::ItemTrait(..) => { let def_id = ccx.tcx.map.local_def_id(it.id); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index eb4775a29bf3..e7873d2f8188 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -753,7 +753,15 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { }); tcx.impl_trait_refs.borrow_mut().insert(def_id, trait_ref); - enforce_impl_params_are_constrained(ccx, generics, &mut ty_predicates, def_id); + // Subtle: before we store the predicates into the tcx, we + // sort them so that predicates like `T: Foo` come + // before uses of `U`. This avoids false ambiguity errors + // in trait checking. See `setup_constraining_predicates` + // for details. + ctp::setup_constraining_predicates(&mut ty_predicates.predicates, + trait_ref, + &mut ctp::parameters_for_impl(selfty, trait_ref)); + tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone()); @@ -788,8 +796,6 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { for &impl_item_id in impl_item_ids { convert_impl_item(ccx, impl_item_id); } - - enforce_impl_lifetimes_are_constrained(ccx, generics, def_id, impl_item_ids); }, hir::ItemTrait(.., ref trait_items) => { let trait_def = trait_def_of_item(ccx, it); @@ -2084,110 +2090,3 @@ pub fn mk_item_substs<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, |def, _| tcx.mk_region(def.to_early_bound_region()), |def, _| tcx.mk_param_from_def(def)) } - -/// Checks that all the type parameters on an impl -fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - generics: &hir::Generics, - impl_predicates: &mut ty::GenericPredicates<'tcx>, - impl_def_id: DefId) -{ - let impl_ty = ccx.tcx.item_type(impl_def_id); - let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id); - - // The trait reference is an input, so find all type parameters - // reachable from there, to start (if this is an inherent impl, - // then just examine the self type). - let mut input_parameters: FxHashSet<_> = - ctp::parameters_for(&impl_ty, false).into_iter().collect(); - if let Some(ref trait_ref) = impl_trait_ref { - input_parameters.extend(ctp::parameters_for(trait_ref, false)); - } - - ctp::setup_constraining_predicates(&mut impl_predicates.predicates, - impl_trait_ref, - &mut input_parameters); - - let ty_generics = generics_of_def_id(ccx, impl_def_id); - for (ty_param, param) in ty_generics.types.iter().zip(&generics.ty_params) { - let param_ty = ty::ParamTy::for_def(ty_param); - if !input_parameters.contains(&ctp::Parameter::from(param_ty)) { - report_unused_parameter(ccx, param.span, "type", ¶m_ty.to_string()); - } - } -} - -fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - ast_generics: &hir::Generics, - impl_def_id: DefId, - impl_item_ids: &[hir::ImplItemId]) -{ - // Every lifetime used in an associated type must be constrained. - let impl_ty = ccx.tcx.item_type(impl_def_id); - let impl_predicates = ccx.tcx.item_predicates(impl_def_id); - let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id); - - let mut input_parameters: FxHashSet<_> = - ctp::parameters_for(&impl_ty, false).into_iter().collect(); - if let Some(ref trait_ref) = impl_trait_ref { - input_parameters.extend(ctp::parameters_for(trait_ref, false)); - } - ctp::identify_constrained_type_params( - &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters); - - let lifetimes_in_associated_types: FxHashSet<_> = impl_item_ids.iter() - .map(|item_id| ccx.tcx.map.local_def_id(item_id.id)) - .filter(|&def_id| { - let item = ccx.tcx.associated_item(def_id); - item.kind == ty::AssociatedKind::Type && item.has_value - }) - .flat_map(|def_id| { - ctp::parameters_for(&ccx.tcx.item_type(def_id), true) - }).collect(); - - for (ty_lifetime, lifetime) in ccx.tcx.item_generics(impl_def_id).regions.iter() - .zip(&ast_generics.lifetimes) - { - let param = ctp::Parameter::from(ty_lifetime.to_early_bound_region_data()); - - if - lifetimes_in_associated_types.contains(¶m) && // (*) - !input_parameters.contains(¶m) - { - report_unused_parameter(ccx, lifetime.lifetime.span, - "lifetime", &lifetime.lifetime.name.to_string()); - } - } - - // (*) This is a horrible concession to reality. I think it'd be - // better to just ban unconstrianed lifetimes outright, but in - // practice people do non-hygenic macros like: - // - // ``` - // macro_rules! __impl_slice_eq1 { - // ($Lhs: ty, $Rhs: ty, $Bound: ident) => { - // impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq { - // .... - // } - // } - // } - // ``` - // - // In a concession to backwards compatbility, we continue to - // permit those, so long as the lifetimes aren't used in - // associated types. I believe this is sound, because lifetimes - // used elsewhere are not projected back out. -} - -fn report_unused_parameter(ccx: &CrateCtxt, - span: Span, - kind: &str, - name: &str) -{ - struct_span_err!( - ccx.tcx.sess, span, E0207, - "the {} parameter `{}` is not constrained by the \ - impl trait, self type, or predicates", - kind, name) - .span_label(span, &format!("unconstrained {} parameter", kind)) - .emit(); -} diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index 7918537a6c08..22be4491273e 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -23,6 +23,18 @@ impl From for Parameter { fn from(param: ty::EarlyBoundRegion) -> Self { Parameter(param.index) } } +/// Return the set of parameters constrained by the impl header. +pub fn parameters_for_impl<'tcx>(impl_self_ty: Ty<'tcx>, + impl_trait_ref: Option>) + -> FxHashSet +{ + let vec = match impl_trait_ref { + Some(tr) => parameters_for(&tr, false), + None => parameters_for(&impl_self_ty, false), + }; + vec.into_iter().collect() +} + /// If `include_projections` is false, returns the list of parameters that are /// constrained by `t` - i.e. the value of each parameter in the list is /// uniquely determined by `t` (see RFC 447). If it is true, return the list diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 2c12959dbdde..222e60bb0545 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -95,6 +95,7 @@ extern crate rustc_platform_intrinsics as intrinsics; extern crate rustc_back; extern crate rustc_const_math; extern crate rustc_const_eval; +extern crate rustc_data_structures; extern crate rustc_errors as errors; pub use rustc::dep_graph; From 29a39ab8346721cf60cfb15f7e025eb24efc818f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 8 Nov 2016 20:26:59 -0500 Subject: [PATCH 133/177] move `convert_impl_item` into the main loop This is better because the edges will be accounted to the impl item itself --- src/librustc_typeck/collect.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index e7873d2f8188..fc1977424556 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -151,7 +151,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> { } fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) { - // handled in `visit_item` above; we may want to break this out later + convert_impl_item(self.ccx, impl_item); intravisit::walk_impl_item(self, impl_item); } } @@ -792,10 +792,6 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } } } - - for &impl_item_id in impl_item_ids { - convert_impl_item(ccx, impl_item_id); - } }, hir::ItemTrait(.., ref trait_items) => { let trait_def = trait_def_of_item(ccx, it); @@ -881,10 +877,12 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } } -fn convert_impl_item(ccx: &CrateCtxt, impl_item_id: hir::ImplItemId) { +fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) { let tcx = ccx.tcx; - let impl_item = tcx.map.impl_item(impl_item_id); - let impl_def_id = tcx.map.get_parent_did(impl_item_id.id); + + // we can lookup details about the impl because items are visited + // before impl-items + let impl_def_id = tcx.map.get_parent_did(impl_item.id); let impl_predicates = tcx.item_predicates(impl_def_id); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); let impl_self_ty = tcx.item_type(impl_def_id); From 4df5288971b9908b77c0c785885a59d91e546a4d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 8 Nov 2016 20:27:28 -0500 Subject: [PATCH 134/177] move duplicate checking into TypeCheck This completes the effort to not touch the impl-items during `Collect(Impl)`. --- .../check/impl_item_duplicate.rs | 46 +++++++++++++++++++ src/librustc_typeck/check/mod.rs | 3 ++ src/librustc_typeck/collect.rs | 36 ++------------- 3 files changed, 54 insertions(+), 31 deletions(-) create mode 100644 src/librustc_typeck/check/impl_item_duplicate.rs diff --git a/src/librustc_typeck/check/impl_item_duplicate.rs b/src/librustc_typeck/check/impl_item_duplicate.rs new file mode 100644 index 000000000000..4111fa9a2c0d --- /dev/null +++ b/src/librustc_typeck/check/impl_item_duplicate.rs @@ -0,0 +1,46 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::hir; +use rustc_data_structures::fx::FxHashMap; +use std::collections::hash_map::Entry::{Occupied, Vacant}; + +use CrateCtxt; + +/// Enforce that we do not have two items in an impl with the same name. +pub fn enforce_impl_items_are_distinct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + impl_item_ids: &[hir::ImplItemId]) +{ + let tcx = ccx.tcx; + let mut seen_type_items = FxHashMap(); + let mut seen_value_items = FxHashMap(); + for &impl_item_id in impl_item_ids { + let impl_item = tcx.map.impl_item(impl_item_id); + let seen_items = match impl_item.node { + hir::ImplItemKind::Type(_) => &mut seen_type_items, + _ => &mut seen_value_items, + }; + match seen_items.entry(impl_item.name) { + Occupied(entry) => { + let mut err = struct_span_err!(tcx.sess, impl_item.span, E0201, + "duplicate definitions with name `{}`:", + impl_item.name); + err.span_label(*entry.get(), + &format!("previous definition of `{}` here", + impl_item.name)); + err.span_label(impl_item.span, &format!("duplicate definition")); + err.emit(); + } + Vacant(entry) => { + entry.insert(impl_item.span); + } + } + } +} diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 12a1cc8279fd..7c21ddbe4019 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -143,6 +143,7 @@ mod closure; mod callee; mod compare_method; mod intrinsic; +mod impl_item_duplicate; mod impl_parameters_used; mod op; @@ -834,6 +835,8 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { impl_def_id, impl_item_ids); + impl_item_duplicate::enforce_impl_items_are_distinct(ccx, + impl_item_ids); } hir::ItemTrait(..) => { let def_id = ccx.tcx.map.local_def_id(it.id); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index fc1977424556..c20e1d1d4d74 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -77,7 +77,6 @@ use CrateCtxt; use rustc_const_math::ConstInt; use std::cell::RefCell; -use std::collections::hash_map::Entry::{Occupied, Vacant}; use syntax::{abi, ast, attr}; use syntax::parse::token::{self, keywords}; @@ -732,7 +731,11 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { ref generics, ref opt_trait_ref, ref selfty, - ref impl_item_ids) => { + ref _impl_item_ids /* [1] */) => { + // [1]: We really don't want to be inspecting the details + // of impl-items here; it creates bad edges in the + // incr. comp. graph. + // Create generics from the generics specified in the impl head. debug!("convert: ast_generics={:?}", generics); let def_id = ccx.tcx.map.local_def_id(it.id); @@ -763,35 +766,6 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { &mut ctp::parameters_for_impl(selfty, trait_ref)); tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone()); - - - // Convert all the associated consts. - // Also, check if there are any duplicate associated items - let mut seen_type_items = FxHashMap(); - let mut seen_value_items = FxHashMap(); - - for &impl_item_id in impl_item_ids { - let impl_item = tcx.map.impl_item(impl_item_id); - let seen_items = match impl_item.node { - hir::ImplItemKind::Type(_) => &mut seen_type_items, - _ => &mut seen_value_items, - }; - match seen_items.entry(impl_item.name) { - Occupied(entry) => { - let mut err = struct_span_err!(tcx.sess, impl_item.span, E0201, - "duplicate definitions with name `{}`:", - impl_item.name); - err.span_label(*entry.get(), - &format!("previous definition of `{}` here", - impl_item.name)); - err.span_label(impl_item.span, &format!("duplicate definition")); - err.emit(); - } - Vacant(entry) => { - entry.insert(impl_item.span); - } - } - } }, hir::ItemTrait(.., ref trait_items) => { let trait_def = trait_def_of_item(ccx, it); From 26d1500e133d50727dfea10043d194a5b9f3761f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 9 Nov 2016 16:45:26 -0500 Subject: [PATCH 135/177] add a `nested_visit_map` method This allows you to enable *all* nested visits in a future-compatible sort of way. Moreover, if you choose to override the `visit_nested` methods yourself, you can "future-proof" against omissions by overriding `nested_visit_map` to panic. --- src/librustc/hir/intravisit.rs | 56 ++++++++++--- src/librustc/hir/map/collector.rs | 5 ++ src/librustc/lint/context.rs | 66 ++++++++-------- src/librustc/middle/dead.rs | 27 +++---- src/librustc/middle/resolve_lifetime.rs | 66 ++++++++-------- src/librustc/middle/stability.rs | 52 +++++------- .../calculate_svh/svh_visitor.rs | 8 -- src/librustc_passes/hir_stats.rs | 8 ++ src/librustc_privacy/lib.rs | 79 ++++++++----------- 9 files changed, 183 insertions(+), 184 deletions(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 5a193a0ac942..0b83a8bc9222 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -38,6 +38,7 @@ use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute}; use syntax::codemap::Spanned; use syntax_pos::Span; use hir::*; +use hir::map::Map; use super::itemlikevisit::DeepVisitor; use std::cmp; @@ -85,23 +86,52 @@ pub trait Visitor<'v> : Sized { /////////////////////////////////////////////////////////////////////////// // Nested items. - /// Invoked when a nested item is encountered. By default, does - /// nothing. If you want a deep walk, you need to override to - /// fetch the item contents. But most of the time, it is easier to - /// use either the "shallow" or "deep" visit patterns described on - /// `itemlikevisit::ItemLikeVisitor`. - #[allow(unused_variables)] - fn visit_nested_item(&mut self, id: ItemId) { + /// The default versions of the `visit_nested_XXX` routines invoke + /// this method to get a map to use; if they get back `None`, they + /// just skip nested things. Otherwise, they will lookup the + /// nested item-like things in the map and visit it. So the best + /// way to implement a nested visitor is to override this method + /// to return a `Map`; one advantage of this is that if we add + /// more types of nested things in the future, they will + /// automatically work. + /// + /// **If for some reason you want the nested behavior, but don't + /// have a `Map` are your disposal:** then you should override the + /// `visit_nested_XXX` methods, and override this method to + /// `panic!()`. This way, if a new `visit_nested_XXX` variant is + /// added in the future, we will see the panic in your code and + /// fix it appropriately. + fn nested_visit_map(&mut self) -> Option<&Map<'v>> { + None } - /// Invoked when a nested impl item is encountered. By default, does - /// nothing. If you want a deep walk, you need to override to - /// fetch the item contents. But most of the time, it is easier - /// (and better) to invoke `Crate::visit_all_item_likes`, which visits - /// all items in the crate in some order (but doesn't respect - /// nesting). + /// Invoked when a nested item is encountered. By default does + /// nothing unless you override `nested_visit_map` to return + /// `Some(_)`, in which case it will walk the item. **You probably + /// don't want to override this method** -- instead, override + /// `nested_visit_map` or use the "shallow" or "deep" visit + /// patterns described on `itemlikevisit::ItemLikeVisitor`. The only + /// reason to override this method is if you want a nested pattern + /// but cannot supply a `Map`; see `nested_visit_map` for advice. + #[allow(unused_variables)] + fn visit_nested_item(&mut self, id: ItemId) { + let opt_item = self.nested_visit_map() + .map(|map| map.expect_item(id.id)); + if let Some(item) = opt_item { + self.visit_item(item); + } + } + + /// Like `visit_nested_item()`, but for impl items. See + /// `visit_nested_item()` for advice on when to override this + /// method. #[allow(unused_variables)] fn visit_nested_impl_item(&mut self, id: ImplItemId) { + let opt_item = self.nested_visit_map() + .map(|map| map.impl_item(id)); + if let Some(item) = opt_item { + self.visit_impl_item(item); + } } /// Visit the top-level item and (optionally) nested items / impl items. See diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index eafb7949da38..5fd0839affef 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -92,6 +92,11 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { /// Because we want to track parent items and so forth, enable /// deep walking so that we walk nested items in the context of /// their outer items. + + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'v>> { + panic!("visit_nested_xxx must be manually implemented in this visitor") + } + fn visit_nested_item(&mut self, item: ItemId) { debug!("visit_nested_item: {:?}", item); if !self.ignore_nested_items { diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 78049663afeb..a490b58964a7 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -792,21 +792,15 @@ impl<'a> LintContext for EarlyContext<'a> { } } -impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { +impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { /// Because lints are scoped lexically, we want to walk nested /// items in the context of the outer item, so enable /// deep-walking. - fn visit_nested_item(&mut self, item: hir::ItemId) { - let item = self.tcx.map.expect_item(item.id); - self.visit_item(item) + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.tcx.map) } - fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { - let impl_item = self.tcx.map.impl_item(item_id); - self.visit_impl_item(impl_item) - } - - fn visit_item(&mut self, it: &hir::Item) { + fn visit_item(&mut self, it: &'tcx hir::Item) { self.with_lint_attrs(&it.attrs, |cx| { run_lints!(cx, check_item, late_passes, it); cx.visit_ids(|v| v.visit_item(it)); @@ -815,7 +809,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { }) } - fn visit_foreign_item(&mut self, it: &hir::ForeignItem) { + fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) { self.with_lint_attrs(&it.attrs, |cx| { run_lints!(cx, check_foreign_item, late_passes, it); hir_visit::walk_foreign_item(cx, it); @@ -823,19 +817,19 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { }) } - fn visit_pat(&mut self, p: &hir::Pat) { + fn visit_pat(&mut self, p: &'tcx hir::Pat) { run_lints!(self, check_pat, late_passes, p); hir_visit::walk_pat(self, p); } - fn visit_expr(&mut self, e: &hir::Expr) { + fn visit_expr(&mut self, e: &'tcx hir::Expr) { self.with_lint_attrs(&e.attrs, |cx| { run_lints!(cx, check_expr, late_passes, e); hir_visit::walk_expr(cx, e); }) } - fn visit_stmt(&mut self, s: &hir::Stmt) { + fn visit_stmt(&mut self, s: &'tcx hir::Stmt) { // statement attributes are actually just attributes on one of // - item // - local @@ -845,17 +839,17 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { hir_visit::walk_stmt(self, s); } - fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, decl: &'v hir::FnDecl, - body: &'v hir::Expr, span: Span, id: ast::NodeId) { + fn visit_fn(&mut self, fk: hir_visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl, + body: &'tcx hir::Expr, span: Span, id: ast::NodeId) { run_lints!(self, check_fn, late_passes, fk, decl, body, span, id); hir_visit::walk_fn(self, fk, decl, body, span, id); run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id); } fn visit_variant_data(&mut self, - s: &hir::VariantData, + s: &'tcx hir::VariantData, name: ast::Name, - g: &hir::Generics, + g: &'tcx hir::Generics, item_id: ast::NodeId, _: Span) { run_lints!(self, check_struct_def, late_passes, s, name, g, item_id); @@ -863,14 +857,17 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { run_lints!(self, check_struct_def_post, late_passes, s, name, g, item_id); } - fn visit_struct_field(&mut self, s: &hir::StructField) { + fn visit_struct_field(&mut self, s: &'tcx hir::StructField) { self.with_lint_attrs(&s.attrs, |cx| { run_lints!(cx, check_struct_field, late_passes, s); hir_visit::walk_struct_field(cx, s); }) } - fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) { + fn visit_variant(&mut self, + v: &'tcx hir::Variant, + g: &'tcx hir::Generics, + item_id: ast::NodeId) { self.with_lint_attrs(&v.node.attrs, |cx| { run_lints!(cx, check_variant, late_passes, v, g); hir_visit::walk_variant(cx, v, g, item_id); @@ -878,7 +875,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { }) } - fn visit_ty(&mut self, t: &hir::Ty) { + fn visit_ty(&mut self, t: &'tcx hir::Ty) { run_lints!(self, check_ty, late_passes, t); hir_visit::walk_ty(self, t); } @@ -887,45 +884,45 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { run_lints!(self, check_name, late_passes, sp, name); } - fn visit_mod(&mut self, m: &hir::Mod, s: Span, n: ast::NodeId) { + fn visit_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: ast::NodeId) { run_lints!(self, check_mod, late_passes, m, s, n); hir_visit::walk_mod(self, m, n); run_lints!(self, check_mod_post, late_passes, m, s, n); } - fn visit_local(&mut self, l: &hir::Local) { + fn visit_local(&mut self, l: &'tcx hir::Local) { self.with_lint_attrs(&l.attrs, |cx| { run_lints!(cx, check_local, late_passes, l); hir_visit::walk_local(cx, l); }) } - fn visit_block(&mut self, b: &hir::Block) { + fn visit_block(&mut self, b: &'tcx hir::Block) { run_lints!(self, check_block, late_passes, b); hir_visit::walk_block(self, b); run_lints!(self, check_block_post, late_passes, b); } - fn visit_arm(&mut self, a: &hir::Arm) { + fn visit_arm(&mut self, a: &'tcx hir::Arm) { run_lints!(self, check_arm, late_passes, a); hir_visit::walk_arm(self, a); } - fn visit_decl(&mut self, d: &hir::Decl) { + fn visit_decl(&mut self, d: &'tcx hir::Decl) { run_lints!(self, check_decl, late_passes, d); hir_visit::walk_decl(self, d); } - fn visit_expr_post(&mut self, e: &hir::Expr) { + fn visit_expr_post(&mut self, e: &'tcx hir::Expr) { run_lints!(self, check_expr_post, late_passes, e); } - fn visit_generics(&mut self, g: &hir::Generics) { + fn visit_generics(&mut self, g: &'tcx hir::Generics) { run_lints!(self, check_generics, late_passes, g); hir_visit::walk_generics(self, g); } - fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) { + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { self.with_lint_attrs(&trait_item.attrs, |cx| { run_lints!(cx, check_trait_item, late_passes, trait_item); cx.visit_ids(|v| hir_visit::walk_trait_item(v, trait_item)); @@ -934,7 +931,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { }); } - fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) { + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { self.with_lint_attrs(&impl_item.attrs, |cx| { run_lints!(cx, check_impl_item, late_passes, impl_item); cx.visit_ids(|v| hir_visit::walk_impl_item(v, impl_item)); @@ -943,20 +940,20 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { }); } - fn visit_lifetime(&mut self, lt: &hir::Lifetime) { + fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) { run_lints!(self, check_lifetime, late_passes, lt); } - fn visit_lifetime_def(&mut self, lt: &hir::LifetimeDef) { + fn visit_lifetime_def(&mut self, lt: &'tcx hir::LifetimeDef) { run_lints!(self, check_lifetime_def, late_passes, lt); } - fn visit_path(&mut self, p: &hir::Path, id: ast::NodeId) { + fn visit_path(&mut self, p: &'tcx hir::Path, id: ast::NodeId) { run_lints!(self, check_path, late_passes, p, id); hir_visit::walk_path(self, p); } - fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) { + fn visit_path_list_item(&mut self, prefix: &'tcx hir::Path, item: &'tcx hir::PathListItem) { run_lints!(self, check_path_list_item, late_passes, item); hir_visit::walk_path_list_item(self, prefix, item); } @@ -1121,7 +1118,6 @@ struct IdVisitor<'a, 'b: 'a, 'tcx: 'a+'b> { // Output any lints that were previously added to the session. impl<'a, 'b, 'tcx, 'v> hir_visit::Visitor<'v> for IdVisitor<'a, 'b, 'tcx> { - fn visit_id(&mut self, id: ast::NodeId) { if let Some(lints) = self.cx.sess().lints.borrow_mut().remove(&id) { debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints); diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 57abf0bdc427..e6722661223e 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -511,22 +511,16 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { } } -impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { /// Walk nested items in place so that we don't report dead-code /// on inner functions when the outer function is already getting /// an error. We could do this also by checking the parents, but /// this is how the code is setup and it seems harmless enough. - fn visit_nested_item(&mut self, item: hir::ItemId) { - let item = self.tcx.map.expect_item(item.id); - self.visit_item(item) + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.tcx.map) } - fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { - let impl_item = self.tcx.map.impl_item(item_id); - self.visit_impl_item(impl_item) - } - - fn visit_item(&mut self, item: &hir::Item) { + fn visit_item(&mut self, item: &'tcx hir::Item) { if self.should_warn_about_item(item) { self.warn_dead_code( item.id, @@ -540,7 +534,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { } } - fn visit_variant(&mut self, variant: &hir::Variant, g: &hir::Generics, id: ast::NodeId) { + fn visit_variant(&mut self, + variant: &'tcx hir::Variant, + g: &'tcx hir::Generics, + id: ast::NodeId) { if self.should_warn_about_variant(&variant.node) { self.warn_dead_code(variant.node.data.id(), variant.span, variant.node.name, "variant"); @@ -549,14 +546,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { } } - fn visit_foreign_item(&mut self, fi: &hir::ForeignItem) { + fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem) { if !self.symbol_is_live(fi.id, None) { self.warn_dead_code(fi.id, fi.span, fi.name, fi.node.descriptive_variant()); } intravisit::walk_foreign_item(self, fi); } - fn visit_struct_field(&mut self, field: &hir::StructField) { + fn visit_struct_field(&mut self, field: &'tcx hir::StructField) { if self.should_warn_about_field(&field) { self.warn_dead_code(field.id, field.span, field.name, "field"); @@ -565,7 +562,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { intravisit::walk_struct_field(self, field); } - fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) { + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { match impl_item.node { hir::ImplItemKind::Const(_, ref expr) => { if !self.symbol_is_live(impl_item.id, None) { @@ -586,7 +583,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { } // Overwrite so that we don't warn the trait item itself. - fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) { + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { match trait_item.node { hir::ConstTraitItem(_, Some(ref body))| hir::MethodTraitItem(_, Some(ref body)) => { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 68d2cceda847..f682dfbf1be9 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -132,21 +132,14 @@ pub fn krate(sess: &Session, Ok(map) } -impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // Override the nested functions -- lifetimes follow lexical scope, // so it's convenient to walk the tree in lexical order. - - fn visit_nested_item(&mut self, id: hir::ItemId) { - let item = self.hir_map.expect_item(id.id); - self.visit_item(item) + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.hir_map) } - fn visit_nested_impl_item(&mut self, id: hir::ImplItemId) { - let impl_item = self.hir_map.impl_item(id); - self.visit_impl_item(impl_item) - } - - fn visit_item(&mut self, item: &hir::Item) { + fn visit_item(&mut self, item: &'tcx hir::Item) { // Save labels for nested items. let saved_labels_in_fn = replace(&mut self.labels_in_fn, vec![]); @@ -192,7 +185,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { self.labels_in_fn = saved_labels_in_fn; } - fn visit_foreign_item(&mut self, item: &hir::ForeignItem) { + fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) { // Items save/restore the set of labels. This way inner items // can freely reuse names, be they loop labels or lifetimes. let saved = replace(&mut self.labels_in_fn, vec![]); @@ -215,8 +208,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { replace(&mut self.labels_in_fn, saved); } - fn visit_fn(&mut self, fk: FnKind<'v>, decl: &'v hir::FnDecl, - b: &'v hir::Expr, s: Span, fn_id: ast::NodeId) { + fn visit_fn(&mut self, fk: FnKind<'tcx>, decl: &'tcx hir::FnDecl, + b: &'tcx hir::Expr, s: Span, fn_id: ast::NodeId) { match fk { FnKind::ItemFn(_, generics, ..) => { self.visit_early_late(fn_id,decl, generics, |this| { @@ -241,7 +234,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { } } - fn visit_ty(&mut self, ty: &hir::Ty) { + fn visit_ty(&mut self, ty: &'tcx hir::Ty) { match ty.node { hir::TyBareFn(ref c) => { self.with(LateScope(&c.lifetimes, self.scope), |old_scope, this| { @@ -271,7 +264,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { } } - fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) { + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { // We reset the labels on every trait item, so that different // methods in an impl can reuse label names. let saved = replace(&mut self.labels_in_fn, vec![]); @@ -288,7 +281,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { replace(&mut self.labels_in_fn, saved); } - fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { + fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { if lifetime_ref.name == keywords::StaticLifetime.name() { self.insert_lifetime(lifetime_ref, DefStaticRegion); return; @@ -296,7 +289,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { self.resolve_lifetime_ref(lifetime_ref); } - fn visit_generics(&mut self, generics: &hir::Generics) { + fn visit_generics(&mut self, generics: &'tcx hir::Generics) { for ty_param in generics.ty_params.iter() { walk_list!(self, visit_ty_param_bound, &ty_param.bounds); if let Some(ref ty) = ty_param.default { @@ -345,8 +338,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { } fn visit_poly_trait_ref(&mut self, - trait_ref: &hir::PolyTraitRef, - _modifier: &hir::TraitBoundModifier) { + trait_ref: &'tcx hir::PolyTraitRef, + _modifier: &'tcx hir::TraitBoundModifier) { debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref); if !self.trait_ref_hack || !trait_ref.bound_lifetimes.is_empty() { @@ -504,13 +497,12 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Expr) { } impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { - fn add_scope_and_walk_fn<'b>(&mut self, - fk: FnKind, - fd: &hir::FnDecl, - fb: &'b hir::Expr, - _span: Span, - fn_id: ast::NodeId) { - + fn add_scope_and_walk_fn(&mut self, + fk: FnKind<'tcx>, + fd: &'tcx hir::FnDecl, + fb: &'tcx hir::Expr, + _span: Span, + fn_id: ast::NodeId) { match fk { FnKind::ItemFn(_, generics, ..) => { intravisit::walk_fn_decl(self, fd); @@ -533,8 +525,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { |_old_scope, this| this.visit_expr(fb)) } + // FIXME(#37666) this works around a limitation in the region inferencer + fn hack(&mut self, f: F) where + F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>), + { + f(self) + } + fn with(&mut self, wrap_scope: ScopeChain, f: F) where - F: FnOnce(Scope, &mut LifetimeContext), + F: for<'b> FnOnce(Scope, &mut LifetimeContext<'b, 'tcx>), { let LifetimeContext {sess, hir_map, ref mut map, ..} = *self; let mut this = LifetimeContext { @@ -571,10 +570,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { /// ordering is not important there. fn visit_early_late(&mut self, fn_id: ast::NodeId, - decl: &hir::FnDecl, - generics: &hir::Generics, + decl: &'tcx hir::FnDecl, + generics: &'tcx hir::Generics, walk: F) where - F: FnOnce(&mut LifetimeContext), + F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>), { let fn_def_id = self.hir_map.local_def_id(fn_id); insert_late_bound_lifetimes(self.map, @@ -604,11 +603,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } - let this = self; - this.with(EarlyScope(&early, start as u32, this.scope), move |old_scope, this| { + self.with(EarlyScope(&early, start as u32, self.scope), move |old_scope, this| { this.with(LateScope(&late, this.scope), move |_, this| { this.check_lifetime_defs(old_scope, &generics.lifetimes); - walk(this); + this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)` }); }); } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index f8d58c5f2d91..239aaa6bb75f 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -120,7 +120,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { // stability. The stability is recorded in the index and used as the parent. fn annotate(&mut self, id: NodeId, attrs: &[Attribute], item_sp: Span, kind: AnnotationKind, visit_children: F) - where F: FnOnce(&mut Annotator) + where F: FnOnce(&mut Self) { if self.index.staged_api[&LOCAL_CRATE] && self.tcx.sess.features.borrow().staged_api { debug!("annotate(id = {:?}, attrs = {:?})", id, attrs); @@ -234,21 +234,15 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { } } -impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { /// Because stability levels are scoped lexically, we want to walk /// nested items in the context of the outer item, so enable /// deep-walking. - fn visit_nested_item(&mut self, item: hir::ItemId) { - let item = self.tcx.map.expect_item(item.id); - self.visit_item(item) + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.tcx.map) } - fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { - let impl_item = self.tcx.map.impl_item(item_id); - self.visit_impl_item(impl_item) - } - - fn visit_item(&mut self, i: &Item) { + fn visit_item(&mut self, i: &'tcx Item) { let orig_in_trait_impl = self.in_trait_impl; let mut kind = AnnotationKind::Required; match i.node { @@ -277,13 +271,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> { self.in_trait_impl = orig_in_trait_impl; } - fn visit_trait_item(&mut self, ti: &hir::TraitItem) { + fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) { self.annotate(ti.id, &ti.attrs, ti.span, AnnotationKind::Required, |v| { intravisit::walk_trait_item(v, ti); }); } - fn visit_impl_item(&mut self, ii: &hir::ImplItem) { + fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) { let kind = if self.in_trait_impl { AnnotationKind::Prohibited } else { @@ -294,25 +288,25 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> { }); } - fn visit_variant(&mut self, var: &Variant, g: &'v Generics, item_id: NodeId) { + fn visit_variant(&mut self, var: &'tcx Variant, g: &'tcx Generics, item_id: NodeId) { self.annotate(var.node.data.id(), &var.node.attrs, var.span, AnnotationKind::Required, |v| { intravisit::walk_variant(v, var, g, item_id); }) } - fn visit_struct_field(&mut self, s: &StructField) { + fn visit_struct_field(&mut self, s: &'tcx StructField) { self.annotate(s.id, &s.attrs, s.span, AnnotationKind::Required, |v| { intravisit::walk_struct_field(v, s); }); } - fn visit_foreign_item(&mut self, i: &hir::ForeignItem) { + fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem) { self.annotate(i.id, &i.attrs, i.span, AnnotationKind::Required, |v| { intravisit::walk_foreign_item(v, i); }); } - fn visit_macro_def(&mut self, md: &'v hir::MacroDef) { + fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) { if md.imported_from.is_none() { self.annotate(md.id, &md.attrs, md.span, AnnotationKind::Required, |_| {}); } @@ -449,21 +443,15 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { } } -impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { /// Because stability levels are scoped lexically, we want to walk /// nested items in the context of the outer item, so enable /// deep-walking. - fn visit_nested_item(&mut self, item: hir::ItemId) { - let item = self.tcx.map.expect_item(item.id); - self.visit_item(item) + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.tcx.map) } - fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { - let impl_item = self.tcx.map.impl_item(item_id); - self.visit_impl_item(impl_item) - } - - fn visit_item(&mut self, item: &hir::Item) { + fn visit_item(&mut self, item: &'tcx hir::Item) { // When compiling with --test we don't enforce stability on the // compiler-generated test module, demarcated with `DUMMY_SP` plus the // name `__test` @@ -474,31 +462,31 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> { intravisit::walk_item(self, item); } - fn visit_expr(&mut self, ex: &hir::Expr) { + fn visit_expr(&mut self, ex: &'tcx hir::Expr) { check_expr(self.tcx, ex, &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); intravisit::walk_expr(self, ex); } - fn visit_path(&mut self, path: &hir::Path, id: ast::NodeId) { + fn visit_path(&mut self, path: &'tcx hir::Path, id: ast::NodeId) { check_path(self.tcx, path, id, &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); intravisit::walk_path(self, path) } - fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) { + fn visit_path_list_item(&mut self, prefix: &'tcx hir::Path, item: &'tcx hir::PathListItem) { check_path_list_item(self.tcx, item, &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); intravisit::walk_path_list_item(self, prefix, item) } - fn visit_pat(&mut self, pat: &hir::Pat) { + fn visit_pat(&mut self, pat: &'tcx hir::Pat) { check_pat(self.tcx, pat, &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); intravisit::walk_pat(self, pat) } - fn visit_block(&mut self, b: &hir::Block) { + fn visit_block(&mut self, b: &'tcx hir::Block) { let old_skip_count = self.in_skip_block; match b.rules { hir::BlockCheckMode::PushUnstableBlock => { diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 3af6ee35f9e5..318cc83d9ad4 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -499,14 +499,6 @@ macro_rules! hash_span { } impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> { - fn visit_nested_item(&mut self, _: ItemId) { - // Each item is hashed independently; ignore nested items. - } - - fn visit_nested_impl_item(&mut self, _: ImplItemId) { - // Impl items are hashed independently; ignore nested impl items. - } - fn visit_variant_data(&mut self, s: &'tcx VariantData, name: Name, diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index 417987d9664e..3bdaf276b40c 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -106,12 +106,20 @@ impl<'k> StatCollector<'k> { } impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'v>> { + panic!("visit_nested_xxx must be manually implemented in this visitor") + } fn visit_nested_item(&mut self, id: hir::ItemId) { let nested_item = self.krate.unwrap().item(id.id); self.visit_item(nested_item) } + fn visit_nested_impl_item(&mut self, impl_item_id: hir::ImplItemId) { + let nested_impl_item = self.krate.unwrap().impl_item(impl_item_id); + self.visit_impl_item(nested_impl_item) + } + fn visit_item(&mut self, i: &'v hir::Item) { self.record("Item", Id::Node(i.id), i); hir_visit::walk_item(self, i) diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 3fd1ed935165..9cbf4c8a6154 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -116,20 +116,14 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> { } } -impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { /// We want to visit items in the context of their containing /// module and so forth, so supply a crate for doing a deep walk. - fn visit_nested_item(&mut self, item: hir::ItemId) { - let tcx = self.tcx; - self.visit_item(tcx.map.expect_item(item.id)) + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.tcx.map) } - fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { - let impl_item = self.tcx.map.impl_item(item_id); - self.visit_impl_item(impl_item) - } - - fn visit_item(&mut self, item: &hir::Item) { + fn visit_item(&mut self, item: &'tcx hir::Item) { let inherited_item_level = match item.node { // Impls inherit level from their types and traits hir::ItemImpl(.., None, ref ty, _) => { @@ -278,7 +272,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { self.prev_level = orig_level; } - fn visit_block(&mut self, b: &'v hir::Block) { + fn visit_block(&mut self, b: &'tcx hir::Block) { let orig_level = replace(&mut self.prev_level, None); // Blocks can have public items, for example impls, but they always @@ -289,7 +283,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { self.prev_level = orig_level; } - fn visit_mod(&mut self, m: &hir::Mod, _sp: Span, id: ast::NodeId) { + fn visit_mod(&mut self, m: &'tcx hir::Mod, _sp: Span, id: ast::NodeId) { // This code is here instead of in visit_item so that the // crate module gets processed as well. if self.prev_level.is_some() { @@ -305,14 +299,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { intravisit::walk_mod(self, m, id); } - fn visit_macro_def(&mut self, md: &'v hir::MacroDef) { + fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) { self.update(md.id, Some(AccessLevel::Public)); } } impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { // Make the type hidden under a type alias reachable - fn reach_aliased_type(&mut self, item: &hir::Item, path: &hir::Path) { + fn reach_aliased_type(&mut self, item: &'tcx hir::Item, path: &'tcx hir::Path) { if let hir::ItemTy(ref ty, ref generics) = item.node { // See `fn is_public_type_alias` for details self.visit_ty(ty); @@ -326,14 +320,14 @@ impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { } } -impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { +impl<'b, 'a, 'tcx: 'a> Visitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { // when we visit an impl, its methods and items are part of its "interface" let impl_item = self.ev.tcx.map.impl_item(item_id); self.visit_impl_item(impl_item) } - fn visit_ty(&mut self, ty: &hir::Ty) { + fn visit_ty(&mut self, ty: &'tcx hir::Ty) { if let hir::TyPath(_, ref path) = ty.node { let def = self.ev.tcx.expect_def(ty.id); match def { @@ -365,7 +359,7 @@ impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor< intravisit::walk_ty(self, ty); } - fn visit_trait_ref(&mut self, trait_ref: &hir::TraitRef) { + fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef) { let def_id = self.ev.tcx.expect_def(trait_ref.ref_id).def_id(); if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) { let item = self.ev.tcx.map.expect_item(node_id); @@ -427,26 +421,20 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { } } -impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> { /// We want to visit items in the context of their containing /// module and so forth, so supply a crate for doing a deep walk. - fn visit_nested_item(&mut self, item: hir::ItemId) { - let tcx = self.tcx; - self.visit_item(tcx.map.expect_item(item.id)) + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.tcx.map) } - fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { - let impl_item = self.tcx.map.impl_item(item_id); - self.visit_impl_item(impl_item) - } - - fn visit_item(&mut self, item: &hir::Item) { + fn visit_item(&mut self, item: &'tcx hir::Item) { let orig_curitem = replace(&mut self.curitem, item.id); intravisit::walk_item(self, item); self.curitem = orig_curitem; } - fn visit_expr(&mut self, expr: &hir::Expr) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr) { match expr.node { hir::ExprMethodCall(..) => { let method_call = ty::MethodCall::expr(expr.id); @@ -506,7 +494,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { intravisit::walk_expr(self, expr); } - fn visit_pat(&mut self, pattern: &hir::Pat) { + fn visit_pat(&mut self, pattern: &'tcx hir::Pat) { // Foreign functions do not have their patterns mapped in the def_map, // and there's nothing really relevant there anyway, so don't bother // checking privacy. If you can name the type then you can pass it to an @@ -542,7 +530,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { intravisit::walk_pat(self, pattern); } - fn visit_foreign_item(&mut self, fi: &hir::ForeignItem) { + fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem) { self.in_foreign = true; intravisit::walk_foreign_item(self, fi); self.in_foreign = false; @@ -636,20 +624,14 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a fn visit_expr(&mut self, _: &hir::Expr) {} } -impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { /// We want to visit items in the context of their containing /// module and so forth, so supply a crate for doing a deep walk. - fn visit_nested_item(&mut self, item: hir::ItemId) { - let tcx = self.tcx; - self.visit_item(tcx.map.expect_item(item.id)) + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.tcx.map) } - fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { - let impl_item = self.tcx.map.impl_item(item_id); - self.visit_impl_item(impl_item) - } - - fn visit_item(&mut self, item: &hir::Item) { + fn visit_item(&mut self, item: &'tcx hir::Item) { match item.node { // contents of a private mod can be reexported, so we need // to check internals. @@ -834,7 +816,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> intravisit::walk_item(self, item); } - fn visit_generics(&mut self, generics: &hir::Generics) { + fn visit_generics(&mut self, generics: &'tcx hir::Generics) { for ty_param in generics.ty_params.iter() { for bound in ty_param.bounds.iter() { self.check_ty_param_bound(bound) @@ -855,13 +837,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> } } - fn visit_foreign_item(&mut self, item: &hir::ForeignItem) { + fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) { if self.access_levels.is_reachable(item.id) { intravisit::walk_foreign_item(self, item) } } - fn visit_ty(&mut self, t: &hir::Ty) { + fn visit_ty(&mut self, t: &'tcx hir::Ty) { if let hir::TyPath(..) = t.node { if self.path_is_private_type(t.id) { self.old_error_set.insert(t.id); @@ -870,7 +852,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> intravisit::walk_ty(self, t) } - fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) { + fn visit_variant(&mut self, + v: &'tcx hir::Variant, + g: &'tcx hir::Generics, + item_id: ast::NodeId) { if self.access_levels.is_reachable(v.node.data.id()) { self.in_variant = true; intravisit::walk_variant(self, v, g, item_id); @@ -878,7 +863,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> } } - fn visit_struct_field(&mut self, s: &hir::StructField) { + fn visit_struct_field(&mut self, s: &'tcx hir::StructField) { if s.vis == hir::Public || self.in_variant { intravisit::walk_struct_field(self, s); } @@ -888,8 +873,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> // expression/block context can't possibly contain exported things. // (Making them no-ops stops us from traversing the whole AST without // having to be super careful about our `walk_...` calls above.) - fn visit_block(&mut self, _: &hir::Block) {} - fn visit_expr(&mut self, _: &hir::Expr) {} + fn visit_block(&mut self, _: &'tcx hir::Block) {} + fn visit_expr(&mut self, _: &'tcx hir::Expr) {} } /////////////////////////////////////////////////////////////////////////////// From 629f5ffb23aeb96621bb4da7f7ea6d605670056b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 10 Nov 2016 09:47:00 -0500 Subject: [PATCH 136/177] include a Name and Span for each item in the HIR of the impl --- src/librustc/hir/intravisit.rs | 15 ++++-- src/librustc/hir/lowering.rs | 24 +++++++-- src/librustc/hir/map/collector.rs | 2 +- src/librustc/hir/map/mod.rs | 2 +- src/librustc/hir/mod.rs | 28 +++++++++- src/librustc/hir/print.rs | 8 +-- src/librustc/middle/dead.rs | 8 +-- src/librustc/middle/reachable.rs | 6 +-- src/librustc/middle/stability.rs | 6 +-- src/librustc/ty/mod.rs | 6 +-- src/librustc_lint/builtin.rs | 6 +-- src/librustc_mir/transform/qualify_consts.rs | 12 ++--- src/librustc_privacy/lib.rs | 52 +++++++++---------- src/librustc_trans/collector.rs | 9 ++-- .../check/impl_item_duplicate.rs | 6 +-- .../check/impl_parameters_used.rs | 6 +-- src/librustc_typeck/check/mod.rs | 18 +++---- 17 files changed, 131 insertions(+), 83 deletions(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 0b83a8bc9222..887b1febf65d 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -205,6 +205,9 @@ pub trait Visitor<'v> : Sized { fn visit_impl_item(&mut self, ii: &'v ImplItem) { walk_impl_item(self, ii) } + fn visit_impl_item_ref(&mut self, ii: &'v ImplItemRef) { + walk_impl_item_ref(self, ii) + } fn visit_trait_ref(&mut self, t: &'v TraitRef) { walk_trait_ref(self, t) } @@ -399,13 +402,13 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_id(item.id); visitor.visit_trait_ref(trait_ref) } - ItemImpl(.., ref type_parameters, ref opt_trait_reference, ref typ, ref impl_item_ids) => { + ItemImpl(.., ref type_parameters, ref opt_trait_reference, ref typ, ref impl_item_refs) => { visitor.visit_id(item.id); visitor.visit_generics(type_parameters); walk_list!(visitor, visit_trait_ref, opt_trait_reference); visitor.visit_ty(typ); - for &impl_item_id in impl_item_ids { - visitor.visit_nested_impl_item(impl_item_id); + for impl_item_ref in impl_item_refs { + visitor.visit_impl_item_ref(impl_item_ref); } } ItemStruct(ref struct_definition, ref generics) | @@ -763,6 +766,12 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt } } +pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef) { + visitor.visit_nested_impl_item(impl_item_ref.id); + visitor.visit_name(impl_item_ref.span, impl_item_ref.name); +} + + pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) { visitor.visit_id(struct_definition.id()); walk_list!(visitor, visit_struct_field, struct_definition.fields()); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 0731c35ff163..d1b57586ffdb 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -116,7 +116,7 @@ impl<'a> LoweringContext<'a> { } fn visit_impl_item(&mut self, item: &ImplItem) { - let id = self.lctx.lower_impl_item_id(item); + let id = self.lctx.lower_impl_item_ref(item).id; self.impl_items.insert(id, self.lctx.lower_impl_item(item)); visit::walk_impl_item(self, item); } @@ -641,7 +641,7 @@ impl<'a> LoweringContext<'a> { } ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => { let new_impl_items = impl_items.iter() - .map(|item| self.lower_impl_item_id(item)) + .map(|item| self.lower_impl_item_ref(item)) .collect(); let ifce = ifce.as_ref().map(|trait_ref| self.lower_trait_ref(trait_ref)); hir::ItemImpl(self.lower_unsafety(unsafety), @@ -717,8 +717,24 @@ impl<'a> LoweringContext<'a> { }) } - fn lower_impl_item_id(&mut self, i: &ImplItem) -> hir::ImplItemId { - hir::ImplItemId { id: i.id } + fn lower_impl_item_ref(&mut self, i: &ImplItem) -> hir::ImplItemRef { + hir::ImplItemRef { + id: hir::ImplItemId { node_id: i.id }, + name: i.ident.name, + span: i.span, + vis: self.lower_visibility(&i.vis), + defaultness: self.lower_defaultness(i.defaultness), + kind: match i.node { + ImplItemKind::Const(..) => hir::AssociatedItemKind::Const, + ImplItemKind::Type(..) => hir::AssociatedItemKind::Type, + ImplItemKind::Method(ref sig, _) => hir::AssociatedItemKind::Method { + has_self: sig.decl.get_self().is_some(), + }, + ImplItemKind::Macro(..) => unimplemented!(), + }, + // since `default impl` is not yet implemented, this is always true in impls + has_value: true, + } } fn lower_mod(&mut self, m: &Mod) -> hir::Mod { diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 5fd0839affef..51a378a08336 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -93,7 +93,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { /// deep walking so that we walk nested items in the context of /// their outer items. - fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'v>> { + fn nested_visit_map(&mut self) -> Option<&map::Map<'ast>> { panic!("visit_nested_xxx must be manually implemented in this visitor") } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index e684040a1735..06cfc8aee8c9 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -384,7 +384,7 @@ impl<'ast> Map<'ast> { } pub fn impl_item(&self, id: ImplItemId) -> &'ast ImplItem { - self.read(id.id); + self.read(id.node_id); // NB: intentionally bypass `self.forest.krate()` so that we // do not trigger a read of the whole krate here diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index c9892135b1d3..9dac6fac1009 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1057,7 +1057,7 @@ pub enum TraitItem_ { // so it can fetched later. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct ImplItemId { - pub id: NodeId, + pub node_id: NodeId, } /// Represents anything within an `impl` block @@ -1546,7 +1546,7 @@ pub enum Item_ { Generics, Option, // (optional) trait this impl implements P, // self - HirVec), + HirVec), } impl Item_ { @@ -1570,6 +1570,30 @@ impl Item_ { } } +/// A reference from an impl to one of its associated items. This +/// contains the item's id, naturally, but also the item's name and +/// some other high-level details (like whether it is an associated +/// type or method, and whether it is public). This allows other +/// passes to find the impl they want without loading the id (which +/// means fewer edges in the incremental compilation graph). +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct ImplItemRef { + pub id: ImplItemId, + pub name: Name, + pub kind: AssociatedItemKind, + pub span: Span, + pub vis: Visibility, + pub defaultness: Defaultness, + pub has_value: bool, +} + +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum AssociatedItemKind { + Const, + Method { has_self: bool }, + Type, +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct ForeignItem { pub name: Name, diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index ed274b5a23ef..5a381a189fc1 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -808,8 +808,8 @@ impl<'a> State<'a> { space(&mut self.s)?; self.bopen()?; self.print_inner_attributes(&item.attrs)?; - for &impl_item in impl_items { - self.print_impl_item_id(impl_item)?; + for impl_item in impl_items { + self.print_impl_item_ref(impl_item)?; } self.bclose(item.span)?; } @@ -1020,10 +1020,10 @@ impl<'a> State<'a> { self.ann.post(self, NodeSubItem(ti.id)) } - pub fn print_impl_item_id(&mut self, item_id: hir::ImplItemId) -> io::Result<()> { + pub fn print_impl_item_ref(&mut self, item_ref: &hir::ImplItemRef) -> io::Result<()> { if let Some(krate) = self.krate { // skip nested items if krate context was not provided - let item = &krate.impl_item(item_id); + let item = &krate.impl_item(item_ref.id); self.print_impl_item(item) } else { Ok(()) diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index e6722661223e..991398813752 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -359,12 +359,12 @@ impl<'v, 'k> ItemLikeVisitor<'v> for LifeSeeder<'k> { } } } - hir::ItemImpl(.., ref opt_trait, _, ref impl_item_ids) => { - for &impl_item_id in impl_item_ids { - let impl_item = self.krate.impl_item(impl_item_id); + hir::ItemImpl(.., ref opt_trait, _, ref impl_item_refs) => { + for impl_item_ref in impl_item_refs { + let impl_item = self.krate.impl_item(impl_item_ref.id); if opt_trait.is_some() || has_allow_dead_code_or_lang_attr(&impl_item.attrs) { - self.worklist.push(impl_item_id.id); + self.worklist.push(impl_item_ref.id.node_id); } } } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 0a45f895d7df..ac614494355a 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -328,10 +328,10 @@ struct CollectPrivateImplItemsVisitor<'a> { impl<'a, 'v> ItemLikeVisitor<'v> for CollectPrivateImplItemsVisitor<'a> { fn visit_item(&mut self, item: &hir::Item) { // We need only trait impls here, not inherent impls, and only non-exported ones - if let hir::ItemImpl(.., Some(_), _, ref impl_items) = item.node { + if let hir::ItemImpl(.., Some(_), _, ref impl_item_refs) = item.node { if !self.access_levels.is_reachable(item.id) { - for impl_item in impl_items { - self.worklist.push(impl_item.id); + for impl_item_ref in impl_item_refs { + self.worklist.push(impl_item_ref.id.node_id); } } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 239aaa6bb75f..7e4efc7ddca0 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -525,10 +525,10 @@ pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // For implementations of traits, check the stability of each item // individually as it's possible to have a stable trait with unstable // items. - hir::ItemImpl(.., Some(ref t), _, ref impl_item_ids) => { + hir::ItemImpl(.., Some(ref t), _, ref impl_item_refs) => { let trait_did = tcx.expect_def(t.ref_id).def_id(); - for &impl_item_id in impl_item_ids { - let impl_item = tcx.map.impl_item(impl_item_id); + for impl_item_ref in impl_item_refs { + let impl_item = tcx.map.impl_item(impl_item_ref.id); let item = tcx.associated_items(trait_did) .find(|item| item.name == impl_item.name).unwrap(); if warn_about_defns { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index c6fff94438fc..4db788a92d64 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2190,9 +2190,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.map.local_def_id(trait_item.id) }).collect()) } - hir::ItemImpl(.., ref impl_items) => { - Rc::new(impl_items.iter().map(|impl_item| { - self.map.local_def_id(impl_item.id) + hir::ItemImpl(.., ref impl_item_refs) => { + Rc::new(impl_item_refs.iter().map(|impl_item_ref| { + self.map.local_def_id(impl_item_ref.id.node_id) }).collect()) } _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait") diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f6b6c89b7cc2..51ffb1ebc8e9 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -387,7 +387,7 @@ impl LateLintPass for MissingDoc { "a trait" } hir::ItemTy(..) => "a type alias", - hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_items) => { + hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_item_refs) => { // If the trait is private, add the impl items to private_traits so they don't get // reported for missing docs. let real_trait = cx.tcx.expect_def(trait_ref.ref_id).def_id(); @@ -395,8 +395,8 @@ impl LateLintPass for MissingDoc { match cx.tcx.map.find(node_id) { Some(hir_map::NodeItem(item)) => { if item.vis == hir::Visibility::Inherited { - for itm in impl_items { - self.private_traits.insert(itm.id); + for impl_item_ref in impl_item_refs { + self.private_traits.insert(impl_item_ref.id.node_id); } } } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 21bebb2562a1..4ff2beb3fdb7 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -277,12 +277,12 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { .and_then(|impl_node_id| self.tcx.map.find(impl_node_id)) .map(|node| { if let hir_map::NodeItem(item) = node { - if let hir::ItemImpl(_, _, _, _, _, ref impl_item_ids) = item.node { - span = impl_item_ids.first() - .map(|&impl_item_id| { - self.tcx.map.impl_item(impl_item_id) - .span - }); + if let hir::ItemImpl(.., ref impl_item_refs) = item.node { + span = impl_item_refs.first() + .map(|iiref| { + self.tcx.map.impl_item(iiref.id) + .span + }); } } }); diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 9cbf4c8a6154..b116408269e4 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -158,17 +158,17 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { } } } - hir::ItemImpl(.., None, _, ref impl_item_ids) => { - for &impl_item_id in impl_item_ids { - let impl_item = self.tcx.map.impl_item(impl_item_id); + hir::ItemImpl(.., None, _, ref impl_item_refs) => { + for impl_item_ref in impl_item_refs { + let impl_item = self.tcx.map.impl_item(impl_item_ref.id); if impl_item.vis == hir::Public { self.update(impl_item.id, item_level); } } } - hir::ItemImpl(.., Some(_), _, ref impl_item_ids) => { - for &impl_item_id in impl_item_ids { - let impl_item = self.tcx.map.impl_item(impl_item_id); + hir::ItemImpl(.., Some(_), _, ref impl_item_refs) => { + for impl_item_ref in impl_item_refs { + let impl_item = self.tcx.map.impl_item(impl_item_ref.id); self.update(impl_item.id, item_level); } } @@ -251,12 +251,12 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { // The interface is empty hir::ItemDefaultImpl(..) => {} // Visit everything except for private impl items - hir::ItemImpl(.., ref generics, None, _, ref impl_item_ids) => { + hir::ItemImpl(.., ref generics, None, _, ref impl_item_refs) => { if item_level.is_some() { self.reach().visit_generics(generics); - for &impl_item_id in impl_item_ids { - if self.get(impl_item_id.id).is_some() { - let impl_item = self.tcx.map.impl_item(impl_item_id); + for impl_item_ref in impl_item_refs { + if self.get(impl_item_ref.id.node_id).is_some() { + let impl_item = self.tcx.map.impl_item(impl_item_ref.id); self.reach().visit_impl_item(impl_item); } } @@ -656,7 +656,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { // (i.e. we could just return here to not check them at // all, or some worse estimation of whether an impl is // publicly visible). - hir::ItemImpl(.., ref g, ref trait_ref, ref self_, ref impl_item_ids) => { + hir::ItemImpl(.., ref g, ref trait_ref, ref self_, ref impl_item_refs) => { // `impl [... for] Private` is never visible. let self_contains_private; // impl [... for] Public<...>, but not `impl [... for] @@ -701,9 +701,9 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { // are private (because `T` won't be visible externally). let trait_or_some_public_method = trait_ref.is_some() || - impl_item_ids.iter() - .any(|&impl_item_id| { - let impl_item = self.tcx.map.impl_item(impl_item_id); + impl_item_refs.iter() + .any(|impl_item_ref| { + let impl_item = self.tcx.map.impl_item(impl_item_ref.id); match impl_item.node { hir::ImplItemKind::Const(..) | hir::ImplItemKind::Method(..) => { @@ -721,13 +721,13 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { match *trait_ref { None => { - for &impl_item_id in impl_item_ids { + for impl_item_ref in impl_item_refs { // This is where we choose whether to walk down // further into the impl to check its items. We // should only walk into public items so that we // don't erroneously report errors for private // types in private items. - let impl_item = self.tcx.map.impl_item(impl_item_id); + let impl_item = self.tcx.map.impl_item(impl_item_ref.id); match impl_item.node { hir::ImplItemKind::Const(..) | hir::ImplItemKind::Method(..) @@ -759,8 +759,8 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { intravisit::walk_path(self, &tr.path); // Those in 3. are warned with this call. - for &impl_item_id in impl_item_ids { - let impl_item = self.tcx.map.impl_item(impl_item_id); + for impl_item_ref in impl_item_refs { + let impl_item = self.tcx.map.impl_item(impl_item_ref.id); if let hir::ImplItemKind::Type(ref ty) = impl_item.node { self.visit_ty(ty); } @@ -771,8 +771,8 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { // impl Public { ... }. Any public static // methods will be visible as `Public::foo`. let mut found_pub_static = false; - for &impl_item_id in impl_item_ids { - let impl_item = self.tcx.map.impl_item(impl_item_id); + for impl_item_ref in impl_item_refs { + let impl_item = self.tcx.map.impl_item(impl_item_ref.id); match impl_item.node { hir::ImplItemKind::Const(..) => { if self.item_is_public(&impl_item.id, &impl_item.vis) { @@ -1099,13 +1099,13 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for PrivateItemsInPublicInterfacesVisitor hir::ItemDefaultImpl(..) => {} // An inherent impl is public when its type is public // Subitems of inherent impls have their own publicity - hir::ItemImpl(.., ref generics, None, ref ty, ref impl_item_ids) => { + hir::ItemImpl(.., ref generics, None, ref ty, ref impl_item_refs) => { let ty_vis = self.ty_visibility(ty); check.required_visibility = ty_vis; check.visit_generics(generics); - for &impl_item_id in impl_item_ids { - let impl_item = self.tcx.map.impl_item(impl_item_id); + for impl_item_ref in impl_item_refs { + let impl_item = self.tcx.map.impl_item(impl_item_ref.id); let impl_item_vis = ty::Visibility::from_hir(&impl_item.vis, item.id, self.tcx); check.required_visibility = min(impl_item_vis, ty_vis); @@ -1114,12 +1114,12 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for PrivateItemsInPublicInterfacesVisitor } // A trait impl is public when both its type and its trait are public // Subitems of trait impls have inherited publicity - hir::ItemImpl(.., ref generics, Some(ref trait_ref), ref ty, ref impl_item_ids) => { + hir::ItemImpl(.., ref generics, Some(ref trait_ref), ref ty, ref impl_item_refs) => { let vis = min(self.ty_visibility(ty), self.trait_ref_visibility(trait_ref)); check.required_visibility = vis; check.visit_generics(generics); - for &impl_item_id in impl_item_ids { - let impl_item = self.tcx.map.impl_item(impl_item_id); + for impl_item_ref in impl_item_refs { + let impl_item = self.tcx.map.impl_item(impl_item_ref.id); check.visit_impl_item(impl_item); } } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 8245b0cf7f53..5902b0b1ce07 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -1135,7 +1135,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' _, ref generics, .., - ref items) => { + ref impl_item_refs) => { if generics.is_type_parameterized() { return } @@ -1148,10 +1148,9 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) { let callee_substs = tcx.erase_regions(&trait_ref.substs); let overridden_methods: FxHashSet<_> = - items.iter() - .map(|&id| tcx.map.impl_item(id)) - .map(|item| item.name) - .collect(); + impl_item_refs.iter() + .map(|iiref| iiref.name) + .collect(); for method in tcx.provided_trait_methods(trait_ref.def_id) { if overridden_methods.contains(&method.name) { continue; diff --git a/src/librustc_typeck/check/impl_item_duplicate.rs b/src/librustc_typeck/check/impl_item_duplicate.rs index 4111fa9a2c0d..7b33aa694a26 100644 --- a/src/librustc_typeck/check/impl_item_duplicate.rs +++ b/src/librustc_typeck/check/impl_item_duplicate.rs @@ -16,13 +16,13 @@ use CrateCtxt; /// Enforce that we do not have two items in an impl with the same name. pub fn enforce_impl_items_are_distinct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - impl_item_ids: &[hir::ImplItemId]) + impl_item_refs: &[hir::ImplItemRef]) { let tcx = ccx.tcx; let mut seen_type_items = FxHashMap(); let mut seen_value_items = FxHashMap(); - for &impl_item_id in impl_item_ids { - let impl_item = tcx.map.impl_item(impl_item_id); + for &impl_item_ref in impl_item_refs { + let impl_item = tcx.map.impl_item(impl_item_ref.id); let seen_items = match impl_item.node { hir::ImplItemKind::Type(_) => &mut seen_type_items, _ => &mut seen_value_items, diff --git a/src/librustc_typeck/check/impl_parameters_used.rs b/src/librustc_typeck/check/impl_parameters_used.rs index defdcc7906c3..650e959ba01f 100644 --- a/src/librustc_typeck/check/impl_parameters_used.rs +++ b/src/librustc_typeck/check/impl_parameters_used.rs @@ -51,7 +51,7 @@ use CrateCtxt; pub fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_hir_generics: &hir::Generics, impl_def_id: DefId, - impl_item_ids: &[hir::ImplItemId]) + impl_item_refs: &[hir::ImplItemRef]) { // Every lifetime used in an associated type must be constrained. let impl_scheme = ccx.tcx.lookup_item_type(impl_def_id); @@ -71,8 +71,8 @@ pub fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } // Disallow unconstrained lifetimes, but only if they appear in assoc types. - let lifetimes_in_associated_types: FxHashSet<_> = impl_item_ids.iter() - .map(|item_id| ccx.tcx.map.local_def_id(item_id.id)) + let lifetimes_in_associated_types: FxHashSet<_> = impl_item_refs.iter() + .map(|item_ref| ccx.tcx.map.local_def_id(item_ref.id.node_id)) .filter(|&def_id| { let item = ccx.tcx.associated_item(def_id); item.kind == ty::AssociatedKind::Type && item.has_value diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7c21ddbe4019..a8e38a362b56 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -817,7 +817,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { it.id); } hir::ItemFn(..) => {} // entirely within check_item_body - hir::ItemImpl(_, _, ref hir_generics, _, _, ref impl_item_ids) => { + hir::ItemImpl(_, _, ref hir_generics, _, _, ref impl_item_refs) => { debug!("ItemImpl {} with id {}", it.name, it.id); let impl_def_id = ccx.tcx.map.local_def_id(it.id); if let Some(impl_trait_ref) = ccx.tcx.impl_trait_ref(impl_def_id) { @@ -825,7 +825,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { it.span, impl_def_id, impl_trait_ref, - impl_item_ids); + impl_item_refs); let trait_def_id = impl_trait_ref.def_id; check_on_unimplemented(ccx, trait_def_id, it); } @@ -833,10 +833,10 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { impl_parameters_used::enforce_impl_params_are_constrained(ccx, hir_generics, impl_def_id, - impl_item_ids); + impl_item_refs); impl_item_duplicate::enforce_impl_items_are_distinct(ccx, - impl_item_ids); + impl_item_refs); } hir::ItemTrait(..) => { let def_id = ccx.tcx.map.local_def_id(it.id); @@ -895,11 +895,11 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { hir::ItemFn(ref decl, .., ref body) => { check_bare_fn(ccx, &decl, &body, it.id, it.span); } - hir::ItemImpl(.., ref impl_item_ids) => { + hir::ItemImpl(.., ref impl_item_refs) => { debug!("ItemImpl {} with id {}", it.name, it.id); - for &impl_item_id in impl_item_ids { - let impl_item = ccx.tcx.map.impl_item(impl_item_id); + for impl_item_ref in impl_item_refs { + let impl_item = ccx.tcx.map.impl_item(impl_item_ref.id); match impl_item.node { hir::ImplItemKind::Const(_, ref expr) => { check_const(ccx, &expr, impl_item.id) @@ -1036,7 +1036,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_span: Span, impl_id: DefId, impl_trait_ref: ty::TraitRef<'tcx>, - impl_item_ids: &[hir::ImplItemId]) { + impl_item_refs: &[hir::ImplItemRef]) { // If the trait reference itself is erroneous (so the compilation is going // to fail), skip checking the items here -- the `impl_item` table in `tcx` // isn't populated for such impls. @@ -1047,7 +1047,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let trait_def = tcx.lookup_trait_def(impl_trait_ref.def_id); let mut overridden_associated_type = None; - let impl_items = || impl_item_ids.iter().map(|&id| ccx.tcx.map.impl_item(id)); + let impl_items = || impl_item_refs.iter().map(|iiref| ccx.tcx.map.impl_item(iiref.id)); // Check existing impl methods to see if they are both present in trait // and compatible with trait signature From 976bfc032266e1b6f8281c1f08df3d6cb8242776 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 16 Nov 2016 20:40:01 +0100 Subject: [PATCH 137/177] Add examples for Ipv4Addr --- src/libstd/net/ip.rs | 125 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index e85c95198c74..7b7be6e2eeeb 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -154,6 +154,14 @@ impl Ipv4Addr { /// Creates a new IPv4 address from four eight-bit octets. /// /// The result will represent the IP address `a`.`b`.`c`.`d`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::new(127, 0, 0, 1); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { Ipv4Addr { @@ -167,6 +175,15 @@ impl Ipv4Addr { } /// Returns the four eight-bit integers that make up this address. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::new(127, 0, 0, 1); + /// assert_eq!(addr.octets(), [127, 0, 0, 1]); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn octets(&self) -> [u8; 4] { let bits = ntoh(self.inner.s_addr); @@ -178,7 +195,16 @@ impl Ipv4Addr { /// This property is defined in _UNIX Network Programming, Second Edition_, /// W. Richard Stevens, p. 891; see also [ip7]. /// - /// [ip7]: (http://man7.org/linux/man-pages/man7/ip.7.html) + /// [ip7]: http://man7.org/linux/man-pages/man7/ip.7.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true); + /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false); + /// ``` #[stable(feature = "ip_shared", since = "1.12.0")] pub fn is_unspecified(&self) -> bool { self.inner.s_addr == 0 @@ -189,6 +215,15 @@ impl Ipv4Addr { /// This property is defined by [RFC 1122]. /// /// [RFC 1122]: https://tools.ietf.org/html/rfc1122 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true); + /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false); + /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_loopback(&self) -> bool { self.octets()[0] == 127 @@ -203,6 +238,20 @@ impl Ipv4Addr { /// - 192.168.0.0/16 /// /// [RFC 1918]: https://tools.ietf.org/html/rfc1918 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true); + /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true); + /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true); + /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true); + /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false); + /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true); + /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false); + /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_private(&self) -> bool { match (self.octets()[0], self.octets()[1]) { @@ -218,6 +267,16 @@ impl Ipv4Addr { /// This property is defined by [RFC 3927]. /// /// [RFC 3927]: https://tools.ietf.org/html/rfc3927 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true); + /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true); + /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false); + /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_link_local(&self) -> bool { self.octets()[0] == 169 && self.octets()[1] == 254 @@ -236,6 +295,22 @@ impl Ipv4Addr { /// - the unspecified address (0.0.0.0) /// /// [ipv4-sr]: http://goo.gl/RaZ7lg + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv4Addr; + /// + /// fn main() { + /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false); + /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false); + /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false); + /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false); + /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); + /// } + /// ``` pub fn is_global(&self) -> bool { !self.is_private() && !self.is_loopback() && !self.is_link_local() && !self.is_broadcast() && !self.is_documentation() && !self.is_unspecified() @@ -247,6 +322,16 @@ impl Ipv4Addr { /// and is defined by [RFC 5771]. /// /// [RFC 5771]: https://tools.ietf.org/html/rfc5771 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true); + /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true); + /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false); + /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_multicast(&self) -> bool { self.octets()[0] >= 224 && self.octets()[0] <= 239 @@ -257,6 +342,15 @@ impl Ipv4Addr { /// A broadcast address has all octets set to 255 as defined in [RFC 919]. /// /// [RFC 919]: https://tools.ietf.org/html/rfc919 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true); + /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false); + /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_broadcast(&self) -> bool { self.octets()[0] == 255 && self.octets()[1] == 255 && @@ -272,6 +366,17 @@ impl Ipv4Addr { /// - 203.0.113.0/24 (TEST-NET-3) /// /// [RFC 5737]: https://tools.ietf.org/html/rfc5737 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true); + /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true); + /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true); + /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false); + /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_documentation(&self) -> bool { match(self.octets()[0], self.octets()[1], self.octets()[2], self.octets()[3]) { @@ -285,6 +390,15 @@ impl Ipv4Addr { /// Converts this address to an IPv4-compatible IPv6 address. /// /// a.b.c.d becomes ::a.b.c.d + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(), + /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767)); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_ipv6_compatible(&self) -> Ipv6Addr { Ipv6Addr::new(0, 0, 0, 0, 0, 0, @@ -295,6 +409,15 @@ impl Ipv4Addr { /// Converts this address to an IPv4-mapped IPv6 address. /// /// a.b.c.d becomes ::ffff:a.b.c.d + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), + /// Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 49152, 767)); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_ipv6_mapped(&self) -> Ipv6Addr { Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, From 0172e463b0f0c720069d96602209f77c50380066 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 16 Nov 2016 07:30:35 +0000 Subject: [PATCH 138/177] Add regression test. --- .../proc-macro/auxiliary/derive-a-b.rs | 28 +++++++++++++++++++ .../proc-macro/issue-37788.rs | 21 ++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a-b.rs create mode 100644 src/test/compile-fail-fulldeps/proc-macro/issue-37788.rs diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a-b.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a-b.rs new file mode 100644 index 000000000000..8a92ca74f376 --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a-b.rs @@ -0,0 +1,28 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// force-host +// no-prefer-dynamic + +#![feature(proc_macro, proc_macro_lib)] +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_derive(A)] +pub fn derive_a(_: TokenStream) -> TokenStream { + "".parse().unwrap() +} + +#[proc_macro_derive(B)] +pub fn derive_b(_: TokenStream) -> TokenStream { + "".parse().unwrap() +} diff --git a/src/test/compile-fail-fulldeps/proc-macro/issue-37788.rs b/src/test/compile-fail-fulldeps/proc-macro/issue-37788.rs new file mode 100644 index 000000000000..6d1030026dba --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/issue-37788.rs @@ -0,0 +1,21 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-a-b.rs + +#![feature(proc_macro)] + +#[macro_use] +extern crate derive_a_b; + +fn main() { + // Test that constructing the `visible_parent_map` (in `cstore_impl.rs`) does not ICE. + std::cell::Cell::new(0) //~ ERROR mismatched types +} From 37903bfcf6dc15f9647b1a7f08af4757198fa189 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 24 Oct 2016 14:52:14 +0200 Subject: [PATCH 139/177] Improve reference cast help message --- src/librustc_typeck/check/cast.rs | 59 +++++++++++-------- src/test/compile-fail/cast-rfc0401.rs | 6 -- src/test/compile-fail/fat-ptr-cast.rs | 3 + src/test/compile-fail/issue-17444.rs | 1 - src/test/compile-fail/issue-21554.rs | 1 - .../typeck-cast-pointer-to-float.rs | 1 - 6 files changed, 39 insertions(+), 32 deletions(-) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index c456b9358b3e..4edf0011cb39 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -105,7 +105,6 @@ enum CastError { NeedViaPtr, NeedViaThinPtr, NeedViaInt, - NeedViaUsize, NonScalar, } @@ -139,26 +138,39 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { fn report_cast_error(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, e: CastError) { match e { - CastError::NeedViaPtr | CastError::NeedViaThinPtr | - CastError::NeedViaInt | - CastError::NeedViaUsize => { + CastError::NeedViaPtr => { + let mut err = fcx.type_error_struct(self.span, + |actual| { + format!("casting `{}` as `{}` is invalid", + actual, + fcx.ty_to_string(self.cast_ty)) + }, + self.expr_ty); + if self.cast_ty.is_uint() { + err.help(&format!("cast through {} first", + match e { + CastError::NeedViaPtr => "a raw pointer", + CastError::NeedViaThinPtr => "a thin pointer", + _ => bug!(), + })); + } + err.emit(); + } + CastError::NeedViaInt => { fcx.type_error_struct(self.span, - |actual| { - format!("casting `{}` as `{}` is invalid", - actual, - fcx.ty_to_string(self.cast_ty)) - }, - self.expr_ty) - .help(&format!("cast through {} first", - match e { - CastError::NeedViaPtr => "a raw pointer", - CastError::NeedViaThinPtr => "a thin pointer", - CastError::NeedViaInt => "an integer", - CastError::NeedViaUsize => "a usize", - _ => bug!(), - })) - .emit(); + |actual| { + format!("casting `{}` as `{}` is invalid", + actual, + fcx.ty_to_string(self.cast_ty)) + }, + self.expr_ty) + .help(&format!("cast through {} first", + match e { + CastError::NeedViaInt => "an integer", + _ => bug!(), + })) + .emit(); } CastError::CastToBool => { struct_span_err!(fcx.tcx.sess, self.span, E0054, "cannot cast as `bool`") @@ -366,21 +378,23 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { (Int(Bool), Float) | (Int(CEnum), Float) | (Int(Char), Float) => Err(CastError::NeedViaInt), + (Int(Bool), Ptr(_)) | (Int(CEnum), Ptr(_)) | - (Int(Char), Ptr(_)) => Err(CastError::NeedViaUsize), + (Int(Char), Ptr(_)) | + (Ptr(_), Float) | + (FnPtr, Float) | + (Float, Ptr(_)) => Err(CastError::IllegalCast), // ptr -> * (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast (Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast - (Ptr(_), Float) | (FnPtr, Float) => Err(CastError::NeedViaUsize), (FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast), (RPtr(_), Int(_)) | (RPtr(_), Float) => Err(CastError::NeedViaPtr), // * -> ptr (Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt), - (Float, Ptr(_)) => Err(CastError::NeedViaUsize), (RPtr(rmt), Ptr(mt)) => self.check_ref_cast(fcx, rmt, mt), // array-ptr-cast // prim -> prim @@ -391,7 +405,6 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { (Int(_), Int(_)) | (Int(_), Float) | (Float, Int(_)) | (Float, Float) => { Ok(CastKind::NumericCast) } - } } diff --git a/src/test/compile-fail/cast-rfc0401.rs b/src/test/compile-fail/cast-rfc0401.rs index 0c373057c76e..1dbad9e30e3a 100644 --- a/src/test/compile-fail/cast-rfc0401.rs +++ b/src/test/compile-fail/cast-rfc0401.rs @@ -48,16 +48,13 @@ fn main() let _ = v as f32; //~^ ERROR casting - //~^^ HELP through a usize first let _ = main as f64; //~^ ERROR casting - //~^^ HELP through a usize first let _ = &v as usize; //~^ ERROR casting //~^^ HELP through a raw pointer first let _ = f as *const u8; //~^ ERROR casting - //~^^ HELP through a usize first let _ = 3_i32 as bool; //~^ ERROR cannot cast as `bool` [E0054] //~| unsupported cast @@ -80,13 +77,10 @@ fn main() let _ = false as *const u8; //~^ ERROR casting - //~^^ HELP through a usize first let _ = E::A as *const u8; //~^ ERROR casting - //~^^ HELP through a usize first let _ = 'a' as *const u8; //~^ ERROR casting - //~^^ HELP through a usize first let _ = 42usize as *const [u8]; //~ ERROR casting let _ = v as *const [u8]; //~ ERROR cannot cast diff --git a/src/test/compile-fail/fat-ptr-cast.rs b/src/test/compile-fail/fat-ptr-cast.rs index b2fd11d4b39e..c62987a5b900 100644 --- a/src/test/compile-fail/fat-ptr-cast.rs +++ b/src/test/compile-fail/fat-ptr-cast.rs @@ -19,6 +19,9 @@ fn main() { a as usize; //~ ERROR casting //~^ HELP cast through a raw pointer first + a as isize; //~ ERROR casting + a as i16; //~ ERROR casting `&[i32]` as `i16` is invalid + a as u32; //~ ERROR casting `&[i32]` as `u32` is invalid b as usize; //~ ERROR non-scalar cast p as usize; //~^ ERROR casting diff --git a/src/test/compile-fail/issue-17444.rs b/src/test/compile-fail/issue-17444.rs index c1d5827eb90c..dafcff238387 100644 --- a/src/test/compile-fail/issue-17444.rs +++ b/src/test/compile-fail/issue-17444.rs @@ -15,5 +15,4 @@ enum Test { fn main() { let _x = Test::Foo as *const isize; //~^ ERROR casting `Test` as `*const isize` is invalid - //~^^ HELP cast through a usize first } diff --git a/src/test/compile-fail/issue-21554.rs b/src/test/compile-fail/issue-21554.rs index 741707a47b60..1b87862a056d 100644 --- a/src/test/compile-fail/issue-21554.rs +++ b/src/test/compile-fail/issue-21554.rs @@ -13,5 +13,4 @@ struct Inches(i32); fn main() { Inches as f32; //~^ ERROR casting - //~^^ cast through a usize first } diff --git a/src/test/compile-fail/typeck-cast-pointer-to-float.rs b/src/test/compile-fail/typeck-cast-pointer-to-float.rs index 2277b1bad776..3f8b8f49cb30 100644 --- a/src/test/compile-fail/typeck-cast-pointer-to-float.rs +++ b/src/test/compile-fail/typeck-cast-pointer-to-float.rs @@ -12,5 +12,4 @@ fn main() { let x : i16 = 22; ((&x) as *const i16) as f32; //~^ ERROR casting `*const i16` as `f32` is invalid - //~^^ HELP cast through a usize first } From 0e1828ab03302799701d291865daa71a7ba7a5ce Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Sat, 23 Jul 2016 13:51:54 +0200 Subject: [PATCH 140/177] Fix grammar verification * Use `make check-lexer` to verify the grammar. * Extend grammar/README * Add make clean-grammar rule * Add target `check-build-lexer-verifier` to `make tidy`, so it will build the verifier with every build and catch future errors * Search for antlr4 with configure and find --- configure | 6 ++++++ mk/clean.mk | 5 ++++- mk/grammar.mk | 2 +- mk/tests.mk | 3 ++- src/grammar/README.md | 21 +++++++++++++++++---- src/grammar/check.sh | 6 +++--- src/grammar/verify.rs | 6 ++++-- 7 files changed, 37 insertions(+), 12 deletions(-) diff --git a/configure b/configure index 9c055e7217aa..591b8e93a409 100755 --- a/configure +++ b/configure @@ -852,6 +852,12 @@ probe_need CFG_CMAKE cmake # probe for it only in this case. if [ -n "$CFG_ANTLR4" ] then + CFG_ANTLR4_JAR="\"$(find /usr/ -name antlr-complete.jar 2>/dev/null | head -n 1)\"" + if [ "x" -eq "x$CFG_ANTLR4_JAR" ] + then + CFG_ANTLR4_JAR="\"$(find ~ -name antlr-complete.jar 2>/dev/null | head -n 1)\"" + fi + putvar CFG_ANTLR4_JAR $CFG_ANTLR4_JAR probe CFG_JAVAC javac fi diff --git a/mk/clean.mk b/mk/clean.mk index 3574f25d9b74..7013d9f03f83 100644 --- a/mk/clean.mk +++ b/mk/clean.mk @@ -35,7 +35,7 @@ clean-all: clean clean-llvm clean-llvm: $(CLEAN_LLVM_RULES) -clean: clean-misc $(CLEAN_STAGE_RULES) +clean: clean-misc clean-grammar $(CLEAN_STAGE_RULES) clean-misc: @$(call E, cleaning) @@ -47,6 +47,9 @@ clean-misc: $(Q)rm -Rf dist/* $(Q)rm -Rf doc +clean-grammar: + @$(call E, cleaning grammar verification) + $(Q)rm -Rf grammar define CLEAN_GENERIC clean-generic-$(2)-$(1): diff --git a/mk/grammar.mk b/mk/grammar.mk index 0d527bd06886..1bd042adb218 100644 --- a/mk/grammar.mk +++ b/mk/grammar.mk @@ -37,7 +37,7 @@ $(BG): $(BG)RustLexer.class: $(BG) $(SG)RustLexer.g4 $(Q)$(CFG_ANTLR4) -o $(BG) $(SG)RustLexer.g4 - $(Q)$(CFG_JAVAC) -d $(BG) $(BG)RustLexer.java + $(Q)$(CFG_JAVAC) -d $(BG) -classpath $(CFG_ANTLR4_JAR) $(BG)RustLexer.java check-build-lexer-verifier: $(BG)verify diff --git a/mk/tests.mk b/mk/tests.mk index 35ee7697a7a6..9885d275e8b6 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -243,7 +243,8 @@ cleantestlibs: .PHONY: tidy tidy: $(HBIN0_H_$(CFG_BUILD))/tidy$(X_$(CFG_BUILD)) \ - $(SNAPSHOT_RUSTC_POST_CLEANUP) + $(SNAPSHOT_RUSTC_POST_CLEANUP) \ + check-build-lexer-verifier $(TARGET_RPATH_VAR0_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $< $(S)src $(HBIN0_H_$(CFG_BUILD))/tidy$(X_$(CFG_BUILD)): \ diff --git a/src/grammar/README.md b/src/grammar/README.md index 6e0cf17a8804..cd2dd38de36a 100644 --- a/src/grammar/README.md +++ b/src/grammar/README.md @@ -1,14 +1,18 @@ -Reference grammar. +# Reference grammar. Uses [antlr4](http://www.antlr.org/) and a custom Rust tool to compare -ASTs/token streams generated. You can use the `check-lexer` make target to +ASTs/token streams generated. You can use the `make check-lexer` target to run all of the available tests. -To use manually: +The build of the rust part is included with `make tidy` and can be run with `make check-build-lexer-verifier`. + +# Manual build + +To use manually, assuming antlr4 ist installed at `/usr/share/java/antlr-complete.jar`: ``` antlr4 RustLexer.g4 -javac *.java +javac -classpath /usr/share/java/antlr-complete.jar *.java rustc -O verify.rs for file in ../*/**.rs; do echo $file; @@ -18,3 +22,12 @@ done Note That the `../*/**.rs` glob will match every `*.rs` file in the above directory and all of its recursive children. This is a zsh extension. + + +## Cleanup + +To cleanup you can use a command like this: + +```bash +rm -f verify *.class *.java *.tokens +``` diff --git a/src/grammar/check.sh b/src/grammar/check.sh index 560b6b72471e..70a8f6fca2e5 100755 --- a/src/grammar/check.sh +++ b/src/grammar/check.sh @@ -20,11 +20,11 @@ skipped=0 check() { grep --silent "// ignore-lexer-test" "$1"; - # if it's *not* found... + # if it is *not* found... if [ $? -eq 1 ]; then - cd $2 # This `cd` is so java will pick up RustLexer.class. I couldn't + cd $2 # This `cd` is so java will pick up RustLexer.class. I could not # figure out how to wrangle the CLASSPATH, just adding build/grammar - # didn't seem to have any effect. + # did not seem to have any effect. if $3 RustLexer tokens -tokens < $1 | $4 $1 $5; then echo "pass: $1" passed=`expr $passed + 1` diff --git a/src/grammar/verify.rs b/src/grammar/verify.rs index 884db3418924..48be58f731cd 100644 --- a/src/grammar/verify.rs +++ b/src/grammar/verify.rs @@ -11,6 +11,7 @@ #![feature(plugin, rustc_private)] extern crate syntax; +extern crate syntax_pos; extern crate rustc; #[macro_use] @@ -290,9 +291,10 @@ fn main() { let options = config::basic_options(); let session = session::build_session(options, &DepGraph::new(false), None, - syntax::diagnostics::registry::Registry::new(&[]), + syntax::errors::registry::Registry::new(&[]), Rc::new(DummyCrateStore)); - let filemap = session.parse_sess.codemap().new_filemap(String::from(""), code); + let filemap = session.parse_sess.codemap() + .new_filemap("".to_string(), None, code); let mut lexer = lexer::StringReader::new(session.diagnostic(), filemap); let cm = session.codemap(); From 5887ee5018c064805a97af9e8331c3bf9571d9e5 Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Wed, 16 Nov 2016 23:34:15 +0100 Subject: [PATCH 141/177] Rebuild rustc_llvm when the rustllvm source files change --- src/librustc_llvm/build.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 8656bb8bf003..10ea6459d97b 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -116,6 +116,9 @@ fn main() { cfg.flag("-DLLVM_RUSTLLVM"); } + println!("cargo:rerun-if-changed=../rustllvm/PassWrapper.cpp"); + println!("cargo:rerun-if-changed=../rustllvm/RustWrapper.cpp"); + println!("cargo:rerun-if-changed=../rustllvm/ArchiveWrapper.cpp"); cfg.file("../rustllvm/PassWrapper.cpp") .file("../rustllvm/RustWrapper.cpp") .file("../rustllvm/ArchiveWrapper.cpp") From 456ceba13784f2f88f7f21239e308a0f195967a1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 16 Nov 2016 17:33:23 -0500 Subject: [PATCH 142/177] fix `extern "aapcs" fn` to actually use the AAPCS calling convention closes #37810 This is technically a [breaking-change] because it changes the ABI of `extern "aapcs"` functions that (a) involve `f32`/`f64` arguments/return values and (b) are compiled for arm-eabihf targets from "aapcs-vfp" (wrong) to "aapcs" (correct). Appendix: What these ABIs mean? - In the "aapcs-vfp" ABI or "hard float" calling convention: Floating point values are passed/returned through FPU registers (s0, s1, d0, etc.) - Whereas, in the "aapcs" ABI or "soft float" calling convention: Floating point values are passed/returned through general purpose registers (r0, r1, etc.) Mixing these ABIs can cause problems if the caller assumes that the routine is using one of these ABIs but it's actually using the other one. --- src/librustc_llvm/ffi.rs | 1 + src/librustc_trans/abi.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 8f21bf32c9e4..2173adf2e6e2 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -41,6 +41,7 @@ pub enum CallConv { ColdCallConv = 9, X86StdcallCallConv = 64, X86FastcallCallConv = 65, + ArmAapcsCallConv = 67, X86_64_SysV = 78, X86_64_Win64 = 79, X86_VectorCall = 80, diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index f2e15a8973c9..cb06fac2c674 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -274,10 +274,10 @@ impl FnType { C => llvm::CCallConv, Win64 => llvm::X86_64_Win64, SysV64 => llvm::X86_64_SysV, + Aapcs => llvm::ArmAapcsCallConv, // These API constants ought to be more specific... Cdecl => llvm::CCallConv, - Aapcs => llvm::CCallConv, }; let mut inputs = &sig.inputs[..]; From ba872f270781ada15426cfac7db20b30b81777dc Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 17 Nov 2016 00:11:10 +0000 Subject: [PATCH 143/177] Revert "Bump the bootstrap cargo to match the one paired with 1.13" This reverts commit 5ad235c8c0416ebab0b80e4750b84c061ef6cc6b. --- src/stage0.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stage0.txt b/src/stage0.txt index 4f37a1d1e128..ac2050a6fc8f 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -13,4 +13,4 @@ # released on `$date` rustc: beta-2016-09-28 -cargo: nightly-2016-11-02 +cargo: nightly-2016-09-26 From 66de87ffb230c3d0c0293dd15eb8571a7b66cdf5 Mon Sep 17 00:00:00 2001 From: Robert Vally Date: Thu, 17 Nov 2016 13:59:28 +0800 Subject: [PATCH 144/177] Improved error reporting when target sysroot is missing. --- src/librustc_metadata/locator.rs | 7 ++++++- src/test/compile-fail/issue-37131.rs | 18 ++++++++++++++++++ src/tools/compiletest/src/runtest.rs | 14 ++++++++++++-- 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 src/test/compile-fail/issue-37131.rs diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index b6b347fff5f2..b677a63edc06 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -217,7 +217,7 @@ use creader::Library; use schema::{METADATA_HEADER, rustc_version}; use rustc::hir::svh::Svh; -use rustc::session::Session; +use rustc::session::{config, Session}; use rustc::session::filesearch::{FileSearch, FileMatches, FileDoesntMatch}; use rustc::session::search_paths::PathKind; use rustc::util::common; @@ -355,6 +355,11 @@ impl<'a> Context<'a> { "can't find crate for `{}`{}", self.ident, add); + + if (self.ident == "std" || self.ident == "core") + && self.triple != config::host_triple() { + err.note(&format!("the `{}` target may not be installed", self.triple)); + } err.span_label(self.span, &format!("can't find crate")); err }; diff --git a/src/test/compile-fail/issue-37131.rs b/src/test/compile-fail/issue-37131.rs new file mode 100644 index 000000000000..88c6eb7f515c --- /dev/null +++ b/src/test/compile-fail/issue-37131.rs @@ -0,0 +1,18 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests that compiling for a target which is not installed will result in a helpful +// error message. + +// compile-flags: --target=s390x-unknown-linux-gnu +// ignore s390x + +// error-pattern:target may not be installed +fn main() { } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 4c024434e17c..3cc14541fcdf 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1334,8 +1334,18 @@ actual:\n\ // FIXME (#9639): This needs to handle non-utf8 paths let mut args = vec![input_file.to_str().unwrap().to_owned(), "-L".to_owned(), - self.config.build_base.to_str().unwrap().to_owned(), - format!("--target={}", target)]; + self.config.build_base.to_str().unwrap().to_owned()]; + + // Optionally prevent default --target if specified in test compile-flags. + let custom_target = self.props.compile_flags + .iter() + .fold(false, |acc, ref x| acc || x.starts_with("--target")); + + if !custom_target { + args.extend(vec![ + format!("--target={}", target), + ]); + } if let Some(revision) = self.revision { args.extend(vec![ From 99b1f9c9c864c86acc733429c1c170af5a45e0e9 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Thu, 17 Nov 2016 08:32:04 +0200 Subject: [PATCH 145/177] doc: nits and typos on comments --- src/librustdoc/html/render.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 2761ab766070..7395cc42ac57 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -874,12 +874,12 @@ fn extern_location(e: &clean::ExternalCrate, dst: &Path) -> ExternalLocation { impl<'a> DocFolder for SourceCollector<'a> { fn fold_item(&mut self, item: clean::Item) -> Option { // If we're including source files, and we haven't seen this file yet, - // then we need to render it out to the filesystem + // then we need to render it out to the filesystem. if self.scx.include_sources // skip all invalid spans && item.source.filename != "" - // macros from other libraries get special filenames which we can - // safely ignore + // Macros from other libraries get special filenames which we can + // safely ignore. && !(item.source.filename.starts_with("<") && item.source.filename.ends_with("macros>")) { @@ -974,13 +974,13 @@ impl DocFolder for Cache { }; // Register any generics to their corresponding string. This is used - // when pretty-printing types + // when pretty-printing types. if let Some(generics) = item.inner.generics() { self.generics(generics); } - // Propagate a trait methods' documentation to all implementors of the - // trait + // Propagate a trait method's documentation to all implementors of the + // trait. if let clean::TraitItem(ref t) = item.inner { self.traits.entry(item.def_id).or_insert_with(|| t.clone()); } @@ -996,7 +996,7 @@ impl DocFolder for Cache { } } - // Index this method for searching later on + // Index this method for searching later on. if let Some(ref s) = item.name { let (parent, is_inherent_impl_item) = match item.inner { clean::StrippedItem(..) => ((None, None), false), @@ -1097,8 +1097,8 @@ impl DocFolder for Cache { (self.stack.clone(), item.type_())); } } - // link variants to their parent enum because pages aren't emitted - // for each variant + // Link variants to their parent enum because pages aren't emitted + // for each variant. clean::VariantItem(..) if !self.stripped_mod => { let mut stack = self.stack.clone(); stack.pop(); @@ -1144,8 +1144,8 @@ impl DocFolder for Cache { _ => false }; - // Once we've recursively found all the generics, then hoard off all the - // implementations elsewhere + // Once we've recursively found all the generics, hoard off all the + // implementations elsewhere. let ret = self.fold_item_recur(item).and_then(|item| { if let clean::Item { inner: clean::ImplItem(_), .. } = item { // Figure out the id of this impl. This may map to a @@ -1206,7 +1206,7 @@ impl Context { } /// Recurse in the directory structure and change the "root path" to make - /// sure it always points to the top (relatively) + /// sure it always points to the top (relatively). fn recurse(&mut self, s: String, f: F) -> T where F: FnOnce(&mut Context) -> T, { @@ -1237,11 +1237,11 @@ impl Context { fn krate(self, mut krate: clean::Crate) -> Result<(), Error> { let mut item = match krate.module.take() { Some(i) => i, - None => return Ok(()) + None => return Ok(()), }; item.name = Some(krate.name); - // render the crate documentation + // Render the crate documentation let mut work = vec![(self, item)]; while let Some((mut cx, item)) = work.pop() { @@ -2987,7 +2987,7 @@ impl<'a> fmt::Display for Sidebar<'a> { let it = self.item; let parentlen = cx.current.len() - if it.is_mod() {1} else {0}; - // the sidebar is designed to display sibling functions, modules and + // The sidebar is designed to display sibling functions, modules and // other miscellaneous information. since there are lots of sibling // items (and that causes quadratic growth in large modules), // we refactor common parts into a shared JavaScript file per module. @@ -3006,7 +3006,7 @@ impl<'a> fmt::Display for Sidebar<'a> { } write!(fmt, "