Auto merge of #41345 - frewsxcv:rollup, r=frewsxcv

Rollup of 3 pull requests

- Successful merges: #41012, #41280, #41290
- Failed merges:
This commit is contained in:
bors 2017-04-17 17:56:29 +00:00
commit 5516bcc458
24 changed files with 742 additions and 43 deletions

4
.gitmodules vendored
View file

@ -5,6 +5,10 @@
[submodule "src/compiler-rt"] [submodule "src/compiler-rt"]
path = src/compiler-rt path = src/compiler-rt
url = https://github.com/rust-lang/compiler-rt.git url = https://github.com/rust-lang/compiler-rt.git
[submodule "src/rt/hoedown"]
path = src/rt/hoedown
url = https://github.com/rust-lang/hoedown.git
branch = rust-2015-09-21-do-not-delete
[submodule "src/jemalloc"] [submodule "src/jemalloc"]
path = src/jemalloc path = src/jemalloc
url = https://github.com/rust-lang/jemalloc.git url = https://github.com/rust-lang/jemalloc.git

View file

@ -197,6 +197,28 @@ their own copyright notices and license terms:
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE. OF SUCH DAMAGE.
* Hoedown, the markdown parser, under src/rt/hoedown, is
licensed as follows.
Copyright (c) 2008, Natacha Porté
Copyright (c) 2011, Vicent Martí
Copyright (c) 2013, Devin Torres and the Hoedown authors
Permission to use, copy, modify, and distribute this
software for any purpose with or without fee is hereby
granted, provided that the above copyright notice and
this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR
DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* libbacktrace, under src/libbacktrace: * libbacktrace, under src/libbacktrace:
Copyright (C) 2012-2014 Free Software Foundation, Inc. Copyright (C) 2012-2014 Free Software Foundation, Inc.

View file

@ -114,6 +114,7 @@
- [lookup_host](lookup-host.md) - [lookup_host](lookup-host.md)
- [loop_break_value](loop-break-value.md) - [loop_break_value](loop-break-value.md)
- [macro_reexport](macro-reexport.md) - [macro_reexport](macro-reexport.md)
- [macro_vis_matcher](macro-vis-matcher.md)
- [main](main.md) - [main](main.md)
- [manually_drop](manually-drop.md) - [manually_drop](manually-drop.md)
- [map_entry_recover_keys](map-entry-recover-keys.md) - [map_entry_recover_keys](map-entry-recover-keys.md)

View file

@ -0,0 +1,14 @@
# `macro_vis_matcher`
The tracking issue for this feature is: [#41022]
With this feature gate enabled, the [list of fragment specifiers][frags] gains one more entry:
* `vis`: a visibility qualifier. Examples: nothing (default visibility); `pub`; `pub(crate)`.
A `vis` variable may be followed by a comma, ident, type, or path.
[#41022]: https://github.com/rust-lang/rust/issues/41022
[frags]: ../book/first-edition/macros.html#syntactic-requirements
------------------------

View file

@ -521,7 +521,9 @@ impl<'a> Resolver<'a> {
LoadedMacro::ProcMacro(ext) => return ext, LoadedMacro::ProcMacro(ext) => return ext,
}; };
let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, &macro_def)); let ext = Rc::new(macro_rules::compile(&self.session.parse_sess,
&self.session.features,
&macro_def));
self.macro_map.insert(def_id, ext.clone()); self.macro_map.insert(def_id, ext.clone());
ext ext
} }

View file

