about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustdoc/clean/mod.rs5
-rw-r--r--src/librustdoc/fold.rs11
-rw-r--r--src/librustdoc/html/render.rs42
-rw-r--r--src/librustdoc/html/static/main.js23
-rw-r--r--src/librustdoc/html/static/rustdoc.css6
-rw-r--r--src/librustdoc/html/static/themes/dark.css2
-rw-r--r--src/librustdoc/html/static/themes/light.css2
7 files changed, 81 insertions, 10 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 2bf1f6e553f..e3dc304128f 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -496,6 +496,11 @@ impl Item {
         self.stability.as_ref().map(|s| &s.since[..])
     }
 
+    pub fn is_non_exhaustive(&self) -> bool {
+        self.attrs.other_attrs.iter()
+            .any(|a| a.name().as_str() == "non_exhaustive")
+    }
+
     /// Returns a documentation-level item type from the item.
     pub fn type_(&self) -> ItemType {
         ItemType::from(self)
diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs
index 8e8566cbbde..ddc5d56b474 100644
--- a/src/librustdoc/fold.rs
+++ b/src/librustdoc/fold.rs
@@ -92,7 +92,16 @@ pub trait DocFolder : Sized {
 
     /// don't override!
     fn fold_item_recur(&mut self, item: Item) -> Option<Item> {
-        let Item { attrs, name, source, visibility, def_id, inner, stability, deprecation } = item;
+        let Item {
+            attrs,
+            name,
+            source,
+            visibility,
+            def_id,
+            inner,
+            stability,
+            deprecation,
+        } = item;
 
         let inner = match inner {
             StrippedItem(box i) => StrippedItem(box self.fold_inner_recur(i)),
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 3070458d0be..d92405612ea 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -2276,6 +2276,37 @@ fn document_stability(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item)
     Ok(())
 }
 
+fn document_non_exhaustive_header(item: &clean::Item) -> &str {
+    if item.is_non_exhaustive() { " (Non-exhaustive)" } else { "" }
+}
+
+fn document_non_exhaustive(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
+    if item.is_non_exhaustive() {
+        write!(w, "<div class='docblock non-exhaustive non-exhaustive-{}'>", {
+            if item.is_struct() { "struct" } else if item.is_enum() { "enum" } else { "type" }
+        })?;
+
+        if item.is_struct() {
+            write!(w, "Non-exhaustive structs could have additional fields added in future. \
+                       Therefore, non-exhaustive structs cannot be constructed in external crates \
+                       using the traditional <code>Struct {{ .. }}</code> syntax; cannot be \
+                       matched against without a wildcard <code>..</code>; and \
+                       struct update syntax will not work.")?;
+        } else if item.is_enum() {
+            write!(w, "Non-exhaustive enums could have additional variants added in future. \
+                       Therefore, when matching against variants of non-exhaustive enums, an \
+                       extra wildcard arm must be added to account for any future variants.")?;
+        } else {
+            write!(w, "This type will require a wildcard arm in any match statements or \
+                       constructors.")?;
+        }
+
+        write!(w, "</div>")?;
+    }
+
+    Ok(())
+}
+
 fn name_key(name: &str) -> (&str, u64, usize) {
     // find number at end
     let split = name.bytes().rposition(|b| b < b'0' || b'9' < b).map_or(0, |s| s + 1);
@@ -3136,7 +3167,9 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
     if let doctree::Plain = s.struct_type {
         if fields.peek().is_some() {
             write!(w, "<h2 id='fields' class='fields small-section-header'>
-                       Fields<a href='#fields' class='anchor'></a></h2>")?;
+                       Fields{}<a href='#fields' class='anchor'></a></h2>",
+                       document_non_exhaustive_header(it))?;
+            document_non_exhaustive(w, it)?;
             for (field, ty) in fields {
                 let id = derive_id(format!("{}.{}",
                                            ItemType::StructField,
@@ -3268,7 +3301,9 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
     document(w, cx, it)?;
     if !e.variants.is_empty() {
         write!(w, "<h2 id='variants' class='variants small-section-header'>
-                   Variants<a href='#variants' class='anchor'></a></h2>\n")?;
+                   Variants{}<a href='#variants' class='anchor'></a></h2>\n",
+                   document_non_exhaustive_header(it))?;
+        document_non_exhaustive(w, it)?;
         for variant in &e.variants {
             let id = derive_id(format!("{}.{}",
                                        ItemType::Variant,
@@ -3369,7 +3404,8 @@ const ATTRIBUTE_WHITELIST: &'static [&'static str] = &[
     "must_use",
     "no_mangle",
     "repr",
-    "unsafe_destructor_blind_to_params"
+    "unsafe_destructor_blind_to_params",
+    "non_exhaustive"
 ];
 
 fn render_attributes(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 3bd343c0c0b..62ef5626ee5 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -2001,7 +2001,7 @@
         onEach(e.getElementsByClassName('associatedconstant'), func);
     });
 
-    function createToggle(otherMessage, extraClass) {
+    function createToggle(otherMessage, fontSize, extraClass) {
         var span = document.createElement('span');
         span.className = 'toggle-label';
         span.style.display = 'none';
@@ -2009,7 +2009,10 @@
             span.innerHTML = '&nbsp;Expand&nbsp;description';
         } else {
             span.innerHTML = otherMessage;
-            span.style.fontSize = '20px';
+        }
+
+        if (fontSize) {
+            span.style.fontSize = fontSize;
         }
 
         var mainToggle = toggle.cloneNode(true);
@@ -2048,13 +2051,27 @@
         }
         if (e.parentNode.id === "main") {
             var otherMessage;
+            var fontSize;
             var extraClass;
+
             if (hasClass(e, "type-decl")) {
+                fontSize = "20px";
                 otherMessage = '&nbsp;Show&nbsp;declaration';
+            } else if (hasClass(e, "non-exhaustive")) {
+                otherMessage = '&nbsp;This&nbsp;';
+                if (hasClass(e, "non-exhaustive-struct")) {
+                    otherMessage += 'struct';
+                } else if (hasClass(e, "non-exhaustive-enum")) {
+                    otherMessage += 'enum';
+                } else if (hasClass(e, "non-exhaustive-type")) {
+                    otherMessage += 'type';
+                }
+                otherMessage += '&nbsp;is&nbsp;marked&nbsp;as&nbsp;non-exhaustive';
             } else if (hasClass(e.childNodes[0], "impl-items")) {
                 extraClass = "marg-left";
             }
-            e.parentNode.insertBefore(createToggle(otherMessage, extraClass), e);
+
+            e.parentNode.insertBefore(createToggle(otherMessage, fontSize, extraClass), e);
             if (otherMessage && getCurrentValue('rustdoc-item-declarations') !== "false") {
                 collapseDocs(e.previousSibling.childNodes[0], "toggle");
             }
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index 575a7ea2792..b689e2fa385 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -1358,4 +1358,8 @@ kbd {
 }
 #all-types > p {
 	margin: 5px 0;
-}
\ No newline at end of file
+}
+
+.non-exhaustive {
+	margin-bottom: 1em;
+}
diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css
index 649ee0b781e..b4342f47491 100644
--- a/src/librustdoc/html/static/themes/dark.css
+++ b/src/librustdoc/html/static/themes/dark.css
@@ -406,4 +406,4 @@ kbd {
 }
 .search-results td span.grey {
 	color: #ccc;
-}
\ No newline at end of file
+}
diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css
index 7d9980363de..e84e3cb5663 100644
--- a/src/librustdoc/html/static/themes/light.css
+++ b/src/librustdoc/html/static/themes/light.css
@@ -400,4 +400,4 @@ kbd {
 }
 .search-results td span.grey {
 	color: #999;
-}
\ No newline at end of file
+}