Auto merge of #64751 - Centril:rollup-hpbmcfj, r=Centril

Rollup of 16 pull requests

Successful merges:

 - #63356 (Issue#63183: Add fs::read_dir() and ReadDir warning about iterator order + example)
 - #63934 (Fix coherence checking for impl trait in type aliases)
 - #64016 (Streamline `Compiler`)
 - #64296 (Document the unstable iter_order_by library feature)
 - #64443 (rustdoc: general cleanup)
 - #64622 (Add a cycle detector for generic `Graph`s and `mir::Body`s)
 - #64689 (Refactor macro by example)
 - #64698 (Recover on `const X = 42;` and infer type + Error Stash API)
 - #64702 (Remove unused dependencies)
 - #64717 (update mem::discriminant test to use assert_eq and assert_ne over comparison operators)
 - #64720 ( remove rtp.rs, and move rtpSpawn and RTP_ID_ERROR to libc)
 - #64721 (Fixed issue from #64447)
 - #64725 (fix one typo)
 - #64737 (fix several issues in String docs)
 - #64742 (relnotes: make compatibility section more sterile and fix rustc version)
 - #64748 (Fix #64744. Account for the Zero sub-pattern case.)

Failed merges:

r? @ghost
This commit is contained in:
bors 2019-09-24 21:46:26 +00:00
commit dcd473d7b5
78 changed files with 2776 additions and 2374 deletions

View File