@ -671,7 +671,9 @@ impl<'a> Resolver<'a> {
} }
let def_id = self.definitions.local_def_id(item.id); let def_id = self.definitions.local_def_id(item.id);
let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, item)); let ext = Rc::new(macro_rules::compile(&self.session.parse_sess,
&self.session.features,
item));
self.macro_map.insert(def_id, ext); self.macro_map.insert(def_id, ext);
*legacy_scope = LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding { *legacy_scope = LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding {
parent: Cell::new(*legacy_scope), name: ident.name, def_id: def_id, span: item.span, parent: Cell::new(*legacy_scope), name: ident.name, def_id: def_id, span: item.span,

View file

@ -2,6 +2,7 @@
authors = ["The Rust Project Developers"] authors = ["The Rust Project Developers"]
name = "rustdoc" name = "rustdoc"
version = "0.0.0" version = "0.0.0"
build = "build.rs"
[lib] [lib]
name = "rustdoc" name = "rustdoc"

30
src/librustdoc/build.rs Normal file
View file

@ -0,0 +1,30 @@
// Copyright 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 <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.
extern crate build_helper;
extern crate gcc;
fn main() {
let src_dir = std::path::Path::new("../rt/hoedown/src");
build_helper::rerun_if_changed_anything_in_dir(src_dir);
let mut cfg = gcc::Config::new();
cfg.file("../rt/hoedown/src/autolink.c")
.file("../rt/hoedown/src/buffer.c")
.file("../rt/hoedown/src/document.c")
.file("../rt/hoedown/src/escape.c")
.file("../rt/hoedown/src/html.c")
.file("../rt/hoedown/src/html_blocks.c")
.file("../rt/hoedown/src/html_smartypants.c")
.file("../rt/hoedown/src/stack.c")
.file("../rt/hoedown/src/version.c")
.include(src_dir)
.compile("libhoedown.a");
}

View file

@ -292,7 +292,7 @@ impl Item {
self.type_() == ItemType::Struct self.type_() == ItemType::Struct
} }
pub fn is_enum(&self) -> bool { pub fn is_enum(&self) -> bool {
self.type_() == ItemType::Module self.type_() == ItemType::Enum
} }
pub fn is_fn(&self) -> bool { pub fn is_fn(&self) -> bool {
self.type_() == ItemType::Function self.type_() == ItemType::Function
@ -312,6 +312,9 @@ impl Item {
pub fn is_primitive(&self) -> bool { pub fn is_primitive(&self) -> bool {
self.type_() == ItemType::Primitive self.type_() == ItemType::Primitive
} }
pub fn is_union(&self) -> bool {
self.type_() == ItemType::Union
}
pub fn is_stripped(&self) -> bool { pub fn is_stripped(&self) -> bool {
match self.inner { StrippedItem(..) => true, _ => false } match self.inner { StrippedItem(..) => true, _ => false }
} }

View file

@ -25,6 +25,9 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
use libc;
use std::slice;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::{HashMap, VecDeque}; use std::collections::{HashMap, VecDeque};
@ -357,6 +360,194 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for Footnotes<'a, I> {
} }
} }
const DEF_OUNIT: libc::size_t = 64;
const HOEDOWN_EXT_NO_INTRA_EMPHASIS: libc::c_uint = 1 << 11;
const HOEDOWN_EXT_TABLES: libc::c_uint = 1 << 0;
const HOEDOWN_EXT_FENCED_CODE: libc::c_uint = 1 << 1;
const HOEDOWN_EXT_AUTOLINK: libc::c_uint = 1 << 3;
const HOEDOWN_EXT_STRIKETHROUGH: libc::c_uint = 1 << 4;
const HOEDOWN_EXT_SUPERSCRIPT: libc::c_uint = 1 << 8;
const HOEDOWN_EXT_FOOTNOTES: libc::c_uint = 1 << 2;
const HOEDOWN_EXTENSIONS: libc::c_uint =
HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES |
HOEDOWN_EXT_FENCED_CODE | HOEDOWN_EXT_AUTOLINK |
HOEDOWN_EXT_STRIKETHROUGH | HOEDOWN_EXT_SUPERSCRIPT |
HOEDOWN_EXT_FOOTNOTES;
enum hoedown_document {}
type blockcodefn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
*const hoedown_buffer, *const hoedown_renderer_data,
libc::size_t);
type blockquotefn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
*const hoedown_renderer_data, libc::size_t);
type headerfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
libc::c_int, *const hoedown_renderer_data,
libc::size_t);
type blockhtmlfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
*const hoedown_renderer_data, libc::size_t);
type codespanfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
*const hoedown_renderer_data, libc::size_t) -> libc::c_int;
type linkfn = extern "C" fn (*mut hoedown_buffer, *const hoedown_buffer,
*const hoedown_buffer, *const hoedown_buffer,
*const hoedown_renderer_data, libc::size_t) -> libc::c_int;
type entityfn = extern "C" fn (*mut hoedown_buffer, *const hoedown_buffer,
*const hoedown_renderer_data, libc::size_t);
type normaltextfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
*const hoedown_renderer_data, libc::size_t);
#[repr(C)]
struct hoedown_renderer_data {
opaque: *mut libc::c_void,
}
#[repr(C)]
struct hoedown_renderer {
opaque: *mut libc::c_void,
blockcode: Option<blockcodefn>,
blockquote: Option<blockquotefn>,
header: Option<headerfn>,
other_block_level_callbacks: [libc::size_t; 11],
blockhtml: Option<blockhtmlfn>,
/* span level callbacks - NULL or return 0 prints the span verbatim */
autolink: libc::size_t, // unused
codespan: Option<codespanfn>,
other_span_level_callbacks_1: [libc::size_t; 7],
link: Option<linkfn>,
other_span_level_callbacks_2: [libc::size_t; 6],
/* low level callbacks - NULL copies input directly into the output */
entity: Option<entityfn>,
normal_text: Option<normaltextfn>,
/* header and footer */
other_callbacks: [libc::size_t; 2],
}
#[repr(C)]
struct hoedown_html_renderer_state {
opaque: *mut libc::c_void,
toc_data: html_toc_data,
flags: libc::c_uint,
link_attributes: Option<extern "C" fn(*mut hoedown_buffer,
*const hoedown_buffer,
*const hoedown_renderer_data)>,
}
#[repr(C)]
struct html_toc_data {
header_count: libc::c_int,
current_level: libc::c_int,
level_offset: libc::c_int,
nesting_level: libc::c_int,
}
#[repr(C)]
struct hoedown_buffer {
data: *const u8,
size: libc::size_t,
asize: libc::size_t,
unit: libc::size_t,
}
extern {
fn hoedown_html_renderer_new(render_flags: libc::c_uint,
nesting_level: libc::c_int)
-> *mut hoedown_renderer;
fn hoedown_html_renderer_free(renderer: *mut hoedown_renderer);
fn hoedown_document_new(rndr: *const hoedown_renderer,
extensions: libc::c_uint,
max_nesting: libc::size_t) -> *mut hoedown_document;
fn hoedown_document_render(doc: *mut hoedown_document,
ob: *mut hoedown_buffer,
document: *const u8,
doc_size: libc::size_t);
fn hoedown_document_free(md: *mut hoedown_document);
fn hoedown_buffer_new(unit: libc::size_t) -> *mut hoedown_buffer;
fn hoedown_buffer_free(b: *mut hoedown_buffer);
}
impl hoedown_buffer {
fn as_bytes(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.data, self.size as usize) }
}
}
pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) {
extern fn block(_ob: *mut hoedown_buffer,
text: *const hoedown_buffer,
lang: *const hoedown_buffer,
data: *const hoedown_renderer_data,
line: libc::size_t) {
unsafe {
if text.is_null() { return }
let block_info = if lang.is_null() {
LangString::all_false()
} else {
let lang = (*lang).as_bytes();
let s = str::from_utf8(lang).unwrap();
LangString::parse(s)
};
if !block_info.rust { return }
let opaque = (*data).opaque as *mut hoedown_html_renderer_state;
let tests = &mut *((*opaque).opaque as *mut ::test::Collector);
let line = tests.get_line() + line;
let filename = tests.get_filename();
tests.add_old_test(line, filename);
}
}
extern fn header(_ob: *mut hoedown_buffer,
text: *const hoedown_buffer,
level: libc::c_int, data: *const hoedown_renderer_data,
_: libc::size_t) {
unsafe {
let opaque = (*data).opaque as *mut hoedown_html_renderer_state;
let tests = &mut *((*opaque).opaque as *mut ::test::Collector);
if text.is_null() {
tests.register_header("", level as u32);
} else {
let text = (*text).as_bytes();
let text = str::from_utf8(text).unwrap();
tests.register_header(text, level as u32);
}
}
}
tests.set_position(position);
unsafe {
let ob = hoedown_buffer_new(DEF_OUNIT);
let renderer = hoedown_html_renderer_new(0, 0);
(*renderer).blockcode = Some(block);
(*renderer).header = Some(header);
(*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque
= tests as *mut _ as *mut libc::c_void;
let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16);
hoedown_document_render(document, ob, doc.as_ptr(),
doc.len() as libc::size_t);
hoedown_document_free(document);
hoedown_html_renderer_free(renderer);
hoedown_buffer_free(ob);
}
}
pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) { pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) {
tests.set_position(position); tests.set_position(position);

View file

@ -2430,7 +2430,7 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
}).peekable(); }).peekable();
if let doctree::Plain = s.struct_type { if let doctree::Plain = s.struct_type {
if fields.peek().is_some() { if fields.peek().is_some() {
write!(w, "<h2 class='fields'>Fields</h2>")?; write!(w, "<h2 id='fields' class='fields'>Fields</h2>")?;
for (field, ty) in fields { for (field, ty) in fields {
let id = derive_id(format!("{}.{}", let id = derive_id(format!("{}.{}",
ItemType::StructField, ItemType::StructField,
@ -2478,7 +2478,7 @@ fn item_union(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
} }
}).peekable(); }).peekable();
if fields.peek().is_some() { if fields.peek().is_some() {
write!(w, "<h2 class='fields'>Fields</h2>")?; write!(w, "<h2 id='fields' class='fields'>Fields</h2>")?;
for (field, ty) in fields { for (field, ty) in fields {
write!(w, "<span id='{shortty}.{name}' class=\"{shortty}\"><code>{name}: {ty}</code> write!(w, "<span id='{shortty}.{name}' class=\"{shortty}\"><code>{name}: {ty}</code>
</span>", </span>",
@ -2550,7 +2550,7 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
document(w, cx, it)?; document(w, cx, it)?;
if !e.variants.is_empty() { if !e.variants.is_empty() {
write!(w, "<h2 class='variants'>Variants</h2>\n")?; write!(w, "<h2 id='variants' class='variants'>Variants</h2>\n")?;
for variant in &e.variants { for variant in &e.variants {
let id = derive_id(format!("{}.{}", let id = derive_id(format!("{}.{}",
ItemType::Variant, ItemType::Variant,
@ -3074,6 +3074,37 @@ impl<'a> fmt::Display for Sidebar<'a> {
let it = self.item; let it = self.item;
let parentlen = cx.current.len() - if it.is_mod() {1} else {0}; let parentlen = cx.current.len() - if it.is_mod() {1} else {0};
if it.is_struct() || it.is_trait() || it.is_primitive() || it.is_union()
|| it.is_enum() || it.is_mod()
{
write!(fmt, "<p class='location'>")?;
match it.inner {
clean::StructItem(..) => write!(fmt, "Struct ")?,
clean::TraitItem(..) => write!(fmt, "Trait ")?,
clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?,
clean::UnionItem(..) => write!(fmt, "Union ")?,
clean::EnumItem(..) => write!(fmt, "Enum ")?,
clean::ModuleItem(..) => if it.is_crate() {
write!(fmt, "Crate ")?;
} else {
write!(fmt, "Module ")?;
},
_ => (),
}
write!(fmt, "{}", it.name.as_ref().unwrap())?;
write!(fmt, "</p>")?;
match it.inner {
clean::StructItem(ref s) => sidebar_struct(fmt, it, s)?,
clean::TraitItem(ref t) => sidebar_trait(fmt, it, t)?,
clean::PrimitiveItem(ref p) => sidebar_primitive(fmt, it, p)?,
clean::UnionItem(ref u) => sidebar_union(fmt, it, u)?,
clean::EnumItem(ref e) => sidebar_enum(fmt, it, e)?,
clean::ModuleItem(ref m) => sidebar_module(fmt, it, &m.items)?,
_ => (),
}
}
// The sidebar is designed to display sibling functions, modules and // The sidebar is designed to display sibling functions, modules and
// other miscellaneous information. since there are lots of sibling // other miscellaneous information. since there are lots of sibling
// items (and that causes quadratic growth in large modules), // items (and that causes quadratic growth in large modules),
@ -3116,6 +3147,193 @@ impl<'a> fmt::Display for Sidebar<'a> {
} }
} }
fn sidebar_assoc_items(it: &clean::Item) -> String {
let mut out = String::new();
let c = cache();
if let Some(v) = c.impls.get(&it.def_id) {
if v.iter().any(|i| i.inner_impl().trait_.is_none()) {
out.push_str("<li><a href=\"#methods\">Methods</a></li>");
}
if v.iter().any(|i| i.inner_impl().trait_.is_some()) {
if let Some(impl_) = v.iter()
.filter(|i| i.inner_impl().trait_.is_some())
.find(|i| i.inner_impl().trait_.def_id() == c.deref_trait_did) {
if let Some(target) = impl_.inner_impl().items.iter().filter_map(|item| {
match item.inner {
clean::TypedefItem(ref t, true) => Some(&t.type_),
_ => None,
}
}).next() {
let inner_impl = target.def_id().or(target.primitive_type().and_then(|prim| {
c.primitive_locations.get(&prim).cloned()
})).and_then(|did| c.impls.get(&did));
if inner_impl.is_some() {
out.push_str("<li><a href=\"#deref-methods\">");
out.push_str(&format!("Methods from {:#}&lt;Target={:#}&gt;",
impl_.inner_impl().trait_.as_ref().unwrap(),
target));
out.push_str("</a></li>");
}
}
}
out.push_str("<li><a href=\"#implementations\">Trait Implementations</a></li>");
}
}
out
}
fn sidebar_struct(fmt: &mut fmt::Formatter, it: &clean::Item,
s: &clean::Struct) -> fmt::Result {
let mut sidebar = String::new();
if s.fields.iter()
.any(|f| if let clean::StructFieldItem(..) = f.inner { true } else { false }) {
if let doctree::Plain = s.struct_type {
sidebar.push_str("<li><a href=\"#fields\">Fields</a></li>");
}
}
sidebar.push_str(&sidebar_assoc_items(it));
if !sidebar.is_empty() {
write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
}
Ok(())
}
fn sidebar_trait(fmt: &mut fmt::Formatter, it: &clean::Item,
t: &clean::Trait) -> fmt::Result {
let mut sidebar = String::new();
let has_types = t.items.iter().any(|m| m.is_associated_type());
let has_consts = t.items.iter().any(|m| m.is_associated_const());
let has_required = t.items.iter().any(|m| m.is_ty_method());
let has_provided = t.items.iter().any(|m| m.is_method());
if has_types {
sidebar.push_str("<li><a href=\"#associated-types\">Associated Types</a></li>");
}
if has_consts {
sidebar.push_str("<li><a href=\"#associated-const\">Associated Constants</a></li>");
}
if has_required {
sidebar.push_str("<li><a href=\"#required-methods\">Required Methods</a></li>");
}
if has_provided {
sidebar.push_str("<li><a href=\"#provided-methods\">Provided Methods</a></li>");
}
sidebar.push_str(&sidebar_assoc_items(it));
sidebar.push_str("<li><a href=\"#implementors\">Implementors</a></li>");
write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)
}
fn sidebar_primitive(fmt: &mut fmt::Formatter, it: &clean::Item,
_p: &clean::PrimitiveType) -> fmt::Result {
let sidebar = sidebar_assoc_items(it);
if !sidebar.is_empty() {
write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
}
Ok(())
}
fn sidebar_union(fmt: &mut fmt::Formatter, it: &clean::Item,
u: &clean::Union) -> fmt::Result {
let mut sidebar = String::new();
if u.fields.iter()
.any(|f| if let clean::StructFieldItem(..) = f.inner { true } else { false }) {
sidebar.push_str("<li><a href=\"#fields\">Fields</a></li>");
}
sidebar.push_str(&sidebar_assoc_items(it));
if !sidebar.is_empty() {
write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
}
Ok(())
}
fn sidebar_enum(fmt: &mut fmt::Formatter, it: &clean::Item,
e: &clean::Enum) -> fmt::Result {
let mut sidebar = String::new();
if !e.variants.is_empty() {
sidebar.push_str("<li><a href=\"#variants\">Variants</a></li>");
}
sidebar.push_str(&sidebar_assoc_items(it));
if !sidebar.is_empty() {
write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
}
Ok(())
}
fn sidebar_module(fmt: &mut fmt::Formatter, _it: &clean::Item,
items: &[clean::Item]) -> fmt::Result {
let mut sidebar = String::new();
if items.iter().any(|it| it.type_() == ItemType::ExternCrate ||
it.type_() == ItemType::Import) {
sidebar.push_str(&format!("<li><a href=\"#{id}\">{name}</a></li>",
id = "reexports",
name = "Reexports"));
}
// ordering taken from item_module, reorder, where it prioritized elements in a certain order
// to print its headings
for &myty in &[ItemType::Primitive, ItemType::Module, ItemType::Macro, ItemType::Struct,
ItemType::Enum, ItemType::Constant, ItemType::Static, ItemType::Trait,
ItemType::Function, ItemType::Typedef, ItemType::Union, ItemType::Impl,
ItemType::TyMethod, ItemType::Method, ItemType::StructField, ItemType::Variant,
ItemType::AssociatedType, ItemType::AssociatedConst] {
if items.iter().any(|it| {
if let clean::DefaultImplItem(..) = it.inner {
false
} else {
!maybe_ignore_item(it) && !it.is_stripped() && it.type_() == myty
}
}) {
let (short, name) = match myty {
ItemType::ExternCrate |
ItemType::Import => ("reexports", "Reexports"),
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"),
};
sidebar.push_str(&format!("<li><a href=\"#{id}\">{name}</a></li>",
id = short,
name = name));
}
}
if !sidebar.is_empty() {
write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
}
Ok(())
}
impl<'a> fmt::Display for Source<'a> { impl<'a> fmt::Display for Source<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let Source(s) = *self; let Source(s) = *self;

View file

@ -25,7 +25,7 @@ use externalfiles::{ExternalHtml, LoadStringError, load_string};
use html::render::reset_ids; use html::render::reset_ids;
use html::escape::Escape; use html::escape::Escape;
use html::markdown; use html::markdown;
use html::markdown::{Markdown, MarkdownWithToc, find_testable_code}; use html::markdown::{Markdown, MarkdownWithToc, find_testable_code, old_find_testable_code};
use test::{TestOptions, Collector}; use test::{TestOptions, Collector};
/// Separate any lines at the start of the file that begin with `# ` or `%`. /// Separate any lines at the start of the file that begin with `# ` or `%`.
@ -159,6 +159,7 @@ pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
let mut collector = Collector::new(input.to_string(), cfgs, libs, externs, let mut collector = Collector::new(input.to_string(), cfgs, libs, externs,
true, opts, maybe_sysroot, None, true, opts, maybe_sysroot, None,
Some(input.to_owned())); Some(input.to_owned()));
old_find_testable_code(&input_str, &mut collector, DUMMY_SP);
find_testable_code(&input_str, &mut collector, DUMMY_SP); find_testable_code(&input_str, &mut collector, DUMMY_SP);
test_args.insert(0, "rustdoctest".to_string()); test_args.insert(0, "rustdoctest".to_string());
testing::test_main(&test_args, collector.tests); testing::test_main(&test_args, collector.tests);

View file

@ -380,6 +380,8 @@ fn partition_source(s: &str) -> (String, String) {
pub struct Collector { pub struct Collector {
pub tests: Vec<testing::TestDescAndFn>, pub tests: Vec<testing::TestDescAndFn>,
// to be removed when hoedown will be definitely gone
pub old_tests: Vec<String>,
names: Vec<String>, names: Vec<String>,
cfgs: Vec<String>, cfgs: Vec<String>,
libs: SearchPaths, libs: SearchPaths,
@ -401,6 +403,7 @@ impl Collector {
codemap: Option<Rc<CodeMap>>, filename: Option<String>) -> Collector { codemap: Option<Rc<CodeMap>>, filename: Option<String>) -> Collector {
Collector { Collector {
tests: Vec::new(), tests: Vec::new(),
old_tests: Vec::new(),
names: Vec::new(), names: Vec::new(),
cfgs: cfgs, cfgs: cfgs,
libs: libs, libs: libs,
@ -417,11 +420,8 @@ impl Collector {
} }
} }
pub fn add_test(&mut self, test: String, fn generate_name(&self, line: usize, filename: &str) -> String {
should_panic: bool, no_run: bool, should_ignore: bool, if self.use_headers {
as_test_harness: bool, compile_fail: bool, error_codes: Vec<String>,
line: usize, filename: String) {
let name = if self.use_headers {
if let Some(ref header) = self.current_header { if let Some(ref header) = self.current_header {
format!("{} - {} (line {})", filename, header, line) format!("{} - {} (line {})", filename, header, line)
} else { } else {
@ -429,7 +429,27 @@ impl Collector {
} }
} else { } else {
format!("{} - {} (line {})", filename, self.names.join("::"), line) format!("{} - {} (line {})", filename, self.names.join("::"), line)
}; }
}
pub fn add_old_test(&mut self, line: usize, filename: String) {
let name = self.generate_name(line, &filename);
self.old_tests.push(name);
}
pub fn add_test(&mut self, test: String,
should_panic: bool, no_run: bool, should_ignore: bool,
as_test_harness: bool, compile_fail: bool, error_codes: Vec<String>,
line: usize, filename: String) {
let name = self.generate_name(line, &filename);
if self.old_tests.iter().find(|&x| x == &name).is_none() {
let _ = writeln!(&mut io::stderr(),
"WARNING: {} Code block is not currently run as a test, but will in \
future versions of rustdoc. Please ensure this code block is a \
runnable test, or use the `ignore` directive.",
name);
return
}
let cfgs = self.cfgs.clone(); let cfgs = self.cfgs.clone();
let libs = self.libs.clone(); let libs = self.libs.clone();
let externs = self.externs.clone(); let externs = self.externs.clone();
@ -544,6 +564,8 @@ impl<'a, 'hir> HirCollector<'a, 'hir> {
attrs.unindent_doc_comments(); attrs.unindent_doc_comments();
if let Some(doc) = attrs.doc_value() { if let Some(doc) = attrs.doc_value() {
self.collector.cnt = 0; self.collector.cnt = 0;
markdown::old_find_testable_code(doc, self.collector,
attrs.span.unwrap_or(DUMMY_SP));
markdown::find_testable_code(doc, self.collector, markdown::find_testable_code(doc, self.collector,
attrs.span.unwrap_or(DUMMY_SP)); attrs.span.unwrap_or(DUMMY_SP));
} }

View file

@ -529,6 +529,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
token::NtPath(panictry!(p.parse_path(PathStyle::Type))) token::NtPath(panictry!(p.parse_path(PathStyle::Type)))
}, },
"meta" => token::NtMeta(panictry!(p.parse_meta_item())), "meta" => token::NtMeta(panictry!(p.parse_meta_item())),
"vis" => token::NtVis(panictry!(p.parse_visibility(true))),
// this is not supposed to happen, since it has been checked // this is not supposed to happen, since it has been checked
// when compiling the macro. // when compiling the macro.
_ => p.span_bug(sp, "invalid fragment specifier") _ => p.span_bug(sp, "invalid fragment specifier")

View file

@ -18,6 +18,7 @@ use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
use ext::tt::macro_parser::{parse, parse_failure_msg}; use ext::tt::macro_parser::{parse, parse_failure_msg};
use ext::tt::quoted; use ext::tt::quoted;
use ext::tt::transcribe::transcribe; use ext::tt::transcribe::transcribe;
use feature_gate::{self, emit_feature_err, Features, GateIssue};
use parse::{Directory, ParseSess}; use parse::{Directory, ParseSess};
use parse::parser::Parser; use parse::parser::Parser;
use parse::token::{self, NtTT}; use parse::token::{self, NtTT};
@ -25,6 +26,7 @@ use parse::token::Token::*;
use symbol::Symbol; use symbol::Symbol;
use tokenstream::{TokenStream, TokenTree}; use tokenstream::{TokenStream, TokenTree};
use std::cell::RefCell;
use std::collections::{HashMap}; use std::collections::{HashMap};
use std::collections::hash_map::{Entry}; use std::collections::hash_map::{Entry};
use std::rc::Rc; use std::rc::Rc;
@ -154,7 +156,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
// Holy self-referential! // Holy self-referential!
/// Converts a `macro_rules!` invocation into a syntax extension. /// Converts a `macro_rules!` invocation into a syntax extension.
pub fn compile(sess: &ParseSess, def: &ast::Item) -> SyntaxExtension { pub fn compile(sess: &ParseSess, features: &RefCell<Features>, def: &ast::Item) -> SyntaxExtension {
let lhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("lhs")); let lhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("lhs"));
let rhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("rhs")); let rhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("rhs"));
@ -208,7 +210,7 @@ pub fn compile(sess: &ParseSess, def: &ast::Item) -> SyntaxExtension {
if let MatchedNonterminal(ref nt) = **m { if let MatchedNonterminal(ref nt) = **m {
if let NtTT(ref tt) = **nt { if let NtTT(ref tt) = **nt {
let tt = quoted::parse(tt.clone().into(), true, sess).pop().unwrap(); let tt = quoted::parse(tt.clone().into(), true, sess).pop().unwrap();
valid &= check_lhs_nt_follows(sess, &tt); valid &= check_lhs_nt_follows(sess, features, &tt);
return tt; return tt;
} }
} }
@ -251,11 +253,13 @@ pub fn compile(sess: &ParseSess, def: &ast::Item) -> SyntaxExtension {
NormalTT(exp, Some(def.span), attr::contains_name(&def.attrs, "allow_internal_unstable")) NormalTT(exp, Some(def.span), attr::contains_name(&def.attrs, "allow_internal_unstable"))
} }
fn check_lhs_nt_follows(sess: &ParseSess, lhs: &quoted::TokenTree) -> bool { fn check_lhs_nt_follows(sess: &ParseSess,
features: &RefCell<Features>,
lhs: &quoted::TokenTree) -> bool {
// lhs is going to be like TokenTree::Delimited(...), where the // lhs is going to be like TokenTree::Delimited(...), where the
// entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens. // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
match lhs { match lhs {
&quoted::TokenTree::Delimited(_, ref tts) => check_matcher(sess, &tts.tts), &quoted::TokenTree::Delimited(_, ref tts) => check_matcher(sess, features, &tts.tts),
_ => { _ => {
let msg = "invalid macro matcher; matchers must be contained in balanced delimiters"; let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
sess.span_diagnostic.span_err(lhs.span(), msg); sess.span_diagnostic.span_err(lhs.span(), msg);
@ -307,11 +311,13 @@ fn check_rhs(sess: &ParseSess, rhs: &quoted::TokenTree) -> bool {
false false
} }
fn check_matcher(sess: &ParseSess, matcher: &[quoted::TokenTree]) -> bool { fn check_matcher(sess: &ParseSess,
features: &RefCell<Features>,
matcher: &[quoted::TokenTree]) -> bool {
let first_sets = FirstSets::new(matcher); let first_sets = FirstSets::new(matcher);
let empty_suffix = TokenSet::empty(); let empty_suffix = TokenSet::empty();
let err = sess.span_diagnostic.err_count(); let err = sess.span_diagnostic.err_count();
check_matcher_core(sess, &first_sets, matcher, &empty_suffix); check_matcher_core(sess, features, &first_sets, matcher, &empty_suffix);
err == sess.span_diagnostic.err_count() err == sess.span_diagnostic.err_count()
} }
@ -553,6 +559,7 @@ impl TokenSet {
// Requires that `first_sets` is pre-computed for `matcher`; // Requires that `first_sets` is pre-computed for `matcher`;
// see `FirstSets::new`. // see `FirstSets::new`.
fn check_matcher_core(sess: &ParseSess, fn check_matcher_core(sess: &ParseSess,
features: &RefCell<Features>,
first_sets: &FirstSets, first_sets: &FirstSets,
matcher: &[quoted::TokenTree], matcher: &[quoted::TokenTree],
follow: &TokenSet) -> TokenSet { follow: &TokenSet) -> TokenSet {
@ -583,12 +590,11 @@ fn check_matcher_core(sess: &ParseSess,
match *token { match *token {
TokenTree::Token(..) | TokenTree::MetaVarDecl(..) => { TokenTree::Token(..) | TokenTree::MetaVarDecl(..) => {
let can_be_followed_by_any; let can_be_followed_by_any;
if let Err(bad_frag) = has_legal_fragment_specifier(token) { if let Err(bad_frag) = has_legal_fragment_specifier(sess, features, token) {
let msg = format!("invalid fragment specifier `{}`", bad_frag); let msg = format!("invalid fragment specifier `{}`", bad_frag);
sess.span_diagnostic.struct_span_err(token.span(), &msg) sess.span_diagnostic.struct_span_err(token.span(), &msg)
.help("valid fragment specifiers are `ident`, `block`, \ .help("valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, \
`stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \ `pat`, `ty`, `path`, `meta`, `tt`, `item` and `vis`")
and `item`")
.emit(); .emit();
// (This eliminates false positives and duplicates // (This eliminates false positives and duplicates
// from error messages.) // from error messages.)
@ -610,7 +616,7 @@ fn check_matcher_core(sess: &ParseSess,
} }
TokenTree::Delimited(span, ref d) => { TokenTree::Delimited(span, ref d) => {
let my_suffix = TokenSet::singleton(d.close_tt(span)); let my_suffix = TokenSet::singleton(d.close_tt(span));
check_matcher_core(sess, first_sets, &d.tts, &my_suffix); check_matcher_core(sess, features, first_sets, &d.tts, &my_suffix);
// don't track non NT tokens // don't track non NT tokens
last.replace_with_irrelevant(); last.replace_with_irrelevant();
@ -642,7 +648,7 @@ fn check_matcher_core(sess: &ParseSess,
// At this point, `suffix_first` is built, and // At this point, `suffix_first` is built, and
// `my_suffix` is some TokenSet that we can use // `my_suffix` is some TokenSet that we can use
// for checking the interior of `seq_rep`. // for checking the interior of `seq_rep`.
let next = check_matcher_core(sess, first_sets, &seq_rep.tts, my_suffix); let next = check_matcher_core(sess, features, first_sets, &seq_rep.tts, my_suffix);
if next.maybe_empty { if next.maybe_empty {
last.add_all(&next); last.add_all(&next);
} else { } else {
@ -790,30 +796,61 @@ fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> Result<bool, (String, &'
// harmless // harmless
Ok(true) Ok(true)
}, },
"vis" => {
// Explicitly disallow `priv`, on the off chance it comes back.
match *tok {
TokenTree::Token(_, ref tok) => match *tok {
Comma => Ok(true),
Ident(i) if i.name != "priv" => Ok(true),
ref tok => Ok(tok.can_begin_type())
},
TokenTree::MetaVarDecl(_, _, frag) if frag.name == "ident"
|| frag.name == "ty"
|| frag.name == "path" => Ok(true),
_ => Ok(false)
}
},
"" => Ok(true), // keywords::Invalid "" => Ok(true), // keywords::Invalid
_ => Err((format!("invalid fragment specifier `{}`", frag), _ => Err((format!("invalid fragment specifier `{}`", frag),
"valid fragment specifiers are `ident`, `block`, \ "valid fragment specifiers are `ident`, `block`, \
`stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \ `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt`, \
and `item`")) `item` and `vis`"))
} }
} }
} }
fn has_legal_fragment_specifier(tok: &quoted::TokenTree) -> Result<(), String> { fn has_legal_fragment_specifier(sess: &ParseSess,
features: &RefCell<Features>,
tok: &quoted::TokenTree) -> Result<(), String> {
debug!("has_legal_fragment_specifier({:?})", tok); debug!("has_legal_fragment_specifier({:?})", tok);
if let quoted::TokenTree::MetaVarDecl(_, _, frag_spec) = *tok { if let quoted::TokenTree::MetaVarDecl(_, _, ref frag_spec) = *tok {
let s = &frag_spec.name.as_str(); let frag_name = frag_spec.name.as_str();
if !is_legal_fragment_specifier(s) { let frag_span = tok.span();
return Err(s.to_string()); if !is_legal_fragment_specifier(sess, features, &frag_name, frag_span) {
return Err(frag_name.to_string());
} }
} }
Ok(()) Ok(())
} }
fn is_legal_fragment_specifier(frag: &str) -> bool { fn is_legal_fragment_specifier(sess: &ParseSess,
match frag { features: &RefCell<Features>,
frag_name: &str,
frag_span: Span) -> bool {
match frag_name {
"item" | "block" | "stmt" | "expr" | "pat" | "item" | "block" | "stmt" | "expr" | "pat" |
"path" | "ty" | "ident" | "meta" | "tt" | "" => true, "path" | "ty" | "ident" | "meta" | "tt" | "" => true,
"vis" => {
if !features.borrow().macro_vis_matcher {
let explain = feature_gate::EXPLAIN_VIS_MATCHER;
emit_feature_err(sess,
"macro_vis_matcher",
frag_span,
GateIssue::Language,
explain);
}
true
},
_ => false, _ => false,
} }
} }

View file

@ -352,6 +352,9 @@ declare_features! (
// Allows overlapping impls of marker traits // Allows overlapping impls of marker traits
(active, overlapping_marker_traits, "1.18.0", Some(29864)), (active, overlapping_marker_traits, "1.18.0", Some(29864)),
// Allows use of the :vis macro fragment specifier
(active, macro_vis_matcher, "1.18.0", Some(41022)),
); );
declare_features! ( declare_features! (
@ -1012,6 +1015,9 @@ pub const EXPLAIN_DEPR_CUSTOM_DERIVE: &'static str =
pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str = pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
"attributes of the form `#[derive_*]` are reserved for the compiler"; "attributes of the form `#[derive_*]` are reserved for the compiler";
pub const EXPLAIN_VIS_MATCHER: &'static str =
":vis fragment specifier is experimental and subject to change";
pub const EXPLAIN_PLACEMENT_IN: &'static str = pub const EXPLAIN_PLACEMENT_IN: &'static str =
"placement-in expression syntax is experimental and subject to change."; "placement-in expression syntax is experimental and subject to change.";

View file

@ -636,6 +636,7 @@ pub fn noop_fold_interpolated<T: Folder>(nt: token::Nonterminal, fld: &mut T)
token::NtWhereClause(where_clause) => token::NtWhereClause(where_clause) =>
token::NtWhereClause(fld.fold_where_clause(where_clause)), token::NtWhereClause(fld.fold_where_clause(where_clause)),
token::NtArg(arg) => token::NtArg(fld.fold_arg(arg)), token::NtArg(arg) => token::NtArg(fld.fold_arg(arg)),
token::NtVis(vis) => token::NtVis(fld.fold_vis(vis)),
} }
} }

View file

@ -5056,7 +5056,9 @@ impl<'a> Parser<'a> {
/// and `pub(super)` for `pub(in super)`. If the following element can't be a tuple (i.e. it's /// and `pub(super)` for `pub(in super)`. If the following element can't be a tuple (i.e. it's
/// a function definition, it's not a tuple struct field) and the contents within the parens /// a function definition, it's not a tuple struct field) and the contents within the parens
/// isn't valid, emit a proper diagnostic. /// isn't valid, emit a proper diagnostic.
fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> { pub fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> {
maybe_whole!(self, NtVis, |x| x);
if !self.eat_keyword(keywords::Pub) { if !self.eat_keyword(keywords::Pub) {
return Ok(Visibility::Inherited) return Ok(Visibility::Inherited)
} }

View file

@ -363,6 +363,7 @@ pub enum Nonterminal {
/// Stuff inside brackets for attributes /// Stuff inside brackets for attributes
NtMeta(ast::MetaItem), NtMeta(ast::MetaItem),
NtPath(ast::Path), NtPath(ast::Path),
NtVis(ast::Visibility),
NtTT(TokenTree), NtTT(TokenTree),
// These are not exposed to macros, but are used by quasiquote. // These are not exposed to macros, but are used by quasiquote.
NtArm(ast::Arm), NtArm(ast::Arm),
@ -392,6 +393,7 @@ impl fmt::Debug for Nonterminal {
NtGenerics(..) => f.pad("NtGenerics(..)"), NtGenerics(..) => f.pad("NtGenerics(..)"),
NtWhereClause(..) => f.pad("NtWhereClause(..)"), NtWhereClause(..) => f.pad("NtWhereClause(..)"),
NtArg(..) => f.pad("NtArg(..)"), NtArg(..) => f.pad("NtArg(..)"),
NtVis(..) => f.pad("NtVis(..)"),
} }
} }
} }

View file

@ -293,6 +293,7 @@ pub fn token_to_string(tok: &Token) -> String {
token::NtGenerics(ref e) => generics_to_string(&e), token::NtGenerics(ref e) => generics_to_string(&e),
token::NtWhereClause(ref e) => where_clause_to_string(&e), token::NtWhereClause(ref e) => where_clause_to_string(&e),
token::NtArg(ref e) => arg_to_string(&e), token::NtArg(ref e) => arg_to_string(&e),
token::NtVis(ref e) => vis_to_string(&e),
} }
} }
} }
@ -373,6 +374,10 @@ pub fn ident_to_string(id: ast::Ident) -> String {
to_string(|s| s.print_ident(id)) to_string(|s| s.print_ident(id))
} }
pub fn vis_to_string(v: &ast::Visibility) -> String {
to_string(|s| s.print_visibility(v))
}
pub fn fun_to_string(decl: &ast::FnDecl, pub fn fun_to_string(decl: &ast::FnDecl,
unsafety: ast::Unsafety, unsafety: ast::Unsafety,
constness: ast::Constness, constness: ast::Constness,
@ -427,13 +432,7 @@ pub fn mac_to_string(arg: &ast::Mac) -> String {
} }
pub fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String { pub fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
match *vis { format!("{}{}", to_string(|s| s.print_visibility(vis)), s)
ast::Visibility::Public => format!("pub {}", s),
ast::Visibility::Crate(_) => format!("pub(crate) {}", s),
ast::Visibility::Restricted { ref path, .. } =>
format!("pub({}) {}", to_string(|s| s.print_path(path, false, 0, true)), s),
ast::Visibility::Inherited => s.to_string()
}
} }
fn needs_parentheses(expr: &ast::Expr) -> bool { fn needs_parentheses(expr: &ast::Expr) -> bool {
@ -1468,7 +1467,11 @@ impl<'a> State<'a> {
ast::Visibility::Crate(_) => self.word_nbsp("pub(crate)"), ast::Visibility::Crate(_) => self.word_nbsp("pub(crate)"),
ast::Visibility::Restricted { ref path, .. } => { ast::Visibility::Restricted { ref path, .. } => {
let path = to_string(|s| s.print_path(path, false, 0, true)); let path = to_string(|s| s.print_path(path, false, 0, true));
self.word_nbsp(&format!("pub({})", path)) if path == "self" || path == "super" {
self.word_nbsp(&format!("pub({})", path))
} else {
self.word_nbsp(&format!("pub(in {})", path))
}
} }
ast::Visibility::Inherited => Ok(()) ast::Visibility::Inherited => Ok(())
} }

1
src/rt/hoedown Submodule

@ -0,0 +1 @@
Subproject commit da282f1bb7277b4d30fa1599ee29ad8eb4dd2a92

View file

@ -0,0 +1,19 @@
// Copyright 2017 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.
// Test that the MSP430 interrupt ABI cannot be used when msp430_interrupt
// feature gate is not used.
macro_rules! m { ($v:vis) => {} }
//~^ ERROR :vis fragment specifier is experimental and subject to change
fn main() {
m!(pub);
}

View file

@ -0,0 +1,115 @@
// Copyright 2017 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.
#![allow(dead_code, unused_imports)]
#![feature(macro_vis_matcher)]
/**
Ensure that `:vis` matches can be captured in existing positions, and passed
through without the need for reparse tricks.
*/
macro_rules! vis_passthru {
($vis:vis const $name:ident: $ty:ty = $e:expr;) => { $vis const $name: $ty = $e; };
($vis:vis enum $name:ident {}) => { $vis struct $name {} };
($vis:vis extern "C" fn $name:ident() {}) => { $vis extern "C" fn $name() {} };
($vis:vis fn $name:ident() {}) => { $vis fn $name() {} };
($vis:vis mod $name:ident {}) => { $vis mod $name {} };
($vis:vis static $name:ident: $ty:ty = $e:expr;) => { $vis static $name: $ty = $e; };
($vis:vis struct $name:ident;) => { $vis struct $name; };
($vis:vis trait $name:ident {}) => { $vis trait $name {} };
($vis:vis type $name:ident = $ty:ty;) => { $vis type $name = $ty; };
($vis:vis use $path:ident as $name:ident;) => { $vis use self::$path as $name; };
}
mod with_pub {
vis_passthru! { pub const A: i32 = 0; }
vis_passthru! { pub enum B {} }
vis_passthru! { pub extern "C" fn c() {} }
vis_passthru! { pub mod d {} }
vis_passthru! { pub static E: i32 = 0; }
vis_passthru! { pub struct F; }
vis_passthru! { pub trait G {} }
vis_passthru! { pub type H = i32; }
vis_passthru! { pub use A as I; }
}
mod without_pub {
vis_passthru! { const A: i32 = 0; }
vis_passthru! { enum B {} }
vis_passthru! { extern "C" fn c() {} }
vis_passthru! { mod d {} }
vis_passthru! { static E: i32 = 0; }
vis_passthru! { struct F; }
vis_passthru! { trait G {} }
vis_passthru! { type H = i32; }
vis_passthru! { use A as I; }
}
mod with_pub_restricted {
vis_passthru! { pub(crate) const A: i32 = 0; }
vis_passthru! { pub(crate) enum B {} }
vis_passthru! { pub(crate) extern "C" fn c() {} }
vis_passthru! { pub(crate) mod d {} }
vis_passthru! { pub(crate) static E: i32 = 0; }
vis_passthru! { pub(crate) struct F; }
vis_passthru! { pub(crate) trait G {} }
vis_passthru! { pub(crate) type H = i32; }
vis_passthru! { pub(crate) use A as I; }
}
mod garden {
mod with_pub_restricted_path {
vis_passthru! { pub(in garden) const A: i32 = 0; }
vis_passthru! { pub(in garden) enum B {} }
vis_passthru! { pub(in garden) extern "C" fn c() {} }
vis_passthru! { pub(in garden) mod d {} }
vis_passthru! { pub(in garden) static E: i32 = 0; }
vis_passthru! { pub(in garden) struct F; }
vis_passthru! { pub(in garden) trait G {} }
vis_passthru! { pub(in garden) type H = i32; }
vis_passthru! { pub(in garden) use A as I; }
}
}
/*
Ensure that the `:vis` matcher works in a more complex situation: parsing a
struct definition.
*/
macro_rules! vis_parse_struct {
($(#[$($attrs:tt)*])* $vis:vis struct $name:ident {$($body:tt)*}) => {
vis_parse_struct! { @parse_fields $(#[$($attrs)*])*, $vis, $name, $($body)* }
};
($(#[$($attrs:tt)*])* $vis:vis struct $name:ident ($($body:tt)*);) => {
vis_parse_struct! { @parse_tuple $(#[$($attrs)*])*, $vis, $name, $($body)* }
};
(@parse_fields
$(#[$attrs:meta])*, $vis:vis, $name:ident, $($fvis:vis $fname:ident: $fty:ty),* $(,)*) => {
$(#[$attrs])* $vis struct $name { $($fvis $fname: $fty,)* }
};
(@parse_tuple
$(#[$attrs:meta])*, $vis:vis, $name:ident, $($fvis:vis $fty:ty),* $(,)*) => {
$(#[$attrs])* $vis struct $name ( $($fvis $fty,)* );
};
}
mod test_struct {
vis_parse_struct! { pub(crate) struct A { pub a: i32, b: i32, pub(crate) c: i32 } }
vis_parse_struct! { pub struct B { a: i32, pub(crate) b: i32, pub c: i32 } }
vis_parse_struct! { struct C { pub(crate) a: i32, pub b: i32, c: i32 } }
vis_parse_struct! { pub(crate) struct D (pub i32, i32, pub(crate) i32); }
vis_parse_struct! { pub struct E (i32, pub(crate) i32, pub i32); }
vis_parse_struct! { struct F (pub(crate) i32, pub i32, i32); }
}
fn main() {}

View file

@ -86,6 +86,7 @@ fn filter_dirs(path: &Path) -> bool {
"src/rust-installer", "src/rust-installer",
"src/liblibc", "src/liblibc",
"src/vendor", "src/vendor",
"src/rt/hoedown",
]; ];
skip.iter().any(|p| path.ends_with(p)) skip.iter().any(|p| path.ends_with(p))
} }