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:
commit
5516bcc458
24 changed files with 742 additions and 43 deletions
4
.gitmodules
vendored
4
.gitmodules
vendored
|
@ -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
|
||||||
|
|
22
COPYRIGHT
22
COPYRIGHT
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
|
|
14
src/doc/unstable-book/src/macro-vis-matcher.md
Normal file
14
src/doc/unstable-book/src/macro-vis-matcher.md
Normal 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
|
||||||
|
|
||||||
|
------------------------
|
|
@ -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, ¯o_def));
|
let ext = Rc::new(macro_rules::compile(&self.session.parse_sess,
|
||||||
|
&self.session.features,
|
||||||
|
¯o_def));
|
||||||
self.macro_map.insert(def_id, ext.clone());
|
self.macro_map.insert(def_id, ext.clone());
|
||||||
ext
|
ext
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
30
src/librustdoc/build.rs
Normal 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");
|
||||||
|
}
|
||||||
|
|
|
@ -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 }
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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 {:#}<Target={:#}>",
|
||||||
|
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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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: "ed::TokenTree) -> bool {
|
fn check_lhs_nt_follows(sess: &ParseSess,
|
||||||
|
features: &RefCell<Features>,
|
||||||
|
lhs: "ed::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 {
|
||||||
"ed::TokenTree::Delimited(_, ref tts) => check_matcher(sess, &tts.tts),
|
"ed::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: "ed::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: "ed::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: "ed::TokenTree) -> Result<(), String> {
|
fn has_legal_fragment_specifier(sess: &ParseSess,
|
||||||
|
features: &RefCell<Features>,
|
||||||
|
tok: "ed::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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.";
|
||||||
|
|
||||||
|
|
|
@ -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)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(..)"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
if path == "self" || path == "super" {
|
||||||
self.word_nbsp(&format!("pub({})", path))
|
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
1
src/rt/hoedown
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit da282f1bb7277b4d30fa1599ee29ad8eb4dd2a92
|
19
src/test/compile-fail/feature-gate-macro-vis-matcher.rs
Normal file
19
src/test/compile-fail/feature-gate-macro-vis-matcher.rs
Normal 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);
|
||||||
|
}
|
115
src/test/run-pass/macro-pub-matcher.rs
Normal file
115
src/test/run-pass/macro-pub-matcher.rs
Normal 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() {}
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue