From 4a6921e10e6134212867df96a8035576759e9d4b Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 13 Oct 2016 10:17:25 -0500 Subject: [PATCH 01/47] 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 625acce27bd64..092e1548446e3 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 cc608a2447574..a1eabb515a5ce 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 02/47] 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 092e1548446e3..6d96b172a2e61 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 03/47] 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 6d96b172a2e61..3b2f2430993a1 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 d8dba00e7d578..067cffc877934 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 04/47] 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 3b2f2430993a1..5fb99a2031fb5 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 f8133ea49ceba..3b6ffa4a462f6 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 05/47] 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 5fb99a2031fb5..c4a4817195b65 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 06/47] 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 c4a4817195b65..eef530081abe3 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 067cffc877934..c0a1abd4aec3f 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 1b39c0a602ad316b8eebd2dd50ae14e45d47dd13 Mon Sep 17 00:00:00 2001 From: nwin Date: Mon, 31 Oct 2016 19:43:50 +0100 Subject: [PATCH 07/47] 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 b0d954adf6771..18e7f07f722e4 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 08/47] 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 fdb629ca5a578..111f3a2cd87ef 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 09/47] 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 111f3a2cd87ef..a47374feecda6 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 10/47] 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 a47374feecda6..6b40837899760 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 11/47] 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 fce640e7c7a2c..2773629c7d7d4 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 9ddbb9133c86df9aab7b98a0e6b641b847c800ec Mon Sep 17 00:00:00 2001 From: Havvy Date: Wed, 2 Nov 2016 02:38:36 -0700 Subject: [PATCH 12/47] 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 6b40837899760..f94ed6b720946 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 be7f48d27e041..a87410e6e1c8c 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 8016dc39aa7fa1b796cf8e3dd7cd93c65c53d7a8 Mon Sep 17 00:00:00 2001 From: Juan Gomez Date: Sun, 6 Nov 2016 13:06:01 +0100 Subject: [PATCH 13/47] 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 0000000000000..98567a03c28a9 --- /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 0000000000000..b9e25c3d9e53f --- /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 4d9315a1a3bdb..14fe02269d142 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 0f817a0dd9b4715ee5df2ae5146a2527ab4f45fc Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 4 Nov 2016 15:59:30 -0700 Subject: [PATCH 14/47] Add release notes for 1.13.0 --- RELEASES.md | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 222ad3aa112af..e468a86e7acc3 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 15/47] 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 0e6cdb8f09ddc..1ae093afafe8b 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 c4285359a4b94541a887dcbef659a4fdea4da91a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 8 Nov 2016 16:18:44 -0500 Subject: [PATCH 16/47] 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 0000000000000..806b94486615f --- /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 21820ca071921..8aac950b778bb 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 3856ea420b0f3..804765ec8811e 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 d8314bd6c2aed..26778c83c3a06 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 6f6538254c46b..3d2277134bb9b 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 0000000000000..d229bcacc501a --- /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 bc4fc6567c892b4bf468175445388dd3e2faf480 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sat, 5 Nov 2016 19:26:57 -0400 Subject: [PATCH 17/47] 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 e844a158484af..ea5544221c9bd 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 18/47] 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 ea5544221c9bd..7f37b744148d1 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 19/47] 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 7f37b744148d1..3726eee9a93c6 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 0d6323f44d3cd2a132a073e7a92893e777ca11fc Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 9 Nov 2016 22:18:02 -0800 Subject: [PATCH 20/47] 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 08a8ca5a63130..a3fabbb3e8094 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -226,13 +226,16 @@ def cargo(self): 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 21/47] 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 b9e25c3d9e53f..37216e20762d4 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 22/47] 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 | 177 +++++++++--------- 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, 400 insertions(+), 492 deletions(-) diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs index 50a478fcc2fd9..50dfe9d22f12f 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 47c0bc5fd60c5..2ef296aacc56c 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 23fc5911259dc..94667b398b080 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 7dbf9aa74144d..0f9748a16f46c 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 a654d65bc6796..f472205b732d4 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 f9afbaf104a66..73ea84e94aec5 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 6de93adce3f83..b4592a03bcd1f 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 36405df6325af..eba24bfd2c9e2 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 c783bd561bb1a..0681be129b67e 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 b1ab61b09757e..f1b69feb545ef 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 5e3f78b1208d5..3944c7e09c0b8 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 9346bbd30f9ce..b94597d475927 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 60a48ba580a0d..ac1c4fc6a1911 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 fdf5185eb69e2..8222583d9a7da 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 43abb61e7fcd8..bf0445858794e 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 1d260fd65feff..3db705140411a 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 92dfb883ef301..7d209093ec776 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 a4ceecd8c9d7b..15f4437ed0aaf 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 fc32029948388..fd81065e61d49 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 155fa4989ea3c..74c6d7d334c35 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 01b44ced8e08e..3ed4580336aac 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 be85069db3135..eced5d1eb1b80 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 c19b3c40f65c0..f6b6c89b7cc21 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 48471282672ad..4155d3e67a26d 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 e009955b92ee4..e2fa535bb44a0 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 7973cd880fe34..818fb4e86f92a 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 2379e744c49e1..2abfff4ceaae9 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 902798ec98006..f43181d8a610f 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 b5343975a9cdf..4af87381c7042 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 ecc2d8fe050ad..038300068fce1 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 af2f9adfc9a8c..f22a2a7ac9c77 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 9d3afe541cca8..ad525d2106947 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 fded34d2c856c..e6b015b8e173a 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 bf2a5d76c10d4..0ad663f05b48b 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 d50669272f726..a990a7c507fd0 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 ffb13a833a582..f49d63b837643 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 2c0ba36f3b412..41071057274f1 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 0dc10aa7759ea..670a84565fafb 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 e81461b662172..679e308c34542 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 62fb40cc389c2..45b8ec1dc80bb 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 c9c12fb6d4534..09a1cbd319ac4 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 8930387c046e2..93790cc27bcaf 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 513b4860d5e87..fae0f932798d4 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 ffde940b3f48a..54a0ef071ce4b 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 a06b3e70881a5..8657b30bf8ee1 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 95d2b2211f5b4..ac6343cae1c8e 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 3894a7a2097eb..0b6f7794e9fe1 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 579a54fb5318d..66a532fd76acf 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 7068b2dea7263..481923c259787 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 08242cff112ce..e0a429ea5aa1b 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 d4e5e9a5bb355..e39d6ae7083be 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 4136f543cccaf..066b3d4be0881 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 9f3214a0d813e..979ce82ff4ecd 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 90541539c1e23..5863305826462 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 bff794364c098..371c182030e24 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 d92a98485103c..968d5d73e7a8b 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 d7573c7a7bd2e..2c12959dbdde2 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 c9e93a1a46d62..10fca644ec16e 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 a2955169cbb81..e8367bca2ef21 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 9e29d191946b7..f4df28a147630 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 15e042f8c0809..19e084905aa92 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 23/47] 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 1ae093afafe8b..c36e0c09401bc 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 24/47] 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 c36e0c09401bc..9cb3e5e48acea 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 25/47] 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 9cb3e5e48acea..95194976c2926 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 26/47] 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 95194976c2926..4fd73e4854bc4 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 27/47] 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 9a939fee43e8b..a630aaf8af484 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 306708f9e4b68..1388dab303a44 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 1b4e86fb30f25..358cfac742777 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 4ce4900218bd8378e08cd7d1d4c57e370c0949a0 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Thu, 10 Nov 2016 17:54:31 +0000 Subject: [PATCH 28/47] 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 9d82006ac9f9d..b3cec6ec8ff3f 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 29/47] 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 0000000000000..d2030d9355462 --- /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 30/47] 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 0000000000000..ba6289f754ede --- /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 dcd80b80ae3fe2f327515e57fdc423a3927e44e6 Mon Sep 17 00:00:00 2001 From: Arthur Silva Date: Thu, 10 Nov 2016 22:02:44 +0100 Subject: [PATCH 31/47] 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 44dd4e9874ac4..cd7a50d07e268 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 32/47] 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 9d402971d18d0..e94582cda7c34 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 33/47] 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 bdb0dd8e7d1a9..9af10966eda4b 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 34/47] 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 10a0c567e142f..41d675b6f88fc 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 35/47] 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 47c0bc5fd60c5..75334a517fb3b 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 6da87fca3f356..4323929e2e37a 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 0000000000000..603f55af465f4 --- /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 0000000000000..353e251369a10 --- /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 2a832a03c5a3efd6388e4eb5c5b5b4568bcd80f6 Mon Sep 17 00:00:00 2001 From: Trotter Cashion Date: Thu, 10 Nov 2016 19:08:45 -0800 Subject: [PATCH 36/47] 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 4fd73e4854bc4..ed916fd798bb6 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 37/47] 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 de78f859f0f61..117bb39f8e789 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 0000000000000..3c802e8334daf --- /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 f336b26ae41f2..f884bed9b5257 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 59c61a42e077f..a23b4b077410c 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 0000000000000..cca45ca9ecdd9 --- /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 0000000000000..0283052a89f53 --- /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 38/47] 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 9ca911837b517..282cb9f80f51e 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 39/47] 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 71c49ee616cbc..53b7ae0703bf4 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 40/47] [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 de7dbab3f12ea..9fb130845fb16 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 bfed8a8e83a5a..12809171b7438 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 41/47] 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 | 149 +++++++++- 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, 573 insertions(+), 286 deletions(-) create mode 100644 src/librustc_data_structures/small_vec.rs diff --git a/mk/crates.mk b/mk/crates.mk index 25192bfd27a44..7ae5846c54b99 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 d3517175d4ced..ee38a043b122c 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 fda08eba02135..641273d2b7626 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 3894db40277a1..937cb3f600746 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 f87426cee59ea..631cf2cfcf6db 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 ManuallyDrop { + fn new() -> ManuallyDrop { + ManuallyDrop { + empty: () + } + } +} + impl Default for ManuallyDrop { fn default() -> Self { - ManuallyDrop { empty: () } + ManuallyDrop::new() } } diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index fdcbec6bac11a..2e4206d2ee1ee 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 0000000000000..565a3c443a34a --- /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 8b61e1b0d3a38..0b38f5450b63f 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 946257a16d5ac..02429f02738fd 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 63eee7df9e85d..b4ac576f57a53 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 c3608aac0b403..877b312539f92 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 ec48cae3f7652..bda84cdaf39eb 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 feed400897c0f..34280812421a1 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 e1078b719bf06..fe05e2958b3a8 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 9be7dbd68174e..31e675836fc72 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 42/47] 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 144329caa71aa..e06444ddf6d0f 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 f3d8f0387bbd6..35ee7697a7a69 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 d4031077639c5..1e73595ec9983 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 0000000000000..c5b70c227c408 --- /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 0000000000000..8d8f60a5ec260 --- /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 0000000000000..418ce69c5b1e5 --- /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 0000000000000..2db1d46ba2273 --- /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 0000000000000..93f20b28b8689 --- /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 0000000000000..d8af878a95863 --- /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 0000000000000..a9ef29daaf1a1 --- /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 0000000000000..d0ddde95b4473 --- /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 0000000000000..c5b1d00fb7cc1 --- /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 0000000000000..dc16c39961c45 --- /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 0000000000000..d4bc886d50ea4 --- /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 0000000000000..1db01f2b48d46 --- /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 0000000000000..9e98215775e51 --- /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 0000000000000..ca06940ae5e2d --- /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 0000000000000..73a3e2c726cee --- /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 0000000000000..d4d0492e2a260 --- /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 0000000000000..f125693e7ae1a --- /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 0000000000000..1afaef2e05678 --- /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 0000000000000..2bfbd646b75c8 --- /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 0000000000000..da238dddecacb --- /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 5553f8427e90f..d321df8431b88 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 43/47] 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 18e7f07f722e4..d1166e686c7b6 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 44/47] 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 e0aa25724c1f9..209107ef92ceb 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 45/47] 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 e7d401f0929fe..b179a16e55e58 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 de78f859f0f61..16c1ab7957604 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 0000000000000..ec715b3f0ba62 --- /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 0000000000000..58b392f0b8d65 --- /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 61b14e8aae4cfc3c51cf275742adcd23236ec865 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 11 Nov 2016 21:56:12 +0000 Subject: [PATCH 46/47] 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 2fa8ccf3621e0..07b52593781cf 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 47/47] 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 3cf32d1a55919..b3f5363f5b15a 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 */ }) } }