@ -3324,8 +3324,6 @@ dependencies = [
"log",
"rustc",
"rustc_data_structures",
"rustc_errors",
"syntax",
"syntax_pos",
]
@ -3347,7 +3345,6 @@ dependencies = [
"log",
"memmap",
"num_cpus",
"parking_lot 0.9.0",
"rustc",
"rustc_apfloat",
"rustc_codegen_utils",
@ -3366,7 +3363,6 @@ dependencies = [
name = "rustc_codegen_utils"
version = "0.0.0"
dependencies = [
"flate2",
"log",
"punycode",
"rustc",
@ -3561,7 +3557,6 @@ name = "rustc_mir"
version = "0.0.0"
dependencies = [
"arena",
"byteorder",
"either",
"graphviz",
"log",
@ -3614,7 +3609,6 @@ name = "rustc_plugin_impl"
version = "0.0.0"
dependencies = [
"rustc",
"rustc_errors",
"rustc_metadata",
"syntax",
"syntax_pos",
@ -3638,7 +3632,6 @@ version = "0.0.0"
dependencies = [
"arena",
"bitflags",
"indexmap",
"log",
"rustc",
"rustc_data_structures",
@ -3660,7 +3653,6 @@ dependencies = [
"rustc_codegen_utils",
"rustc_data_structures",
"rustc_target",
"rustc_typeck",
"serde_json",
"syntax",
"syntax_pos",
@ -3691,9 +3683,7 @@ checksum = "b725dadae9fabc488df69a287f5a99c5eaf5d10853842a8a3dfac52476f544ee"
name = "rustc_traits"
version = "0.0.0"
dependencies = [
"bitflags",
"chalk-engine",
"graphviz",
"log",
"rustc",
"rustc_data_structures",
@ -4056,7 +4046,6 @@ version = "0.0.0"
dependencies = [
"alloc",
"backtrace",
"cc",
"cfg-if",
"compiler_builtins",
"core",
@ -4241,7 +4230,6 @@ dependencies = [
"rustc_data_structures",
"rustc_errors",
"rustc_lexer",
"rustc_macros",
"rustc_target",
"scoped-tls",
"serialize",
@ -4257,7 +4245,6 @@ dependencies = [
"log",
"rustc_data_structures",
"rustc_errors",
"rustc_lexer",
"rustc_target",
"smallvec",
"syntax",

View File

@ -70,10 +70,10 @@ Misc
Compatibility Notes
-------------------
- Unfortunately the [`x86_64-unknown-uefi` platform can not be built][62785]
with rustc 1.39.0.
- The [`armv7-unknown-linux-gnueabihf` platform is also known to have
issues][62896] for certain crates such as libc.
- The [`x86_64-unknown-uefi` platform can not be built][62785] with rustc
1.38.0.
- The [`armv7-unknown-linux-gnueabihf` platform is known to have
issues][62896] with certain crates such as libc.
[60260]: https://github.com/rust-lang/rust/pull/60260/
[61457]: https://github.com/rust-lang/rust/pull/61457/

View File

@ -429,7 +429,7 @@ impl String {
/// Converts a vector of bytes to a `String`.
///
/// A string slice ([`&str`]) is made of bytes ([`u8`]), and a vector of bytes
/// A string ([`String`]) is made of bytes ([`u8`]), and a vector of bytes
/// ([`Vec<u8>`]) is made of bytes, so this function converts between the
/// two. Not all byte slices are valid `String`s, however: `String`
/// requires that it is valid UTF-8. `from_utf8()` checks to ensure that
@ -446,7 +446,7 @@ impl String {
/// If you need a [`&str`] instead of a `String`, consider
/// [`str::from_utf8`].
///
/// The inverse of this method is [`as_bytes`].
/// The inverse of this method is [`into_bytes`].
///
/// # Errors
///
@ -480,11 +480,11 @@ impl String {
/// with this error.
///
/// [`from_utf8_unchecked`]: struct.String.html#method.from_utf8_unchecked
/// [`&str`]: ../../std/primitive.str.html
/// [`String`]: struct.String.html
/// [`u8`]: ../../std/primitive.u8.html
/// [`Vec<u8>`]: ../../std/vec/struct.Vec.html
/// [`str::from_utf8`]: ../../std/str/fn.from_utf8.html
/// [`as_bytes`]: struct.String.html#method.as_bytes
/// [`into_bytes`]: struct.String.html#method.into_bytes
/// [`FromUtf8Error`]: struct.FromUtf8Error.html
/// [`Err`]: ../../std/result/enum.Result.html#variant.Err
#[inline]

View File

@ -2581,7 +2581,7 @@ pub trait Iterator {
/// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (x * x).cmp(&y)), Ordering::Equal);
/// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (2 * x).cmp(&y)), Ordering::Greater);
/// ```
#[unstable(feature = "iter_order_by", issue = "0")]
#[unstable(feature = "iter_order_by", issue = "64295")]
fn cmp_by<I, F>(mut self, other: I, mut cmp: F) -> Ordering
where
Self: Sized,
@ -2664,7 +2664,7 @@ pub trait Iterator {
/// Some(Ordering::Greater)
/// );
/// ```
#[unstable(feature = "iter_order_by", issue = "0")]
#[unstable(feature = "iter_order_by", issue = "64295")]
fn partial_cmp_by<I, F>(mut self, other: I, mut partial_cmp: F) -> Option<Ordering>
where
Self: Sized,
@ -2729,7 +2729,7 @@ pub trait Iterator {
///
/// assert!(xs.iter().eq_by(&ys, |&x, &y| x * x == y));
/// ```
#[unstable(feature = "iter_order_by", issue = "0")]
#[unstable(feature = "iter_order_by", issue = "64295")]
fn eq_by<I, F>(mut self, other: I, mut eq: F) -> bool
where
Self: Sized,

View File

@ -818,9 +818,9 @@ impl<T> fmt::Debug for Discriminant<T> {
///
/// enum Foo { A(&'static str), B(i32), C(i32) }
///
/// assert!(mem::discriminant(&Foo::A("bar")) == mem::discriminant(&Foo::A("baz")));
/// assert!(mem::discriminant(&Foo::B(1)) == mem::discriminant(&Foo::B(2)));
/// assert!(mem::discriminant(&Foo::B(3)) != mem::discriminant(&Foo::C(3)));
/// assert_eq!(mem::discriminant(&Foo::A("bar")), mem::discriminant(&Foo::A("baz")));
/// assert_eq!(mem::discriminant(&Foo::B(1)), mem::discriminant(&Foo::B(2)));
/// assert_ne!(mem::discriminant(&Foo::B(3)), mem::discriminant(&Foo::C(3)));
/// ```
#[stable(feature = "discriminant_value", since = "1.21.0")]
pub fn discriminant<T>(v: &T) -> Discriminant<T> {

View File

@ -262,6 +262,12 @@ impl<'tcx> Body<'tcx> {
dominators(self)
}
/// Returns `true` if a cycle exists in the control-flow graph that is reachable from the
/// `START_BLOCK`.
pub fn is_cfg_cyclic(&self) -> bool {
graph::is_cyclic(self)
}
#[inline]
pub fn local_kind(&self, local: Local) -> LocalKind {
let index = local.as_usize();

View File

@ -321,6 +321,7 @@ impl Session {
}
pub fn compile_status(&self) -> Result<(), ErrorReported> {
if self.has_errors() {
self.diagnostic().emit_stashed_diagnostics();
Err(ErrorReported)
} else {
Ok(())

View File

@ -432,7 +432,7 @@ fn orphan_check_trait_ref<'tcx>(
}
fn uncovered_tys<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, in_crate: InCrate) -> Vec<Ty<'tcx>> {
if ty_is_local_constructor(ty, in_crate) {
if ty_is_local_constructor(tcx, ty, in_crate) {
vec![]
} else if fundamental_ty(ty) {
ty.walk_shallow()
@ -451,7 +451,7 @@ fn is_possibly_remote_type(ty: Ty<'_>, _in_crate: InCrate) -> bool {
}
fn ty_is_local(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool {
ty_is_local_constructor(ty, in_crate) ||
ty_is_local_constructor(tcx, ty, in_crate) ||
fundamental_ty(ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, in_crate))
}
@ -472,7 +472,7 @@ fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool {
}
}
fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
fn ty_is_local_constructor(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool {
debug!("ty_is_local_constructor({:?})", ty);
match ty.sty {
@ -504,6 +504,15 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
ty::Adt(def, _) => def_id_is_local(def.did, in_crate),
ty::Foreign(did) => def_id_is_local(did, in_crate),
ty::Opaque(did, _) => {
// Check the underlying type that this opaque
// type resolves to.
// This recursion will eventually terminate,
// since we've already managed to successfully
// resolve all opaque types by this point
let real_ty = tcx.type_of(did);
ty_is_local_constructor(tcx, real_ty, in_crate)
}
ty::Dynamic(ref tt, ..) => {
if let Some(principal) = tt.principal() {
@ -518,8 +527,7 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
ty::UnnormalizedProjection(..) |
ty::Closure(..) |
ty::Generator(..) |
ty::GeneratorWitness(..) |
ty::Opaque(..) => {
ty::GeneratorWitness(..) => {
bug!("ty_is_local invoked on unexpected type: {:?}", ty)
}
}

View File

@ -395,7 +395,7 @@ impl<'tcx> Graph {
/// The parent of a given impl, which is the `DefId` of the trait when the
/// impl is a "specialization root".
pub fn parent(&self, child: DefId) -> DefId {
*self.parent.get(&child).unwrap()
*self.parent.get(&child).unwrap_or_else(|| panic!("Failed to get parent for {:?}", child))
}
}

View File

@ -12,11 +12,9 @@ doctest = false
[dependencies]
log = "0.4"
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }
# for "clarity", rename the graphviz crate to dot; graphviz within `borrowck`
# refers to the borrowck-specific graphviz adapter traits.
dot = { path = "../libgraphviz", package = "graphviz" }
rustc = { path = "../librustc" }
errors = { path = "../librustc_errors", package = "rustc_errors" }
rustc_data_structures = { path = "../librustc_data_structures" }

View File

@ -17,7 +17,6 @@ memmap = "0.6"
log = "0.4.5"
libc = "0.2.44"
jobserver = "0.1.11"
parking_lot = "0.9"
tempfile = "3.1"
rustc_serialize = { path = "../libserialize", package = "serialize" }

View File

@ -10,7 +10,6 @@ path = "lib.rs"
test = false
[dependencies]
flate2 = "1.0"
log = "0.4"
punycode = "0.4.0"
rustc-demangle = "0.1.16"

View File

@ -1,5 +1,5 @@
use super::super::indexed_vec::IndexVec;
use super::{DirectedGraph, WithNumNodes, WithSuccessors};
use super::{DirectedGraph, WithNumNodes, WithSuccessors, WithStartNode};
use crate::bit_set::BitSet;
#[cfg(test)]
@ -85,3 +85,205 @@ where
Some(n)
}
}
/// Allows searches to terminate early with a value.
#[derive(Clone, Copy, Debug)]
pub enum ControlFlow<T> {
Break(T),
Continue,
}
/// The status of a node in the depth-first search.
///
/// See the documentation of `TriColorDepthFirstSearch` to see how a node's status is updated
/// during DFS.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NodeStatus {
/// This node has been examined by the depth-first search but is not yet `Settled`.
///
/// Also referred to as "gray" or "discovered" nodes in [CLR][].
///
/// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
Visited,
/// This node and all nodes reachable from it have been examined by the depth-first search.
///
/// Also referred to as "black" or "finished" nodes in [CLR][].
///
/// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
Settled,
}
struct Event<N> {
node: N,
becomes: NodeStatus,
}
/// A depth-first search that also tracks when all successors of a node have been examined.
///
/// This is based on the DFS described in [Introduction to Algorithms (1st ed.)][CLR], hereby
/// referred to as **CLR**. However, we use the terminology in [`NodeStatus`][] above instead of
/// "discovered"/"finished" or "white"/"grey"/"black". Each node begins the search with no status,
/// becomes `Visited` when it is first examined by the DFS and is `Settled` when all nodes
/// reachable from it have been examined. This allows us to differentiate between "tree", "back"
/// and "forward" edges (see [`TriColorVisitor::node_examined`]).
///
/// Unlike the pseudocode in [CLR][], this implementation is iterative and does not use timestamps.
/// We accomplish this by storing `Event`s on the stack that result in a (possible) state change
/// for each node. A `Visited` event signifies that we should examine this node if it has not yet
/// been `Visited` or `Settled`. When a node is examined for the first time, we mark it as
/// `Visited` and push a `Settled` event for it on stack followed by `Visited` events for all of
/// its predecessors, scheduling them for examination. Multiple `Visited` events for a single node
/// may exist on the stack simultaneously if a node has multiple predecessors, but only one
/// `Settled` event will ever be created for each node. After all `Visited` events for a node's
/// successors have been popped off the stack (as well as any new events triggered by visiting
/// those successors), we will pop off that node's `Settled` event.
///
/// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
/// [`NodeStatus`]: ./enum.NodeStatus.html
/// [`TriColorVisitor::node_examined`]: ./trait.TriColorVisitor.html#method.node_examined
pub struct TriColorDepthFirstSearch<'graph, G>
where
G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
{
graph: &'graph G,
stack: Vec<Event<G::Node>>,
visited: BitSet<G::Node>,
settled: BitSet<G::Node>,
}
impl<G> TriColorDepthFirstSearch<'graph, G>
where
G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
{
pub fn new(graph: &'graph G) -> Self {
TriColorDepthFirstSearch {
graph,
stack: vec![],
visited: BitSet::new_empty(graph.num_nodes()),
settled: BitSet::new_empty(graph.num_nodes()),
}
}
/// Performs a depth-first search, starting from the given `root`.
///
/// This won't visit nodes that are not reachable from `root`.
pub fn run_from<V>(mut self, root: G::Node, visitor: &mut V) -> Option<V::BreakVal>
where
V: TriColorVisitor<G>,
{
use NodeStatus::{Visited, Settled};
self.stack.push(Event { node: root, becomes: Visited });
loop {
match self.stack.pop()? {
Event { node, becomes: Settled } => {
let not_previously_settled = self.settled.insert(node);
assert!(not_previously_settled, "A node should be settled exactly once");
if let ControlFlow::Break(val) = visitor.node_settled(node) {
return Some(val);
}
}
Event { node, becomes: Visited } => {
let not_previously_visited = self.visited.insert(node);
let prior_status = if not_previously_visited {
None
} else if self.settled.contains(node) {
Some(Settled)
} else {
Some(Visited)
};
if let ControlFlow::Break(val) = visitor.node_examined(node, prior_status) {
return Some(val);
}
// If this node has already been examined, we are done.
if prior_status.is_some() {
continue;
}
// Otherwise, push a `Settled` event for this node onto the stack, then
// schedule its successors for examination.
self.stack.push(Event { node, becomes: Settled });
for succ in self.graph.successors(node) {
self.stack.push(Event { node: succ, becomes: Visited });
}
}
}
}
}
}
impl<G> TriColorDepthFirstSearch<'graph, G>
where
G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors + WithStartNode,
{
/// Performs a depth-first search, starting from `G::start_node()`.
///
/// This won't visit nodes that are not reachable from the start node.
pub fn run_from_start<V>(self, visitor: &mut V) -> Option<V::BreakVal>
where
V: TriColorVisitor<G>,
{
let root = self.graph.start_node();
self.run_from(root, visitor)
}
}
/// What to do when a node is examined or becomes `Settled` during DFS.
pub trait TriColorVisitor<G>
where
G: ?Sized + DirectedGraph,
{
/// The value returned by this search.
type BreakVal;
/// Called when a node is examined by the depth-first search.
///
/// By checking the value of `prior_status`, this visitor can determine whether the edge
/// leading to this node was a tree edge (`None`), forward edge (`Some(Settled)`) or back edge
/// (`Some(Visited)`). For a full explanation of each edge type, see the "Depth-first Search"
/// chapter in [CLR][] or [wikipedia][].
///
/// If you want to know *both* nodes linked by each edge, you'll need to modify
/// `TriColorDepthFirstSearch` to store a `source` node for each `Visited` event.
///
/// [wikipedia]: https://en.wikipedia.org/wiki/Depth-first_search#Output_of_a_depth-first_search
/// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
fn node_examined(
&mut self,
_target: G::Node,
_prior_status: Option<NodeStatus>,
) -> ControlFlow<Self::BreakVal> {
ControlFlow::Continue
}
/// Called after all nodes reachable from this one have been examined.
fn node_settled(&mut self, _target: G::Node) -> ControlFlow<Self::BreakVal> {
ControlFlow::Continue
}
}
/// This `TriColorVisitor` looks for back edges in a graph, which indicate that a cycle exists.
pub struct CycleDetector;
impl<G> TriColorVisitor<G> for CycleDetector
where
G: ?Sized + DirectedGraph,
{
type BreakVal = ();
fn node_examined(
&mut self,
_node: G::Node,
prior_status: Option<NodeStatus>,
) -> ControlFlow<Self::BreakVal> {
match prior_status {
Some(NodeStatus::Visited) => ControlFlow::Break(()),
_ => ControlFlow::Continue,
}
}
}

View File

@ -9,3 +9,14 @@ fn diamond_post_order() {
let result = post_order_from(&graph, 0);
assert_eq!(result, vec![3, 1, 2, 0]);
}
#[test]
fn is_cyclic() {
use super::super::is_cyclic;
let diamond_acyclic = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]);
let diamond_cyclic = TestGraph::new(0, &[(0, 1), (1, 2), (2, 3), (3, 0)]);
assert!(!is_cyclic(&diamond_acyclic));
assert!(is_cyclic(&diamond_cyclic));
}

View File

@ -81,3 +81,13 @@ where
+ WithNumNodes,
{
}
/// Returns `true` if the graph has a cycle that is reachable from the start node.
pub fn is_cyclic<G>(graph: &G) -> bool
where
G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors + WithNumNodes,
{
iterate::TriColorDepthFirstSearch::new(graph)
.run_from_start(&mut iterate::CycleDetector)
.is_some()
}

View File

@ -296,7 +296,6 @@ pub fn run_compiler(
);
Ok(())
})?;
return sess.compile_status();
} else {
let mut krate = compiler.parse()?.take();
pretty::visit_crate(sess, &mut krate, ppm);
@ -307,8 +306,8 @@ pub fn run_compiler(
ppm,
compiler.output_file().as_ref().map(|p| &**p),
);
return sess.compile_status();
}
return sess.compile_status();
}
if callbacks.after_parsing(compiler) == Compilation::Stop {

View File

@ -1,10 +1,6 @@
use crate::Diagnostic;
use crate::DiagnosticId;
use crate::DiagnosticStyledString;
use crate::Applicability;
use crate::{Diagnostic, DiagnosticId, DiagnosticStyledString};
use crate::{Applicability, Level, Handler, StashKey};
use crate::Level;
use crate::Handler;
use std::fmt::{self, Debug};
use std::ops::{Deref, DerefMut};
use std::thread::panicking;
@ -117,18 +113,30 @@ impl<'a> DiagnosticBuilder<'a> {
}
}
/// Buffers the diagnostic for later emission, unless handler
/// has disabled such buffering.
pub fn buffer(mut self, buffered_diagnostics: &mut Vec<Diagnostic>) {
/// Stashes diagnostic for possible later improvement in a different,
/// later stage of the compiler. The diagnostic can be accessed with
/// the provided `span` and `key` through `.steal_diagnostic` on `Handler`.
///
/// As with `buffer`, this is unless the handler has disabled such buffering.
pub fn stash(self, span: Span, key: StashKey) {
if let Some((diag, handler)) = self.into_diagnostic() {
handler.stash_diagnostic(span, key, diag);
}
}
/// Converts the builder to a `Diagnostic` for later emission,
/// unless handler has disabled such buffering.
pub fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a Handler)> {
if self.0.handler.flags.dont_buffer_diagnostics ||
self.0.handler.flags.treat_err_as_bug.is_some()
{
self.emit();
return;
return None;
}
// We need to use `ptr::read` because `DiagnosticBuilder`
// implements `Drop`.
let handler = self.0.handler;
// We need to use `ptr::read` because `DiagnosticBuilder` implements `Drop`.
let diagnostic;
unsafe {
diagnostic = std::ptr::read(&self.0.diagnostic);
@ -137,7 +145,14 @@ impl<'a> DiagnosticBuilder<'a> {
// Logging here is useful to help track down where in logs an error was
// actually emitted.
debug!("buffer: diagnostic={:?}", diagnostic);
buffered_diagnostics.push(diagnostic);
Some((diagnostic, handler))
}
/// Buffers the diagnostic for later emission,
/// unless handler has disabled such buffering.
pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) {
buffered_diagnostics.extend(self.into_diagnostic().map(|(diag, _)| diag));
}
/// Convenience function for internal use, clients should use one of the

View File

@ -1043,14 +1043,13 @@ impl EmitterWriter {
}
fn get_max_line_num(&mut self, span: &MultiSpan, children: &[SubDiagnostic]) -> usize {
let mut max = 0;
let primary = self.get_multispan_max_line_num(span);
max = if primary > max { primary } else { max };
let mut max = primary;
for sub in children {
let sub_result = self.get_multispan_max_line_num(&sub.span);
max = if sub_result > max { primary } else { max };
max = std::cmp::max(sub_result, max);
}
max
}

View File

@ -17,7 +17,7 @@ use emitter::{Emitter, EmitterWriter};
use registry::Registry;
use rustc_data_structures::sync::{self, Lrc, Lock};
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_data_structures::stable_hasher::StableHasher;
use std::borrow::Cow;
@ -302,6 +302,9 @@ pub struct Handler {
inner: Lock<HandlerInner>,
}
/// This inner struct exists to keep it all behind a single lock;
/// this is done to prevent possible deadlocks in a multi-threaded compiler,
/// as well as inconsistent state observation.
struct HandlerInner {
flags: HandlerFlags,
/// The number of errors that have been emitted, including duplicates.
@ -326,6 +329,18 @@ struct HandlerInner {
/// this handler. These hashes is used to avoid emitting the same error
/// twice.
emitted_diagnostics: FxHashSet<u128>,
/// Stashed diagnostics emitted in one stage of the compiler that may be
/// stolen by other stages (e.g. to improve them and add more information).
/// The stashed diagnostics count towards the total error count.
/// When `.abort_if_errors()` is called, these are also emitted.
stashed_diagnostics: FxIndexMap<(Span, StashKey), Diagnostic>,
}
/// A key denoting where from a diagnostic was stashed.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum StashKey {
ItemNoType,
}
fn default_track_diagnostic(_: &Diagnostic) {}
@ -354,7 +369,9 @@ pub struct HandlerFlags {
impl Drop for HandlerInner {
fn drop(&mut self) {
if self.err_count == 0 {
self.emit_stashed_diagnostics();
if !self.has_errors() {
let bugs = std::mem::replace(&mut self.delayed_span_bugs, Vec::new());
let has_bugs = !bugs.is_empty();
for bug in bugs {
@ -368,57 +385,71 @@ impl Drop for HandlerInner {
}
impl Handler {
pub fn with_tty_emitter(color_config: ColorConfig,
can_emit_warnings: bool,
treat_err_as_bug: Option<usize>,
cm: Option<Lrc<SourceMapperDyn>>)
-> Handler {
Handler::with_tty_emitter_and_flags(
pub fn with_tty_emitter(
color_config: ColorConfig,
can_emit_warnings: bool,
treat_err_as_bug: Option<usize>,
cm: Option<Lrc<SourceMapperDyn>>,
) -> Self {
Self::with_tty_emitter_and_flags(
color_config,
cm,
HandlerFlags {
can_emit_warnings,
treat_err_as_bug,
.. Default::default()
})
},
)
}
pub fn with_tty_emitter_and_flags(color_config: ColorConfig,
cm: Option<Lrc<SourceMapperDyn>>,
flags: HandlerFlags)
-> Handler {
pub fn with_tty_emitter_and_flags(
color_config: ColorConfig,
cm: Option<Lrc<SourceMapperDyn>>,
flags: HandlerFlags,
) -> Self {
let emitter = Box::new(EmitterWriter::stderr(
color_config, cm, false, false, None, flags.external_macro_backtrace));
Handler::with_emitter_and_flags(emitter, flags)
color_config,
cm,
false,
false,
None,
flags.external_macro_backtrace,
));
Self::with_emitter_and_flags(emitter, flags)
}
pub fn with_emitter(can_emit_warnings: bool,
treat_err_as_bug: Option<usize>,
e: Box<dyn Emitter + sync::Send>)
-> Handler {
pub fn with_emitter(
can_emit_warnings: bool,
treat_err_as_bug: Option<usize>,
emitter: Box<dyn Emitter + sync::Send>,
) -> Self {
Handler::with_emitter_and_flags(
e,
emitter,
HandlerFlags {
can_emit_warnings,
treat_err_as_bug,
.. Default::default()
})
},
)
}
pub fn with_emitter_and_flags(e: Box<dyn Emitter + sync::Send>, flags: HandlerFlags) -> Handler
{
Handler {
pub fn with_emitter_and_flags(
emitter: Box<dyn Emitter + sync::Send>,
flags: HandlerFlags
) -> Self {
Self {
flags,
inner: Lock::new(HandlerInner {
flags,
err_count: 0,
deduplicated_err_count: 0,
emitter: e,
emitter,
continue_after_error: true,
delayed_span_bugs: Vec::new(),
taught_diagnostics: Default::default(),
emitted_diagnostic_codes: Default::default(),
emitted_diagnostics: Default::default(),
stashed_diagnostics: Default::default(),
}),
}
}
@ -445,36 +476,68 @@ impl Handler {
inner.emitted_diagnostics = Default::default();
inner.deduplicated_err_count = 0;
inner.err_count = 0;
inner.stashed_diagnostics.clear();
}
/// Stash a given diagnostic with the given `Span` and `StashKey` as the key for later stealing.
/// If the diagnostic with this `(span, key)` already exists, this will result in an ICE.
pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) {
let mut inner = self.inner.borrow_mut();
if let Some(mut old_diag) = inner.stashed_diagnostics.insert((span, key), diag) {
// We are removing a previously stashed diagnostic which should not happen.
old_diag.level = Bug;
old_diag.note(&format!(
"{}:{}: already existing stashed diagnostic with (span = {:?}, key = {:?})",
file!(), line!(), span, key
));
inner.emit_diag_at_span(old_diag, span);
panic!(ExplicitBug);
}
}
/// Steal a previously stashed diagnostic with the given `Span` and `StashKey` as the key.
pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_>> {
self.inner
.borrow_mut()
.stashed_diagnostics
.remove(&(span, key))
.map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
}
/// Emit all stashed diagnostics.
pub fn emit_stashed_diagnostics(&self) {
self.inner.borrow_mut().emit_stashed_diagnostics();
}
/// Construct a dummy builder with `Level::Cancelled`.
///
/// Using this will neither report anything to the user (e.g. a warning),
/// nor will compilation cancel as a result.
pub fn struct_dummy(&self) -> DiagnosticBuilder<'_> {
DiagnosticBuilder::new(self, Level::Cancelled, "")
}
pub fn struct_span_warn<S: Into<MultiSpan>>(&self,
sp: S,
msg: &str)
-> DiagnosticBuilder<'_> {
let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
result.set_span(sp);
if !self.flags.can_emit_warnings {
result.cancel();
}
/// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
pub fn struct_span_warn(&self, span: impl Into<MultiSpan>, msg: &str) -> DiagnosticBuilder<'_> {
let mut result = self.struct_warn(msg);
result.set_span(span);
result
}
pub fn struct_span_warn_with_code<S: Into<MultiSpan>>(&self,
sp: S,
msg: &str,
code: DiagnosticId)
-> DiagnosticBuilder<'_> {
let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
result.set_span(sp);
/// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
/// Also include a code.
pub fn struct_span_warn_with_code(
&self,
span: impl Into<MultiSpan>,
msg: &str,
code: DiagnosticId,
) -> DiagnosticBuilder<'_> {
let mut result = self.struct_span_warn(span, msg);
result.code(code);
if !self.flags.can_emit_warnings {
result.cancel();
}
result
}
/// Construct a builder at the `Warning` level with the `msg`.
pub fn struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_> {
let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
if !self.flags.can_emit_warnings {
@ -482,146 +545,151 @@ impl Handler {
}
result
}
pub fn struct_span_err<S: Into<MultiSpan>>(&self,
sp: S,
msg: &str)
-> DiagnosticBuilder<'_> {
let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
result.set_span(sp);
/// Construct a builder at the `Error` level at the given `span` and with the `msg`.
pub fn struct_span_err(&self, span: impl Into<MultiSpan>, msg: &str) -> DiagnosticBuilder<'_> {
let mut result = self.struct_err(msg);
result.set_span(span);
result
}
pub fn struct_span_err_with_code<S: Into<MultiSpan>>(&self,
sp: S,
msg: &str,
code: DiagnosticId)
-> DiagnosticBuilder<'_> {
let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
result.set_span(sp);
/// Construct a builder at the `Error` level at the given `span`, with the `msg`, and `code`.
pub fn struct_span_err_with_code(
&self,
span: impl Into<MultiSpan>,
msg: &str,
code: DiagnosticId,
) -> DiagnosticBuilder<'_> {
let mut result = self.struct_span_err(span, msg);
result.code(code);
result
}
/// Construct a builder at the `Error` level with the `msg`.
// FIXME: This method should be removed (every error should have an associated error code).
pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_> {
DiagnosticBuilder::new(self, Level::Error, msg)
}
pub fn struct_err_with_code(
/// Construct a builder at the `Error` level with the `msg` and the `code`.
pub fn struct_err_with_code(&self, msg: &str, code: DiagnosticId) -> DiagnosticBuilder<'_> {
let mut result = self.struct_err(msg);
result.code(code);
result
}
/// Construct a builder at the `Fatal` level at the given `span` and with the `msg`.
pub fn struct_span_fatal(
&self,
span: impl Into<MultiSpan>,
msg: &str,
) -> DiagnosticBuilder<'_> {
let mut result = self.struct_fatal(msg);
result.set_span(span);
result
}
/// Construct a builder at the `Fatal` level at the given `span`, with the `msg`, and `code`.
pub fn struct_span_fatal_with_code(
&self,
span: impl Into<MultiSpan>,
msg: &str,
code: DiagnosticId,
) -> DiagnosticBuilder<'_> {
let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
result.code(code);
result
}
pub fn struct_span_fatal<S: Into<MultiSpan>>(&self,
sp: S,
msg: &str)
-> DiagnosticBuilder<'_> {
let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
result.set_span(sp);
result
}
pub fn struct_span_fatal_with_code<S: Into<MultiSpan>>(&self,
sp: S,
msg: &str,
code: DiagnosticId)
-> DiagnosticBuilder<'_> {
let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
result.set_span(sp);
let mut result = self.struct_span_fatal(span, msg);
result.code(code);
result
}
/// Construct a builder at the `Error` level with the `msg`.
pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_> {
DiagnosticBuilder::new(self, Level::Fatal, msg)
}
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> FatalError {
self.emit_diagnostic(Diagnostic::new(Fatal, msg).set_span(sp));
self.abort_if_errors_and_should_abort();
pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: &str) -> FatalError {
self.emit_diag_at_span(Diagnostic::new(Fatal, msg), span);
FatalError
}
pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self,
sp: S,
msg: &str,
code: DiagnosticId)
-> FatalError {
self.emit_diagnostic(Diagnostic::new_with_code(Fatal, Some(code), msg).set_span(sp));
self.abort_if_errors_and_should_abort();
pub fn span_fatal_with_code(
&self,
span: impl Into<MultiSpan>,
msg: &str,
code: DiagnosticId,
) -> FatalError {
self.emit_diag_at_span(Diagnostic::new_with_code(Fatal, Some(code), msg), span);
FatalError
}
pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.emit_diagnostic(Diagnostic::new(Error, msg).set_span(sp));
self.abort_if_errors_and_should_abort();
pub fn span_err(&self, span: impl Into<MultiSpan>, msg: &str) {
self.emit_diag_at_span(Diagnostic::new(Error, msg), span);
}
pub fn mut_span_err<S: Into<MultiSpan>>(&self,
sp: S,
msg: &str)
-> DiagnosticBuilder<'_> {
let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
result.set_span(sp);
result
pub fn span_err_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId) {
self.emit_diag_at_span(Diagnostic::new_with_code(Error, Some(code), msg), span);
}
pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
self.emit_diagnostic(Diagnostic::new_with_code(Error, Some(code), msg).set_span(sp));
self.abort_if_errors_and_should_abort();
pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: &str) {
self.emit_diag_at_span(Diagnostic::new(Warning, msg), span);
}
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.emit_diagnostic(Diagnostic::new(Warning, msg).set_span(sp));
self.abort_if_errors_and_should_abort();
pub fn span_warn_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId) {
self.emit_diag_at_span(Diagnostic::new_with_code(Warning, Some(code), msg), span);
}
pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
self.emit_diagnostic(Diagnostic::new_with_code(Warning, Some(code), msg).set_span(sp));
self.abort_if_errors_and_should_abort();
pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: &str) -> ! {
self.inner.borrow_mut().span_bug(span, msg)
}
pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
self.inner.borrow_mut().span_bug(sp, msg)
pub fn delay_span_bug(&self, span: impl Into<MultiSpan>, msg: &str) {
self.inner.borrow_mut().delay_span_bug(span, msg)
}
pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.inner.borrow_mut().delay_span_bug(sp, msg)
pub fn span_bug_no_panic(&self, span: impl Into<MultiSpan>, msg: &str) {
self.emit_diag_at_span(Diagnostic::new(Bug, msg), span);
}
pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.emit_diagnostic(Diagnostic::new(Bug, msg).set_span(sp));
self.abort_if_errors_and_should_abort();
pub fn span_note_without_error(&self, span: impl Into<MultiSpan>, msg: &str) {
self.emit_diag_at_span(Diagnostic::new(Note, msg), span);
}
pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.emit_diagnostic(Diagnostic::new(Note, msg).set_span(sp));
self.abort_if_errors_and_should_abort();
}
pub fn span_note_diag(&self,
sp: Span,
msg: &str)
-> DiagnosticBuilder<'_> {
pub fn span_note_diag(&self, span: Span, msg: &str) -> DiagnosticBuilder<'_> {
let mut db = DiagnosticBuilder::new(self, Note, msg);
db.set_span(sp);
db.set_span(span);
db
}
pub fn failure(&self, msg: &str) {
self.inner.borrow_mut().failure(msg);
}
pub fn fatal(&self, msg: &str) -> FatalError {
self.inner.borrow_mut().fatal(msg)
}
pub fn err(&self, msg: &str) {
self.inner.borrow_mut().err(msg);
}
pub fn warn(&self, msg: &str) {
let mut db = DiagnosticBuilder::new(self, Warning, msg);
db.emit();
}
pub fn note_without_error(&self, msg: &str) {
let mut db = DiagnosticBuilder::new(self, Note, msg);
db.emit();
DiagnosticBuilder::new(self, Note, msg).emit();
}
pub fn bug(&self, msg: &str) -> ! {
self.inner.borrow_mut().bug(msg)
}
pub fn err_count(&self) -> usize {
self.inner.borrow().err_count
self.inner.borrow().err_count()
}
pub fn has_errors(&self) -> bool {
self.err_count() > 0
self.inner.borrow().has_errors()
}
pub fn print_error_count(&self, registry: &Registry) {
@ -629,13 +697,18 @@ impl Handler {
}
pub fn abort_if_errors(&self) {
self.inner.borrow().abort_if_errors()
self.inner.borrow_mut().abort_if_errors()
}
pub fn abort_if_errors_and_should_abort(&self) {
self.inner.borrow().abort_if_errors_and_should_abort()
self.inner.borrow_mut().abort_if_errors_and_should_abort()
}
/// `true` if we haven't taught a diagnostic with this code already.
/// The caller must then teach the user about such a diagnostic.
///
/// Used to suppress emitting the same error multiple times with extended explanation when
/// calling `-Zteach`.
pub fn must_teach(&self, code: &DiagnosticId) -> bool {
self.inner.borrow_mut().must_teach(code)
}
@ -648,6 +721,12 @@ impl Handler {
self.inner.borrow_mut().emit_diagnostic(diagnostic)
}
fn emit_diag_at_span(&self, mut diag: Diagnostic, sp: impl Into<MultiSpan>) {
let mut inner = self.inner.borrow_mut();
inner.emit_diagnostic(diag.set_span(sp));
inner.abort_if_errors_and_should_abort();
}
pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
self.inner.borrow_mut().emit_artifact_notification(path, artifact_type)
}
@ -658,11 +737,6 @@ impl Handler {
}
impl HandlerInner {
/// `true` if we haven't taught a diagnostic with this code already.
/// The caller must then teach the user about such a diagnostic.
///
/// Used to suppress emitting the same error multiple times with extended explanation when
/// calling `-Zteach`.
fn must_teach(&mut self, code: &DiagnosticId) -> bool {
self.taught_diagnostics.insert(code.clone())
}
@ -671,6 +745,12 @@ impl HandlerInner {
self.emitter.emit_diagnostic(&db);
}
/// Emit all stashed diagnostics.
fn emit_stashed_diagnostics(&mut self) {
let diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::<Vec<_>>();
diags.iter().for_each(|diag| self.emit_diagnostic(diag));
}
fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) {
if diagnostic.cancelled() {
return;
@ -713,10 +793,12 @@ impl HandlerInner {
}
fn treat_err_as_bug(&self) -> bool {
self.flags.treat_err_as_bug.map(|c| self.err_count >= c).unwrap_or(false)
self.flags.treat_err_as_bug.map(|c| self.err_count() >= c).unwrap_or(false)
}
fn print_error_count(&mut self, registry: &Registry) {
self.emit_stashed_diagnostics();
let s = match self.deduplicated_err_count {
0 => return,
1 => "aborting due to previous error".to_string(),
@ -760,25 +842,41 @@ impl HandlerInner {
}
}
fn abort_if_errors_and_should_abort(&self) {
if self.err_count > 0 && !self.continue_after_error {
fn err_count(&self) -> usize {
self.err_count + self.stashed_diagnostics.len()
}
fn has_errors(&self) -> bool {
self.err_count() > 0
}
fn abort_if_errors_and_should_abort(&mut self) {
self.emit_stashed_diagnostics();
if self.has_errors() && !self.continue_after_error {
FatalError.raise();
}
}
fn abort_if_errors(&self) {
if self.err_count > 0 {
fn abort_if_errors(&mut self) {
self.emit_stashed_diagnostics();
if self.has_errors() {
FatalError.raise();
}
}
fn span_bug<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> ! {
self.emit_diagnostic(Diagnostic::new(Bug, msg).set_span(sp));
self.abort_if_errors_and_should_abort();
fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) -> ! {
self.emit_diag_at_span(Diagnostic::new(Bug, msg), sp);
panic!(ExplicitBug);
}
fn delay_span_bug<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) {
fn emit_diag_at_span(&mut self, mut diag: Diagnostic, sp: impl Into<MultiSpan>) {
self.emit_diagnostic(diag.set_span(sp));
self.abort_if_errors_and_should_abort();
}
fn delay_span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) {
if self.treat_err_as_bug() {
// FIXME: don't abort here if report_delayed_bugs is off
self.span_bug(sp, msg);
@ -793,18 +891,20 @@ impl HandlerInner {
}
fn fatal(&mut self, msg: &str) -> FatalError {
if self.treat_err_as_bug() {
self.bug(msg);
}
self.emit_diagnostic(&Diagnostic::new(Fatal, msg));
self.emit_error(Fatal, msg);
FatalError
}
fn err(&mut self, msg: &str) {
self.emit_error(Error, msg);
}
/// Emit an error; level should be `Error` or `Fatal`.
fn emit_error(&mut self, level: Level, msg: &str,) {
if self.treat_err_as_bug() {
self.bug(msg);
}
self.emit_diagnostic(&Diagnostic::new(Error, msg));
self.emit_diagnostic(&Diagnostic::new(level, msg));
}
fn bug(&mut self, msg: &str) -> ! {
@ -826,7 +926,7 @@ impl HandlerInner {
fn panic_if_treat_err_as_bug(&self) {
if self.treat_err_as_bug() {
let s = match (self.err_count, self.flags.treat_err_as_bug.unwrap_or(0)) {
let s = match (self.err_count(), self.flags.treat_err_as_bug.unwrap_or(0)) {
(0, _) => return,
(1, 1) => "aborting due to `-Z treat-err-as-bug=1`".to_string(),
(1, _) => return,

View File

@ -221,7 +221,6 @@ pub struct PluginInfo {
}
pub fn register_plugins<'a>(
compiler: &Compiler,
sess: &'a Session,
cstore: &'a CStore,
mut krate: ast::Crate,
@ -261,9 +260,6 @@ pub fn register_plugins<'a>(
});
}
// If necessary, compute the dependency graph (in the background).
compiler.dep_graph_future().ok();
time(sess, "recursion limit", || {
middle::recursion_limit::update_limits(sess, &krate);
});

View File

@ -114,29 +114,38 @@ impl Compiler {
let crate_name = self.crate_name()?.peek().clone();
let krate = self.parse()?.take();
passes::register_plugins(
self,
let result = passes::register_plugins(
self.session(),
self.cstore(),
krate,
&crate_name,
)
);
// Compute the dependency graph (in the background). We want to do
// this as early as possible, to give the DepGraph maximum time to
// load before dep_graph() is called, but it also can't happen
// until after rustc_incremental::prepare_session_directory() is
// called, which happens within passes::register_plugins().
self.dep_graph_future().ok();
result
})
}
pub fn crate_name(&self) -> Result<&Query<String>> {
self.queries.crate_name.compute(|| {
let parse_result = self.parse()?;
let krate = parse_result.peek();
let result = match self.crate_name {
Ok(match self.crate_name {
Some(ref crate_name) => crate_name.clone(),
None => rustc_codegen_utils::link::find_crate_name(
Some(self.session()),
&krate.attrs,
&self.input
),
};
Ok(result)
None => {
let parse_result = self.parse()?;
let krate = parse_result.peek();
rustc_codegen_utils::link::find_crate_name(
Some(self.session()),
&krate.attrs,
&self.input
)
}
})
})
}
@ -194,7 +203,6 @@ impl Compiler {
pub fn prepare_outputs(&self) -> Result<&Query<OutputFilenames>> {
self.queries.prepare_outputs.compute(|| {
self.lower_to_hir()?;
let krate = self.expansion()?;
let krate = krate.peek();
let crate_name = self.crate_name()?;
@ -267,6 +275,11 @@ impl Compiler {
})
}
// This method is different to all the other methods in `Compiler` because
// it lacks a `Queries` entry. It's also not currently used. It does serve
// as an example of how `Compiler` can be used, with additional steps added
// between some passes. And see `rustc_driver::run_compiler` for a more
// complex example.
pub fn compile(&self) -> Result<()> {
self.prepare_outputs()?;
@ -278,12 +291,12 @@ impl Compiler {
self.global_ctxt()?;
// Drop AST after creating GlobalCtxt to free memory
// Drop AST after creating GlobalCtxt to free memory.
mem::drop(self.expansion()?.take());
self.ongoing_codegen()?;
// Drop GlobalCtxt after starting codegen to free memory
// Drop GlobalCtxt after starting codegen to free memory.
mem::drop(self.global_ctxt()?.take());
self.link().map(|_| ())

View File

@ -24,6 +24,5 @@ rustc_lexer = { path = "../librustc_lexer" }
rustc_serialize = { path = "../libserialize", package = "serialize" }
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }
byteorder = { version = "1.3" }
rustc_apfloat = { path = "../librustc_apfloat" }
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }

View File

@ -15,4 +15,3 @@ rustc = { path = "../librustc" }
rustc_metadata = { path = "../librustc_metadata" }
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }
rustc_errors = { path = "../librustc_errors" }

View File

@ -12,7 +12,6 @@ doctest = false
[dependencies]
bitflags = "1.0"
indexmap = "1"
log = "0.4"
syntax = { path = "../libsyntax" }
rustc = { path = "../librustc" }

View File

@ -18,7 +18,7 @@ use syntax::ext::base::{self, InvocationRes, Indeterminate, SpecialDerives};
use syntax::ext::base::{MacroKind, SyntaxExtension};
use syntax::ext::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind};
use syntax::ext::hygiene::{self, ExpnId, ExpnData, ExpnKind};
use syntax::ext::tt::macro_rules;
use syntax::ext::compile_declarative_macro;
use syntax::feature_gate::{emit_feature_err, is_builtin_attr_name};
use syntax::feature_gate::GateIssue;
use syntax::symbol::{Symbol, kw, sym};
@ -843,7 +843,7 @@ impl<'a> Resolver<'a> {
/// Compile the macro into a `SyntaxExtension` and possibly replace it with a pre-defined
/// extension partially or entirely for built-in macros and legacy plugin macros.
crate fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> SyntaxExtension {
let mut result = macro_rules::compile(
let mut result = compile_declarative_macro(
&self.session.parse_sess, self.session.features_untracked(), item, edition
);

View File

@ -14,7 +14,6 @@ rustc = { path = "../librustc" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_codegen_utils = { path = "../librustc_codegen_utils" }
rustc_target = { path = "../librustc_target" }
rustc_typeck = { path = "../librustc_typeck" }
serde_json = "1"
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }

View File

@ -9,8 +9,6 @@ name = "rustc_traits"
path = "lib.rs"
[dependencies]
bitflags = "1.0"
graphviz = { path = "../libgraphviz" }
log = { version = "0.4" }
rustc = { path = "../librustc" }
rustc_data_structures = { path = "../librustc_data_structures" }

View File

@ -232,7 +232,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let mut err = if !actual.references_error() {
// Suggest clamping down the type if the method that is being attempted to
// be used exists at all, and the type is an ambiuous numeric type
// be used exists at all, and the type is an ambiguous numeric type
// ({integer}/{float}).
let mut candidates = all_traits(self.tcx)
.into_iter()

View File

@ -676,7 +676,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
} else {
// Pattern has wrong number of fields.
self.e0023(pat.span, res, &subpats, &variant.fields, expected);
self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected);
on_error();
return tcx.types.err;
}
@ -687,22 +687,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
pat_span: Span,
res: Res,
qpath: &hir::QPath,
subpats: &'tcx [P<Pat>],
fields: &[ty::FieldDef],
expected: Ty<'tcx>
) {
let subpats_ending = pluralise!(subpats.len());
let fields_ending = pluralise!(fields.len());
let missing_parenthesis = match expected.sty {
ty::Adt(_, substs) if fields.len() == 1 => {
let field_ty = fields[0].ty(self.tcx, substs);
match field_ty.sty {
ty::Tuple(_) => field_ty.tuple_fields().count() == subpats.len(),
_ => false,
}
}
_ => false,
};
let res_span = self.tcx.def_span(res.def_id());
let mut err = struct_span_err!(
self.tcx.sess,
@ -723,11 +714,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
))
.span_label(res_span, format!("{} defined here", res.descr()));
// Identify the case `Some(x, y)` where the expected type is e.g. `Option<(T, U)>`.
// More generally, the expected type wants a tuple variant with one field of an
// N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern
// with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`.
let missing_parenthesis = match expected.sty {
ty::Adt(_, substs) if fields.len() == 1 => {
let field_ty = fields[0].ty(self.tcx, substs);
match field_ty.sty {
ty::Tuple(_) => field_ty.tuple_fields().count() == subpats.len(),
_ => false,
}
}
_ => false,
};
if missing_parenthesis {
let (left, right) = match subpats {
// This is the zero case; we aim to get the "hi" part of the `QPath`'s
// span as the "lo" and then the "hi" part of the pattern's span as the "hi".
// This looks like:
//
// help: missing parenthesis
// |
// L | let A(()) = A(());
// | ^ ^
[] => {
let qpath_span = match qpath {
hir::QPath::Resolved(_, path) => path.span,
hir::QPath::TypeRelative(_, ps) => ps.ident.span,
};
(qpath_span.shrink_to_hi(), pat_span)
},
// Easy case. Just take the "lo" of the first sub-pattern and the "hi" of the
// last sub-pattern. In the case of `A(x)` the first and last may coincide.
// This looks like:
//
// help: missing parenthesis
// |
// L | let A((x, y)) = A((1, 2));
// | ^ ^
[first, ..] => (first.span.shrink_to_lo(), subpats.last().unwrap().span),
};
err.multipart_suggestion(
"missing parenthesis",
vec![(subpats[0].span.shrink_to_lo(), "(".to_string()),
(subpats[subpats.len()-1].span.shrink_to_hi(), ")".to_string())],
vec![
(left, "(".to_string()),
(right.shrink_to_hi(), ")".to_string()),
],
Applicability::MachineApplicable,
);
}

View File

@ -832,7 +832,7 @@ fn check_method_receiver<'fcx, 'tcx>(
}
fn e0307(fcx: &FnCtxt<'fcx, 'tcx>, span: Span, receiver_ty: Ty<'_>) {
fcx.tcx.sess.diagnostic().mut_span_err(
fcx.tcx.sess.diagnostic().struct_span_err(
span,
&format!("invalid `self` parameter type: {:?}", receiver_ty)
).note("type of `self` must be `Self` or a type that dereferences to it")

View File

@ -46,7 +46,7 @@ use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc::hir::GenericParamKind;
use rustc::hir::{self, CodegenFnAttrFlags, CodegenFnAttrs, Unsafety};
use errors::{Applicability, DiagnosticId};
use errors::{Applicability, DiagnosticId, StashKey};
struct OnlySelfBounds(bool);
@ -1149,18 +1149,41 @@ fn infer_placeholder_type(
def_id: DefId,
body_id: hir::BodyId,
span: Span,
item_ident: Ident,
) -> Ty<'_> {
let ty = tcx.typeck_tables_of(def_id).node_type(body_id.hir_id);
let mut diag = bad_placeholder_type(tcx, span);
if ty != tcx.types.err {
diag.span_suggestion(
span,
"replace `_` with the correct type",
ty.to_string(),
Applicability::MaybeIncorrect,
);
// If this came from a free `const` or `static mut?` item,
// then the user may have written e.g. `const A = 42;`.
// In this case, the parser has stashed a diagnostic for
// us to improve in typeck so we do that now.
match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) {
Some(mut err) => {
// The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
// We are typeck and have the real type, so remove that and suggest the actual type.
err.suggestions.clear();
err.span_suggestion(
span,
"provide a type for the item",
format!("{}: {}", item_ident, ty),
Applicability::MachineApplicable,
)
.emit();
}
None => {
let mut diag = bad_placeholder_type(tcx, span);
if ty != tcx.types.err {
diag.span_suggestion(
span,
"replace `_` with the correct type",
ty.to_string(),
Applicability::MaybeIncorrect,
);
}
diag.emit();
}
}
diag.emit();
ty
}
@ -1192,7 +1215,7 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
TraitItemKind::Const(ref ty, body_id) => {
body_id.and_then(|body_id| {
if let hir::TyKind::Infer = ty.node {
Some(infer_placeholder_type(tcx, def_id, body_id, ty.span))
Some(infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident))
} else {
None
}
@ -1214,7 +1237,7 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
}
ImplItemKind::Const(ref ty, body_id) => {
if let hir::TyKind::Infer = ty.node {
infer_placeholder_type(tcx, def_id, body_id, ty.span)
infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)
} else {
icx.to_ty(ty)
}
@ -1246,7 +1269,7 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
ItemKind::Static(ref ty, .., body_id)
| ItemKind::Const(ref ty, body_id) => {
if let hir::TyKind::Infer = ty.node {
infer_placeholder_type(tcx, def_id, body_id, ty.span)
infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)
} else {
icx.to_ty(ty)
}

View File

@ -119,7 +119,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
source: Span::empty(),
name: None,
attrs: Default::default(),
visibility: None,
visibility: Inherited,
def_id: self.cx.next_def_id(param_env_def_id.krate),
stability: None,
deprecation: None,

View File

@ -99,7 +99,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
source: self.cx.tcx.def_span(impl_def_id).clean(self.cx),
name: None,
attrs: Default::default(),
visibility: None,
visibility: Inherited,
def_id: self.cx.next_def_id(impl_def_id.krate),
stability: None,
deprecation: None,

View File

@ -131,7 +131,7 @@ pub fn try_inline(
name: Some(name.clean(cx)),
attrs,
inner,
visibility: Some(clean::Public),
visibility: clean::Public,
stability: cx.tcx.lookup_stability(did).clean(cx),
deprecation: cx.tcx.lookup_deprecation(did).clean(cx),
def_id: did,
@ -418,7 +418,7 @@ pub fn build_impl(cx: &DocContext<'_>, did: DefId, attrs: Option<Attrs<'_>>,
source: tcx.def_span(did).clean(cx),
name: None,
attrs,
visibility: Some(clean::Inherited),
visibility: clean::Inherited,
stability: tcx.lookup_stability(did).clean(cx),
deprecation: tcx.lookup_deprecation(did).clean(cx),
def_id: did,

View File

@ -187,7 +187,7 @@ pub fn krate(mut cx: &mut DocContext<'_>) -> Crate {
source: Span::empty(),
name: Some(prim.to_url_str().to_string()),
attrs: attrs.clone(),
visibility: Some(Public),
visibility: Public,
stability: get_stability(cx, def_id),
deprecation: get_deprecation(cx, def_id),
def_id,
@ -199,7 +199,7 @@ pub fn krate(mut cx: &mut DocContext<'_>) -> Crate {
source: Span::empty(),
name: Some(kw.clone()),
attrs: attrs,
visibility: Some(Public),
visibility: Public,
stability: get_stability(cx, def_id),
deprecation: get_deprecation(cx, def_id),
def_id,
@ -361,7 +361,7 @@ pub struct Item {
pub name: Option<String>,
pub attrs: Attributes,
pub inner: ItemEnum,
pub visibility: Option<Visibility>,
pub visibility: Visibility,
pub def_id: DefId,
pub stability: Option<Stability>,
pub deprecation: Option<Deprecation>,
@ -1849,7 +1849,7 @@ fn get_real_types(
cx: &DocContext<'_>,
recurse: i32,
) -> FxHashSet<Type> {
let arg_s = arg.to_string();
let arg_s = arg.print().to_string();
let mut res = FxHashSet::default();
if recurse >= 10 { // FIXME: remove this whole recurse thing when the recursion bug is fixed
return res;
@ -2311,7 +2311,7 @@ impl Clean<Item> for hir::TraitItem {
attrs: self.attrs.clean(cx),
source: self.span.clean(cx),
def_id: local_did,
visibility: None,
visibility: Visibility::Inherited,
stability: get_stability(cx, local_did),
deprecation: get_deprecation(cx, local_did),
inner,
@ -2496,7 +2496,7 @@ impl Clean<Item> for ty::AssocItem {
let visibility = match self.container {
ty::ImplContainer(_) => self.vis.clean(cx),
ty::TraitContainer(_) => None,
ty::TraitContainer(_) => Inherited,
};
Item {
@ -3293,9 +3293,9 @@ pub enum Visibility {
Restricted(DefId, Path),
}
impl Clean<Option<Visibility>> for hir::Visibility {
fn clean(&self, cx: &DocContext<'_>) -> Option<Visibility> {
Some(match self.node {
impl Clean<Visibility> for hir::Visibility {
fn clean(&self, cx: &DocContext<'_>) -> Visibility {
match self.node {
hir::VisibilityKind::Public => Visibility::Public,
hir::VisibilityKind::Inherited => Visibility::Inherited,
hir::VisibilityKind::Crate(_) => Visibility::Crate,
@ -3304,13 +3304,13 @@ impl Clean<Option<Visibility>> for hir::Visibility {
let did = register_res(cx, path.res);
Visibility::Restricted(did, path)
}
})
}
}
}
impl Clean<Option<Visibility>> for ty::Visibility {
fn clean(&self, _: &DocContext<'_>) -> Option<Visibility> {
Some(if *self == ty::Visibility::Public { Public } else { Inherited })
impl Clean<Visibility> for ty::Visibility {
fn clean(&self, _: &DocContext<'_>) -> Visibility {
if *self == ty::Visibility::Public { Public } else { Inherited }
}
}
@ -3427,7 +3427,7 @@ impl Clean<Item> for doctree::Variant<'_> {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
visibility: None,
visibility: Inherited,
stability: cx.stability(self.id).clean(cx),
deprecation: cx.deprecation(self.id).clean(cx),
def_id: cx.tcx.hir().local_def_id(self.id),
@ -3470,7 +3470,7 @@ impl Clean<Item> for ty::VariantDef {
name: Some(self.ident.clean(cx)),
attrs: inline::load_attrs(cx, self.def_id).clean(cx),
source: cx.tcx.def_span(self.def_id).clean(cx),
visibility: Some(Inherited),
visibility: Inherited,
def_id: self.def_id,
inner: VariantItem(Variant { kind }),
stability: get_stability(cx, self.def_id),
@ -3573,16 +3573,6 @@ pub enum GenericArg {
Const(Constant),
}
impl fmt::Display for GenericArg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
GenericArg::Lifetime(lt) => lt.fmt(f),
GenericArg::Type(ty) => ty.fmt(f),
GenericArg::Const(ct) => ct.fmt(f),
}
}
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum GenericArgs {
AngleBracketed {
@ -4274,7 +4264,7 @@ fn resolve_type(cx: &DocContext<'_>,
return Generic(kw::SelfUpper.to_string());
}
Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => {
return Generic(format!("{:#}", path));
return Generic(format!("{:#}", path.print()));
}
Res::SelfTy(..)
| Res::Def(DefKind::TyParam, _)
@ -4343,7 +4333,7 @@ impl Clean<Item> for doctree::Macro<'_> {
name: Some(name.clone()),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
visibility: Some(Public),
visibility: Public,
stability: cx.stability(self.hid).clean(cx),
deprecation: cx.deprecation(self.hid).clean(cx),
def_id: self.def_id,
@ -4371,7 +4361,7 @@ impl Clean<Item> for doctree::ProcMacro<'_> {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
visibility: Some(Public),
visibility: Public,
stability: cx.stability(self.id).clean(cx),
deprecation: cx.deprecation(self.id).clean(cx),
def_id: cx.tcx.hir().local_def_id(self.id),

File diff suppressed because it is too large Load Diff

View File

@ -46,14 +46,6 @@ pub enum ItemType {
}
#[derive(Copy, Eq, PartialEq, Clone)]
pub enum NameSpace {
Type,
Value,
Macro,
Keyword,
}
impl<'a> From<&'a clean::Item> for ItemType {
fn from(item: &'a clean::Item) -> ItemType {
let inner = match item.inner {
@ -120,7 +112,7 @@ impl From<clean::TypeKind> for ItemType {
}
impl ItemType {
pub fn css_class(&self) -> &'static str {
pub fn as_str(&self) -> &'static str {
match *self {
ItemType::Module => "mod",
ItemType::ExternCrate => "externcrate",
@ -151,7 +143,7 @@ impl ItemType {
}
}
pub fn name_space(&self) -> NameSpace {
pub fn name_space(&self) -> &'static str {
match *self {
ItemType::Struct |
ItemType::Union |
@ -163,7 +155,7 @@ impl ItemType {
ItemType::AssocType |
ItemType::OpaqueTy |
ItemType::TraitAlias |
ItemType::ForeignType => NameSpace::Type,
ItemType::ForeignType => NAMESPACE_TYPE,
ItemType::ExternCrate |
ItemType::Import |
@ -175,20 +167,20 @@ impl ItemType {
ItemType::StructField |
ItemType::Variant |
ItemType::Constant |
ItemType::AssocConst => NameSpace::Value,
ItemType::AssocConst => NAMESPACE_VALUE,
ItemType::Macro |
ItemType::ProcAttribute |
ItemType::ProcDerive => NameSpace::Macro,
ItemType::ProcDerive => NAMESPACE_MACRO,
ItemType::Keyword => NameSpace::Keyword,
ItemType::Keyword => NAMESPACE_KEYWORD,
}
}
}
impl fmt::Display for ItemType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.css_class().fmt(f)
write!(f, "{}", self.as_str())
}
}
@ -196,20 +188,3 @@ pub const NAMESPACE_TYPE: &'static str = "t";
pub const NAMESPACE_VALUE: &'static str = "v";
pub const NAMESPACE_MACRO: &'static str = "m";
pub const NAMESPACE_KEYWORD: &'static str = "k";
impl NameSpace {
pub fn to_static_str(&self) -> &'static str {
match *self {
NameSpace::Type => NAMESPACE_TYPE,
NameSpace::Value => NAMESPACE_VALUE,
NameSpace::Macro => NAMESPACE_MACRO,
NameSpace::Keyword => NAMESPACE_KEYWORD,
}
}
}
impl fmt::Display for NameSpace {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.to_static_str().fmt(f)
}
}

View File

@ -1,7 +1,7 @@
use std::path::PathBuf;
use crate::externalfiles::ExternalHtml;
use crate::html::render::SlashChecker;
use crate::html::render::ensure_trailing_slash;
use crate::html::format::{Buffer, Print};
#[derive(Clone)]
@ -180,7 +180,7 @@ pub fn render<T: Print, S: Print>(
css_class = page.css_class,
logo = {
let p = format!("{}{}", page.root_path, layout.krate);
let p = SlashChecker(&p);
let p = ensure_trailing_slash(&p);
if layout.logo.is_empty() {
format!("<a href='{path}index.html'>\
<div class='logo-container'>\

View File

@ -752,7 +752,7 @@ impl MarkdownWithToc<'_> {
html::push_html(&mut s, p);
}
format!("<nav id=\"TOC\">{}</nav>{}", toc.into_toc(), s)
format!("<nav id=\"TOC\">{}</nav>{}", toc.into_toc().print(), s)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,675 @@
use crate::clean::{self, GetDefId, AttributesExt};
use crate::fold::DocFolder;
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
use rustc::middle::privacy::AccessLevels;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use std::mem;
use std::path::{Path, PathBuf};
use std::collections::BTreeMap;
use syntax::source_map::FileName;
use syntax::symbol::sym;
use serialize::json::{ToJson, Json, as_json};
use super::{ItemType, IndexItem, IndexItemFunctionType, Impl, shorten, plain_summary_line};
use super::{Type, RenderInfo};
/// Indicates where an external crate can be found.
pub enum ExternalLocation {
/// Remote URL root of the external crate
Remote(String),
/// This external crate can be found in the local doc/ folder
Local,
/// The external crate could not be found.
Unknown,
}
/// This cache is used to store information about the `clean::Crate` being
/// rendered in order to provide more useful documentation. This contains
/// information like all implementors of a trait, all traits a type implements,
/// documentation for all known traits, etc.
///
/// This structure purposefully does not implement `Clone` because it's intended
/// to be a fairly large and expensive structure to clone. Instead this adheres
/// to `Send` so it may be stored in a `Arc` instance and shared among the various
/// rendering threads.
#[derive(Default)]
crate struct Cache {
/// Maps a type ID to all known implementations for that type. This is only
/// recognized for intra-crate `ResolvedPath` types, and is used to print
/// out extra documentation on the page of an enum/struct.
///
/// The values of the map are a list of implementations and documentation
/// found on that implementation.
pub impls: FxHashMap<DefId, Vec<Impl>>,
/// Maintains a mapping of local crate `NodeId`s to the fully qualified name
/// and "short type description" of that node. This is used when generating
/// URLs when a type is being linked to. External paths are not located in
/// this map because the `External` type itself has all the information
/// necessary.
pub paths: FxHashMap<DefId, (Vec<String>, ItemType)>,
/// Similar to `paths`, but only holds external paths. This is only used for
/// generating explicit hyperlinks to other crates.
pub external_paths: FxHashMap<DefId, (Vec<String>, ItemType)>,
/// Maps local `DefId`s of exported types to fully qualified paths.
/// Unlike 'paths', this mapping ignores any renames that occur
/// due to 'use' statements.
///
/// This map is used when writing out the special 'implementors'
/// javascript file. By using the exact path that the type
/// is declared with, we ensure that each path will be identical
/// to the path used if the corresponding type is inlined. By
/// doing this, we can detect duplicate impls on a trait page, and only display
/// the impl for the inlined type.
pub exact_paths: FxHashMap<DefId, Vec<String>>,
/// This map contains information about all known traits of this crate.
/// Implementations of a crate should inherit the documentation of the
/// parent trait if no extra documentation is specified, and default methods
/// should show up in documentation about trait implementations.
pub traits: FxHashMap<DefId, clean::Trait>,
/// When rendering traits, it's often useful to be able to list all
/// implementors of the trait, and this mapping is exactly, that: a mapping
/// of trait ids to the list of known implementors of the trait
pub implementors: FxHashMap<DefId, Vec<Impl>>,
/// Cache of where external crate documentation can be found.
pub extern_locations: FxHashMap<CrateNum, (String, PathBuf, ExternalLocation)>,
/// Cache of where documentation for primitives can be found.
pub primitive_locations: FxHashMap<clean::PrimitiveType, DefId>,
// Note that external items for which `doc(hidden)` applies to are shown as
// non-reachable while local items aren't. This is because we're reusing
// the access levels from the privacy check pass.
pub access_levels: AccessLevels<DefId>,
/// The version of the crate being documented, if given from the `--crate-version` flag.
pub crate_version: Option<String>,
// Private fields only used when initially crawling a crate to build a cache
stack: Vec<String>,
parent_stack: Vec<DefId>,
parent_is_trait_impl: bool,
search_index: Vec<IndexItem>,
stripped_mod: bool,
pub deref_trait_did: Option<DefId>,
pub deref_mut_trait_did: Option<DefId>,
pub owned_box_did: Option<DefId>,
masked_crates: FxHashSet<CrateNum>,
// In rare case where a structure is defined in one module but implemented
// in another, if the implementing module is parsed before defining module,
// then the fully qualified name of the structure isn't presented in `paths`
// yet when its implementation methods are being indexed. Caches such methods
// and their parent id here and indexes them at the end of crate parsing.
orphan_impl_items: Vec<(DefId, clean::Item)>,
// Similarly to `orphan_impl_items`, sometimes trait impls are picked up
// even though the trait itself is not exported. This can happen if a trait
// was defined in function/expression scope, since the impl will be picked
// up by `collect-trait-impls` but the trait won't be scraped out in the HIR
// crawl. In order to prevent crashes when looking for spotlight traits or
// when gathering trait documentation on a type, hold impls here while
// folding and add them to the cache later on if we find the trait.
orphan_trait_impls: Vec<(DefId, FxHashSet<DefId>, Impl)>,
/// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias,
/// we need the alias element to have an array of items.
pub(super) aliases: FxHashMap<String, Vec<IndexItem>>,
}
impl Cache {
pub fn from_krate(
renderinfo: RenderInfo,
extern_html_root_urls: &BTreeMap<String, String>,
dst: &Path,
mut krate: clean::Crate,
) -> (clean::Crate, String, Cache) {
// Crawl the crate to build various caches used for the output
let RenderInfo {
inlined: _,
external_paths,
exact_paths,
access_levels,
deref_trait_did,
deref_mut_trait_did,
owned_box_did,
} = renderinfo;
let external_paths = external_paths.into_iter()
.map(|(k, (v, t))| (k, (v, ItemType::from(t))))
.collect();
let mut cache = Cache {
impls: Default::default(),
external_paths,
exact_paths,
paths: Default::default(),
implementors: Default::default(),
stack: Vec::new(),
parent_stack: Vec::new(),
search_index: Vec::new(),
parent_is_trait_impl: false,
extern_locations: Default::default(),
primitive_locations: Default::default(),
stripped_mod: false,
access_levels,
crate_version: krate.version.take(),
orphan_impl_items: Vec::new(),
orphan_trait_impls: Vec::new(),
traits: krate.external_traits.replace(Default::default()),
deref_trait_did,
deref_mut_trait_did,
owned_box_did,
masked_crates: mem::take(&mut krate.masked_crates),
aliases: Default::default(),
};
// Cache where all our extern crates are located
for &(n, ref e) in &krate.externs {
let src_root = match e.src {
FileName::Real(ref p) => match p.parent() {
Some(p) => p.to_path_buf(),
None => PathBuf::new(),
},
_ => PathBuf::new(),
};
let extern_url = extern_html_root_urls.get(&e.name).map(|u| &**u);
cache.extern_locations.insert(n, (e.name.clone(), src_root,
extern_location(e, extern_url, &dst)));
let did = DefId { krate: n, index: CRATE_DEF_INDEX };
cache.external_paths.insert(did, (vec![e.name.to_string()], ItemType::Module));
}
// Cache where all known primitives have their documentation located.
//
// Favor linking to as local extern as possible, so iterate all crates in
// reverse topological order.
for &(_, ref e) in krate.externs.iter().rev() {
for &(def_id, prim, _) in &e.primitives {
cache.primitive_locations.insert(prim, def_id);
}
}
for &(def_id, prim, _) in &krate.primitives {
cache.primitive_locations.insert(prim, def_id);
}
cache.stack.push(krate.name.clone());
krate = cache.fold_crate(krate);
for (trait_did, dids, impl_) in cache.orphan_trait_impls.drain(..) {
if cache.traits.contains_key(&trait_did) {
for did in dids {
cache.impls.entry(did).or_insert(vec![]).push(impl_.clone());
}
}
}
// Build our search index
let index = build_index(&krate, &mut cache);
(krate, index, cache)
}
}
impl DocFolder for Cache {
fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
if item.def_id.is_local() {
debug!("folding {} \"{:?}\", id {:?}", item.type_(), item.name, item.def_id);
}
// If this is a stripped module,
// we don't want it or its children in the search index.
let orig_stripped_mod = match item.inner {
clean::StrippedItem(box clean::ModuleItem(..)) => {
mem::replace(&mut self.stripped_mod, true)
}
_ => self.stripped_mod,
};
// If the impl is from a masked crate or references something from a
// masked crate then remove it completely.
if let clean::ImplItem(ref i) = item.inner {
if self.masked_crates.contains(&item.def_id.krate) ||
i.trait_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)) ||
i.for_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)) {
return None;
}
}
// Propagate a trait method's documentation to all implementors of the
// trait.
if let clean::TraitItem(ref t) = item.inner {
self.traits.entry(item.def_id).or_insert_with(|| t.clone());
}
// Collect all the implementors of traits.
if let clean::ImplItem(ref i) = item.inner {
if let Some(did) = i.trait_.def_id() {
if i.blanket_impl.is_none() {
self.implementors.entry(did).or_default().push(Impl {
impl_item: item.clone(),
});
}
}
}
// Index this method for searching later on.
if let Some(ref s) = item.name {
let (parent, is_inherent_impl_item) = match item.inner {
clean::StrippedItem(..) => ((None, None), false),
clean::AssocConstItem(..) |
clean::TypedefItem(_, true) if self.parent_is_trait_impl => {
// skip associated items in trait impls
((None, None), false)
}
clean::AssocTypeItem(..) |
clean::TyMethodItem(..) |
clean::StructFieldItem(..) |
clean::VariantItem(..) => {
((Some(*self.parent_stack.last().unwrap()),
Some(&self.stack[..self.stack.len() - 1])),
false)
}
clean::MethodItem(..) | clean::AssocConstItem(..) => {
if self.parent_stack.is_empty() {
((None, None), false)
} else {
let last = self.parent_stack.last().unwrap();
let did = *last;
let path = match self.paths.get(&did) {
// The current stack not necessarily has correlation
// for where the type was defined. On the other
// hand, `paths` always has the right
// information if present.
Some(&(ref fqp, ItemType::Trait)) |
Some(&(ref fqp, ItemType::Struct)) |
Some(&(ref fqp, ItemType::Union)) |
Some(&(ref fqp, ItemType::Enum)) =>
Some(&fqp[..fqp.len() - 1]),
Some(..) => Some(&*self.stack),
None => None
};
((Some(*last), path), true)
}
}
_ => ((None, Some(&*self.stack)), false)
};
match parent {
(parent, Some(path)) if is_inherent_impl_item || (!self.stripped_mod) => {
debug_assert!(!item.is_stripped());
// A crate has a module at its root, containing all items,
// which should not be indexed. The crate-item itself is
// inserted later on when serializing the search-index.
if item.def_id.index != CRATE_DEF_INDEX {
self.search_index.push(IndexItem {
ty: item.type_(),
name: s.to_string(),
path: path.join("::"),
desc: shorten(plain_summary_line(item.doc_value())),
parent,
parent_idx: None,
search_type: get_index_search_type(&item),
});
}
}
(Some(parent), None) if is_inherent_impl_item => {
// We have a parent, but we don't know where they're
// defined yet. Wait for later to index this item.
self.orphan_impl_items.push((parent, item.clone()));
}
_ => {}
}
}
// Keep track of the fully qualified path for this item.
let pushed = match item.name {
Some(ref n) if !n.is_empty() => {
self.stack.push(n.to_string());
true
}
_ => false,
};
match item.inner {
clean::StructItem(..) | clean::EnumItem(..) |
clean::TypedefItem(..) | clean::TraitItem(..) |
clean::FunctionItem(..) | clean::ModuleItem(..) |
clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) |
clean::ConstantItem(..) | clean::StaticItem(..) |
clean::UnionItem(..) | clean::ForeignTypeItem |
clean::MacroItem(..) | clean::ProcMacroItem(..)
if !self.stripped_mod => {
// Re-exported items mean that the same id can show up twice
// in the rustdoc ast that we're looking at. We know,
// however, that a re-exported item doesn't show up in the
// `public_items` map, so we can skip inserting into the
// paths map if there was already an entry present and we're
// not a public item.
if !self.paths.contains_key(&item.def_id) ||
self.access_levels.is_public(item.def_id)
{
self.paths.insert(item.def_id,
(self.stack.clone(), item.type_()));
}
self.add_aliases(&item);
}
// Link variants to their parent enum because pages aren't emitted
// for each variant.
clean::VariantItem(..) if !self.stripped_mod => {
let mut stack = self.stack.clone();
stack.pop();
self.paths.insert(item.def_id, (stack, ItemType::Enum));
}
clean::PrimitiveItem(..) => {
self.add_aliases(&item);
self.paths.insert(item.def_id, (self.stack.clone(),
item.type_()));
}
_ => {}
}
// Maintain the parent stack
let orig_parent_is_trait_impl = self.parent_is_trait_impl;
let parent_pushed = match item.inner {
clean::TraitItem(..) | clean::EnumItem(..) | clean::ForeignTypeItem |
clean::StructItem(..) | clean::UnionItem(..) => {
self.parent_stack.push(item.def_id);
self.parent_is_trait_impl = false;
true
}
clean::ImplItem(ref i) => {
self.parent_is_trait_impl = i.trait_.is_some();
match i.for_ {
clean::ResolvedPath{ did, .. } => {
self.parent_stack.push(did);
true
}
ref t => {
let prim_did = t.primitive_type().and_then(|t| {
self.primitive_locations.get(&t).cloned()
});
match prim_did {
Some(did) => {
self.parent_stack.push(did);
true
}
None => false,
}
}
}
}
_ => false
};
// Once we've recursively found all the generics, hoard off all the
// implementations elsewhere.
let ret = self.fold_item_recur(item).and_then(|item| {
if let clean::Item { inner: clean::ImplItem(_), .. } = item {
// Figure out the id of this impl. This may map to a
// primitive rather than always to a struct/enum.
// Note: matching twice to restrict the lifetime of the `i` borrow.
let mut dids = FxHashSet::default();
if let clean::Item { inner: clean::ImplItem(ref i), .. } = item {
match i.for_ {
clean::ResolvedPath { did, .. } |
clean::BorrowedRef {
type_: box clean::ResolvedPath { did, .. }, ..
} => {
dids.insert(did);
}
ref t => {
let did = t.primitive_type().and_then(|t| {
self.primitive_locations.get(&t).cloned()
});
if let Some(did) = did {
dids.insert(did);
}
}
}
if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
for bound in generics {
if let Some(did) = bound.def_id() {
dids.insert(did);
}
}
}
} else {
unreachable!()
};
let impl_item = Impl {
impl_item: item,
};
if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) {
for did in dids {
self.impls.entry(did).or_insert(vec![]).push(impl_item.clone());
}
} else {
let trait_did = impl_item.trait_did().unwrap();
self.orphan_trait_impls.push((trait_did, dids, impl_item));
}
None
} else {
Some(item)
}
});
if pushed { self.stack.pop().unwrap(); }
if parent_pushed { self.parent_stack.pop().unwrap(); }
self.stripped_mod = orig_stripped_mod;
self.parent_is_trait_impl = orig_parent_is_trait_impl;
ret
}
}
impl Cache {
fn add_aliases(&mut self, item: &clean::Item) {
if item.def_id.index == CRATE_DEF_INDEX {
return
}
if let Some(ref item_name) = item.name {
let path = self.paths.get(&item.def_id)
.map(|p| p.0[..p.0.len() - 1].join("::"))
.unwrap_or("std".to_owned());
for alias in item.attrs.lists(sym::doc)
.filter(|a| a.check_name(sym::alias))
.filter_map(|a| a.value_str()
.map(|s| s.to_string().replace("\"", "")))
.filter(|v| !v.is_empty())
.collect::<FxHashSet<_>>()
.into_iter() {
self.aliases.entry(alias)
.or_insert(Vec::with_capacity(1))
.push(IndexItem {
ty: item.type_(),
name: item_name.to_string(),
path: path.clone(),
desc: shorten(plain_summary_line(item.doc_value())),
parent: None,
parent_idx: None,
search_type: get_index_search_type(&item),
});
}
}
}
}
/// Attempts to find where an external crate is located, given that we're
/// rendering in to the specified source destination.
fn extern_location(e: &clean::ExternalCrate, extern_url: Option<&str>, dst: &Path)
-> ExternalLocation
{
use ExternalLocation::*;
// See if there's documentation generated into the local directory
let local_location = dst.join(&e.name);
if local_location.is_dir() {
return Local;
}
if let Some(url) = extern_url {
let mut url = url.to_string();
if !url.ends_with("/") {
url.push('/');
}
return Remote(url);
}
// Failing that, see if there's an attribute specifying where to find this
// external crate
e.attrs.lists(sym::doc)
.filter(|a| a.check_name(sym::html_root_url))
.filter_map(|a| a.value_str())
.map(|url| {
let mut url = url.to_string();
if !url.ends_with("/") {
url.push('/')
}
Remote(url)
}).next().unwrap_or(Unknown) // Well, at least we tried.
}
/// Builds the search index from the collected metadata
fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
let mut nodeid_to_pathid = FxHashMap::default();
let mut crate_items = Vec::with_capacity(cache.search_index.len());
let mut crate_paths = Vec::<Json>::new();
let Cache { ref mut search_index,
ref orphan_impl_items,
ref paths, .. } = *cache;
// Attach all orphan items to the type's definition if the type
// has since been learned.
for &(did, ref item) in orphan_impl_items {
if let Some(&(ref fqp, _)) = paths.get(&did) {
search_index.push(IndexItem {
ty: item.type_(),
name: item.name.clone().unwrap(),
path: fqp[..fqp.len() - 1].join("::"),
desc: shorten(plain_summary_line(item.doc_value())),
parent: Some(did),
parent_idx: None,
search_type: get_index_search_type(&item),
});
}
}
// Reduce `NodeId` in paths into smaller sequential numbers,
// and prune the paths that do not appear in the index.
let mut lastpath = String::new();
let mut lastpathid = 0usize;
for item in search_index {
item.parent_idx = item.parent.map(|nodeid| {
if nodeid_to_pathid.contains_key(&nodeid) {
*nodeid_to_pathid.get(&nodeid).unwrap()
} else {
let pathid = lastpathid;
nodeid_to_pathid.insert(nodeid, pathid);
lastpathid += 1;
let &(ref fqp, short) = paths.get(&nodeid).unwrap();
crate_paths.push(((short as usize), fqp.last().unwrap().clone()).to_json());
pathid
}
});
// Omit the parent path if it is same to that of the prior item.
if lastpath == item.path {
item.path.clear();
} else {
lastpath = item.path.clone();
}
crate_items.push(item.to_json());
}
let crate_doc = krate.module.as_ref().map(|module| {
shorten(plain_summary_line(module.doc_value()))
}).unwrap_or(String::new());
let mut crate_data = BTreeMap::new();
crate_data.insert("doc".to_owned(), Json::String(crate_doc));
crate_data.insert("i".to_owned(), Json::Array(crate_items));
crate_data.insert("p".to_owned(), Json::Array(crate_paths));
// Collect the index into a string
format!("searchIndex[{}] = {};",
as_json(&krate.name),
Json::Object(crate_data))
}
fn get_index_search_type(item: &clean::Item) -> Option<IndexItemFunctionType> {
let (all_types, ret_types) = match item.inner {
clean::FunctionItem(ref f) => (&f.all_types, &f.ret_types),
clean::MethodItem(ref m) => (&m.all_types, &m.ret_types),
clean::TyMethodItem(ref m) => (&m.all_types, &m.ret_types),
_ => return None,
};
let inputs = all_types.iter().map(|arg| {
get_index_type(&arg)
}).filter(|a| a.name.is_some()).collect();
let output = ret_types.iter().map(|arg| {
get_index_type(&arg)
}).filter(|a| a.name.is_some()).collect::<Vec<_>>();
let output = if output.is_empty() {
None
} else {
Some(output)
};
Some(IndexItemFunctionType { inputs, output })
}
fn get_index_type(clean_type: &clean::Type) -> Type {
let t = Type {
name: get_index_type_name(clean_type, true).map(|s| s.to_ascii_lowercase()),
generics: get_generics(clean_type),
};
t
}
fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option<String> {
match *clean_type {
clean::ResolvedPath { ref path, .. } => {
let segments = &path.segments;
let path_segment = segments.into_iter().last().unwrap_or_else(|| panic!(
"get_index_type_name(clean_type: {:?}, accept_generic: {:?}) had length zero path",
clean_type, accept_generic
));
Some(path_segment.name.clone())
}
clean::Generic(ref s) if accept_generic => Some(s.clone()),
clean::Primitive(ref p) => Some(format!("{:?}", p)),
clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic),
// FIXME: add all from clean::Type.
_ => None
}
}
fn get_generics(clean_type: &clean::Type) -> Option<Vec<String>> {
clean_type.generics()
.and_then(|types| {
let r = types.iter()
.filter_map(|t| get_index_type_name(t, false))
.map(|s| s.to_ascii_lowercase())
.collect::<Vec<_>>();
if r.is_empty() {
None
} else {
Some(r)
}
})
}

View File

@ -1,10 +1,7 @@
//! Table-of-contents creation.
use std::fmt;
use std::string::String;
/// A (recursive) table of contents
#[derive(PartialEq)]
#[derive(Debug, PartialEq)]
pub struct Toc {
/// The levels are strictly decreasing, i.e.
///
@ -28,7 +25,7 @@ impl Toc {
}
}
#[derive(PartialEq)]
#[derive(Debug, PartialEq)]
pub struct TocEntry {
level: u32,
sec_number: String,
@ -165,25 +162,23 @@ impl TocBuilder {
}
}
impl fmt::Debug for Toc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl fmt::Display for Toc {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "<ul>")?;
impl Toc {
fn print_inner(&self, v: &mut String) {
v.push_str("<ul>");
for entry in &self.entries {
// recursively format this table of contents (the
// `{children}` is the key).
write!(fmt,
"\n<li><a href=\"#{id}\">{num} {name}</a>{children}</li>",
// recursively format this table of contents
v.push_str(&format!("\n<li><a href=\"#{id}\">{num} {name}</a>",
id = entry.id,
num = entry.sec_number, name = entry.name,
children = entry.children)?
num = entry.sec_number, name = entry.name));
entry.children.print_inner(&mut *v);
v.push_str("</li>");
}
write!(fmt, "</ul>")
v.push_str("</ul>");
}
crate fn print(&self) -> String {
let mut v = String::new();
self.print_inner(&mut v);
v
}
}

View File

@ -142,7 +142,8 @@ impl fold::DocFolder for CoverageCalculator {
}
clean::ImplItem(ref impl_) => {
if let Some(ref tr) = impl_.trait_ {
debug!("impl {:#} for {:#} in {}", tr, impl_.for_, i.source.filename);
debug!("impl {:#} for {:#} in {}",
tr.print(), impl_.for_.print(), i.source.filename);
// don't count trait impls, the missing-docs lint doesn't so we shouldn't
// either
@ -151,11 +152,11 @@ impl fold::DocFolder for CoverageCalculator {
// inherent impls *can* be documented, and those docs show up, but in most
// cases it doesn't make sense, as all methods on a type are in one single
// impl block
debug!("impl {:#} in {}", impl_.for_, i.source.filename);
debug!("impl {:#} in {}", impl_.for_.print(), i.source.filename);
}
}
_ => {
debug!("counting {} {:?} in {}", i.type_(), i.name, i.source.filename);
debug!("counting {:?} {:?} in {}", i.type_(), i.name, i.source.filename);
self.items.entry(i.source.filename.clone())
.or_default()
.count_item(has_docs);

View File

@ -237,7 +237,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
});
if parent_node.is_some() {
debug!("got parent node for {} {:?}, id {:?}", item.type_(), item.name, item.def_id);
debug!("got parent node for {:?} {:?}, id {:?}", item.type_(), item.name, item.def_id);
}
let current_item = match item.inner {

View File

@ -153,7 +153,7 @@ impl<'a> DocFolder for Stripper<'a> {
// We need to recurse into stripped modules to strip things
// like impl methods but when doing so we must not add any
// items to the `retained` set.
debug!("Stripper: recursing into stripped {} {:?}", i.type_(), i.name);
debug!("Stripper: recursing into stripped {:?} {:?}", i.type_(), i.name);
let old = mem::replace(&mut self.update_retained, false);
let ret = self.fold_item_recur(i);
self.update_retained = old;
@ -178,20 +178,20 @@ impl<'a> DocFolder for Stripper<'a> {
| clean::ForeignTypeItem => {
if i.def_id.is_local() {
if !self.access_levels.is_exported(i.def_id) {
debug!("Stripper: stripping {} {:?}", i.type_(), i.name);
debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name);
return None;
}
}
}
clean::StructFieldItem(..) => {
if i.visibility != Some(clean::Public) {
if i.visibility != clean::Public {
return StripItem(i).strip();
}
}
clean::ModuleItem(..) => {
if i.def_id.is_local() && i.visibility != Some(clean::Public) {
if i.def_id.is_local() && i.visibility != clean::Public {
debug!("Stripper: stripping module {:?}", i.name);
let old = mem::replace(&mut self.update_retained, false);
let ret = StripItem(self.fold_item_recur(i).unwrap()).strip();
@ -299,7 +299,7 @@ impl DocFolder for ImportStripper {
fn fold_item(&mut self, i: Item) -> Option<Item> {
match i.inner {
clean::ExternCrateItem(..) | clean::ImportItem(..)
if i.visibility != Some(clean::Public) =>
if i.visibility != clean::Public =>
{
None
}

View File

@ -39,7 +39,7 @@ struct Stripper<'a> {
impl<'a> DocFolder for Stripper<'a> {
fn fold_item(&mut self, i: Item) -> Option<Item> {
if i.attrs.lists(sym::doc).has_word(sym::hidden) {
debug!("strip_hidden: stripping {} {:?}", i.type_(), i.name);
debug!("strip_hidden: stripping {:?} {:?}", i.type_(), i.name);
// use a dedicated hidden item for given item type if any
match i.inner {
clean::StructFieldItem(..) | clean::ModuleItem(..) => {

View File

@ -53,9 +53,6 @@ fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }
[target.wasm32-wasi.dependencies]
wasi = { version = "0.7.0", features = ['rustc-dep-of-std', 'alloc'] }
[build-dependencies]
cc = "1.0"
[features]
default = ["std_detect_file_io", "std_detect_dlsym_getauxval"]

View File

@ -114,6 +114,9 @@ pub struct Metadata(fs_imp::FileAttr);
/// information like the entry's path and possibly other metadata can be
/// learned.
///
/// The order in which this iterator returns entries is platform and filesystem
/// dependent.
///
/// # Errors
///
/// This [`io::Result`] will be an [`Err`] if there's some sort of intermittent
@ -1962,6 +1965,9 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// The order in which this iterator returns entries is platform and filesystem
/// dependent.
///
/// # Errors
///
/// This function will return an error in the following situations, but is not
@ -1994,6 +2000,25 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// Ok(())
/// }
/// ```
///
/// ```rust,no_run
/// use std::{fs, io};
///
/// fn main() -> io::Result<()> {
/// let mut entries = fs::read_dir(".")?
/// .map(|res| res.map(|e| e.path()))
/// .collect::<Result<Vec<_>, io::Error>>()?;
///
/// // The order in which `read_dir` returns entries is not guaranteed. If reproducible
/// // ordering is required the entries should be explicitly sorted.
///
/// entries.sort();
///
/// // The entries have now been sorted by their path.
///
/// Ok(())
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
fs_imp::readdir(path.as_ref()).map(ReadDir)

View File

@ -5,4 +5,3 @@ pub use crate::ffi::OsString as EnvKey;
mod process_common;
#[path = "process_vxworks.rs"]
mod process_inner;
mod rtp;

View File

@ -3,7 +3,6 @@ use libc::{self, c_int, c_char};
use libc::{RTP_ID};
use crate::sys;
use crate::sys::cvt;
use crate::sys::process::rtp;
use crate::sys::process::process_common::*;
use crate::sys_common::thread;
@ -53,7 +52,7 @@ impl Command {
t!(cvt(libc::chdir(cwd.as_ptr())));
}
let ret = rtp::rtpSpawn(
let ret = libc::rtpSpawn(
self.get_argv()[0], // executing program
self.get_argv().as_ptr() as *const _, // argv
*sys::os::environ() as *const *const c_char,
@ -78,7 +77,7 @@ impl Command {
libc::close(orig_stderr);
}
if ret != rtp::RTP_ID_ERROR {
if ret != libc::RTP_ID_ERROR {
p.pid = ret;
Ok((p, ours))
} else {

View File

@ -1,298 +0,0 @@
#![allow(non_camel_case_types, unused)]
use libc::{self, c_int, size_t, c_char, BOOL, RTP_DESC, RTP_ID, TASK_ID};
// Copied directly from rtpLibCommon.h, rtpLib.h, signal.h and taskLibCommon.h (for task options)
// **** definitions for rtpLibCommon.h ****
pub const RTP_GLOBAL_SYMBOLS : c_int = 0x01; // register global symbols for RTP
pub const RTP_LOCAL_SYMBOLS : c_int = 0x02; // idem for local symbols
pub const RTP_ALL_SYMBOLS : c_int = (RTP_GLOBAL_SYMBOLS | RTP_LOCAL_SYMBOLS);
pub const RTP_DEBUG : c_int = 0x10; // set RTP in debug mode when created
pub const RTP_BUFFER_VAL_OFF : c_int = 0x20; // disable buffer validation for all
// system calls issued from the RTP
pub const RTP_LOADED_WAIT : c_int = 0x40; // Wait until the RTP is loaded
pub const RTP_CPU_AFFINITY_NONE : c_int = 0x80; // Remove any CPU affinity (SMP)
// Error Status codes
pub const M_rtpLib : c_int = 178 << 16;
pub const S_rtpLib_INVALID_FILE : c_int = (M_rtpLib | 1);
pub const S_rtpLib_INVALID_OPTION : c_int = (M_rtpLib | 2);
pub const S_rtpLib_ACCESS_DENIED : c_int = (M_rtpLib | 3);
pub const S_rtpLib_INVALID_RTP_ID : c_int = (M_rtpLib | 4);
pub const S_rtpLib_NO_SYMBOL_TABLE : c_int = (M_rtpLib | 5);
pub const S_rtpLib_INVALID_SEGMENT_START_ADDRESS : c_int = (M_rtpLib | 6);
pub const S_rtpLib_INVALID_SYMBOL_REGISTR_POLICY : c_int = (M_rtpLib | 7);
pub const S_rtpLib_INSTANTIATE_FAILED : c_int = (M_rtpLib | 8);
pub const S_rtpLib_INVALID_TASK_OPTION : c_int = (M_rtpLib | 9);
pub const S_rtpLib_RTP_NAME_LENGTH_EXCEEDED : c_int = (M_rtpLib | 10); // rtpInfoGet
pub const VX_RTP_NAME_LENGTH : c_int = 255; // max name length for diplay
// The 'status' field (32 bit integer) of a RTP holds the RTP state and status.
//
// NOTE: RTP_STATE_GET() : read the RTP state(s)
// RTP_STATE_PUT() : write the RTP state(s)
// RTP_STATE_SET() : set a RTP state
// RTP_STATE_UNSET() : unset a RTP state
//
// RTP_STATUS_GET() : read the RTP status
// RTP_STATUS_PUT() : write the RTP status
// RTP_STATUS_SET() : set a RTP status
// RTP_STATUS_UNSET() : unset a RTP status
//
// The PUT/SET/UNSET macros are available only in the kernel headers.
// RTP states
pub const RTP_STATE_CREATE : c_int = 0x0001; // RrtpStructTP is under construction
pub const RTP_STATE_NORMAL : c_int = 0x0002; // RrtpStructTP is ready
pub const RTP_STATE_DELETE : c_int = 0x0004; // RrtpStructTP is being deleted
pub const RTP_STATUS_STOP : c_int = 0x0100; // RTP hrtpStructas recieved stopped signal
pub const RTP_STATUS_ELECTED_DELETER : c_int = 0x0200; // RTP drtpStructelete has started
pub const RTP_STATE_MASK : c_int = (RTP_STATE_CREATE | RTP_STATE_NORMAL |
RTP_STATE_DELETE);
pub const RTP_STATUS_MASK : c_int = (RTP_STATUS_STOP | RTP_STATUS_ELECTED_DELETER);
pub fn RTP_STATE_GET (value : c_int) -> c_int {
value & RTP_STATE_MASK
}
pub fn RTP_STATUS_GET (value : c_int) -> c_int {
value & RTP_STATUS_MASK
}
// Indicates that the RTP_ID returned is not valid.
// RTP_ID_ERROR is supposed to be set to -1, but you can't set
// an unsigned value to a negative without casting, and you
// can't cast unless the size of the integer types are the same,
// but the size of RTP_ID may differ between kernel and user space.
// Bitwise or-ing min and max should get the same result.
pub const RTP_ID_ERROR : RTP_ID = RTP_ID::min_value() | RTP_ID::max_value();
// IS_RTP_ C macros
pub fn IS_RTP_STATE_NORMAL (value : c_int) -> bool {
(RTP_STATE_GET(value) & RTP_STATE_NORMAL) == RTP_STATE_NORMAL
}
pub fn IS_RTP_STATE_CREATE (value : c_int) -> bool {
(RTP_STATE_GET(value) & RTP_STATE_CREATE) == RTP_STATE_CREATE
}
pub fn IS_RTP_STATE_DELETE (value : c_int) -> bool {
(RTP_STATE_GET(value) & RTP_STATE_DELETE) == RTP_STATE_DELETE
}
pub fn IS_RTP_STATUS_STOP (value : c_int) -> bool {
(RTP_STATUS_GET(value) & RTP_STATUS_STOP ) == RTP_STATUS_STOP
}
pub fn IS_RTP_STATUS_ELECTED_DELETER (value : c_int) -> bool {
(RTP_STATUS_GET(value) & RTP_STATUS_ELECTED_DELETER) == RTP_STATUS_ELECTED_DELETER
}
// **** end of definitions for rtpLibCommon.h ****
// **** definitions for rtpLib.h ****
pub fn rtpExit(exitCode : c_int) -> ! {
unsafe{ libc::exit (exitCode) }
}
/* rtpLib.h in the kernel
pub const RTP_DEL_VIA_TASK_DELETE : c_int = 0x1; // rtpDelete() via taskDestroy()
pub const RTP_DEL_FORCE : c_int = 0x2; // Forceful rtpDelete()
pub const RTP_ID_ANY : RTP_ID = 0; // used for when a kernel task
// wants to wait for the next
// RTP to finish
// Function pointers
pub type RTP_PRE_CREATE_HOOK = size_t;
pub type RTP_POST_CREATE_HOOK = size_t;
pub type RTP_INIT_COMPLETE_HOOK = size_t;
pub type RTP_DELETE_HOOK = size_t;
*/
// **** end of definitions for rtpLib.h ****
// **** definitions for signal.h ****
pub fn rtpKill(rtpId : RTP_ID, signo : c_int) -> c_int {
unsafe{ libc::kill(rtpId as c_int, signo) }
}
pub fn rtpSigqueue(rtpId : RTP_ID, signo : c_int, value : size_t) -> c_int {
unsafe{ libc::sigqueue(rtpId as c_int, signo, value) }
}
pub fn _rtpSigqueue(rtpId : RTP_ID, signo : c_int, value : *mut size_t, code : c_int) -> c_int {
unsafe{ libc::_sigqueue(rtpId, signo, value, code) }
}
pub fn taskRaise(signo : c_int) -> c_int {
unsafe{ libc::taskKill(libc::taskIdSelf(), signo) }
}
pub fn rtpRaise(signo : c_int) -> c_int {
unsafe{ libc::raise(signo) }
}
// **** end of definitions for signal.h ****
// **** definitions for taskLibCommon.h ****
pub const VX_PRIVATE_ENV : c_int = 0x0080; // 1 = private environment variables
pub const VX_NO_STACK_FILL : c_int = 0x0100; // 1 = avoid stack fill of 0xee
pub const VX_PRIVATE_UMASK : c_int = 0x0400; // 1 = private file creation mode mask
pub const VX_TASK_NOACTIVATE : c_int = 0x2000; // taskOpen() does not taskActivate()
pub const VX_NO_STACK_PROTECT : c_int = 0x4000; // no over/underflow stack protection,
// stack space remains executable
// define for all valid user task options
pub const VX_USR_TASK_OPTIONS_BASE: c_int = (VX_PRIVATE_ENV |
VX_NO_STACK_FILL |
VX_TASK_NOACTIVATE |
VX_NO_STACK_PROTECT |
VX_PRIVATE_UMASK);
// **** end of definitions for taskLibCommon.h ****
extern "C" {
// functions in rtpLibCommon.h
// forward declarations
pub fn rtpSpawn (
pubrtpFileName : *const c_char,
argv : *const *const c_char,
envp : *const *const c_char,
priority : c_int,
uStackSize : size_t,
options : c_int,
taskOptions : c_int,
) -> RTP_ID;
pub fn rtpInfoGet (
rtpId : RTP_ID,
rtpStruct : *mut RTP_DESC,
) -> c_int;
/* functions in rtpLib.h for kernel
// function declarations
pub fn rtpDelete (
id : RTP_ID,
options : c_int,
status : c_int,
) -> c_int;
pub fn rtpDeleteForce (
rtpId : RTP_ID
) -> c_int;
pub fn rtpShow (
rtpNameOrId : *mut c_char,
level : c_int,
) -> BOOL;
// RTP signals are always present when RTPs are included. The public RTP
// signal APIs are declared here.
pub fn rtpKill (
rtpId : RTP_ID,
signo : c_int,
) -> c_int;
pub fn rtpSigqueue (
rtpId : RTP_ID,
signo : c_int,
value : size_t, // Actual type is const union sigval value,
// which is a union of int and void *
) -> c_int;
pub fn rtpTaskKill (
tid : TASK_ID,
signo : c_int,
) -> c_int;
pub fn rtpTaskSigqueue (
tid : TASK_ID,
signo : c_int,
value : const size_t, // Actual type is const union sigval,
// which is a union of int and void *
) -> c_int;
pub fn rtpWait (
rtpWaitId : RTP_ID,
timeout : libc::alloc_jemalloc_Vx_ticks_t,
pRtpId : *mut RTP_ID,
pStatus : *mut c_int,
) -> c_int;
// Other public functions
pub fn rtpPreCreateHookAdd (
hook : RTP_PRE_CREATE_HOOK,
addToHead : BOOL,
) -> c_int;
pub fn rtpPreCreateHookDelete (
hook : RTP_POST_CREATE_HOOK,
) -> c_int;
pub fn rtpPostCreateHookAdd (
hook : RTP_POST_CREATE_HOOK,
addToHead : BOOL,
) -> c_int;
pub fn rtpPostCreateHookDelete (
hook : RTP_POST_CREATE_HOOK,
) -> c_int;
pub fn rtpInitCompleteHookAdd (
hook : RTP_INIT_COMPLETE_HOOK,
addToHead : BOOL,
) -> c_int;
pub fn rtpInitCompleteHookDelete (
hook : RTP_INIT_COMPLETE_HOOK,
) -> c_int;
pub fn rtpDeleteHookAdd (
hook : RTP_DELETE_HOOK,
addToHead : BOOL,
) -> c_int;
pub fn rtpDeleteHookDelete (
hook : RTP_DELETE_HOOK,
) -> c_int;
pub fn rtpMemShow (
rtpNameOrId : *mut c_char,
level : c_int,
) -> c_int;
pub fn rtpHookShow (
);
*/
}

View File

@ -19,6 +19,5 @@ syntax_pos = { path = "../libsyntax_pos" }
errors = { path = "../librustc_errors", package = "rustc_errors" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_lexer = { path = "../librustc_lexer" }
rustc_macros = { path = "../librustc_macros" }
rustc_target = { path = "../librustc_target" }
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }

View File

@ -1017,10 +1017,6 @@ impl<'a> ExtCtxt<'a> {
pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
self.parse_sess.span_diagnostic.span_err_with_code(sp, msg, code);
}
pub fn mut_span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str)
-> DiagnosticBuilder<'a> {
self.parse_sess.span_diagnostic.mut_span_err(sp, msg)
}
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.parse_sess.span_diagnostic.span_warn(sp, msg);
}

View File

@ -6,7 +6,7 @@ use crate::config::StripUnconfigured;
use crate::ext::base::*;
use crate::ext::proc_macro::{collect_derives, MarkAttrs};
use crate::ext::hygiene::{ExpnId, SyntaxContext, ExpnData, ExpnKind};
use crate::ext::tt::macro_rules::annotate_err_with_kind;
use crate::ext::mbe::macro_rules::annotate_err_with_kind;
use crate::ext::placeholders::{placeholder, PlaceholderExpander};
use crate::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err};
use crate::mut_visit::*;
@ -115,8 +115,8 @@ macro_rules! ast_fragments {
}
}
impl<'a> MacResult for crate::ext::tt::macro_rules::ParserAnyMacro<'a> {
$(fn $make_ast(self: Box<crate::ext::tt::macro_rules::ParserAnyMacro<'a>>)
impl<'a> MacResult for crate::ext::mbe::macro_rules::ParserAnyMacro<'a> {
$(fn $make_ast(self: Box<crate::ext::mbe::macro_rules::ParserAnyMacro<'a>>)
-> Option<$AstTy> {
Some(self.make(AstFragmentKind::$Kind).$make_ast())
})*
@ -384,7 +384,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let attr = attr::find_by_name(item.attrs(), sym::derive)
.expect("`derive` attribute should exist");
let span = attr.span;
let mut err = self.cx.mut_span_err(span,
let mut err = self.cx.struct_span_err(span,
"`derive` may only be applied to structs, enums and unions");
if let ast::AttrStyle::Inner = attr.style {
let trait_list = derives.iter()

166
src/libsyntax/ext/mbe.rs Normal file
View File

@ -0,0 +1,166 @@
//! This module implements declarative macros: old `macro_rules` and the newer
//! `macro`. Declarative macros are also known as "macro by example", and that's
//! why we call this module `mbe`. For external documentation, prefer the
//! official terminology: "declarative macros".
crate mod transcribe;
crate mod macro_check;
crate mod macro_parser;
crate mod macro_rules;
crate mod quoted;
use crate::ast;
use crate::parse::token::{self, Token, TokenKind};
use crate::tokenstream::{DelimSpan};
use syntax_pos::{BytePos, Span};
use rustc_data_structures::sync::Lrc;
/// Contains the sub-token-trees of a "delimited" token tree, such as the contents of `(`. Note
/// that the delimiter itself might be `NoDelim`.
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)]
struct Delimited {
delim: token::DelimToken,
tts: Vec<TokenTree>,
}
impl Delimited {
/// Returns a `self::TokenTree` with a `Span` corresponding to the opening delimiter.
fn open_tt(&self, span: Span) -> TokenTree {
let open_span = if span.is_dummy() {
span
} else {
span.with_hi(span.lo() + BytePos(self.delim.len() as u32))
};
TokenTree::token(token::OpenDelim(self.delim), open_span)
}
/// Returns a `self::TokenTree` with a `Span` corresponding to the closing delimiter.
fn close_tt(&self, span: Span) -> TokenTree {
let close_span = if span.is_dummy() {
span
} else {
span.with_lo(span.hi() - BytePos(self.delim.len() as u32))
};
TokenTree::token(token::CloseDelim(self.delim), close_span)
}
}
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)]
struct SequenceRepetition {
/// The sequence of token trees
tts: Vec<TokenTree>,
/// The optional separator
separator: Option<Token>,
/// Whether the sequence can be repeated zero (*), or one or more times (+)
kleene: KleeneToken,
/// The number of `Match`s that appear in the sequence (and subsequences)
num_captures: usize,
}
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
struct KleeneToken {
span: Span,
op: KleeneOp,
}
impl KleeneToken {
fn new(op: KleeneOp, span: Span) -> KleeneToken {
KleeneToken { span, op }
}
}
/// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star)
/// for token sequences.
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
enum KleeneOp {
/// Kleene star (`*`) for zero or more repetitions
ZeroOrMore,
/// Kleene plus (`+`) for one or more repetitions
OneOrMore,
/// Kleene optional (`?`) for zero or one reptitions
ZeroOrOne,
}
/// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, and `$(...)`
/// are "first-class" token trees. Useful for parsing macros.
#[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)]
enum TokenTree {
Token(Token),
Delimited(DelimSpan, Lrc<Delimited>),
/// A kleene-style repetition sequence
Sequence(DelimSpan, Lrc<SequenceRepetition>),
/// e.g., `$var`
MetaVar(Span, ast::Ident),
/// e.g., `$var:expr`. This is only used in the left hand side of MBE macros.
MetaVarDecl(
Span,
ast::Ident, /* name to bind */
ast::Ident, /* kind of nonterminal */
),
}
impl TokenTree {
/// Return the number of tokens in the tree.
fn len(&self) -> usize {
match *self {
TokenTree::Delimited(_, ref delimed) => match delimed.delim {
token::NoDelim => delimed.tts.len(),
_ => delimed.tts.len() + 2,
},
TokenTree::Sequence(_, ref seq) => seq.tts.len(),
_ => 0,
}
}
/// Returns `true` if the given token tree is delimited.
fn is_delimited(&self) -> bool {
match *self {
TokenTree::Delimited(..) => true,
_ => false,
}
}
/// Returns `true` if the given token tree is a token of the given kind.
fn is_token(&self, expected_kind: &TokenKind) -> bool {
match self {
TokenTree::Token(Token { kind: actual_kind, .. }) => actual_kind == expected_kind,
_ => false,
}
}
/// Gets the `index`-th sub-token-tree. This only makes sense for delimited trees and sequences.
fn get_tt(&self, index: usize) -> TokenTree {
match (self, index) {
(&TokenTree::Delimited(_, ref delimed), _) if delimed.delim == token::NoDelim => {
delimed.tts[index].clone()
}
(&TokenTree::Delimited(span, ref delimed), _) => {
if index == 0 {
return delimed.open_tt(span.open);
}
if index == delimed.tts.len() + 1 {
return delimed.close_tt(span.close);
}
delimed.tts[index - 1].clone()
}
(&TokenTree::Sequence(_, ref seq), _) => seq.tts[index].clone(),
_ => panic!("Cannot expand a token tree"),
}
}
/// Retrieves the `TokenTree`'s span.
fn span(&self) -> Span {
match *self {
TokenTree::Token(Token { span, .. })
| TokenTree::MetaVar(span, _)
| TokenTree::MetaVarDecl(span, _, _) => span,
TokenTree::Delimited(span, _) | TokenTree::Sequence(span, _) => span.entire(),
}
}
fn token(kind: TokenKind, span: Span) -> TokenTree {
TokenTree::Token(Token::new(kind, span))
}
}

View File

@ -106,7 +106,7 @@
//! bound.
use crate::ast::NodeId;
use crate::early_buffered_lints::BufferedEarlyLintId;
use crate::ext::tt::quoted::{KleeneToken, TokenTree};
use crate::ext::mbe::{KleeneToken, TokenTree};
use crate::parse::token::TokenKind;
use crate::parse::token::{DelimToken, Token};
use crate::parse::ParseSess;
@ -196,7 +196,7 @@ struct MacroState<'a> {
/// - `node_id` is used to emit lints
/// - `span` is used when no spans are available
/// - `lhses` and `rhses` should have the same length and represent the macro definition
pub fn check_meta_variables(
pub(super) fn check_meta_variables(
sess: &ParseSess,
node_id: NodeId,
span: Span,

View File

@ -70,12 +70,12 @@
//! eof: [a $( a )* a b ·]
//! ```
pub use NamedMatch::*;
pub use ParseResult::*;
crate use NamedMatch::*;
crate use ParseResult::*;
use TokenTreeOrTokenTreeSlice::*;
use crate::ast::{Ident, Name};
use crate::ext::tt::quoted::{self, TokenTree};
use crate::ext::mbe::{self, TokenTree};
use crate::parse::{Directory, ParseSess};
use crate::parse::parser::{Parser, PathStyle};
use crate::parse::token::{self, DocComment, Nonterminal, Token};
@ -195,7 +195,7 @@ struct MatcherPos<'root, 'tt> {
// `None`.
/// The KleeneOp of this sequence if we are in a repetition.
seq_op: Option<quoted::KleeneOp>,
seq_op: Option<mbe::KleeneOp>,
/// The separator if we are in a repetition.
sep: Option<Token>,
@ -267,7 +267,7 @@ impl<'root, 'tt> DerefMut for MatcherPosHandle<'root, 'tt> {
}
/// Represents the possible results of an attempted parse.
pub enum ParseResult<T> {
crate enum ParseResult<T> {
/// Parsed successfully.
Success(T),
/// Arm failed to match. If the second parameter is `token::Eof`, it indicates an unexpected
@ -279,10 +279,10 @@ pub enum ParseResult<T> {
/// A `ParseResult` where the `Success` variant contains a mapping of `Ident`s to `NamedMatch`es.
/// This represents the mapping of metavars to the token trees they bind to.
pub type NamedParseResult = ParseResult<FxHashMap<Ident, NamedMatch>>;
crate type NamedParseResult = ParseResult<FxHashMap<Ident, NamedMatch>>;
/// Count how many metavars are named in the given matcher `ms`.
pub fn count_names(ms: &[TokenTree]) -> usize {
pub(super) fn count_names(ms: &[TokenTree]) -> usize {
ms.iter().fold(0, |count, elt| {
count + match *elt {
TokenTree::Sequence(_, ref seq) => seq.num_captures,
@ -352,7 +352,7 @@ fn initial_matcher_pos<'root, 'tt>(ms: &'tt [TokenTree], open: Span) -> MatcherP
/// only on the nesting depth of `ast::TTSeq`s in the originating
/// token tree it was derived from.
#[derive(Debug, Clone)]
pub enum NamedMatch {
crate enum NamedMatch {
MatchedSeq(Lrc<NamedMatchVec>, DelimSpan),
MatchedNonterminal(Lrc<Nonterminal>),
}
@ -415,7 +415,7 @@ fn nameize<I: Iterator<Item = NamedMatch>>(
/// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For
/// other tokens, this is "unexpected token...".
pub fn parse_failure_msg(tok: &Token) -> String {
crate fn parse_failure_msg(tok: &Token) -> String {
match tok.kind {
token::Eof => "unexpected end of macro invocation".to_string(),
_ => format!(
@ -532,7 +532,7 @@ fn inner_parse_loop<'root, 'tt>(
}
// We don't need a separator. Move the "dot" back to the beginning of the matcher
// and try to match again UNLESS we are only allowed to have _one_ repetition.
else if item.seq_op != Some(quoted::KleeneOp::ZeroOrOne) {
else if item.seq_op != Some(mbe::KleeneOp::ZeroOrOne) {
item.match_cur = item.match_lo;
item.idx = 0;
cur_items.push(item);
@ -555,8 +555,8 @@ fn inner_parse_loop<'root, 'tt>(
// implicitly disallowing OneOrMore from having 0 matches here. Thus, that will
// result in a "no rules expected token" error by virtue of this matcher not
// working.
if seq.kleene.op == quoted::KleeneOp::ZeroOrMore
|| seq.kleene.op == quoted::KleeneOp::ZeroOrOne
if seq.kleene.op == mbe::KleeneOp::ZeroOrMore
|| seq.kleene.op == mbe::KleeneOp::ZeroOrOne
{
let mut new_item = item.clone();
new_item.match_cur += seq.num_captures;
@ -648,7 +648,7 @@ fn inner_parse_loop<'root, 'tt>(
/// - `directory`: Information about the file locations (needed for the black-box parser)
/// - `recurse_into_modules`: Whether or not to recurse into modules (needed for the black-box
/// parser)
pub fn parse(
pub(super) fn parse(
sess: &ParseSess,
tts: TokenStream,
ms: &[TokenTree],

View File

@ -4,12 +4,12 @@ use crate::edition::Edition;
use crate::ext::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander};
use crate::ext::base::{SyntaxExtension, SyntaxExtensionKind};
use crate::ext::expand::{AstFragment, AstFragmentKind};
use crate::ext::tt::macro_check;
use crate::ext::tt::macro_parser::{parse, parse_failure_msg};
use crate::ext::tt::macro_parser::{Error, Failure, Success};
use crate::ext::tt::macro_parser::{MatchedNonterminal, MatchedSeq};
use crate::ext::tt::quoted;
use crate::ext::tt::transcribe::transcribe;
use crate::ext::mbe;
use crate::ext::mbe::macro_check;
use crate::ext::mbe::macro_parser::{parse, parse_failure_msg};
use crate::ext::mbe::macro_parser::{Error, Failure, Success};
use crate::ext::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedParseResult};
use crate::ext::mbe::transcribe::transcribe;
use crate::feature_gate::Features;
use crate::parse::parser::Parser;
use crate::parse::token::TokenKind::*;
@ -35,7 +35,7 @@ const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
`ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \
`literal`, `path`, `meta`, `tt`, `item` and `vis`";
pub struct ParserAnyMacro<'a> {
crate struct ParserAnyMacro<'a> {
parser: Parser<'a>,
/// Span of the expansion site of the macro this parser is for
@ -45,7 +45,11 @@ pub struct ParserAnyMacro<'a> {
arm_span: Span,
}
pub fn annotate_err_with_kind(err: &mut DiagnosticBuilder<'_>, kind: AstFragmentKind, span: Span) {
crate fn annotate_err_with_kind(
err: &mut DiagnosticBuilder<'_>,
kind: AstFragmentKind,
span: Span,
) {
match kind {
AstFragmentKind::Ty => {
err.span_label(span, "this macro call doesn't expand to a type");
@ -58,7 +62,7 @@ pub fn annotate_err_with_kind(err: &mut DiagnosticBuilder<'_>, kind: AstFragment
}
impl<'a> ParserAnyMacro<'a> {
pub fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
crate fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self;
let fragment = panictry!(parser.parse_ast_fragment(kind, true).map_err(|mut e| {
if parser.token == token::Eof && e.message().ends_with(", found `<eof>`") {
@ -131,8 +135,8 @@ struct MacroRulesMacroExpander {
name: ast::Ident,
span: Span,
transparency: Transparency,
lhses: Vec<quoted::TokenTree>,
rhses: Vec<quoted::TokenTree>,
lhses: Vec<mbe::TokenTree>,
rhses: Vec<mbe::TokenTree>,
valid: bool,
}
@ -165,8 +169,8 @@ fn generic_extension<'cx>(
name: ast::Ident,
transparency: Transparency,
arg: TokenStream,
lhses: &[quoted::TokenTree],
rhses: &[quoted::TokenTree],
lhses: &[mbe::TokenTree],
rhses: &[mbe::TokenTree],
) -> Box<dyn MacResult + 'cx> {
if cx.trace_macros() {
trace_macros_note(cx, sp, format!("expanding `{}! {{ {} }}`", name, arg));
@ -178,7 +182,7 @@ fn generic_extension<'cx>(
for (i, lhs) in lhses.iter().enumerate() {
// try each arm's matchers
let lhs_tt = match *lhs {
quoted::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
_ => cx.span_bug(sp, "malformed macro lhs"),
};
@ -186,7 +190,7 @@ fn generic_extension<'cx>(
Success(named_matches) => {
let rhs = match rhses[i] {
// ignore delimiters
quoted::TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(),
mbe::TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(),
_ => cx.span_bug(sp, "malformed macro rhs"),
};
let arm_span = rhses[i].span();
@ -254,7 +258,7 @@ fn generic_extension<'cx>(
for lhs in lhses {
// try each arm's matchers
let lhs_tt = match *lhs {
quoted::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
_ => continue,
};
match TokenTree::parse(cx, lhs_tt, arg.clone()) {
@ -284,8 +288,8 @@ fn generic_extension<'cx>(
//
// Holy self-referential!
/// Converts a `macro_rules!` invocation into a syntax extension.
pub fn compile(
/// Converts a macro item into a syntax extension.
pub fn compile_declarative_macro(
sess: &ParseSess,
features: &Features,
def: &ast::Item,
@ -308,32 +312,32 @@ pub fn compile(
// ...quasiquoting this would be nice.
// These spans won't matter, anyways
let argument_gram = vec![
quoted::TokenTree::Sequence(
mbe::TokenTree::Sequence(
DelimSpan::dummy(),
Lrc::new(quoted::SequenceRepetition {
Lrc::new(mbe::SequenceRepetition {
tts: vec![
quoted::TokenTree::MetaVarDecl(def.span, lhs_nm, tt_spec),
quoted::TokenTree::token(token::FatArrow, def.span),
quoted::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec),
mbe::TokenTree::MetaVarDecl(def.span, lhs_nm, tt_spec),
mbe::TokenTree::token(token::FatArrow, def.span),
mbe::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec),
],
separator: Some(Token::new(
if body.legacy { token::Semi } else { token::Comma },
def.span,
)),
kleene: quoted::KleeneToken::new(quoted::KleeneOp::OneOrMore, def.span),
kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, def.span),
num_captures: 2,
}),
),
// to phase into semicolon-termination instead of semicolon-separation
quoted::TokenTree::Sequence(
mbe::TokenTree::Sequence(
DelimSpan::dummy(),
Lrc::new(quoted::SequenceRepetition {
tts: vec![quoted::TokenTree::token(
Lrc::new(mbe::SequenceRepetition {
tts: vec![mbe::TokenTree::token(
if body.legacy { token::Semi } else { token::Comma },
def.span,
)],
separator: None,
kleene: quoted::KleeneToken::new(quoted::KleeneOp::ZeroOrMore, def.span),
kleene: mbe::KleeneToken::new(mbe::KleeneOp::ZeroOrMore, def.span),
num_captures: 0,
}),
),
@ -363,7 +367,7 @@ pub fn compile(
.map(|m| {
if let MatchedNonterminal(ref nt) = *m {
if let NtTT(ref tt) = **nt {
let tt = quoted::parse(
let tt = mbe::quoted::parse(
tt.clone().into(),
true,
sess,
@ -380,7 +384,7 @@ pub fn compile(
}
sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
})
.collect::<Vec<quoted::TokenTree>>(),
.collect::<Vec<mbe::TokenTree>>(),
_ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs"),
};
@ -390,7 +394,7 @@ pub fn compile(
.map(|m| {
if let MatchedNonterminal(ref nt) = *m {
if let NtTT(ref tt) = **nt {
return quoted::parse(
return mbe::quoted::parse(
tt.clone().into(),
false,
sess,
@ -405,7 +409,7 @@ pub fn compile(
}
sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
})
.collect::<Vec<quoted::TokenTree>>(),
.collect::<Vec<mbe::TokenTree>>(),
_ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs"),
};
@ -450,11 +454,11 @@ fn check_lhs_nt_follows(
sess: &ParseSess,
features: &Features,
attrs: &[ast::Attribute],
lhs: &quoted::TokenTree,
lhs: &mbe::TokenTree,
) -> bool {
// 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.
if let quoted::TokenTree::Delimited(_, ref tts) = *lhs {
if let mbe::TokenTree::Delimited(_, ref tts) = *lhs {
check_matcher(sess, features, attrs, &tts.tts)
} else {
let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
@ -467,8 +471,8 @@ fn check_lhs_nt_follows(
/// Checks that the lhs contains no repetition which could match an empty token
/// tree, because then the matcher would hang indefinitely.
fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool {
use quoted::TokenTree;
fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
use mbe::TokenTree;
for tt in tts {
match *tt {
TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => (),
@ -482,8 +486,8 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool {
&& seq.tts.iter().all(|seq_tt| match *seq_tt {
TokenTree::MetaVarDecl(_, _, id) => id.name == sym::vis,
TokenTree::Sequence(_, ref sub_seq) => {
sub_seq.kleene.op == quoted::KleeneOp::ZeroOrMore
|| sub_seq.kleene.op == quoted::KleeneOp::ZeroOrOne
sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore
|| sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne
}
_ => false,
})
@ -502,9 +506,9 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool {
true
}
fn check_rhs(sess: &ParseSess, rhs: &quoted::TokenTree) -> bool {
fn check_rhs(sess: &ParseSess, rhs: &mbe::TokenTree) -> bool {
match *rhs {
quoted::TokenTree::Delimited(..) => return true,
mbe::TokenTree::Delimited(..) => return true,
_ => sess.span_diagnostic.span_err(rhs.span(), "macro rhs must be delimited"),
}
false
@ -514,7 +518,7 @@ fn check_matcher(
sess: &ParseSess,
features: &Features,
attrs: &[ast::Attribute],
matcher: &[quoted::TokenTree],
matcher: &[mbe::TokenTree],
) -> bool {
let first_sets = FirstSets::new(matcher);
let empty_suffix = TokenSet::empty();
@ -546,8 +550,8 @@ struct FirstSets {
}
impl FirstSets {
fn new(tts: &[quoted::TokenTree]) -> FirstSets {
use quoted::TokenTree;
fn new(tts: &[mbe::TokenTree]) -> FirstSets {
use mbe::TokenTree;
let mut sets = FirstSets { first: FxHashMap::default() };
build_recur(&mut sets, tts);
@ -594,8 +598,8 @@ impl FirstSets {
// Reverse scan: Sequence comes before `first`.
if subfirst.maybe_empty
|| seq_rep.kleene.op == quoted::KleeneOp::ZeroOrMore
|| seq_rep.kleene.op == quoted::KleeneOp::ZeroOrOne
|| seq_rep.kleene.op == mbe::KleeneOp::ZeroOrMore
|| seq_rep.kleene.op == mbe::KleeneOp::ZeroOrOne
{
// If sequence is potentially empty, then
// union them (preserving first emptiness).
@ -615,8 +619,8 @@ impl FirstSets {
// walks forward over `tts` until all potential FIRST tokens are
// identified.
fn first(&self, tts: &[quoted::TokenTree]) -> TokenSet {
use quoted::TokenTree;
fn first(&self, tts: &[mbe::TokenTree]) -> TokenSet {
use mbe::TokenTree;
let mut first = TokenSet::empty();
for tt in tts.iter() {
@ -652,8 +656,8 @@ impl FirstSets {
assert!(first.maybe_empty);
first.add_all(subfirst);
if subfirst.maybe_empty
|| seq_rep.kleene.op == quoted::KleeneOp::ZeroOrMore
|| seq_rep.kleene.op == quoted::KleeneOp::ZeroOrOne
|| seq_rep.kleene.op == mbe::KleeneOp::ZeroOrMore
|| seq_rep.kleene.op == mbe::KleeneOp::ZeroOrOne
{
// Continue scanning for more first
// tokens, but also make sure we
@ -674,7 +678,7 @@ impl FirstSets {
}
}
// A set of `quoted::TokenTree`s, which may include `TokenTree::Match`s
// A set of `mbe::TokenTree`s, which may include `TokenTree::Match`s
// (for macro-by-example syntactic variables). It also carries the
// `maybe_empty` flag; that is true if and only if the matcher can
// match an empty token sequence.
@ -686,7 +690,7 @@ impl FirstSets {
// (Notably, we must allow for *-op to occur zero times.)
#[derive(Clone, Debug)]
struct TokenSet {
tokens: Vec<quoted::TokenTree>,
tokens: Vec<mbe::TokenTree>,
maybe_empty: bool,
}
@ -698,13 +702,13 @@ impl TokenSet {
// Returns the set `{ tok }` for the single-token (and thus
// non-empty) sequence [tok].
fn singleton(tok: quoted::TokenTree) -> Self {
fn singleton(tok: mbe::TokenTree) -> Self {
TokenSet { tokens: vec![tok], maybe_empty: false }
}
// Changes self to be the set `{ tok }`.
// Since `tok` is always present, marks self as non-empty.
fn replace_with(&mut self, tok: quoted::TokenTree) {
fn replace_with(&mut self, tok: mbe::TokenTree) {
self.tokens.clear();
self.tokens.push(tok);
self.maybe_empty = false;
@ -719,7 +723,7 @@ impl TokenSet {
}
// Adds `tok` to the set for `self`, marking sequence as non-empy.
fn add_one(&mut self, tok: quoted::TokenTree) {
fn add_one(&mut self, tok: mbe::TokenTree) {
if !self.tokens.contains(&tok) {
self.tokens.push(tok);
}
@ -727,7 +731,7 @@ impl TokenSet {
}
// Adds `tok` to the set for `self`. (Leaves `maybe_empty` flag alone.)
fn add_one_maybe(&mut self, tok: quoted::TokenTree) {
fn add_one_maybe(&mut self, tok: mbe::TokenTree) {
if !self.tokens.contains(&tok) {
self.tokens.push(tok);
}
@ -768,10 +772,10 @@ fn check_matcher_core(
features: &Features,
attrs: &[ast::Attribute],
first_sets: &FirstSets,
matcher: &[quoted::TokenTree],
matcher: &[mbe::TokenTree],
follow: &TokenSet,
) -> TokenSet {
use quoted::TokenTree;
use mbe::TokenTree;
let mut last = TokenSet::empty();
@ -946,8 +950,8 @@ fn check_matcher_core(
last
}
fn token_can_be_followed_by_any(tok: &quoted::TokenTree) -> bool {
if let quoted::TokenTree::MetaVarDecl(_, _, frag_spec) = *tok {
fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool {
if let mbe::TokenTree::MetaVarDecl(_, _, frag_spec) = *tok {
frag_can_be_followed_by_any(frag_spec.name)
} else {
// (Non NT's can always be followed by anthing in matchers.)
@ -993,8 +997,8 @@ enum IsInFollow {
/// break macros that were relying on that binary operator as a
/// separator.
// when changing this do not forget to update doc/book/macros.md!
fn is_in_follow(tok: &quoted::TokenTree, frag: Symbol) -> IsInFollow {
use quoted::TokenTree;
fn is_in_follow(tok: &mbe::TokenTree, frag: Symbol) -> IsInFollow {
use mbe::TokenTree;
if let TokenTree::Token(Token { kind: token::CloseDelim(_), .. }) = *tok {
// closing a token tree can never be matched by any fragment;
@ -1112,10 +1116,10 @@ fn has_legal_fragment_specifier(
sess: &ParseSess,
features: &Features,
attrs: &[ast::Attribute],
tok: &quoted::TokenTree,
tok: &mbe::TokenTree,
) -> Result<(), String> {
debug!("has_legal_fragment_specifier({:?})", tok);
if let quoted::TokenTree::MetaVarDecl(_, _, ref frag_spec) = *tok {
if let mbe::TokenTree::MetaVarDecl(_, _, ref frag_spec) = *tok {
let frag_span = tok.span();
if !is_legal_fragment_specifier(sess, features, attrs, frag_spec.name, frag_span) {
return Err(frag_spec.to_string());
@ -1156,14 +1160,27 @@ fn is_legal_fragment_specifier(
}
}
fn quoted_tt_to_string(tt: &quoted::TokenTree) -> String {
fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
match *tt {
quoted::TokenTree::Token(ref token) => crate::print::pprust::token_to_string(&token),
quoted::TokenTree::MetaVar(_, name) => format!("${}", name),
quoted::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind),
mbe::TokenTree::Token(ref token) => crate::print::pprust::token_to_string(&token),
mbe::TokenTree::MetaVar(_, name) => format!("${}", name),
mbe::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind),
_ => panic!(
"unexpected quoted::TokenTree::{{Sequence or Delimited}} \
"unexpected mbe::TokenTree::{{Sequence or Delimited}} \
in follow set checker"
),
}
}
impl TokenTree {
/// Use this token tree as a matcher to parse given tts.
fn parse(cx: &ExtCtxt<'_>, mtch: &[mbe::TokenTree], tts: TokenStream)
-> NamedParseResult {
// `None` is because we're not interpolating
let directory = Directory {
path: Cow::from(cx.current_expansion.module.directory.as_path()),
ownership: cx.current_expansion.directory_ownership,
};
parse(cx.parse_sess(), tts, mtch, Some(directory), true)
}
}

View File

@ -1,179 +1,19 @@
use crate::ast;
use crate::ast::NodeId;
use crate::ext::tt::macro_parser;
use crate::ext::mbe::macro_parser;
use crate::ext::mbe::{TokenTree, KleeneOp, KleeneToken, SequenceRepetition, Delimited};
use crate::feature_gate::Features;
use crate::parse::token::{self, Token, TokenKind};
use crate::parse::token::{self, Token};
use crate::parse::ParseSess;
use crate::print::pprust;
use crate::symbol::kw;
use crate::tokenstream::{self, DelimSpan};
use crate::tokenstream;
use syntax_pos::{edition::Edition, BytePos, Span};
use syntax_pos::{edition::Edition, Span};
use rustc_data_structures::sync::Lrc;
use std::iter::Peekable;
/// Contains the sub-token-trees of a "delimited" token tree, such as the contents of `(`. Note
/// that the delimiter itself might be `NoDelim`.
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)]
pub struct Delimited {
pub delim: token::DelimToken,
pub tts: Vec<TokenTree>,
}
impl Delimited {
/// Returns a `self::TokenTree` with a `Span` corresponding to the opening delimiter.
pub fn open_tt(&self, span: Span) -> TokenTree {
let open_span = if span.is_dummy() {
span
} else {
span.with_hi(span.lo() + BytePos(self.delim.len() as u32))
};
TokenTree::token(token::OpenDelim(self.delim), open_span)
}
/// Returns a `self::TokenTree` with a `Span` corresponding to the closing delimiter.
pub fn close_tt(&self, span: Span) -> TokenTree {
let close_span = if span.is_dummy() {
span
} else {
span.with_lo(span.hi() - BytePos(self.delim.len() as u32))
};
TokenTree::token(token::CloseDelim(self.delim), close_span)
}
}
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)]
pub struct SequenceRepetition {
/// The sequence of token trees
pub tts: Vec<TokenTree>,
/// The optional separator
pub separator: Option<Token>,
/// Whether the sequence can be repeated zero (*), or one or more times (+)
pub kleene: KleeneToken,
/// The number of `Match`s that appear in the sequence (and subsequences)
pub num_captures: usize,
}
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
pub struct KleeneToken {
pub span: Span,
pub op: KleeneOp,
}
impl KleeneToken {
pub fn new(op: KleeneOp, span: Span) -> KleeneToken {
KleeneToken { span, op }
}
}
/// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star)
/// for token sequences.
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum KleeneOp {
/// Kleene star (`*`) for zero or more repetitions
ZeroOrMore,
/// Kleene plus (`+`) for one or more repetitions
OneOrMore,
/// Kleene optional (`?`) for zero or one reptitions
ZeroOrOne,
}
/// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, and `$(...)`
/// are "first-class" token trees. Useful for parsing macros.
#[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub enum TokenTree {
Token(Token),
Delimited(DelimSpan, Lrc<Delimited>),
/// A kleene-style repetition sequence
Sequence(DelimSpan, Lrc<SequenceRepetition>),
/// e.g., `$var`
MetaVar(Span, ast::Ident),
/// e.g., `$var:expr`. This is only used in the left hand side of MBE macros.
MetaVarDecl(
Span,
ast::Ident, /* name to bind */
ast::Ident, /* kind of nonterminal */
),
}
impl TokenTree {
/// Return the number of tokens in the tree.
pub fn len(&self) -> usize {
match *self {
TokenTree::Delimited(_, ref delimed) => match delimed.delim {
token::NoDelim => delimed.tts.len(),
_ => delimed.tts.len() + 2,
},
TokenTree::Sequence(_, ref seq) => seq.tts.len(),
_ => 0,
}
}
/// Returns `true` if the given token tree contains no other tokens. This is vacuously true for
/// single tokens or metavar/decls, but may be false for delimited trees or sequences.
pub fn is_empty(&self) -> bool {
match *self {
TokenTree::Delimited(_, ref delimed) => match delimed.delim {
token::NoDelim => delimed.tts.is_empty(),
_ => false,
},
TokenTree::Sequence(_, ref seq) => seq.tts.is_empty(),
_ => true,
}
}
/// Returns `true` if the given token tree is delimited.
pub fn is_delimited(&self) -> bool {
match *self {
TokenTree::Delimited(..) => true,
_ => false,
}
}
/// Returns `true` if the given token tree is a token of the given kind.
pub fn is_token(&self, expected_kind: &TokenKind) -> bool {
match self {
TokenTree::Token(Token { kind: actual_kind, .. }) => actual_kind == expected_kind,
_ => false,
}
}
/// Gets the `index`-th sub-token-tree. This only makes sense for delimited trees and sequences.
pub fn get_tt(&self, index: usize) -> TokenTree {
match (self, index) {
(&TokenTree::Delimited(_, ref delimed), _) if delimed.delim == token::NoDelim => {
delimed.tts[index].clone()
}
(&TokenTree::Delimited(span, ref delimed), _) => {
if index == 0 {
return delimed.open_tt(span.open);
}
if index == delimed.tts.len() + 1 {
return delimed.close_tt(span.close);
}
delimed.tts[index - 1].clone()
}
(&TokenTree::Sequence(_, ref seq), _) => seq.tts[index].clone(),
_ => panic!("Cannot expand a token tree"),
}
}
/// Retrieves the `TokenTree`'s span.
pub fn span(&self) -> Span {
match *self {
TokenTree::Token(Token { span, .. })
| TokenTree::MetaVar(span, _)
| TokenTree::MetaVarDecl(span, _, _) => span,
TokenTree::Delimited(span, _) | TokenTree::Sequence(span, _) => span.entire(),
}
}
crate fn token(kind: TokenKind, span: Span) -> TokenTree {
TokenTree::Token(Token::new(kind, span))
}
}
/// Takes a `tokenstream::TokenStream` and returns a `Vec<self::TokenTree>`. Specifically, this
/// takes a generic `TokenStream`, such as is used in the rest of the compiler, and returns a
/// collection of `TokenTree` for use in parsing a macro.
@ -195,7 +35,7 @@ impl TokenTree {
/// # Returns
///
/// A collection of `self::TokenTree`. There may also be some errors emitted to `sess`.
pub fn parse(
pub(super) fn parse(
input: tokenstream::TokenStream,
expect_matchers: bool,
sess: &ParseSess,

View File

@ -1,7 +1,7 @@
use crate::ast::{Ident, Mac};
use crate::ext::base::ExtCtxt;
use crate::ext::tt::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch};
use crate::ext::tt::quoted;
use crate::ext::mbe;
use crate::ext::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch};
use crate::mut_visit::{self, MutVisitor};
use crate::parse::token::{self, NtTT, Token};
use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint};
@ -38,22 +38,22 @@ impl Marker {
/// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`).
enum Frame {
Delimited { forest: Lrc<quoted::Delimited>, idx: usize, span: DelimSpan },
Sequence { forest: Lrc<quoted::SequenceRepetition>, idx: usize, sep: Option<Token> },
Delimited { forest: Lrc<mbe::Delimited>, idx: usize, span: DelimSpan },
Sequence { forest: Lrc<mbe::SequenceRepetition>, idx: usize, sep: Option<Token> },
}
impl Frame {
/// Construct a new frame around the delimited set of tokens.
fn new(tts: Vec<quoted::TokenTree>) -> Frame {
let forest = Lrc::new(quoted::Delimited { delim: token::NoDelim, tts });
fn new(tts: Vec<mbe::TokenTree>) -> Frame {
let forest = Lrc::new(mbe::Delimited { delim: token::NoDelim, tts });
Frame::Delimited { forest, idx: 0, span: DelimSpan::dummy() }
}
}
impl Iterator for Frame {
type Item = quoted::TokenTree;
type Item = mbe::TokenTree;
fn next(&mut self) -> Option<quoted::TokenTree> {
fn next(&mut self) -> Option<mbe::TokenTree> {
match *self {
Frame::Delimited { ref forest, ref mut idx, .. } => {
*idx += 1;
@ -90,7 +90,7 @@ impl Iterator for Frame {
pub(super) fn transcribe(
cx: &ExtCtxt<'_>,
interp: &FxHashMap<Ident, NamedMatch>,
src: Vec<quoted::TokenTree>,
src: Vec<mbe::TokenTree>,
transparency: Transparency,
) -> TokenStream {
// Nothing for us to transcribe...
@ -178,7 +178,7 @@ pub(super) fn transcribe(
// We are descending into a sequence. We first make sure that the matchers in the RHS
// and the matches in `interp` have the same shape. Otherwise, either the caller or the
// macro writer has made a mistake.
seq @ quoted::TokenTree::Sequence(..) => {
seq @ mbe::TokenTree::Sequence(..) => {
match lockstep_iter_size(&seq, interp, &repeats) {
LockstepIterSize::Unconstrained => {
cx.span_fatal(
@ -199,7 +199,7 @@ pub(super) fn transcribe(
LockstepIterSize::Constraint(len, _) => {
// We do this to avoid an extra clone above. We know that this is a
// sequence already.
let (sp, seq) = if let quoted::TokenTree::Sequence(sp, seq) = seq {
let (sp, seq) = if let mbe::TokenTree::Sequence(sp, seq) = seq {
(sp, seq)
} else {
unreachable!()
@ -207,7 +207,7 @@ pub(super) fn transcribe(
// Is the repetition empty?
if len == 0 {
if seq.kleene.op == quoted::KleeneOp::OneOrMore {
if seq.kleene.op == mbe::KleeneOp::OneOrMore {
// FIXME: this really ought to be caught at macro definition
// time... It happens when the Kleene operator in the matcher and
// the body for the same meta-variable do not match.
@ -232,7 +232,7 @@ pub(super) fn transcribe(
}
// Replace the meta-var with the matched token tree from the invocation.
quoted::TokenTree::MetaVar(mut sp, mut ident) => {
mbe::TokenTree::MetaVar(mut sp, mut ident) => {
// Find the matched nonterminal from the macro invocation, and use it to replace
// the meta-var.
if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) {
@ -269,7 +269,7 @@ pub(super) fn transcribe(
// We will produce all of the results of the inside of the `Delimited` and then we will
// jump back out of the Delimited, pop the result_stack and add the new results back to
// the previous results (from outside the Delimited).
quoted::TokenTree::Delimited(mut span, delimited) => {
mbe::TokenTree::Delimited(mut span, delimited) => {
marker.visit_delim_span(&mut span);
stack.push(Frame::Delimited { forest: delimited, idx: 0, span });
result_stack.push(mem::take(&mut result));
@ -277,14 +277,14 @@ pub(super) fn transcribe(
// Nothing much to do here. Just push the token to the result, being careful to
// preserve syntax context.
quoted::TokenTree::Token(token) => {
mbe::TokenTree::Token(token) => {
let mut tt = TokenTree::Token(token);
marker.visit_tt(&mut tt);
result.push(tt.into());
}
// There should be no meta-var declarations in the invocation of a macro.
quoted::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl"),
mbe::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl"),
}
}
}
@ -368,11 +368,11 @@ impl LockstepIterSize {
/// `lookup_cur_matched` will return `None`, which is why this still works even in the presnece of
/// multiple nested matcher sequences.
fn lockstep_iter_size(
tree: &quoted::TokenTree,
tree: &mbe::TokenTree,
interpolations: &FxHashMap<Ident, NamedMatch>,
repeats: &[(usize, usize)],
) -> LockstepIterSize {
use quoted::TokenTree;
use mbe::TokenTree;
match *tree {
TokenTree::Delimited(_, ref delimed) => {
delimed.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| {

View File

@ -162,19 +162,14 @@ pub mod ext {
mod proc_macro_server;
pub use syntax_pos::hygiene;
pub use mbe::macro_rules::compile_declarative_macro;
pub mod allocator;
pub mod base;
pub mod build;
pub mod expand;
pub mod proc_macro;
pub mod tt {
pub mod transcribe;
pub mod macro_check;
pub mod macro_parser;
pub mod macro_rules;
pub mod quoted;
}
crate mod mbe;
}
pub mod early_buffered_lints;

View File

@ -24,7 +24,7 @@ use crate::symbol::{kw, sym};
use std::mem;
use log::debug;
use rustc_target::spec::abi::Abi;
use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
use errors::{Applicability, DiagnosticBuilder, DiagnosticId, StashKey};
/// Whether the type alias or associated type is a concrete type or an opaque type.
#[derive(Debug)]
@ -1477,10 +1477,23 @@ impl<'a> Parser<'a> {
}
}
/// Parse `["const" | ("static" "mut"?)] $ident ":" $ty = $expr` with
/// `["const" | ("static" "mut"?)]` already parsed and stored in `m`.
///
/// When `m` is `"const"`, `$ident` may also be `"_"`.
fn parse_item_const(&mut self, m: Option<Mutability>) -> PResult<'a, ItemInfo> {
let id = if m.is_none() { self.parse_ident_or_underscore() } else { self.parse_ident() }?;
self.expect(&token::Colon)?;
let ty = self.parse_ty()?;
// Parse the type of a `const` or `static mut?` item.
// That is, the `":" $ty` fragment.
let ty = if self.token == token::Eq {
self.recover_missing_const_type(id, m)
} else {
// Not `=` so expect `":"" $ty` as usual.
self.expect(&token::Colon)?;
self.parse_ty()?
};
self.expect(&token::Eq)?;
let e = self.parse_expr()?;
self.expect(&token::Semi)?;
@ -1491,6 +1504,34 @@ impl<'a> Parser<'a> {
Ok((id, item, None))
}
/// We were supposed to parse `:` but instead, we're already at `=`.
/// This means that the type is missing.
fn recover_missing_const_type(&mut self, id: Ident, m: Option<Mutability>) -> P<Ty> {
// Construct the error and stash it away with the hope
// that typeck will later enrich the error with a type.
let kind = match m {
Some(Mutability::Mutable) => "static mut",
Some(Mutability::Immutable) => "static",
None => "const",
};
let mut err = self.struct_span_err(id.span, &format!("missing type for `{}` item", kind));
err.span_suggestion(
id.span,
"provide a type for the item",
format!("{}: <type>", id),
Applicability::HasPlaceholders,
);
err.stash(id.span, StashKey::ItemNoType);
// The user intended that the type be inferred,
// so treat this as if the user wrote e.g. `const A: _ = expr;`.
P(Ty {
node: TyKind::Infer,
span: id.span,
id: ast::DUMMY_NODE_ID,
})
}
/// Parses `type Foo = Bar;` or returns `None`
/// without modifying the parser state.
fn eat_type(&mut self) -> Option<PResult<'a, (Ident, AliasKind, Generics)>> {

View File

@ -13,9 +13,6 @@
//! and a borrowed `TokenStream` is sufficient to build an owned `TokenStream` without taking
//! ownership of the original.
use crate::ext::base;
use crate::ext::tt::{macro_parser, quoted};
use crate::parse::Directory;
use crate::parse::token::{self, DelimToken, Token, TokenKind};
use crate::print::pprust;
@ -26,7 +23,6 @@ use rustc_data_structures::sync::Lrc;
use rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
use smallvec::{SmallVec, smallvec};
use std::borrow::Cow;
use std::{fmt, iter, mem};
#[cfg(test)]
@ -63,17 +59,6 @@ where
{}
impl TokenTree {
/// Use this token tree as a matcher to parse given tts.
pub fn parse(cx: &base::ExtCtxt<'_>, mtch: &[quoted::TokenTree], tts: TokenStream)
-> macro_parser::NamedParseResult {
// `None` is because we're not interpolating
let directory = Directory {
path: Cow::from(cx.current_expansion.module.directory.as_path()),
ownership: cx.current_expansion.directory_ownership,
};
macro_parser::parse(cx.parse_sess(), tts, mtch, Some(directory), true)
}
/// Checks if this TokenTree is equal to the other, regardless of span information.
pub fn eq_unspanned(&self, other: &TokenTree) -> bool {
match (self, other) {

View File

@ -18,4 +18,3 @@ rustc_target = { path = "../librustc_target" }
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }
rustc_lexer = { path = "../librustc_lexer" }

View File

@ -295,7 +295,7 @@ impl<'a, 'b> Context<'a, 'b> {
.filter(|fmt| fmt.precision_span.is_some())
.count();
if self.names.is_empty() && !numbered_position_args && count != self.args.len() {
e = self.ecx.mut_span_err(
e = self.ecx.struct_span_err(
sp,
&format!(
"{} positional argument{} in format string, but {}",
@ -336,7 +336,7 @@ impl<'a, 'b> Context<'a, 'b> {
sp = MultiSpan::from_span(self.fmtsp);
}
e = self.ecx.mut_span_err(sp,
e = self.ecx.struct_span_err(sp,
&format!("invalid reference to positional {} ({})",
arg_list,
self.describe_num_args()));

View File

@ -62,6 +62,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
};
interface::run_compiler(config, |compiler| {
compiler.compile().ok();
// This runs all the passes prior to linking, too.
compiler.link().ok();
});
}

View File

@ -2,9 +2,9 @@ enum Fruit {
Apple(String, String),
Pear(u32),
Orange((String, String)),
Banana(()),
}
fn main() {
let x = Fruit::Apple(String::new(), String::new());
match x {
@ -12,5 +12,6 @@ fn main() {
Fruit::Apple(a, b, c) => {}, //~ ERROR E0023
Fruit::Pear(1, 2) => {}, //~ ERROR E0023
Fruit::Orange(a, b) => {}, //~ ERROR E0023
Fruit::Banana() => {}, //~ ERROR E0023
}
}

View File

@ -38,6 +38,19 @@ help: missing parenthesis
LL | Fruit::Orange((a, b)) => {},
| ^ ^
error: aborting due to 4 previous errors
error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 1 field
--> $DIR/E0023.rs:15:9
|
LL | Banana(()),
| ---------- tuple variant defined here
...
LL | Fruit::Banana() => {},
| ^^^^^^^^^^^^^^^ expected 1 field, found 0
help: missing parenthesis
|
LL | Fruit::Banana(()) => {},
| ^ ^
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0023`.

View File

@ -0,0 +1,23 @@
// Tests that type alias impls traits do not leak auto-traits for
// the purposes of coherence checking
#![feature(type_alias_impl_trait)]
trait OpaqueTrait { }
impl<T> OpaqueTrait for T { }
type OpaqueType = impl OpaqueTrait;
fn mk_opaque() -> OpaqueType { () }
#[derive(Debug)]
struct D<T>(T);
trait AnotherTrait { }
impl<T: Send> AnotherTrait for T { }
// This is in error, because we cannot assume that `OpaqueType: !Send`.
// (We treat opaque types as "foreign types" that could grow more impls
// in the future.)
impl AnotherTrait for D<OpaqueType> {
//~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
}
fn main() {}

View File

@ -0,0 +1,12 @@
error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`:
--> $DIR/auto-trait.rs:19:1
|
LL | impl<T: Send> AnotherTrait for T { }
| -------------------------------- first implementation here
...
LL | impl AnotherTrait for D<OpaqueType> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0119`.

View File

@ -0,0 +1,22 @@
// Tests that we cannot assume that an opaque type does *not* implement some
// other trait
#![feature(type_alias_impl_trait)]
trait OpaqueTrait { }
impl<T> OpaqueTrait for T { }
type OpaqueType = impl OpaqueTrait;
fn mk_opaque() -> OpaqueType { () }
#[derive(Debug)]
struct D<T>(T);
trait AnotherTrait { }
impl<T: std::fmt::Debug> AnotherTrait for T { }
// This is in error, because we cannot assume that `OpaqueType: !Debug`
impl AnotherTrait for D<OpaqueType> {
//~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
}
fn main() {}

View File

@ -0,0 +1,14 @@
error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`:
--> $DIR/negative-reasoning.rs:18:1
|
LL | impl<T: std::fmt::Debug> AnotherTrait for T { }
| ------------------------------------------- first implementation here
...
LL | impl AnotherTrait for D<OpaqueType> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
|
= note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions
error: aborting due to previous error
For more information about this error, try `rustc --explain E0119`.

View File

@ -0,0 +1,46 @@
// In the cases below, the type is missing from the `const` and `static` items.
//
// Here, we test that we:
//
// a) Perform parser recovery.
//
// b) Emit a diagnostic with the actual inferred type to RHS of `=` as the suggestion.
fn main() {}
// These will not reach typeck:
#[cfg(FALSE)]
const C2 = 42;
//~^ ERROR missing type for `const` item
//~| HELP provide a type for the item
//~| SUGGESTION C2: <type>
#[cfg(FALSE)]
static S2 = "abc";
//~^ ERROR missing type for `static` item
//~| HELP provide a type for the item
//~| SUGGESTION S2: <type>
#[cfg(FALSE)]
static mut SM2 = "abc";
//~^ ERROR missing type for `static mut` item
//~| HELP provide a type for the item
//~| SUGGESTION SM2: <type>
// These will, so the diagnostics should be stolen by typeck:
const C = 42;
//~^ ERROR missing type for `const` item
//~| HELP provide a type for the item
//~| SUGGESTION C: i32
static S = Vec::<String>::new();
//~^ ERROR missing type for `static` item
//~| HELP provide a type for the item
//~| SUGGESTION S: std::vec::Vec<std::string::String>
static mut SM = "abc";
//~^ ERROR missing type for `static mut` item
//~| HELP provide a type for the item
//~| SUGGESTION &'static str

View File

@ -0,0 +1,38 @@
error: missing type for `const` item
--> $DIR/const-no-type.rs:33:7
|
LL | const C = 42;
| ^ help: provide a type for the item: `C: i32`
error: missing type for `static` item
--> $DIR/const-no-type.rs:38:8
|
LL | static S = Vec::<String>::new();
| ^ help: provide a type for the item: `S: std::vec::Vec<std::string::String>`
error: missing type for `static mut` item
--> $DIR/const-no-type.rs:43:12
|
LL | static mut SM = "abc";
| ^^ help: provide a type for the item: `SM: &'static str`
error: missing type for `const` item
--> $DIR/const-no-type.rs:14:7
|
LL | const C2 = 42;
| ^^ help: provide a type for the item: `C2: <type>`
error: missing type for `static` item
--> $DIR/const-no-type.rs:20:8
|
LL | static S2 = "abc";
| ^^ help: provide a type for the item: `S2: <type>`
error: missing type for `static mut` item
--> $DIR/const-no-type.rs:26:12
|
LL | static mut SM2 = "abc";
| ^^^ help: provide a type for the item: `SM2: <type>`
error: aborting due to 6 previous errors

View File

@ -0,0 +1,2 @@
pub trait ForeignTrait {}
pub struct ForeignType<T>(pub T);

View File

@ -0,0 +1,17 @@
// aux-build:foreign-crate.rs
#![feature(type_alias_impl_trait)]
extern crate foreign_crate;
trait LocalTrait {}
impl<T> LocalTrait for foreign_crate::ForeignType<T> {}
type AliasOfForeignType<T> = impl LocalTrait;
fn use_alias<T>(val: T) -> AliasOfForeignType<T> {
foreign_crate::ForeignType(val)
}
impl<T> foreign_crate::ForeignTrait for AliasOfForeignType<T> {}
//~^ ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates
fn main() {}

View File

@ -0,0 +1,9 @@
error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
--> $DIR/coherence.rs:14:6
|
LL | impl<T> foreign_crate::ForeignTrait for AliasOfForeignType<T> {}
| ^ unconstrained type parameter
error: aborting due to previous error
For more information about this error, try `rustc --explain E0207`.

View File

@ -0,0 +1,21 @@
// check-pass
// Regression test for issue #63677 - ensure that
// coherence checking can properly handle 'impl trait'
// in type aliases
#![feature(type_alias_impl_trait)]
pub trait Trait {}
pub struct S1<T>(T);
pub struct S2<T>(T);
pub type T1 = impl Trait;
pub type T2 = S1<T1>;
pub type T3 = S2<T2>;
impl<T> Trait for S1<T> {}
impl<T: Trait> S2<T> {}
impl T3 {}
pub fn use_t1() -> T1 { S1(()) }
fn main() {}