]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #51308 - fanzier:const-prop-array-bounds-check, r=oli-obk
authorMark Simulacrum <mark.simulacrum@gmail.com>
Tue, 5 Jun 2018 14:33:48 +0000 (08:33 -0600)
committerGitHub <noreply@github.com>
Tue, 5 Jun 2018 14:33:48 +0000 (08:33 -0600)
Check array indices in constant propagation

Previously, uses of constant weren't correctly propagated.
This fixes #48920.

r? @oli-obk because you suggested it

22 files changed:
src/doc/rustdoc/src/documentation-tests.md
src/etc/htmldocck.py
src/librustc_errors/emitter.rs
src/librustdoc/clean/mod.rs
src/librustdoc/core.rs
src/librustdoc/html/item_type.rs
src/librustdoc/html/render.rs
src/librustdoc/html/static/main.js
src/librustdoc/html/static/rustdoc.css
src/librustdoc/html/static/themes/dark.css
src/librustdoc/html/static/themes/light.css
src/librustdoc/passes/mod.rs
src/libstd/lib.rs
src/libstd/sys/redox/time.rs
src/libstd/sys/unix/time.rs
src/libsyntax/feature_gate.rs
src/libsyntax_pos/symbol.rs
src/test/rustdoc/invalid.crate.name.rs [new file with mode: 0644]
src/test/rustdoc/keyword.rs [new file with mode: 0644]
src/test/ui/feature-gate-doc_keyword.rs [new file with mode: 0644]
src/test/ui/feature-gate-doc_keyword.stderr [new file with mode: 0644]
src/tools/rustdoc-js/tester.js

index fd7d1713ca574eefeebff662b3f1f3d07088c064..cb233cc84cbed8fd95ddbce645dcabfe35a0cd45 100644 (file)
@@ -79,8 +79,9 @@ from your example, but are important to make the tests work. Consider
 an example block that looks like this:
 
 ```text
-/// Some documentation.
-# fn foo() {}
+/// /// Some documentation.
+/// # fn foo() {} // this function will be hidden
+/// println!("Hello, World!");
 ```
 
 It will render like this:
@@ -88,6 +89,7 @@ It will render like this:
 ```rust
 /// Some documentation.
 # fn foo() {}
+println!("Hello, World!");
 ```
 
 Yes, that's right: you can add lines that start with `# `, and they will
@@ -168,37 +170,56 @@ By repeating all parts of the example, you can ensure that your example still
 compiles, while only showing the parts that are relevant to that part of your
 explanation.
 
-Another case where the use of `#` is handy is when you want to ignore
-error handling. Lets say you want the following,
+
+## Using `?` in doc tests
+
+When writing an example, it is rarely useful to include a complete error
+handling, as it would add significant amounts of boilerplate code. Instead, you
+may want the following:
 
 ```ignore
+/// ```
 /// use std::io;
 /// let mut input = String::new();
 /// io::stdin().read_line(&mut input)?;
+/// ```
 ```
 
-The problem is that `?` returns a `Result<T, E>` and test functions
-don't return anything so this will give a mismatched types error.
+The problem is that `?` returns a `Result<T, E>` and test functions don't
+return anything, so this will give a mismatched types error.
+
+You can get around this limitation by manually adding a `main` that returns
+`Result<T, E>`, because `Result<T, E>` implements the `Termination` trait:
 
 ```ignore
 /// A doc test using ?
 ///
 /// ```
 /// use std::io;
-/// # fn foo() -> io::Result<()> {
+///
+/// fn main() -> io::Result<()> {
+///     let mut input = String::new();
+///     io::stdin().read_line(&mut input)?;
+///     Ok(())
+/// }
+/// ```
+```
+
+Together with the `# ` from the section above, you arrive at a solution that
+appears to the reader as the initial idea but works with doc tests:
+
+```ignore
+/// ```
+/// use std::io;
+/// # fn main() -> io::Result<()> {
 /// let mut input = String::new();
 /// io::stdin().read_line(&mut input)?;
 /// # Ok(())
 /// # }
 /// ```
-# fn foo() {}
 ```
 
-You can get around this by wrapping the code in a function. This catches
-and swallows the `Result<T, E>` when running tests on the docs. This
-pattern appears regularly in the standard library.
-
-### Documenting macros
+## Documenting macros
 
 Here’s an example of documenting a macro:
 
index 8a11c6f7cfc4c9d27950537feb79ab27572dc4ca..569788fe9c08a93cfca05915a7835ea629c34be0 100644 (file)
@@ -346,15 +346,19 @@ def check_tree_attr(tree, path, attr, pat, regexp):
 def check_tree_text(tree, path, pat, regexp):
     path = normalize_xpath(path)
     ret = False
-    for e in tree.findall(path):
-        try:
-            value = flatten(e)
-        except KeyError:
-            continue
-        else:
-            ret = check_string(value, pat, regexp)
-            if ret:
-                break
+    try:
+        for e in tree.findall(path):
+            try:
+                value = flatten(e)
+            except KeyError:
+                continue
+            else:
+                ret = check_string(value, pat, regexp)
+                if ret:
+                    break
+    except Exception as e:
+        print('Failed to get path "{}"'.format(path))
+        raise e
     return ret
 
 
index f65acf08c86d8f3ad109829c5b264a4c4fe5efa6..92e72fe91d3e8dad19aca526b966492f3ab4211f 100644 (file)
@@ -1287,7 +1287,7 @@ fn emit_suggestion_default(&mut self,
                         });
 
                         // length of the code to be substituted
-                        let snippet_len = (span_end_pos - span_start_pos) as isize;
+                        let snippet_len = span_end_pos as isize - span_start_pos as isize;
                         // For multiple substitutions, use the position *after* the previous
                         // substitutions have happened.
                         offset += full_sub_len - snippet_len;
index 1c1ba208678ed0e418faac4eba8cbd3025321142..178a85f9364de71457c8500be459320f19495708 100644 (file)
@@ -26,7 +26,7 @@
 use syntax::codemap::{dummy_spanned, Spanned};
 use syntax::feature_gate::UnstableFeatures;
 use syntax::ptr::P;
-use syntax::symbol::keywords;
+use syntax::symbol::keywords::{self, Keyword};
 use syntax::symbol::{Symbol, InternedString};
 use syntax_pos::{self, DUMMY_SP, Pos, FileName};
 
@@ -54,6 +54,7 @@
 use std::iter::{FromIterator, once};
 use rustc_data_structures::sync::Lrc;
 use std::rc::Rc;
+use std::str::FromStr;
 use std::cell::RefCell;
 use std::sync::Arc;
 use std::u32;
@@ -177,7 +178,7 @@ fn clean(&self, cx: &DocContext) -> Crate {
             _ => unreachable!(),
         }
 
-        let ExternalCrate { name, src, primitives, .. } = LOCAL_CRATE.clean(cx);
+        let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx);
         {
             let m = match module.inner {
                 ModuleItem(ref mut m) => m,
@@ -195,6 +196,18 @@ fn clean(&self, cx: &DocContext) -> Crate {
                     inner: PrimitiveItem(prim),
                 }
             }));
+            m.items.extend(keywords.into_iter().map(|(def_id, kw, attrs)| {
+                Item {
+                    source: Span::empty(),
+                    name: Some(kw.clone()),
+                    attrs: attrs,
+                    visibility: Some(Public),
+                    stability: get_stability(cx, def_id),
+                    deprecation: get_deprecation(cx, def_id),
+                    def_id,
+                    inner: KeywordItem(kw),
+                }
+            }));
         }
 
         let mut access_levels = cx.access_levels.borrow_mut();
@@ -220,6 +233,7 @@ pub struct ExternalCrate {
     pub src: FileName,
     pub attrs: Attributes,
     pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
+    pub keywords: Vec<(DefId, String, Attributes)>,
 }
 
 impl Clean<ExternalCrate> for CrateNum {
@@ -286,11 +300,53 @@ fn clean(&self, cx: &DocContext) -> ExternalCrate {
               .filter_map(as_primitive).collect()
         };
 
+        let as_keyword = |def: Def| {
+            if let Def::Mod(def_id) = def {
+                let attrs = cx.tcx.get_attrs(def_id).clean(cx);
+                let mut keyword = None;
+                for attr in attrs.lists("doc") {
+                    if let Some(v) = attr.value_str() {
+                        if attr.check_name("keyword") {
+                            keyword = Keyword::from_str(&v.as_str()).ok()
+                                                                    .map(|x| x.name().to_string());
+                            if keyword.is_some() {
+                                break
+                            }
+                            // FIXME: should warn on unknown keywords?
+                        }
+                    }
+                }
+                return keyword.map(|p| (def_id, p, attrs));
+            }
+            None
+        };
+        let keywords = if root.is_local() {
+            cx.tcx.hir.krate().module.item_ids.iter().filter_map(|&id| {
+                let item = cx.tcx.hir.expect_item(id.id);
+                match item.node {
+                    hir::ItemMod(_) => {
+                        as_keyword(Def::Mod(cx.tcx.hir.local_def_id(id.id)))
+                    }
+                    hir::ItemUse(ref path, hir::UseKind::Single)
+                    if item.vis == hir::Visibility::Public => {
+                        as_keyword(path.def).map(|(_, prim, attrs)| {
+                            (cx.tcx.hir.local_def_id(id.id), prim, attrs)
+                        })
+                    }
+                    _ => None
+                }
+            }).collect()
+        } else {
+            cx.tcx.item_children(root).iter().map(|item| item.def)
+              .filter_map(as_keyword).collect()
+        };
+
         ExternalCrate {
             name: cx.tcx.crate_name(*self).to_string(),
             src: krate_src,
             attrs: cx.tcx.get_attrs(root).clean(cx),
             primitives,
+            keywords,
         }
     }
 }
@@ -397,6 +453,9 @@ pub fn is_import(&self) -> bool {
     pub fn is_extern_crate(&self) -> bool {
         self.type_() == ItemType::ExternCrate
     }
+    pub fn is_keyword(&self) -> bool {
+        self.type_() == ItemType::Keyword
+    }
 
     pub fn is_stripped(&self) -> bool {
         match self.inner { StrippedItem(..) => true, _ => false }
@@ -475,6 +534,7 @@ pub enum ItemEnum {
     AssociatedTypeItem(Vec<TyParamBound>, Option<Type>),
     /// An item that has been stripped by a rustdoc pass
     StrippedItem(Box<ItemEnum>),
+    KeywordItem(String),
 }
 
 impl ItemEnum {
index 458ed105d2650b04c54cc56658c94988f06cf2b8..bad5ff2596fd3496f2086729a34ffd2288106577 100644 (file)
@@ -230,7 +230,10 @@ pub fn run_core(search_paths: SearchPaths,
 
         let krate = panictry!(driver::phase_1_parse_input(control, &sess, &input));
 
-        let name = ::rustc_codegen_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input);
+        let name = match crate_name {
+            Some(ref crate_name) => crate_name.clone(),
+            None => ::rustc_codegen_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input),
+        };
 
         let mut crate_loader = CrateLoader::new(&sess, &cstore, &name);
 
index 537828de2c7f35fd56bdabc7a4e89b5400c60675..9b8ada1f6e6b29968e9db708499584b8a01ce396 100644 (file)
@@ -42,6 +42,7 @@ pub enum ItemType {
     AssociatedConst = 18,
     Union           = 19,
     ForeignType     = 20,
+    Keyword         = 21,
 }
 
 
@@ -50,6 +51,7 @@ pub enum NameSpace {
     Type,
     Value,
     Macro,
+    Keyword,
 }
 
 impl<'a> From<&'a clean::Item> for ItemType {
@@ -83,6 +85,7 @@ fn from(item: &'a clean::Item) -> ItemType {
             clean::AssociatedConstItem(..) => ItemType::AssociatedConst,
             clean::AssociatedTypeItem(..)  => ItemType::AssociatedType,
             clean::ForeignTypeItem         => ItemType::ForeignType,
+            clean::KeywordItem(..)         => ItemType::Keyword,
             clean::StrippedItem(..)        => unreachable!(),
         }
     }
@@ -131,6 +134,7 @@ pub fn css_class(&self) -> &'static str {
             ItemType::Constant        => "constant",
             ItemType::AssociatedConst => "associatedconstant",
             ItemType::ForeignType     => "foreigntype",
+            ItemType::Keyword         => "keyword",
         }
     }
 
@@ -159,6 +163,8 @@ pub fn name_space(&self) -> NameSpace {
             ItemType::AssociatedConst => NameSpace::Value,
 
             ItemType::Macro => NameSpace::Macro,
+
+            ItemType::Keyword => NameSpace::Keyword,
         }
     }
 }
@@ -172,6 +178,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 pub const NAMESPACE_TYPE: &'static str = "t";
 pub const NAMESPACE_VALUE: &'static str = "v";
 pub const NAMESPACE_MACRO: &'static str = "m";
+pub const NAMESPACE_KEYWORD: &'static str = "k";
 
 impl NameSpace {
     pub fn to_static_str(&self) -> &'static str {
@@ -179,6 +186,7 @@ pub fn to_static_str(&self) -> &'static str {
             NameSpace::Type => NAMESPACE_TYPE,
             NameSpace::Value => NAMESPACE_VALUE,
             NameSpace::Macro => NAMESPACE_MACRO,
+            NameSpace::Keyword => NAMESPACE_KEYWORD,
         }
     }
 }
index 5377cd9a39143a4faeb40298897cc5b595aa6c34..5c2ec2058ee9d703d0723b6cda9c8dc3a6592ee6 100644 (file)
@@ -1541,6 +1541,7 @@ struct AllTypes {
     typedefs: HashSet<ItemEntry>,
     statics: HashSet<ItemEntry>,
     constants: HashSet<ItemEntry>,
+    keywords: HashSet<ItemEntry>,
 }
 
 impl AllTypes {
@@ -1556,6 +1557,7 @@ fn new() -> AllTypes {
             typedefs: HashSet::with_capacity(100),
             statics: HashSet::with_capacity(100),
             constants: HashSet::with_capacity(100),
+            keywords: HashSet::with_capacity(100),
         }
     }
 
@@ -2063,12 +2065,13 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
             clean::StaticItem(..) | clean::ForeignStaticItem(..) => write!(fmt, "Static ")?,
             clean::ConstantItem(..) => write!(fmt, "Constant ")?,
             clean::ForeignTypeItem => write!(fmt, "Foreign Type ")?,
+            clean::KeywordItem(..) => write!(fmt, "Keyword ")?,
             _ => {
                 // We don't generate pages for any other type.
                 unreachable!();
             }
         }
-        if !self.item.is_primitive() {
+        if !self.item.is_primitive() && !self.item.is_keyword() {
             let cur = &self.cx.current;
             let amt = if self.item.is_mod() { cur.len() - 1 } else { cur.len() };
             for (i, component) in cur.iter().enumerate().take(amt) {
@@ -2126,6 +2129,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
                 item_static(fmt, self.cx, self.item, i),
             clean::ConstantItem(ref c) => item_constant(fmt, self.cx, self.item, c),
             clean::ForeignTypeItem => item_foreign_type(fmt, self.cx, self.item),
+            clean::KeywordItem(ref k) => item_keyword(fmt, self.cx, self.item, k),
             _ => {
                 // We don't generate pages for any other type.
                 unreachable!();
@@ -2353,29 +2357,7 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
                 write!(w, "</table>")?;
             }
             curty = myty;
-            let (short, name) = match myty.unwrap() {
-                ItemType::ExternCrate |
-                ItemType::Import          => ("reexports", "Re-exports"),
-                ItemType::Module          => ("modules", "Modules"),
-                ItemType::Struct          => ("structs", "Structs"),
-                ItemType::Union           => ("unions", "Unions"),
-                ItemType::Enum            => ("enums", "Enums"),
-                ItemType::Function        => ("functions", "Functions"),
-                ItemType::Typedef         => ("types", "Type Definitions"),
-                ItemType::Static          => ("statics", "Statics"),
-                ItemType::Constant        => ("constants", "Constants"),
-                ItemType::Trait           => ("traits", "Traits"),
-                ItemType::Impl            => ("impls", "Implementations"),
-                ItemType::TyMethod        => ("tymethods", "Type Methods"),
-                ItemType::Method          => ("methods", "Methods"),
-                ItemType::StructField     => ("fields", "Struct Fields"),
-                ItemType::Variant         => ("variants", "Variants"),
-                ItemType::Macro           => ("macros", "Macros"),
-                ItemType::Primitive       => ("primitives", "Primitive Types"),
-                ItemType::AssociatedType  => ("associated-types", "Associated Types"),
-                ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
-                ItemType::ForeignType     => ("foreign-types", "Foreign Types"),
-            };
+            let (short, name) = item_ty_to_strs(&myty.unwrap());
             write!(w, "<h2 id='{id}' class='section-header'>\
                        <a href=\"#{id}\">{name}</a></h2>\n<table>",
                    id = derive_id(short.to_owned()), name = name)?;
@@ -4360,6 +4342,33 @@ fn sidebar_enum(fmt: &mut fmt::Formatter, it: &clean::Item,
     Ok(())
 }
 
+fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) {
+    match *ty {
+        ItemType::ExternCrate |
+        ItemType::Import          => ("reexports", "Re-exports"),
+        ItemType::Module          => ("modules", "Modules"),
+        ItemType::Struct          => ("structs", "Structs"),
+        ItemType::Union           => ("unions", "Unions"),
+        ItemType::Enum            => ("enums", "Enums"),
+        ItemType::Function        => ("functions", "Functions"),
+        ItemType::Typedef         => ("types", "Type Definitions"),
+        ItemType::Static          => ("statics", "Statics"),
+        ItemType::Constant        => ("constants", "Constants"),
+        ItemType::Trait           => ("traits", "Traits"),
+        ItemType::Impl            => ("impls", "Implementations"),
+        ItemType::TyMethod        => ("tymethods", "Type Methods"),
+        ItemType::Method          => ("methods", "Methods"),
+        ItemType::StructField     => ("fields", "Struct Fields"),
+        ItemType::Variant         => ("variants", "Variants"),
+        ItemType::Macro           => ("macros", "Macros"),
+        ItemType::Primitive       => ("primitives", "Primitive Types"),
+        ItemType::AssociatedType  => ("associated-types", "Associated Types"),
+        ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
+        ItemType::ForeignType     => ("foreign-types", "Foreign Types"),
+        ItemType::Keyword         => ("keywords", "Keywords"),
+    }
+}
+
 fn sidebar_module(fmt: &mut fmt::Formatter, _it: &clean::Item,
                   items: &[clean::Item]) -> fmt::Result {
     let mut sidebar = String::new();
@@ -4379,29 +4388,7 @@ fn sidebar_module(fmt: &mut fmt::Formatter, _it: &clean::Item,
                    ItemType::TyMethod, ItemType::Method, ItemType::StructField, ItemType::Variant,
                    ItemType::AssociatedType, ItemType::AssociatedConst, ItemType::ForeignType] {
         if items.iter().any(|it| !it.is_stripped() && it.type_() == myty) {
-            let (short, name) = match myty {
-                ItemType::ExternCrate |
-                ItemType::Import          => ("reexports", "Re-exports"),
-                ItemType::Module          => ("modules", "Modules"),
-                ItemType::Struct          => ("structs", "Structs"),
-                ItemType::Union           => ("unions", "Unions"),
-                ItemType::Enum            => ("enums", "Enums"),
-                ItemType::Function        => ("functions", "Functions"),
-                ItemType::Typedef         => ("types", "Type Definitions"),
-                ItemType::Static          => ("statics", "Statics"),
-                ItemType::Constant        => ("constants", "Constants"),
-                ItemType::Trait           => ("traits", "Traits"),
-                ItemType::Impl            => ("impls", "Implementations"),
-                ItemType::TyMethod        => ("tymethods", "Type Methods"),
-                ItemType::Method          => ("methods", "Methods"),
-                ItemType::StructField     => ("fields", "Struct Fields"),
-                ItemType::Variant         => ("variants", "Variants"),
-                ItemType::Macro           => ("macros", "Macros"),
-                ItemType::Primitive       => ("primitives", "Primitive Types"),
-                ItemType::AssociatedType  => ("associated-types", "Associated Types"),
-                ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
-                ItemType::ForeignType     => ("foreign-types", "Foreign Types"),
-            };
+            let (short, name) = item_ty_to_strs(&myty);
             sidebar.push_str(&format!("<li><a href=\"#{id}\">{name}</a></li>",
                                       id = short,
                                       name = name));
@@ -4462,6 +4449,12 @@ fn item_primitive(w: &mut fmt::Formatter, cx: &Context,
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
 }
 
+fn item_keyword(w: &mut fmt::Formatter, cx: &Context,
+                it: &clean::Item,
+                _p: &str) -> fmt::Result {
+    document(w, cx, it)
+}
+
 const BASIC_KEYWORDS: &'static str = "rust, rustlang, rust-lang";
 
 fn make_item_keywords(it: &clean::Item) -> String {
index 0c937759120ef47e39df76218cffe5b6ab9cb6fd..983da51779ca25a6094a245a30ebf896a5adf85f 100644 (file)
@@ -38,7 +38,8 @@
                      "constant",
                      "associatedconstant",
                      "union",
-                     "foreigntype"];
+                     "foreigntype",
+                     "keyword"];
 
     var search_input = document.getElementsByClassName('search-input')[0];
 
 
     // used for special search precedence
     var TY_PRIMITIVE = itemTypes.indexOf("primitive");
+    var TY_KEYWORD = itemTypes.indexOf("keyword");
 
     onEach(document.getElementsByClassName('js-only'), function(e) {
         removeClass(e, 'js-only');
                     b = bbb.index;
                     if (a !== b) { return a - b; }
 
-                    // special precedence for primitive pages
-                    if ((aaa.item.ty === TY_PRIMITIVE) && (bbb.item.ty !== TY_PRIMITIVE)) {
+                    // special precedence for primitive and keyword pages
+                    if ((aaa.item.ty === TY_PRIMITIVE && bbb.item.ty !== TY_KEYWORD) ||
+                        (aaa.item.ty === TY_KEYWORD && bbb.item.ty !== TY_PRIMITIVE)) {
                         return -1;
                     }
-                    if ((bbb.item.ty === TY_PRIMITIVE) && (aaa.item.ty !== TY_PRIMITIVE)) {
+                    if ((bbb.item.ty === TY_PRIMITIVE && aaa.item.ty !== TY_PRIMITIVE) ||
+                        (bbb.item.ty === TY_KEYWORD && aaa.item.ty !== TY_KEYWORD)) {
                         return 1;
                     }
 
                 displayPath = item.path + '::';
                 href = rootPath + item.path.replace(/::/g, '/') + '/' +
                        name + '/index.html';
-            } else if (type === "primitive") {
+            } else if (type === "primitive" || type === "keyword") {
                 displayPath = "";
                 href = rootPath + item.path.replace(/::/g, '/') +
                        '/' + type + '.' + name + '.html';
         block("fn", "Functions");
         block("type", "Type Definitions");
         block("foreigntype", "Foreign Types");
+        block("keyword", "Keywords");
     }
 
     window.initSidebarItems = initSidebarItems;
index 773b8174e56bc98b20c07298e3c96249d940493b..d684db152df0129aff972b2570da44eb8a0555fd 100644 (file)
@@ -628,6 +628,11 @@ tr.result span.primitive::after {
        font-style: italic;
 }
 
+tr.result span.keyword::after {
+       content: ' (keyword)';
+       font-style: italic;
+}
+
 body.blur > :not(#help) {
        filter: blur(8px);
        -webkit-filter: blur(8px);
index f96dcd9ec1c888bbfe6a8f5991a214b64ab7c5f2..7add0e21f548c7b4f16e361f2ee21a6721b1246a 100644 (file)
@@ -128,6 +128,7 @@ pre {
 .content .highlighted.constant,
 .content .highlighted.static { background-color: #0063cc; }
 .content .highlighted.primitive { background-color: #00708a; }
+.content .highlighted.keyword { background-color: #884719; }
 
 .content span.enum, .content a.enum, .block a.current.enum { color: #82b089; }
 .content span.struct, .content a.struct, .block a.current.struct { color: #2dbfb8; }
@@ -145,6 +146,7 @@ pre {
 .content span.method, .content a.method, .block a.current.method,
 .content span.tymethod, .content a.tymethod, .block a.current.tymethod,
 .content .fnname{ color: #2BAB63; }
+.content span.keyword, .content a.keyword, .block a.current.keyword { color: #de5249; }
 
 pre.rust .comment { color: #8d8d8b; }
 pre.rust .doccomment { color: #8ca375; }
@@ -209,7 +211,7 @@ a.test-arrow {
        color: grey;
 }
 
-tr.result span.primitive::after {
+tr.result span.primitive::after, tr.result span.keyword::after {
        color: #ddd;
 }
 
index 54cf50cfffd1e030467aa6bcc705aebab2c819ef..7d9980363de9c582021c6b311a401209abc76177 100644 (file)
@@ -128,6 +128,7 @@ pre {
 .content .highlighted.constant,
 .content .highlighted.static { background-color: #c3e0ff; }
 .content .highlighted.primitive { background-color: #9aecff; }
+.content .highlighted.keyword { background-color: #f99650; }
 
 .content span.enum, .content a.enum, .block a.current.enum { color: #508157; }
 .content span.struct, .content a.struct, .block a.current.struct { color: #ad448e; }
@@ -145,6 +146,7 @@ pre {
 .content span.method, .content a.method, .block a.current.method,
 .content span.tymethod, .content a.tymethod, .block a.current.tymethod,
 .content .fnname { color: #9a6e31; }
+.content span.keyword, .content a.keyword, .block a.current.keyword { color: #de5249; }
 
 pre.rust .comment { color: #8E908C; }
 pre.rust .doccomment { color: #4D4D4C; }
@@ -203,7 +205,7 @@ a.test-arrow {
        color: grey;
 }
 
-tr.result span.primitive::after {
+tr.result span.primitive::after, tr.result span.keyword::after {
        color: black;
 }
 
index 32f0bcada1d20924414211dcdd462dc7c7bdbe0c..fe116a22eccbfa4e465a8a9d21471f8931add8c1 100644 (file)
@@ -126,6 +126,9 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
 
             // Associated types are never stripped
             clean::AssociatedTypeItem(..) => {}
+
+            // Keywords are never stripped
+            clean::KeywordItem(..) => {}
         }
 
         let fastreturn = match i.inner {
index c576245edb755c1d271fbf04f431951efe50a265..8266cec5139f966267bd012007683596c8fe6fb6 100644 (file)
 #![cfg_attr(test, feature(update_panic_count))]
 #![cfg_attr(windows, feature(used))]
 #![feature(doc_alias)]
+#![feature(doc_keyword)]
 #![feature(float_internals)]
 #![feature(panic_info_message)]
 #![cfg_attr(not(stage0), feature(panic_implementation))]
index cf798500b7fd2d716dcccaaa7adb62250b879a88..5c491115c55160dafcc356c2082699454b9b29f4 100644 (file)
@@ -144,7 +144,7 @@ pub fn now() -> Instant {
 
     pub fn sub_instant(&self, other: &Instant) -> Duration {
         self.t.sub_timespec(&other.t).unwrap_or_else(|_| {
-            panic!("other was less than the current instant")
+            panic!("specified instant was later than self")
         })
     }
 
index 83127935909931211957d8df0e34e7c599e92ceb..89786eb2a6c486005c27ba46da3375fa3fd79aa7 100644 (file)
@@ -289,7 +289,7 @@ pub fn now() -> Instant {
 
         pub fn sub_instant(&self, other: &Instant) -> Duration {
             self.t.sub_timespec(&other.t).unwrap_or_else(|_| {
-                panic!("other was less than the current instant")
+                panic!("specified instant was later than self")
             })
         }
 
index 7349745fefea100b1b9b1c6de4739e7ee089dd49..51788b6063a333c5700d00a6c24b94a24cb0eefa 100644 (file)
@@ -476,8 +476,12 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
     // 'a: { break 'a; }
     (active, label_break_value, "1.28.0", Some(48594), None),
 
+
     // #[panic_implementation]
     (active, panic_implementation, "1.28.0", Some(44489), None),
+
+    // #[doc(keyword = "...")]
+    (active, doc_keyword, "1.28.0", Some(51315), None),
 );
 
 declare_features! (
@@ -1506,6 +1510,10 @@ fn visit_attribute(&mut self, attr: &ast::Attribute) {
                     gate_feature_post!(&self, doc_alias, attr.span,
                         "#[doc(alias = \"...\")] is experimental"
                     );
+                } else if content.iter().any(|c| c.check_name("keyword")) {
+                    gate_feature_post!(&self, doc_keyword, attr.span,
+                        "#[doc(keyword = \"...\")] is experimental"
+                    );
                 }
             }
         }
index a4b2d9de932a71194994202cfa4fc548b29dcce1..283b41e5725a95959383d8295885633e5e8d084d 100644 (file)
@@ -311,6 +311,17 @@ impl Keyword {
                 ident: Ident::with_empty_ctxt(super::Symbol($index))
             };
         )*
+
+        impl ::std::str::FromStr for Keyword {
+            type Err = ();
+
+            fn from_str(s: &str) -> Result<Self, ()> {
+                match s {
+                    $($string => Ok($konst),)*
+                    _ => Err(()),
+                }
+            }
+        }
     }
 
     impl Interner {
diff --git a/src/test/rustdoc/invalid.crate.name.rs b/src/test/rustdoc/invalid.crate.name.rs
new file mode 100644 (file)
index 0000000..4e4946a
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --crate-name foo
+
+pub fn foo() {}
diff --git a/src/test/rustdoc/keyword.rs b/src/test/rustdoc/keyword.rs
new file mode 100644 (file)
index 0000000..b255ffd
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name = "foo"]
+
+#![feature(doc_keyword)]
+
+// @has foo/index.html '//h2[@id="keywords"]' 'Keywords'
+// @has foo/index.html '//a[@href="keyword.match.html"]' 'match'
+// @has foo/keyword.match.html '//a[@class="keyword"]' 'match'
+// @has foo/keyword.match.html '//section[@id="main"]//div[@class="docblock"]//p' 'this is a test!'
+// @!has foo/index.html '//a/@href' 'foo/index.html'
+// @!has foo/foo/index.html
+// @!has-dir foo/foo
+#[doc(keyword = "match")]
+/// this is a test!
+mod foo{}
diff --git a/src/test/ui/feature-gate-doc_keyword.rs b/src/test/ui/feature-gate-doc_keyword.rs
new file mode 100644 (file)
index 0000000..2ff4462
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[doc(keyword = "match")] //~ ERROR: #[doc(keyword = "...")] is experimental
+/// wonderful
+mod foo{}
diff --git a/src/test/ui/feature-gate-doc_keyword.stderr b/src/test/ui/feature-gate-doc_keyword.stderr
new file mode 100644 (file)
index 0000000..e4f5109
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0658]: #[doc(keyword = "...")] is experimental (see issue #51315)
+  --> $DIR/feature-gate-doc_keyword.rs:11:1
+   |
+LL | #[doc(keyword = "match")] //~ ERROR: #[doc(keyword = "...")] is experimental
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(doc_keyword)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
index bc4503903d665589ab3bf1c0beb887bf8eb795ed..a05c8a8ac9133301bcfc5ea0763d03527f49bed5 100644 (file)
@@ -231,7 +231,9 @@ function main(argv) {
     finalJS = "";
 
     var arraysToLoad = ["itemTypes"];
-    var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS", "TY_PRIMITIVE", "levenshtein_row2"];
+    var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS",
+                           "TY_PRIMITIVE", "TY_KEYWORD",
+                           "levenshtein_row2"];
     // execQuery first parameter is built in getQuery (which takes in the search input).
     // execQuery last parameter is built in buildIndex.
     // buildIndex requires the hashmap from search-index.