Language
--------
- [Procedural macros are now available.][52081] These kinds of macros allow for
- more powerful code generation, there is a [new chapter available][proc-macros]
- in Rust Programming Language book that goes further in depth.
+ more powerful code generation. There is a [new chapter available][proc-macros]
+ in the Rust Programming Language book that goes further in depth.
- [You can now use keywords as identifiers using the raw identifiers
- syntax (`r#`).][53236] e.g. `let r#for = true;`
+ syntax (`r#`),][53236] e.g. `let r#for = true;`
- [Using anonymous parameters in traits is now deprecated with a warning and
will be a hard error in the 2018 edition.][53272]
- [You can now use `crate` in paths.][54404] This allows you to refer to the
- crate root in the path. e.g. `use crate::foo;` refers to `foo` in `src/lib.rs`.
-- [Using a external crate now no longer requires being prefixed with `::`.][54404]
- e.g. previously using a external crate in a module without a use statement
- required `let json = ::serde_json::from_str(foo);` can now be written
+ crate root in the path, e.g. `use crate::foo;` refers to `foo` in `src/lib.rs`.
+- [Using a external crate no longer requires being prefixed with `::`.][54404]
+ Previously, using a external crate in a module without a use statement
+ required `let json = ::serde_json::from_str(foo);` but can now be written
as `let json = serde_json::from_str(foo);`.
- [You can now apply the `#[used]` attribute to static items to prevent the
- compiler from optimising them away even if they appear to be unused.][51363]
+ compiler from optimising them away, even if they appear to be unused,][51363]
e.g. `#[used] static FOO: u32 = 1;`
- [You can now import and reexport macros from other crates with the `use`
syntax.][50911] Macros exported with `#[macro_export]` are now placed into
the root module of the crate. If your macro relies on calling other local
- macros it is recommended to export with the
- `#[macro_export(local_inner_macros)]` attribute so that users won't have to
- import those macros.
-- [`mod.rs` files are now optional.][54146] Previously if you had a `foo` module
- with a `bar` submodule, you would have `src/foo/mod.rs` and `src/foo/bar.rs`.
- Now you can have `src/foo.rs` and `src/foo/bar.rs` to achieve the same effect.
+ macros, it is recommended to export with the
+ `#[macro_export(local_inner_macros)]` attribute so users won't have to import
+ those macros.
- [You can now catch visibility keywords (e.g. `pub`, `pub(crate)`) in macros
using the `vis` specifier.][53370]
-- [Non-macro attributes now allow all forms of literals not just
- strings.][53044] e.g. Previously you would write `#[attr("true")]` you can now
+- [Non-macro attributes now allow all forms of literals, not just
+ strings.][53044] Previously, you would write `#[attr("true")]`, and you can now
write `#[attr(true)]`.
- [You can now specify a function to handle a panic in the Rust runtime with the
`#[panic_handler]` attribute.][51366]
- [`Ipv6Addr::UNSPECIFIED`]
- [`Iterator::find_map`]
- The following methods are a replacement methods for `trim_left`, `trim_right`,
- `trim_left_matches`, and `trim_right_matches`. Which will be deprecated
- in 1.33.0.
+ The following methods are replacement methods for `trim_left`, `trim_right`,
+ `trim_left_matches`, and `trim_right_matches`, which will be deprecated
+ in 1.33.0:
- [`str::trim_end_matches`]
- [`str::trim_end`]
- [`str::trim_start_matches`]
- [`cargo run` doesn't require specifying a package in workspaces.][cargo/5877]
- [`cargo doc` now supports `--message-format=json`.][cargo/5878] This is
equivalent to calling `rustdoc --error-format=json`.
-- [You can specify which edition to create a project in cargo
- with `cargo new --edition`.][cargo/5984] Currently only `2015` is a
- valid option.
- [Cargo will now provide a progress bar for builds.][cargo/5995]
Misc
----
- [`rustdoc` allows you to specify what edition to treat your code as with the
`--edition` option.][54057]
-- [`rustdoc` now has the `--color` (Specify whether to output color) and
- `--error-format` (Specify error format e.g. `json`) options.][53003]
+- [`rustdoc` now has the `--color` (specify whether to output color) and
+ `--error-format` (specify error format, e.g. `json`) options.][53003]
- [We now distribute a `rust-gdbgui` script that invokes `gdbgui` with Rust
debug symbols.][53774]
- [Attributes from Rust tools such as `rustfmt` or `clippy` are now
- available.][53459] e.g. `#[rustfmt::skip]` will skip formatting the next item.
+ available,][53459] e.g. `#[rustfmt::skip]` will skip formatting the next item.
[50911]: https://github.com/rust-lang/rust/pull/50911/
[51363]: https://github.com/rust-lang/rust/pull/51363/
[54404]: https://github.com/rust-lang/rust/pull/54404/
[cargo/5877]: https://github.com/rust-lang/cargo/pull/5877/
[cargo/5878]: https://github.com/rust-lang/cargo/pull/5878/
-[cargo/5984]: https://github.com/rust-lang/cargo/pull/5984/
[cargo/5995]: https://github.com/rust-lang/cargo/pull/5995/
-[proc-macros]: https://doc.rust-lang.org/book/2018-edition/ch19-06-macros.html
+[proc-macros]: https://doc.rust-lang.org/nightly/book/2018-edition/ch19-06-macros.html
[`Ipv4Addr::BROADCAST`]: https://doc.rust-lang.org/nightly/std/net/struct.Ipv4Addr.html#associatedconstant.BROADCAST
[`Ipv4Addr::LOCALHOST`]: https://doc.rust-lang.org/nightly/std/net/struct.Ipv4Addr.html#associatedconstant.LOCALHOST
Libraries
---------
-- [`Once::call_once` now no longer requires `Once` to be `'static`.][52239]
+- [`Once::call_once` no longer requires `Once` to be `'static`.][52239]
- [`BuildHasherDefault` now implements `PartialEq` and `Eq`.][52402]
- [`Box<CStr>`, `Box<OsStr>`, and `Box<Path>` now implement `Clone`.][51912]
- [Implemented `PartialEq<&str>` for `OsString` and `PartialEq<OsString>`
Cargo
-----
-- [Cargo can silently fix some bad lockfiles ][cargo/5831] You can use
- `--locked` to disable this behaviour.
+- [Cargo can silently fix some bad lockfiles.][cargo/5831] You can use
+ `--locked` to disable this behavior.
- [`cargo-install` will now allow you to cross compile an install
- using `--target`][cargo/5614]
+ using `--target`.][cargo/5614]
- [Added the `cargo-fix` subcommand to automatically move project code from
2015 edition to 2018.][cargo/5723]
- [`cargo doc` can now optionally document private types using the
the specified level to that level.][52354] For example `--cap-lints warn`
will demote `deny` and `forbid` lints to `warn`.
- [`rustc` and `rustdoc` will now have the exit code of `1` if compilation
- fails, and `101` if there is a panic.][52197]
+ fails and `101` if there is a panic.][52197]
- [A preview of clippy has been made available through rustup.][51122]
- You can install the preview with `rustup component add clippy-preview`
+ You can install the preview with `rustup component add clippy-preview`.
Compatibility Notes
-------------------
- [`str::{slice_unchecked, slice_unchecked_mut}` are now deprecated.][51807]
Use `str::get_unchecked(begin..end)` instead.
-- [`std::env::home_dir` is now deprecated for its unintuitive behaviour.][51656]
+- [`std::env::home_dir` is now deprecated for its unintuitive behavior.][51656]
Consider using the `home_dir` function from
https://crates.io/crates/dirs instead.
- [`rustc` will no longer silently ignore invalid data in target spec.][52330]
be used as an identifier.
- [The dyn syntax is now available.][49968] This syntax is equivalent to the
bare `Trait` syntax, and should make it clearer when being used in tandem with
- `impl Trait`. Since it is equivalent to the following syntax:
+ `impl Trait` because it is equivalent to the following syntax:
`&Trait == &dyn Trait`, `&mut Trait == &mut dyn Trait`, and
`Box<Trait> == Box<dyn Trait>`.
- [Attributes on generic parameters such as types and lifetimes are
a different directory than `target` for placing compilation artifacts.
- [Cargo will be adding automatic target inference for binaries, benchmarks,
examples, and tests in the Rust 2018 edition.][cargo/5335] If your project specifies
- specific targets e.g. using `[[bin]]` and have other binaries in locations
+ specific targets, e.g. using `[[bin]]`, and have other binaries in locations
where cargo would infer a binary, Cargo will produce a warning. You can
- disable this feature ahead of time by setting any of the following `autobins`,
- `autobenches`, `autoexamples`, `autotests` to false.
+ disable this feature ahead of time by setting any of the following to false:
+ `autobins`, `autobenches`, `autoexamples`, `autotests`.
- [Cargo will now cache compiler information.][cargo/5359] This can be disabled by
setting `CARGO_CACHE_RUSTC_INFO=0` in your environment.
work.][49896] e.g. `::core::prelude::v1::StrExt::is_empty("")` will not
compile, `"".is_empty()` will still compile.
- [`Debug` output on `atomic::{AtomicBool, AtomicIsize, AtomicPtr, AtomicUsize}`
- will only print the inner type.][48553] e.g.
- `print!("{:?}", AtomicBool::new(true))` will print `true`
+ will only print the inner type.][48553] E.g.
+ `print!("{:?}", AtomicBool::new(true))` will print `true`,
not `AtomicBool(true)`.
- [The maximum number for `repr(align(N))` is now 2²⁹.][50378] Previously you
could enter higher numbers but they were not supported by LLVM. Up to 512MB
Compatibility Notes
-------------------
-- [The borrow checker was fixed to avoid unsoundness when using match ergonomics][51117]
+- [The borrow checker was fixed to avoid unsoundness when using match ergonomics.][51117]
[51117]: https://github.com/rust-lang/rust/issues/51117
Tools
-----
-- [RLS now works on Windows][50646]
-- [Rustfmt stopped badly formatting text in some cases][rustfmt/2695]
+- [RLS now works on Windows.][50646]
+- [Rustfmt stopped badly formatting text in some cases.][rustfmt/2695]
Compatibility Notes
--------
- [`fn main() -> impl Trait` no longer works for non-Termination
- trait][50656]
+ trait.][50656]
This reverts an accidental stabilization.
-- [`NaN > NaN` no longer returns true in const-fn contexts][50812]
-- [Prohibit using turbofish for `impl Trait` in method arguments][50950]
+- [`NaN > NaN` no longer returns true in const-fn contexts.][50812]
+- [Prohibit using turbofish for `impl Trait` in method arguments.][50950]
[50646]: https://github.com/rust-lang/rust/issues/50646
[50656]: https://github.com/rust-lang/rust/pull/50656
- [Closures now implement `Copy` and/or `Clone` if all captured variables
implement either or both traits.][49299]
- [The inclusive range syntax e.g. `for x in 0..=10` is now stable.][47813]
-- [The `'_` lifetime is now stable. The underscore lifetime can be used anywhere where a
+- [The `'_` lifetime is now stable. The underscore lifetime can be used anywhere a
lifetime can be elided.][49458]
- [`impl Trait` is now stable allowing you to have abstract types in returns
- or in function parameters.][49255] e.g. `fn foo() -> impl Iterator<Item=u8>` or
+ or in function parameters.][49255] E.g. `fn foo() -> impl Iterator<Item=u8>` or
`fn open(path: impl AsRef<Path>)`.
- [Pattern matching will now automatically apply dereferences.][49394]
- [128-bit integers in the form of `u128` and `i128` are now stable.][49101]
- [`main` can now return `Result<(), E: Debug>`][49162] in addition to `()`.
- [A lot of operations are now available in a const context.][46882] E.g. You
can now index into constant arrays, reference and dereference into constants,
- and use Tuple struct constructors.
-- [Fixed entry slice patterns are now stable.][48516] e.g.
+ and use tuple struct constructors.
+- [Fixed entry slice patterns are now stable.][48516] E.g.
```rust
let points = [1, 2, 3, 4];
match points {
Compiler
--------
- [Enabled `TrapUnreachable` in LLVM which should mitigate the impact of
- undefined behaviour.][45920]
+ undefined behavior.][45920]
- [rustc now suggests renaming import if names clash.][45660]
- [Display errors/warnings correctly when there are zero-width or
wide characters.][45711]
"itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
return ''
def bootstrap_binary(self):
- """Return the path of the boostrap binary
+ """Return the path of the bootstrap binary
>>> rb = RustBuild()
>>> rb.build_dir = "build"
#=--------------------------------------------------------------------------------------------------
def print_array_of_values(array_name, data_ptr_val, length, internal_dict):
- """Prints a contigous memory range, interpreting it as values of the
+ """Prints a contiguous memory range, interpreting it as values of the
pointee-type of data_ptr_val."""
data_ptr_type = data_ptr_val.type
/// movie_reviews.insert("Office Space", "Deals with real issues in the workplace.");
/// movie_reviews.insert("Pulp Fiction", "Masterpiece.");
/// movie_reviews.insert("The Godfather", "Very enjoyable.");
-/// movie_reviews.insert("The Blues Brothers", "Eye lyked it alot.");
+/// movie_reviews.insert("The Blues Brothers", "Eye lyked it a lot.");
///
/// // check for a specific one.
/// if !movie_reviews.contains_key("Les Misérables") {
/// The block is described by the given `ptr` pointer and `layout`.
///
/// If this returns a non-null pointer, then ownership of the memory block
- /// referenced by `ptr` has been transferred to this alloctor.
+ /// referenced by `ptr` has been transferred to this allocator.
/// The memory may or may not have been deallocated,
/// and should be considered unusable (unless of course it was
/// transferred back to the caller again via the return value of
/// // to avoid problems in case something further down panics.
/// src.set_len(0);
///
- /// // The two regions cannot overlap becuase mutable references do
+ /// // The two regions cannot overlap because mutable references do
/// // not alias, and two different vectors cannot own the same
/// // memory.
/// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len);
}
}
-/// An range bounded inclusively below and above (`start..=end`).
+/// A range bounded inclusively below and above (`start..=end`).
///
/// The `RangeInclusive` `start..=end` contains all values with `x >= start`
/// and `x <= end`. It is empty unless `start <= end`.
/// value in place, preventing the value referenced by that pointer from being moved
/// unless it implements [`Unpin`].
///
-/// See the [`pin` module] documentation for furthur explanation on pinning.
+/// See the [`pin` module] documentation for further explanation on pinning.
///
/// [`Unpin`]: ../../std/marker/trait.Unpin.html
/// [`pin` module]: ../../std/pin/index.html
//! underlying object is live and no reference (just raw pointers) is used to
//! access the same memory.
//!
-//! These axioms, along with careful use of [`offset`] for pointer arithmentic,
+//! These axioms, along with careful use of [`offset`] for pointer arithmetic,
//! are enough to correctly implement many useful things in unsafe code. Stronger guarantees
//! will be provided eventually, as the [aliasing] rules are being determined. For more
//! information, see the [book] as well as the section in the reference devoted
}
impl From<LocalWaker> for Waker {
+ /// Converts a `LocalWaker` into a `Waker`.
+ ///
+ /// This conversion turns a `!Sync` `LocalWaker` into a `Sync` `Waker`, allowing a wakeup
+ /// object to be sent to another thread, but giving up its ability to do specialized
+ /// thread-local wakeup behavior.
#[inline]
fn from(local_waker: LocalWaker) -> Self {
local_waker.0
use syntax_pos::symbol::InternedString;
use traits;
use traits::query::{
- CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal,
- CanonicalPredicateGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal,
+ CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal,
+ CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, CanonicalPredicateGoal,
+ CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal,
};
use ty::{TyCtxt, FnSig, Instance, InstanceDef,
ParamEnv, ParamEnvAnd, Predicate, PolyFnSig, PolyTraitRef, Ty};
[] ImpliedOutlivesBounds(CanonicalTyGoal<'tcx>),
[] DropckOutlives(CanonicalTyGoal<'tcx>),
[] EvaluateObligation(CanonicalPredicateGoal<'tcx>),
+ [] TypeOpAscribeUserType(CanonicalTypeOpAscribeUserTypeGoal<'tcx>),
[] TypeOpEq(CanonicalTypeOpEqGoal<'tcx>),
[] TypeOpSubtype(CanonicalTypeOpSubtypeGoal<'tcx>),
[] TypeOpProvePredicate(CanonicalTypeOpProvePredicateGoal<'tcx>),
match self {
CrateNum::Index(id) => write!(fmt, "crate{}", id.private),
CrateNum::Invalid => write!(fmt, "invalid crate"),
- CrateNum::BuiltinMacros => write!(fmt, "bultin macros crate"),
+ CrateNum::BuiltinMacros => write!(fmt, "builtin macros crate"),
CrateNum::ReservedForIncrCompCache => write!(fmt, "crate for decoding incr comp cache"),
}
}
match self {
CrateNum::Index(id) => fmt::Display::fmt(&id.private, f),
CrateNum::Invalid => write!(f, "invalid crate"),
- CrateNum::BuiltinMacros => write!(f, "bultin macros crate"),
+ CrateNum::BuiltinMacros => write!(f, "builtin macros crate"),
CrateNum::ReservedForIncrCompCache => write!(f, "crate for decoding incr comp cache"),
}
}
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: BodyId, s: Span, id: NodeId) {
walk_fn(self, fk, fd, b, s, id)
}
+ fn visit_use(&mut self, path: &'v Path, id: NodeId, hir_id: HirId) {
+ walk_use(self, path, id, hir_id)
+ }
fn visit_trait_item(&mut self, ti: &'v TraitItem) {
walk_trait_item(self, ti)
}
}
}
ItemKind::Use(ref path, _) => {
- visitor.visit_id(item.id);
- visitor.visit_path(path, item.hir_id);
+ visitor.visit_use(path, item.id, item.hir_id);
}
ItemKind::Static(ref typ, _, body) |
ItemKind::Const(ref typ, body) => {
walk_list!(visitor, visit_attribute, &item.attrs);
}
+pub fn walk_use<'v, V: Visitor<'v>>(visitor: &mut V,
+ path: &'v Path,
+ item_id: NodeId,
+ hir_id: HirId) {
+ visitor.visit_id(item_id);
+ visitor.visit_path(path, hir_id);
+}
+
pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V,
enum_definition: &'v EnumDef,
generics: &'v Generics,
path_span: Span,
segment: &'v PathSegment) {
visitor.visit_ident(segment.ident);
+ if let Some(id) = segment.id {
+ visitor.visit_id(id);
+ }
if let Some(ref args) = segment.args {
visitor.visit_generic_args(path_span, args);
}
}
pub trait Resolver {
- /// Resolve a hir path generated by the lowerer when expanding `for`, `if let`, etc.
- fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool);
+ /// Resolve a path generated by the lowerer when expanding `for`, `if let`, etc.
+ fn resolve_hir_path(
+ &mut self,
+ path: &ast::Path,
+ is_value: bool,
+ ) -> hir::Path;
/// Obtain the resolution for a node id
fn get_resolution(&mut self, id: NodeId) -> Option<PathResolution>;
span: Span,
crate_root: Option<&str>,
components: &[&str],
- params: Option<P<hir::GenericArgs>>,
is_value: bool,
) -> hir::Path;
}
}
fn lower_attr(&mut self, attr: &Attribute) -> Attribute {
+ // Note that we explicitly do not walk the path. Since we don't really
+ // lower attributes (we use the AST version) there is nowhere to keep
+ // the HirIds. We don't actually need HIR version of attributes anyway.
Attribute {
id: attr.id,
style: attr.style,
TyKind::Slice(ref ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
TyKind::Rptr(ref region, ref mt) => {
- let span = t.span.shrink_to_lo();
+ let span = self.sess.source_map().next_point(t.span.shrink_to_lo());
let lifetime = match *region {
Some(ref lt) => self.lower_lifetime(lt),
None => self.elided_ref_lifetime(span),
num_lifetimes,
parenthesized_generic_args,
itctx.reborrow(),
+ None,
)
})
.collect(),
0,
ParenthesizedGenericArgs::Warn,
itctx.reborrow(),
+ None,
));
let qpath = hir::QPath::TypeRelative(ty, segment);
p: &Path,
ident: Option<Ident>,
param_mode: ParamMode,
+ explicit_owner: Option<NodeId>,
) -> hir::Path {
hir::Path {
def,
0,
ParenthesizedGenericArgs::Err,
ImplTraitContext::disallowed(),
+ explicit_owner,
)
})
.chain(ident.map(|ident| hir::PathSegment::from_ident(ident)))
fn lower_path(&mut self, id: NodeId, p: &Path, param_mode: ParamMode) -> hir::Path {
let def = self.expect_full_def(id);
- self.lower_path_extra(def, p, None, param_mode)
+ self.lower_path_extra(def, p, None, param_mode, None)
}
fn lower_path_segment(
expected_lifetimes: usize,
parenthesized_generic_args: ParenthesizedGenericArgs,
itctx: ImplTraitContext<'_>,
+ explicit_owner: Option<NodeId>,
) -> hir::PathSegment {
let (mut generic_args, infer_types) = if let Some(ref generic_args) = segment.args {
let msg = "parenthesized parameters may only be used with a trait";
}
}
+ let def = self.expect_full_def(segment.id);
+ let id = if let Some(owner) = explicit_owner {
+ self.lower_node_id_with_owner(segment.id, owner)
+ } else {
+ self.lower_node_id(segment.id)
+ };
+
hir::PathSegment::new(
segment.ident,
+ Some(id.node_id),
+ Some(def),
generic_args,
infer_types,
)
attrs: &hir::HirVec<Attribute>,
) -> hir::ItemKind {
let path = &tree.prefix;
+ let segments = prefix
+ .segments
+ .iter()
+ .chain(path.segments.iter())
+ .cloned()
+ .collect();
match tree.kind {
UseTreeKind::Simple(rename, id1, id2) => {
// First apply the prefix to the path
let mut path = Path {
- segments: prefix
- .segments
- .iter()
- .chain(path.segments.iter())
- .cloned()
- .collect(),
+ segments,
span: path.span,
};
// for later
let ret_def = defs.next().unwrap_or(Def::Err);
+ // Here, we are looping over namespaces, if they exist for the definition
+ // being imported. We only handle type and value namespaces because we
+ // won't be dealing with macros in the rest of the compiler.
+ // Essentially a single `use` which imports two names is desugared into
+ // two imports.
for (def, &new_node_id) in defs.zip([id1, id2].iter()) {
let vis = vis.clone();
let name = name.clone();
+ let mut path = path.clone();
+ for seg in &mut path.segments {
+ seg.id = self.sess.next_node_id();
+ }
let span = path.span;
self.resolver.definitions().create_def_with_parent(
parent_def_index,
self.with_hir_id_owner(new_node_id, |this| {
let new_id = this.lower_node_id(new_node_id);
- let path = this.lower_path_extra(def, &path, None, ParamMode::Explicit);
+ let path =
+ this.lower_path_extra(def, &path, None, ParamMode::Explicit, None);
let item = hir::ItemKind::Use(P(path), hir::UseKind::Single);
let vis_kind = match vis.node {
hir::VisibilityKind::Public => hir::VisibilityKind::Public,
let id = this.next_id();
hir::VisibilityKind::Restricted {
path: path.clone(),
- // We are allocating a new NodeId here
id: id.node_id,
hir_id: id.hir_id,
}
});
}
- let path = P(self.lower_path_extra(ret_def, &path, None, ParamMode::Explicit));
+ let path =
+ P(self.lower_path_extra(ret_def, &path, None, ParamMode::Explicit, None));
hir::ItemKind::Use(path, hir::UseKind::Single)
}
UseTreeKind::Glob => {
let path = P(self.lower_path(
id,
&Path {
- segments: prefix
- .segments
- .iter()
- .chain(path.segments.iter())
- .cloned()
- .collect(),
+ segments,
span: path.span,
},
ParamMode::Explicit,
hir::ItemKind::Use(path, hir::UseKind::Glob)
}
UseTreeKind::Nested(ref trees) => {
+ // Nested imports are desugared into simple imports.
+
let prefix = Path {
- segments: prefix
- .segments
- .iter()
- .chain(path.segments.iter())
- .cloned()
- .collect(),
+ segments,
span: prefix.span.to(path.span),
};
- // Add all the nested PathListItems in the HIR
+ // Add all the nested PathListItems to the HIR.
for &(ref use_tree, id) in trees {
self.allocate_hir_id_counter(id, &use_tree);
+
let LoweredNodeId {
node_id: new_id,
hir_id: new_hir_id,
let mut vis = vis.clone();
let mut name = name.clone();
- let item =
- self.lower_use_tree(use_tree, &prefix, new_id, &mut vis, &mut name, &attrs);
+ let mut prefix = prefix.clone();
+ // Give the segments new ids since they are being cloned.
+ for seg in &mut prefix.segments {
+ seg.id = self.sess.next_node_id();
+ }
+
+ // Each `use` import is an item and thus are owners of the
+ // names in the path. Up to this point the nested import is
+ // the current owner, since we want each desugared import to
+ // own its own names, we have to adjust the owner before
+ // lowering the rest of the import.
self.with_hir_id_owner(new_id, |this| {
+ let item = this.lower_use_tree(use_tree,
+ &prefix,
+ new_id,
+ &mut vis,
+ &mut name,
+ attrs);
+
let vis_kind = match vis.node {
hir::VisibilityKind::Public => hir::VisibilityKind::Public,
hir::VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar),
let id = this.next_id();
hir::VisibilityKind::Restricted {
path: path.clone(),
- // We are allocating a new NodeId here
id: id.node_id,
hir_id: id.hir_id,
}
hir::Item {
id: new_id,
hir_id: new_hir_id,
- name: name,
+ name,
attrs: attrs.clone(),
node: item,
vis,
0,
ParenthesizedGenericArgs::Err,
ImplTraitContext::disallowed(),
+ None,
);
let args = args.iter().map(|x| self.lower_expr(x)).collect();
hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args)
} else {
self.lower_node_id(id)
};
+ let def = self.expect_full_def(id);
hir::VisibilityKind::Restricted {
- path: P(self.lower_path(id, path, ParamMode::Explicit)),
+ path: P(self.lower_path_extra(
+ def,
+ path,
+ None,
+ ParamMode::Explicit,
+ explicit_owner,
+ )),
id: lowered_id.node_id,
hir_id: lowered_id.hir_id,
}
params: Option<P<hir::GenericArgs>>,
is_value: bool
) -> hir::Path {
- self.resolver
- .resolve_str_path(span, self.crate_root, components, params, is_value)
+ let mut path = self.resolver
+ .resolve_str_path(span, self.crate_root, components, is_value);
+ path.segments.last_mut().unwrap().args = params;
+
+
+ for seg in path.segments.iter_mut() {
+ if let Some(id) = seg.id {
+ seg.id = Some(self.lower_node_id(id).node_id);
+ }
+ }
+ path
}
fn ty_path(&mut self, id: LoweredNodeId, span: Span, qpath: hir::QPath) -> hir::Ty {
None => format!("{:?}", node)
};
- if hir_id == ::hir::DUMMY_HIR_ID {
- debug!("Maybe you forgot to lower the node id {:?}?", id);
- }
+ let forgot_str = if hir_id == ::hir::DUMMY_HIR_ID {
+ format!("\nMaybe you forgot to lower the node id {:?}?", id)
+ } else {
+ String::new()
+ };
bug!("inconsistent DepNode for `{}`: \
- current_dep_node_owner={}, hir_id.owner={}",
+ current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?}) {}",
node_str,
self.definitions
.def_path(self.current_dep_node_owner)
.to_string_no_crate(),
- self.definitions.def_path(hir_id.owner).to_string_no_crate())
+ self.current_dep_node_owner,
+ self.definitions.def_path(hir_id.owner).to_string_no_crate(),
+ hir_id.owner,
+ forgot_str)
}
}
});
}
+ fn visit_path_segment(&mut self, path_span: Span, path_segment: &'hir PathSegment) {
+ if let Some(id) = path_segment.id {
+ self.insert(id, Node::PathSegment(path_segment));
+ }
+ intravisit::walk_path_segment(self, path_span, path_segment);
+ }
+
fn visit_ty(&mut self, ty: &'hir Ty) {
self.insert(ty.id, Node::Ty(ty));
walk(self);
if owner_def_index == CRATE_DEF_INDEX {
- return
+ return;
}
// There's always at least one entry for the owning item itself
local_id,
self.hir_map.node_to_string(node_id)));
}
-
self.errors.push(format!(
"ItemLocalIds not assigned densely in {}. \
- Max ItemLocalId = {}, missing IDs = {:?}",
+ Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}",
self.hir_map.def_path(DefId::local(owner_def_index)).to_string_no_crate(),
max,
- missing_items));
+ missing_items,
+ self.hir_ids_seen
+ .values()
+ .map(|n| format!("({:?} {})", n, self.hir_map.node_to_string(*n)))
+ .collect::<Vec<_>>()));
}
}
}
self.errors.push(format!("HirIdValidator: No HirId assigned for NodeId {}: {:?}",
node_id,
self.hir_map.node_to_string(node_id)));
+ return;
}
if owner != stable_id.owner {
if let Some(entry) = self.map[id.as_usize()] {
self.dep_graph.read_index(entry.dep_node);
} else {
- bug!("called `HirMap::read()` with invalid `NodeId`")
+ bug!("called `HirMap::read()` with invalid `NodeId`: {:?}", id)
}
}
Node::AnonConst(_) |
Node::Expr(_) |
Node::Stmt(_) |
+ Node::PathSegment(_) |
Node::Ty(_) |
Node::TraitRef(_) |
Node::Pat(_) |
Some(Node::AnonConst(constant)) => self.body(constant.body).value.span,
Some(Node::Expr(expr)) => expr.span,
Some(Node::Stmt(stmt)) => stmt.span,
+ Some(Node::PathSegment(seg)) => seg.ident.span,
Some(Node::Ty(ty)) => ty.span,
Some(Node::TraitRef(tr)) => tr.path.span,
Some(Node::Binding(pat)) => pat.span,
Node::AnonConst(a) => self.print_anon_const(&a),
Node::Expr(a) => self.print_expr(&a),
Node::Stmt(a) => self.print_stmt(&a),
+ Node::PathSegment(a) => self.print_path_segment(&a),
Node::Ty(a) => self.print_type(&a),
Node::TraitRef(a) => self.print_trait_ref(&a),
Node::Binding(a) |
Some(Node::Stmt(_)) => {
format!("stmt {}{}", map.node_to_pretty_string(id), id_str)
}
+ Some(Node::PathSegment(_)) => {
+ format!("path segment {}{}", map.node_to_pretty_string(id), id_str)
+ }
Some(Node::Ty(_)) => {
format!("type {}{}", map.node_to_pretty_string(id), id_str)
}
pub struct PathSegment {
/// The identifier portion of this path segment.
pub ident: Ident,
+ // `id` and `def` are optional. We currently only use these in save-analysis,
+ // any path segments without these will not have save-analysis info and
+ // therefore will not have 'jump to def' in IDEs, but otherwise will not be
+ // affected. (In general, we don't bother to get the defs for synthesized
+ // segments, only for segments which have come from the AST).
+ pub id: Option<NodeId>,
+ pub def: Option<Def>,
/// Type/lifetime parameters attached to this path. They come in
/// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`. Note that
pub fn from_ident(ident: Ident) -> PathSegment {
PathSegment {
ident,
+ id: None,
+ def: None,
infer_types: true,
args: None,
}
}
- pub fn new(ident: Ident, args: GenericArgs, infer_types: bool) -> Self {
+ pub fn new(
+ ident: Ident,
+ id: Option<NodeId>,
+ def: Option<Def>,
+ args: GenericArgs,
+ infer_types: bool,
+ ) -> Self {
PathSegment {
ident,
+ id,
+ def,
infer_types,
args: if args.is_empty() {
None
AnonConst(&'hir AnonConst),
Expr(&'hir Expr),
Stmt(&'hir Stmt),
+ PathSegment(&'hir PathSegment),
Ty(&'hir Ty),
TraitRef(&'hir TraitRef),
Binding(&'hir Pat),
State {
s: pp::mk_printer(out, default_columns),
cm: Some(cm),
- comments: comments.clone(),
+ comments,
literals: literals.unwrap_or_default().into_iter().peekable(),
cur_cmnt: 0,
boxes: Vec::new(),
Ok(())
}
+ pub fn print_path_segment(&mut self, segment: &hir::PathSegment) -> io::Result<()> {
+ if segment.ident.name != keywords::CrateRoot.name() &&
+ segment.ident.name != keywords::DollarCrate.name() {
+ self.print_ident(segment.ident)?;
+ segment.with_generic_args(|generic_args| {
+ self.print_generic_args(generic_args, segment.infer_types, false)
+ })?;
+ }
+ Ok(())
+ }
+
pub fn print_qpath(&mut self,
qpath: &hir::QPath,
colons_before_params: bool)
CachingSourceMapView {
source_map,
- line_cache: [entry.clone(), entry.clone(), entry.clone()],
+ line_cache: [entry.clone(), entry.clone(), entry],
time_stamp: 0,
}
}
impl_stable_hash_for!(struct hir::PathSegment {
ident -> (ident.name),
+ id,
+ def,
infer_types,
args
});
self.trace(expected, actual).eq(&expected, &actual)
}
+ pub fn relate<T>(
+ self,
+ expected: T,
+ variance: ty::Variance,
+ actual: T,
+ ) -> InferResult<'tcx, ()>
+ where T: ToTrace<'tcx>
+ {
+ match variance {
+ ty::Variance::Covariant => self.sub(expected, actual),
+ ty::Variance::Invariant => self.eq(expected, actual),
+ ty::Variance::Contravariant => self.sup(expected, actual),
+
+ // We could make this make sense but it's not readily
+ // exposed and I don't feel like dealing with it. Note
+ // that bivariance in general does a bit more than just
+ // *nothing*, it checks that the types are the same
+ // "modulo variance" basically.
+ ty::Variance::Bivariant => panic!("Bivariant given to `relate()`"),
+ }
+ }
+
/// Compute the least-upper-bound, or mutual supertype, of two
/// values. The order of the arguments doesn't matter, but since
/// this can result in an error (e.g., if asked to compute LUB of
dir: RelationDir)
-> RelateResult<'tcx, Generalization<'tcx>>
{
+ debug!("generalize(ty={:?}, for_vid={:?}, dir={:?}", ty, for_vid, dir);
// Determine the ambient variance within which `ty` appears.
// The surrounding equation is:
//
root_ty: ty,
};
- let ty = generalize.relate(&ty, &ty)?;
+ let ty = match generalize.relate(&ty, &ty) {
+ Ok(ty) => ty,
+ Err(e) => {
+ debug!("generalize: failure {:?}", e);
+ return Err(e);
+ }
+ };
let needs_wf = generalize.needs_wf;
+ debug!("generalize: success {{ {:?}, {:?} }}", ty, needs_wf);
Ok(Generalization { ty, needs_wf })
}
}
let infcx = self.fields.infcx;
let a = infcx.type_variables.borrow_mut().replace_if_possible(a);
let b = infcx.type_variables.borrow_mut().replace_if_possible(b);
+
+ debug!("{}.tys: replacements ({:?}, {:?})", self.tag(), a, b);
+
match (&a.sty, &b.sty) {
(&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => {
infcx.type_variables.borrow_mut().equate(a_id, b_id);
"detect mut variables which don't need to be mutable"
}
+declare_lint! {
+ pub UNCONDITIONAL_RECURSION,
+ Warn,
+ "functions that cannot return without calling themselves"
+}
+
declare_lint! {
pub SINGLE_USE_LIFETIMES,
Allow,
DEPRECATED,
UNUSED_UNSAFE,
UNUSED_MUT,
+ UNCONDITIONAL_RECURSION,
SINGLE_USE_LIFETIMES,
UNUSED_LIFETIMES,
UNUSED_LABELS,
macro_rules! impl_stable_hash_for {
// FIXME(mark-i-m): Some of these should be `?` rather than `*`. See the git blame and change
// them back when `?` is supported again.
- (enum $enum_name:path { $( $variant:ident $( ( $($field:ident $(-> $delegate:tt)*),* ) )* ),* $(,)* }) => {
+ (enum $enum_name:path {
+ $( $variant:ident
+ // this incorrectly allows specifying both tuple-like and struct-like fields, as in `Variant(a,b){c,d}`,
+ // when it should be only one or the other
+ $( ( $($field:ident $(-> $delegate:tt)*),* ) )*
+ $( { $($named_field:ident $(-> $named_delegate:tt)*),* } )*
+ ),* $(,)*
+ }) => {
impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $enum_name {
#[inline]
fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
match *self {
$(
- $variant $( ( $(ref $field),* ) )* => {
+ $variant $( ( $(ref $field),* ) )* $( { $(ref $named_field),* } )* => {
$($( __impl_stable_hash_field!($field, __ctx, __hasher $(, $delegate)*) );*)*
+ $($( __impl_stable_hash_field!($named_field, __ctx, __hasher $(, $named_delegate)*) );*)*
}
)*
}
}
};
- (impl<$tcx:lifetime $(, $T:ident)*> for struct $struct_name:path {
- $($field:ident),* $(,)*
+ (impl<$tcx:lifetime $(, $lt:lifetime $(: $lt_bound:lifetime)*)* $(, $T:ident)*> for struct $struct_name:path {
+ $($field:ident $(-> $delegate:tt)*),* $(,)*
}) => {
- impl<'a, $tcx, $($T,)*> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $struct_name
+ impl<'a, $tcx, $($lt $(: $lt_bound)*,)* $($T,)*>
+ ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $struct_name
where $($T: ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>>),*
{
#[inline]
$(ref $field),*
} = *self;
- $( $field.hash_stable(__ctx, __hasher));*
+ $( __impl_stable_hash_field!($field, __ctx, __hasher $(, $delegate)*) );*
}
}
};
};
let mut err = report_missing_lifetime_specifiers(self.tcx.sess, span, lifetime_refs.len());
+ let mut add_label = true;
if let Some(params) = error {
if lifetime_refs.len() == 1 {
- self.report_elision_failure(&mut err, params);
+ add_label = add_label && self.report_elision_failure(&mut err, params, span);
}
}
+ if add_label {
+ add_missing_lifetime_specifiers_label(&mut err, span, lifetime_refs.len());
+ }
err.emit();
}
+ fn suggest_lifetime(&self, db: &mut DiagnosticBuilder<'_>, span: Span, msg: &str) -> bool {
+ match self.tcx.sess.source_map().span_to_snippet(span) {
+ Ok(ref snippet) => {
+ let (sugg, applicability) = if snippet == "&" {
+ ("&'static ".to_owned(), Applicability::MachineApplicable)
+ } else if snippet == "'_" {
+ ("'static".to_owned(), Applicability::MachineApplicable)
+ } else {
+ (format!("{} + 'static", snippet), Applicability::MaybeIncorrect)
+ };
+ db.span_suggestion_with_applicability(span, msg, sugg, applicability);
+ false
+ }
+ Err(_) => {
+ db.help(msg);
+ true
+ }
+ }
+ }
+
fn report_elision_failure(
&mut self,
db: &mut DiagnosticBuilder<'_>,
params: &[ElisionFailureInfo],
- ) {
+ span: Span,
+ ) -> bool {
let mut m = String::new();
let len = params.len();
"this function's return type contains a borrowed value, but \
there is no value for it to be borrowed from"
);
- help!(db, "consider giving it a 'static lifetime");
+ self.suggest_lifetime(db, span, "consider giving it a 'static lifetime")
} else if elided_len == 0 {
help!(
db,
an elided lifetime, but the lifetime cannot be derived from \
the arguments"
);
- help!(
- db,
- "consider giving it an explicit bounded or 'static \
- lifetime"
- );
+ let msg = "consider giving it an explicit bounded or 'static lifetime";
+ self.suggest_lifetime(db, span, msg)
} else if elided_len == 1 {
help!(
db,
the signature does not say which {} it is borrowed from",
m
);
+ true
} else {
help!(
db,
the signature does not say whether it is borrowed from {}",
m
);
+ true
}
}
}
}
-pub fn report_missing_lifetime_specifiers(
+fn report_missing_lifetime_specifiers(
sess: &Session,
span: Span,
count: usize,
) -> DiagnosticBuilder<'_> {
- let mut err = struct_span_err!(
+ struct_span_err!(
sess,
span,
E0106,
"missing lifetime specifier{}",
if count > 1 { "s" } else { "" }
- );
+ )
+}
- let msg: Cow<'static, str> = if count > 1 {
- format!("expected {} lifetime parameters", count).into()
+fn add_missing_lifetime_specifiers_label(
+ err: &mut DiagnosticBuilder<'_>,
+ span: Span,
+ count: usize,
+) {
+ if count > 1 {
+ err.span_label(span, format!("expected {} lifetime parameters", count));
} else {
- "expected lifetime parameter".into()
+ err.span_label(span, "expected lifetime parameter");
};
-
- err.span_label(span, msg);
-
- err
}
}
////////////////////////////////////////////////////////////////////////////////
-// Methods to faciliate working with signed integers stored in a u128
+// Methods to facilitate working with signed integers stored in a u128
////////////////////////////////////////////////////////////////////////////////
pub fn sign_extend(value: u128, size: Size) -> u128 {
#[inline]
pub fn is_null_ptr(self, cx: impl HasDataLayout) -> bool {
match self {
- Scalar::Bits { bits, size } => {
+ Scalar::Bits { bits, size } => {
assert_eq!(size as u64, cx.data_layout().pointer_size.bytes());
bits == 0
},
}
}
- #[inline]
- pub fn is_null(self) -> bool {
- match self {
- Scalar::Bits { bits, .. } => bits == 0,
- Scalar::Ptr(_) => false
- }
- }
-
#[inline]
pub fn from_bool(b: bool) -> Self {
Scalar::Bits { bits: b as u128, size: 1 }
/// }
///
/// This can't be a shared borrow because mutably borrowing (*x as Some).0
- /// should not prevent `if let None = x { ... }`, for example, becase the
+ /// should not prevent `if let None = x { ... }`, for example, because the
/// mutating `(*x as Some).0` can't affect the discriminant of `x`.
/// We can also report errors with this kind of borrow differently.
Shallow,
///////////////////////////////////////////////////////////////////////////
// Operands
-/// These are values that can appear inside an rvalue (or an index
-/// place). They are intentionally limited to prevent rvalues from
-/// being nested in one another.
+/// These are values that can appear inside an rvalue. They are intentionally
+/// limited to prevent rvalues from being nested in one another.
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub enum Operand<'tcx> {
/// Copy: The value must be available for use afterwards.
}
}
+EnumLiftImpl! {
+ impl<'a, 'tcx> Lift<'tcx> for UserTypeAnnotation<'a> {
+ type Lifted = UserTypeAnnotation<'tcx>;
+ (UserTypeAnnotation::Ty)(ty),
+ (UserTypeAnnotation::TypeOf)(def, substs),
+ }
+}
+
newtype_index! {
pub struct Promoted {
DEBUG_FORMAT = "promoted[{}]"
mir: &'a Mir<'tcx>,
visited: BitSet<BasicBlock>,
worklist: Vec<BasicBlock>,
+ root_is_start_block: bool,
}
impl<'a, 'tcx> Preorder<'a, 'tcx> {
mir,
visited: BitSet::new_empty(mir.basic_blocks().len()),
worklist,
+ root_is_start_block: root == START_BLOCK,
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
// All the blocks, minus the number of blocks we've visited.
- let remaining = self.mir.basic_blocks().len() - self.visited.count();
+ let upper = self.mir.basic_blocks().len() - self.visited.count();
- // We will visit all remaining blocks exactly once.
- (remaining, Some(remaining))
+ let lower = if self.root_is_start_block {
+ // We will visit all remaining blocks exactly once.
+ upper
+ } else {
+ self.worklist.len()
+ };
+
+ (lower, Some(upper))
}
}
-impl<'a, 'tcx> ExactSizeIterator for Preorder<'a, 'tcx> {}
-
/// Postorder traversal of a graph.
///
/// Postorder traversal is when each node is visited after all of it's
pub struct Postorder<'a, 'tcx: 'a> {
mir: &'a Mir<'tcx>,
visited: BitSet<BasicBlock>,
- visit_stack: Vec<(BasicBlock, Successors<'a>)>
+ visit_stack: Vec<(BasicBlock, Successors<'a>)>,
+ root_is_start_block: bool,
}
impl<'a, 'tcx> Postorder<'a, 'tcx> {
let mut po = Postorder {
mir,
visited: BitSet::new_empty(mir.basic_blocks().len()),
- visit_stack: Vec::new()
+ visit_stack: Vec::new(),
+ root_is_start_block: root == START_BLOCK,
};
fn size_hint(&self) -> (usize, Option<usize>) {
// All the blocks, minus the number of blocks we've visited.
- let remaining = self.mir.basic_blocks().len() - self.visited.count();
+ let upper = self.mir.basic_blocks().len() - self.visited.count();
- // We will visit all remaining blocks exactly once.
- (remaining, Some(remaining))
+ let lower = if self.root_is_start_block {
+ // We will visit all remaining blocks exactly once.
+ upper
+ } else {
+ self.visit_stack.len()
+ };
+
+ (lower, Some(upper))
}
}
-impl<'a, 'tcx> ExactSizeIterator for Postorder<'a, 'tcx> {}
-
/// Reverse postorder traversal of a graph
///
/// Reverse postorder is the reverse order of a postorder traversal.
flags.push(("crate_local".to_owned(), None));
}
- // Allow targetting all integers using `{integral}`, even if the exact type was resolved
+ // Allow targeting all integers using `{integral}`, even if the exact type was resolved
if self_ty.is_integral() {
flags.push(("_Self".to_owned(), Some("{integral}".to_owned())));
}
let value = self.selcx.infcx().resolve_type_vars_if_possible(value);
if !value.has_projections() {
- value.clone()
+ value
} else {
value.fold_with(self)
}
pub type CanonicalPredicateGoal<'tcx> =
Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>;
+pub type CanonicalTypeOpAscribeUserTypeGoal<'tcx> =
+ Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::ascribe_user_type::AscribeUserType<'tcx>>>;
+
pub type CanonicalTypeOpEqGoal<'tcx> =
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::eq::Eq<'tcx>>>;
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse};
+use traits::query::Fallible;
+use hir::def_id::DefId;
+use ty::{self, ParamEnvAnd, Ty, TyCtxt};
+use ty::subst::UserSubsts;
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct AscribeUserType<'tcx> {
+ pub mir_ty: Ty<'tcx>,
+ pub variance: ty::Variance,
+ pub def_id: DefId,
+ pub user_substs: UserSubsts<'tcx>,
+}
+
+impl<'tcx> AscribeUserType<'tcx> {
+ pub fn new(
+ mir_ty: Ty<'tcx>,
+ variance: ty::Variance,
+ def_id: DefId,
+ user_substs: UserSubsts<'tcx>,
+ ) -> Self {
+ AscribeUserType { mir_ty, variance, def_id, user_substs }
+ }
+}
+
+impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for AscribeUserType<'tcx> {
+ type QueryResponse = ();
+
+ fn try_fast_path(
+ _tcx: TyCtxt<'_, 'gcx, 'tcx>,
+ _key: &ParamEnvAnd<'tcx, Self>,
+ ) -> Option<Self::QueryResponse> {
+ None
+ }
+
+ fn perform_query(
+ tcx: TyCtxt<'_, 'gcx, 'tcx>,
+ canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>,
+ ) -> Fallible<CanonicalizedQueryResponse<'gcx, ()>> {
+ tcx.type_op_ascribe_user_type(canonicalized)
+ }
+
+ fn shrink_to_tcx_lifetime(
+ v: &'a CanonicalizedQueryResponse<'gcx, ()>,
+ ) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> {
+ v
+ }
+}
+
+BraceStructTypeFoldableImpl! {
+ impl<'tcx> TypeFoldable<'tcx> for AscribeUserType<'tcx> {
+ mir_ty, variance, def_id, user_substs
+ }
+}
+
+BraceStructLiftImpl! {
+ impl<'a, 'tcx> Lift<'tcx> for AscribeUserType<'a> {
+ type Lifted = AscribeUserType<'tcx>;
+ mir_ty, variance, def_id, user_substs
+ }
+}
+
+impl_stable_hash_for! {
+ struct AscribeUserType<'tcx> {
+ mir_ty, variance, def_id, user_substs
+ }
+}
use ty::fold::TypeFoldable;
use ty::{Lift, ParamEnvAnd, TyCtxt};
+pub mod ascribe_user_type;
pub mod custom;
pub mod eq;
pub mod implied_outlives_bounds;
.map(|v| v.get(tcx))
}
+ /// Determines whether can we safely cache the result
+ /// of selecting an obligation. This is almost always 'true',
+ /// except when dealing with certain ParamCandidates.
+ ///
+ /// Ordinarily, a ParamCandidate will contain no inference variables,
+ /// since it was usually produced directly from a DefId. However,
+ /// certain cases (currently only librustdoc's blanket impl finder),
+ /// a ParamEnv may be explicitly constructed with inference types.
+ /// When this is the case, we do *not* want to cache the resulting selection
+ /// candidate. This is due to the fact that it might not always be possible
+ /// to equate the obligation's trait ref and the candidate's trait ref,
+ /// if more constraints end up getting added to an inference variable.
+ ///
+ /// Because of this, we always want to re-run the full selection
+ /// process for our obligation the next time we see it, since
+ /// we might end up picking a different SelectionCandidate (or none at all)
+ fn can_cache_candidate(&self,
+ result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>
+ ) -> bool {
+ match result {
+ Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => {
+ !trait_ref.skip_binder().input_types().any(|t| t.walk().any(|t_| t_.is_ty_infer()))
+ },
+ _ => true
+ }
+ }
+
fn insert_candidate_cache(
&mut self,
param_env: ty::ParamEnv<'tcx>,
) {
let tcx = self.tcx();
let trait_ref = cache_fresh_trait_pred.skip_binder().trait_ref;
+
+ if !self.can_cache_candidate(&candidate) {
+ debug!("insert_candidate_cache(trait_ref={:?}, candidate={:?} -\
+ candidate is not cacheable", trait_ref, candidate);
+ return;
+
+ }
+
if self.can_use_global_caches(param_env) {
if let Err(Overflow) = candidate {
// Don't cache overflow globally; we only produce this
maybe_unused_trait_imports: FxHashSet<DefId>,
maybe_unused_extern_crates: Vec<(DefId, Span)>,
- pub extern_prelude: FxHashSet<ast::Name>,
+ /// Extern prelude entries. The value is `true` if the entry was introduced
+ /// via `extern crate` item and not `--extern` option or compiler built-in.
+ pub extern_prelude: FxHashMap<ast::Name, bool>,
// Internal cache for metadata decoding. No need to track deps on this.
pub rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
// printing the `CrateRoot` so we don't prepend a `crate::` to paths.
let mut is_prelude_crate = false;
if let DefPathData::CrateRoot = self.def_key(parent_did).disambiguated_data.data {
- if self.extern_prelude.contains(&data.as_interned_str().as_symbol()) {
+ if self.extern_prelude.contains_key(&data.as_interned_str().as_symbol()) {
is_prelude_crate = true;
}
}
use ty::util::{IntTypeExt, Discr};
use ty::walk::TypeWalker;
use util::captures::Captures;
-use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet};
+use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
use arena::SyncDroplessArena;
use session::DataTypeKind;
pub maybe_unused_trait_imports: NodeSet,
pub maybe_unused_extern_crates: Vec<(NodeId, Span)>,
pub export_map: ExportMap,
- pub extern_prelude: FxHashSet<Name>,
+ /// Extern prelude entries. The value is `true` if the entry was introduced
+ /// via `extern crate` item and not `--extern` option or compiler built-in.
+ pub extern_prelude: FxHashMap<Name, bool>,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
}
}
-#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Copy)]
+#[derive(Copy, Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Hash)]
pub enum Variance {
Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type
Invariant, // T<A> <: T<B> iff B == A -- e.g., type of mutable cell
use mir::interpret::GlobalId;
use traits;
use traits::query::{
- CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpEqGoal,
- CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
+ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
+ CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
+ CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
};
use ty::{self, ParamEnvAnd, Ty, TyCtxt};
use ty::subst::Substs;
}
}
+impl<'tcx> QueryDescription<'tcx> for queries::type_op_ascribe_user_type<'tcx> {
+ fn describe(
+ _tcx: TyCtxt<'_, '_, '_>,
+ goal: CanonicalTypeOpAscribeUserTypeGoal<'tcx>,
+ ) -> Cow<'static, str> {
+ format!("evaluating `type_op_ascribe_user_type` `{:?}`", goal).into()
+ }
+}
+
impl<'tcx> QueryDescription<'tcx> for queries::type_op_eq<'tcx> {
fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: CanonicalTypeOpEqGoal<'tcx>) -> Cow<'static, str> {
format!("evaluating `type_op_eq` `{:?}`", goal).into()
use session::{CompileResult, CrateDisambiguator};
use session::config::OutputFilenames;
use traits::{self, Vtable};
-use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal,
- CanonicalTyGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal,
- CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, NoSolution};
+use traits::query::{
+ CanonicalPredicateGoal, CanonicalProjectionGoal,
+ CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal,
+ CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal,
+ CanonicalTypeOpNormalizeGoal, NoSolution,
+};
use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
use traits::query::normalize::NormalizationResult;
use traits::query::outlives_bounds::OutlivesBound;
CanonicalPredicateGoal<'tcx>
) -> Result<traits::EvaluationResult, traits::OverflowError>,
+ /// Do not call this query directly: part of the `Eq` type-op
+ [] fn type_op_ascribe_user_type: TypeOpAscribeUserType(
+ CanonicalTypeOpAscribeUserTypeGoal<'tcx>
+ ) -> Result<
+ Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>>,
+ NoSolution,
+ >,
+
/// Do not call this query directly: part of the `Eq` type-op
[] fn type_op_eq: TypeOpEq(
CanonicalTypeOpEqGoal<'tcx>
DepKind::ImpliedOutlivesBounds |
DepKind::DropckOutlives |
DepKind::EvaluateObligation |
+ DepKind::TypeOpAscribeUserType |
DepKind::TypeOpEq |
DepKind::TypeOpSubtype |
DepKind::TypeOpProvePredicate |
self.map_bound_ref(|fn_sig| fn_sig.inputs_and_output)
}
pub fn output(&self) -> ty::Binder<Ty<'tcx>> {
- self.map_bound_ref(|fn_sig| fn_sig.output().clone())
+ self.map_bound_ref(|fn_sig| fn_sig.output())
}
pub fn variadic(&self) -> bool {
self.skip_binder().variadic
fty, asm, cons, volatile, alignstack, dia);
Some(self.call(v, inputs, None))
} else {
- // LLVM has detected an issue with our constaints, bail out
+ // LLVM has detected an issue with our constraints, bail out
None
}
}
trait_map: resolver.trait_map,
maybe_unused_trait_imports: resolver.maybe_unused_trait_imports,
maybe_unused_extern_crates: resolver.maybe_unused_extern_crates,
- extern_prelude: resolver.extern_prelude,
+ extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| {
+ (ident.name, entry.introduced_by_item)
+ }).collect(),
},
analysis: ty::CrateAnalysis {
use rustc::hir::def::Def;
use rustc::hir::def_id::DefId;
-use rustc::cfg;
-use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty};
-use rustc::traits;
use hir::Node;
use util::nodemap::NodeSet;
use lint::{LateContext, LintContext, LintArray};
}
}
-declare_lint! {
- pub UNCONDITIONAL_RECURSION,
- Warn,
- "functions that cannot return without calling themselves"
-}
-
-#[derive(Copy, Clone)]
-pub struct UnconditionalRecursion;
-
-
-impl LintPass for UnconditionalRecursion {
- fn get_lints(&self) -> LintArray {
- lint_array![UNCONDITIONAL_RECURSION]
- }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
- fn check_fn(&mut self,
- cx: &LateContext,
- fn_kind: FnKind,
- _: &hir::FnDecl,
- body: &hir::Body,
- sp: Span,
- id: ast::NodeId) {
- let method = match fn_kind {
- FnKind::ItemFn(..) => None,
- FnKind::Method(..) => {
- Some(cx.tcx.associated_item(cx.tcx.hir.local_def_id(id)))
- }
- // closures can't recur, so they don't matter.
- FnKind::Closure(_) => return,
- };
-
- // Walk through this function (say `f`) looking to see if
- // every possible path references itself, i.e. the function is
- // called recursively unconditionally. This is done by trying
- // to find a path from the entry node to the exit node that
- // *doesn't* call `f` by traversing from the entry while
- // pretending that calls of `f` are sinks (i.e. ignoring any
- // exit edges from them).
- //
- // NB. this has an edge case with non-returning statements,
- // like `loop {}` or `panic!()`: control flow never reaches
- // the exit node through these, so one can have a function
- // that never actually calls itself but is still picked up by
- // this lint:
- //
- // fn f(cond: bool) {
- // if !cond { panic!() } // could come from `assert!(cond)`
- // f(false)
- // }
- //
- // In general, functions of that form may be able to call
- // itself a finite number of times and then diverge. The lint
- // considers this to be an error for two reasons, (a) it is
- // easier to implement, and (b) it seems rare to actually want
- // to have behaviour like the above, rather than
- // e.g. accidentally recursing after an assert.
-
- let cfg = cfg::CFG::new(cx.tcx, &body);
-
- let mut work_queue = vec![cfg.entry];
- let mut reached_exit_without_self_call = false;
- let mut self_call_spans = vec![];
- let mut visited = FxHashSet::default();
-
- while let Some(idx) = work_queue.pop() {
- if idx == cfg.exit {
- // found a path!
- reached_exit_without_self_call = true;
- break;
- }
-
- let cfg_id = idx.node_id();
- if visited.contains(&cfg_id) {
- // already done
- continue;
- }
- visited.insert(cfg_id);
-
- // is this a recursive call?
- let local_id = cfg.graph.node_data(idx).id();
- if local_id != hir::DUMMY_ITEM_LOCAL_ID {
- let node_id = cx.tcx.hir.hir_to_node_id(hir::HirId {
- owner: body.value.hir_id.owner,
- local_id
- });
- let self_recursive = match method {
- Some(ref method) => expr_refers_to_this_method(cx, method, node_id),
- None => expr_refers_to_this_fn(cx, id, node_id),
- };
- if self_recursive {
- self_call_spans.push(cx.tcx.hir.span(node_id));
- // this is a self call, so we shouldn't explore past
- // this node in the CFG.
- continue;
- }
- }
-
- // add the successors of this node to explore the graph further.
- for (_, edge) in cfg.graph.outgoing_edges(idx) {
- let target_idx = edge.target();
- let target_cfg_id = target_idx.node_id();
- if !visited.contains(&target_cfg_id) {
- work_queue.push(target_idx)
- }
- }
- }
-
- // Check the number of self calls because a function that
- // doesn't return (e.g. calls a `-> !` function or `loop { /*
- // no break */ }`) shouldn't be linted unless it actually
- // recurs.
- if !reached_exit_without_self_call && !self_call_spans.is_empty() {
- let sp = cx.tcx.sess.source_map().def_span(sp);
- let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION,
- sp,
- "function cannot return without recursing");
- db.span_label(sp, "cannot return without recursing");
- // offer some help to the programmer.
- for call in &self_call_spans {
- db.span_label(*call, "recursive call site");
- }
- db.help("a `loop` may express intention better if this is on purpose");
- db.emit();
- }
-
- // all done
- return;
-
- // Functions for identifying if the given Expr NodeId `id`
- // represents a call to the function `fn_id`/method `method`.
-
- fn expr_refers_to_this_fn(cx: &LateContext, fn_id: ast::NodeId, id: ast::NodeId) -> bool {
- match cx.tcx.hir.get(id) {
- Node::Expr(&hir::Expr { node: hir::ExprKind::Call(ref callee, _), .. }) => {
- let def = if let hir::ExprKind::Path(ref qpath) = callee.node {
- cx.tables.qpath_def(qpath, callee.hir_id)
- } else {
- return false;
- };
- match def {
- Def::Local(..) | Def::Upvar(..) => false,
- _ => def.def_id() == cx.tcx.hir.local_def_id(fn_id)
- }
- }
- _ => false,
- }
- }
-
- // Check if the expression `id` performs a call to `method`.
- fn expr_refers_to_this_method(cx: &LateContext,
- method: &ty::AssociatedItem,
- id: ast::NodeId)
- -> bool {
- use rustc::ty::adjustment::*;
-
- // Ignore non-expressions.
- let expr = if let Node::Expr(e) = cx.tcx.hir.get(id) {
- e
- } else {
- return false;
- };
-
- // Check for overloaded autoderef method calls.
- let mut source = cx.tables.expr_ty(expr);
- for adjustment in cx.tables.expr_adjustments(expr) {
- if let Adjust::Deref(Some(deref)) = adjustment.kind {
- let (def_id, substs) = deref.method_call(cx.tcx, source);
- if method_call_refers_to_method(cx, method, def_id, substs, id) {
- return true;
- }
- }
- source = adjustment.target;
- }
-
- // Check for method calls and overloaded operators.
- if cx.tables.is_method_call(expr) {
- let hir_id = cx.tcx.hir.definitions().node_to_hir_id(id);
- if let Some(def) = cx.tables.type_dependent_defs().get(hir_id) {
- let def_id = def.def_id();
- let substs = cx.tables.node_substs(hir_id);
- if method_call_refers_to_method(cx, method, def_id, substs, id) {
- return true;
- }
- } else {
- cx.tcx.sess.delay_span_bug(expr.span,
- "no type-dependent def for method call");
- }
- }
-
- // Check for calls to methods via explicit paths (e.g. `T::method()`).
- match expr.node {
- hir::ExprKind::Call(ref callee, _) => {
- let def = if let hir::ExprKind::Path(ref qpath) = callee.node {
- cx.tables.qpath_def(qpath, callee.hir_id)
- } else {
- return false;
- };
- match def {
- Def::Method(def_id) => {
- let substs = cx.tables.node_substs(callee.hir_id);
- method_call_refers_to_method(cx, method, def_id, substs, id)
- }
- _ => false,
- }
- }
- _ => false,
- }
- }
-
- // Check if the method call to the method with the ID `callee_id`
- // and instantiated with `callee_substs` refers to method `method`.
- fn method_call_refers_to_method<'a, 'tcx>(cx: &LateContext<'a, 'tcx>,
- method: &ty::AssociatedItem,
- callee_id: DefId,
- callee_substs: &Substs<'tcx>,
- expr_id: ast::NodeId)
- -> bool {
- let tcx = cx.tcx;
- let callee_item = tcx.associated_item(callee_id);
-
- match callee_item.container {
- // This is an inherent method, so the `def_id` refers
- // directly to the method definition.
- ty::ImplContainer(_) => callee_id == method.def_id,
-
- // A trait method, from any number of possible sources.
- // Attempt to select a concrete impl before checking.
- ty::TraitContainer(trait_def_id) => {
- let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, callee_substs);
- let trait_ref = ty::Binder::bind(trait_ref);
- let span = tcx.hir.span(expr_id);
- let obligation =
- traits::Obligation::new(traits::ObligationCause::misc(span, expr_id),
- cx.param_env,
- trait_ref.to_poly_trait_predicate());
-
- tcx.infer_ctxt().enter(|infcx| {
- let mut selcx = traits::SelectionContext::new(&infcx);
- match selcx.select(&obligation) {
- // The method comes from a `T: Trait` bound.
- // If `T` is `Self`, then this call is inside
- // a default method definition.
- Ok(Some(traits::VtableParam(_))) => {
- let on_self = trait_ref.self_ty().is_self();
- // We can only be recursing in a default
- // method if we're being called literally
- // on the `Self` type.
- on_self && callee_id == method.def_id
- }
-
- // The `impl` is known, so we check that with a
- // special case:
- Ok(Some(traits::VtableImpl(vtable_impl))) => {
- let container = ty::ImplContainer(vtable_impl.impl_def_id);
- // It matches if it comes from the same impl,
- // and has the same method name.
- container == method.container &&
- callee_item.ident.name == method.ident.name
- }
-
- // There's no way to know if this call is
- // recursive, so we assume it's not.
- _ => false,
- }
- })
- }
- }
- }
- }
-}
-
declare_lint! {
PLUGIN_AS_LIBRARY,
Warn,
MISSING_DEBUG_IMPLEMENTATIONS,
ANONYMOUS_PARAMETERS,
UNUSED_DOC_COMMENTS,
- UNCONDITIONAL_RECURSION,
PLUGIN_AS_LIBRARY,
NO_MANGLE_CONST_ITEMS,
NO_MANGLE_GENERIC_ITEMS,
UnusedAllocation: UnusedAllocation,
MissingCopyImplementations: MissingCopyImplementations,
UnstableFeatures: UnstableFeatures,
- UnconditionalRecursion: UnconditionalRecursion,
InvalidNoMangleItems: InvalidNoMangleItems,
PluginAsLibrary: PluginAsLibrary,
MutableTransmutes: MutableTransmutes,
parser::contains_exterior_struct_lit(&inner)
};
if !necessary {
- let pattern = pprust::expr_to_string(value);
- Self::remove_outer_parens(cx, value.span, &pattern, msg);
+ let expr_text = if let Ok(snippet) = cx.sess().source_map()
+ .span_to_snippet(value.span) {
+ snippet
+ } else {
+ pprust::expr_to_string(value)
+ };
+ Self::remove_outer_parens(cx, value.span, &expr_text, msg);
}
}
}
value: &ast::Pat,
msg: &str) {
if let ast::PatKind::Paren(_) = value.node {
- let pattern = pprust::pat_to_string(value);
- Self::remove_outer_parens(cx, value.span, &pattern, msg);
+ let pattern_text = if let Ok(snippet) = cx.sess().source_map()
+ .span_to_snippet(value.span) {
+ snippet
+ } else {
+ pprust::pat_to_string(value)
+ };
+ Self::remove_outer_parens(cx, value.span, &pattern_text, msg);
}
}
let $cdata = $tcx.crate_data_as_rc_any($def_id.krate);
let $cdata = $cdata.downcast_ref::<cstore::CrateMetadata>()
- .expect("CrateStore crated ata is not a CrateMetadata");
+ .expect("CrateStore created data is not a CrateMetadata");
$compute
})*
use rustc::traits::query::{Fallible, NoSolution};
use rustc::traits::{ObligationCause, PredicateObligations};
use rustc::ty::fold::TypeFoldable;
-use rustc::ty::subst::{Subst, Substs, UnpackedKind, UserSelfTy, UserSubsts};
+use rustc::ty::subst::{Subst, Substs, UnpackedKind};
use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
use std::rc::Rc;
use std::{fmt, iter};
locations: Locations,
category: ConstraintCategory,
) -> Fallible<()> {
- let tcx = self.tcx();
-
debug!(
- "relate_type_and_user_type(a={:?}, v={:?}, b={:?}, locations={:?})",
- a, v, user_ty, locations
+ "relate_type_and_user_type(a={:?}, v={:?}, user_ty={:?}, locations={:?})",
+ a, v, user_ty, locations,
);
- // The `TypeRelating` code assumes that "unresolved inference
- // variables" appear in the "a" side, so flip `Contravariant`
- // ambient variance to get the right relationship.
- let v1 = ty::Contravariant.xform(v);
-
match user_ty {
UserTypeAnnotation::Ty(canonical_ty) => {
let (ty, _) = self.infcx
.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty);
- self.relate_types(ty, v1, a, locations, category)?;
+ // The `TypeRelating` code assumes that "unresolved inference
+ // variables" appear in the "a" side, so flip `Contravariant`
+ // ambient variance to get the right relationship.
+ let v1 = ty::Contravariant.xform(v);
- self.prove_predicate(ty::Predicate::WellFormed(ty), locations, category);
+ self.relate_types(ty, v1, a, locations, category)?;
}
UserTypeAnnotation::TypeOf(def_id, canonical_substs) => {
let (
- UserSubsts {
- substs,
- user_self_ty,
- },
+ user_substs,
_,
) = self.infcx
.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs);
- let ty = self.tcx().type_of(def_id);
- let ty = ty.subst(tcx, substs);
- let ty = self.normalize(ty, locations);
-
- self.relate_types(ty, v1, a, locations, category)?;
-
- if let Some(UserSelfTy {
- impl_def_id,
- self_ty,
- }) = user_self_ty
- {
- let impl_self_ty = tcx.type_of(impl_def_id);
- let impl_self_ty = impl_self_ty.subst(tcx, &substs);
- let impl_self_ty = self.normalize(impl_self_ty, locations);
-
- // There may be type variables in `substs` and hence
- // in `impl_self_ty`, but they should all have been
- // resolved to some fixed value during the first call
- // to `relate`, above. Therefore, if we use
- // `resolve_type_vars_if_possible` we should get to
- // something without type variables. This is important
- // because the `b` type in `relate_with_variance`
- // below is not permitted to have inference variables.
- let impl_self_ty = self.infcx.resolve_type_vars_if_possible(&impl_self_ty);
- assert!(!impl_self_ty.has_infer_types());
-
- self.eq_types(self_ty, impl_self_ty, locations, category)?;
-
- self.prove_predicate(
- ty::Predicate::WellFormed(impl_self_ty),
- locations,
- category,
- );
- }
-
- // Prove the predicates coming along with `def_id`.
- //
- // Also, normalize the `instantiated_predicates`
- // because otherwise we wind up with duplicate "type
- // outlives" error messages.
- let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
- let instantiated_predicates = self.fold_to_region_vid(instantiated_predicates);
- self.normalize_and_prove_instantiated_predicates(
- instantiated_predicates,
+ self.fully_perform_op(
locations,
- );
-
- // In addition to proving the predicates, we have to
- // prove that `ty` is well-formed -- this is because
- // the WF of `ty` is predicated on the substs being
- // well-formed, and we haven't proven *that*. We don't
- // want to prove the WF of types from `substs` directly because they
- // haven't been normalized.
- //
- // FIXME(nmatsakis): Well, perhaps we should normalize
- // them? This would only be relevant if some input
- // type were ill-formed but did not appear in `ty`,
- // which...could happen with normalization...
- self.prove_predicate(ty::Predicate::WellFormed(ty), locations, category);
+ category,
+ self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
+ a, v, def_id, user_substs,
+ )),
+ )?;
}
}
Ok(())
}
- /// Replace all free regions in `value` with their NLL `RegionVid`
- /// equivalents; if not in NLL, does nothing. This is never
- /// particularly necessary -- we'll do it lazilly as we process
- /// the value anyway -- but in some specific cases it is useful to
- /// normalize so we can suppress duplicate error messages.
- fn fold_to_region_vid<T>(&self, value: T) -> T
- where
- T: TypeFoldable<'tcx>,
- {
- if let Some(borrowck_context) = &self.borrowck_context {
- self.tcx().fold_regions(&value, &mut false, |r, _debruijn| {
- if r.has_free_regions() {
- self.tcx().mk_region(ty::RegionKind::ReVar(
- borrowck_context.universal_regions.to_region_vid(r),
- ))
- } else {
- r
- }
- })
- } else {
- value
- }
- }
-
fn eq_opaque_type_and_type(
&mut self,
revealed_ty: Ty<'tcx>,
use transform::MirSource;
use util as mir_util;
+use super::lints;
+
/// Construct the MIR for a given def-id.
pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'tcx> {
let id = tcx.hir.as_local_node_id(def_id).unwrap();
mir_util::dump_mir(tcx, None, "mir_map", &0,
MirSource::item(def_id), &mir, |_, _| Ok(()) );
+ lints::check(tcx, &mir, def_id);
+
mir
})
}
assert!(alloc.bytes.len() as u64 - ptr.offset.bytes() >= op.layout.size.bytes());
let mut alloc = alloc.clone();
alloc.align = align;
- // FIXME shouldnt it be the case that `mark_static_initialized` has already
+ // FIXME shouldn't it be the case that `mark_static_initialized` has already
// interned this? I thought that is the entire point of that `FinishStatic` stuff?
let alloc = ecx.tcx.intern_const_alloc(alloc);
ConstValue::ByRef(ptr.alloc_id, alloc, ptr.offset)
Note that this approach needs a reference to S with lifetime `'a`.
Nothing shorter than `'a` will suffice: a shorter lifetime would imply
-that after `demo` finishes excuting, something else (such as the
+that after `demo` finishes executing, something else (such as the
destructor!) could access `s.data` after the end of that shorter
lifetime, which would again violate the `&mut`-borrow's exclusive
access.
}
}
-// Return a set of constructors equivalent to `all_ctors \ used_ctors`.
+// A request for missing constructor data in terms of either:
+// - whether or not there any missing constructors; or
+// - the actual set of missing constructors.
+#[derive(PartialEq)]
+enum MissingCtorsInfo {
+ Emptiness,
+ Ctors,
+}
+
+// Used by `compute_missing_ctors`.
+#[derive(Debug, PartialEq)]
+enum MissingCtors<'tcx> {
+ Empty,
+ NonEmpty,
+
+ // Note that the Vec can be empty.
+ Ctors(Vec<Constructor<'tcx>>),
+}
+
+// When `info` is `MissingCtorsInfo::Ctors`, compute a set of constructors
+// equivalent to `all_ctors \ used_ctors`. When `info` is
+// `MissingCtorsInfo::Emptiness`, just determines if that set is empty or not.
+// (The split logic gives a performance win, because we always need to know if
+// the set is empty, but we rarely need the full set, and it can be expensive
+// to compute the full set.)
fn compute_missing_ctors<'a, 'tcx: 'a>(
+ info: MissingCtorsInfo,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
all_ctors: &Vec<Constructor<'tcx>>,
used_ctors: &Vec<Constructor<'tcx>>,
-) -> Vec<Constructor<'tcx>> {
+) -> MissingCtors<'tcx> {
let mut missing_ctors = vec![];
for req_ctor in all_ctors {
// We add `refined_ctors` instead of `req_ctor`, because then we can
// provide more detailed error information about precisely which
// ranges have been omitted.
- missing_ctors.extend(refined_ctors);
+ if info == MissingCtorsInfo::Emptiness {
+ if !refined_ctors.is_empty() {
+ // The set is non-empty; return early.
+ return MissingCtors::NonEmpty;
+ }
+ } else {
+ missing_ctors.extend(refined_ctors);
+ }
}
- missing_ctors
+ if info == MissingCtorsInfo::Emptiness {
+ // If we reached here, the set is empty.
+ MissingCtors::Empty
+ } else {
+ MissingCtors::Ctors(missing_ctors)
+ }
}
/// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html
if let Some(constructors) = pat_constructors(cx, v[0], pcx) {
debug!("is_useful - expanding constructors: {:#?}", constructors);
split_grouped_constructors(cx.tcx, constructors, matrix, pcx.ty).into_iter().map(|c|
- is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
+ is_useful_specialized(cx, matrix, v, c, pcx.ty, witness)
).find(|result| result.is_useful()).unwrap_or(NotUseful)
} else {
debug!("is_useful - expanding wildcard");
// feature flag is not present, so this is only
// needed for that case.
- // Find those constructors that are not matched by any non-wildcard patterns in the
- // current column.
- let missing_ctors = compute_missing_ctors(cx.tcx, &all_ctors, &used_ctors);
+ // Missing constructors are those that are not matched by any
+ // non-wildcard patterns in the current column. We always determine if
+ // the set is empty, but we only fully construct them on-demand,
+ // because they're rarely used and can be big.
+ let cheap_missing_ctors =
+ compute_missing_ctors(MissingCtorsInfo::Emptiness, cx.tcx, &all_ctors, &used_ctors);
let is_privately_empty = all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
let is_declared_nonexhaustive = cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty);
- debug!("missing_ctors={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}",
- missing_ctors, is_privately_empty, is_declared_nonexhaustive);
+ debug!("cheap_missing_ctors={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}",
+ cheap_missing_ctors, is_privately_empty, is_declared_nonexhaustive);
// For privately empty and non-exhaustive enums, we work as if there were an "extra"
// `_` constructor for the type, so we can never match over all constructors.
let is_non_exhaustive = is_privately_empty || is_declared_nonexhaustive;
- if missing_ctors.is_empty() && !is_non_exhaustive {
+ if cheap_missing_ctors == MissingCtors::Empty && !is_non_exhaustive {
split_grouped_constructors(cx.tcx, all_ctors, matrix, pcx.ty).into_iter().map(|c| {
- is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
+ is_useful_specialized(cx, matrix, v, c, pcx.ty, witness)
}).find(|result| result.is_useful()).unwrap_or(NotUseful)
} else {
let matrix = rows.iter().filter_map(|r| {
witness
}).collect()
} else {
- pats.into_iter().flat_map(|witness| {
- missing_ctors.iter().map(move |ctor| {
- // Extends the witness with a "wild" version of this
- // constructor, that matches everything that can be built with
- // it. For example, if `ctor` is a `Constructor::Variant` for
- // `Option::Some`, this pushes the witness for `Some(_)`.
- witness.clone().push_wild_constructor(cx, ctor, pcx.ty)
- })
- }).collect()
+ let expensive_missing_ctors =
+ compute_missing_ctors(MissingCtorsInfo::Ctors, cx.tcx, &all_ctors,
+ &used_ctors);
+ if let MissingCtors::Ctors(missing_ctors) = expensive_missing_ctors {
+ pats.into_iter().flat_map(|witness| {
+ missing_ctors.iter().map(move |ctor| {
+ // Extends the witness with a "wild" version of this
+ // constructor, that matches everything that can be built with
+ // it. For example, if `ctor` is a `Constructor::Variant` for
+ // `Option::Some`, this pushes the witness for `Some(_)`.
+ witness.clone().push_wild_constructor(cx, ctor, pcx.ty)
+ })
+ }).collect()
+ } else {
+ bug!("cheap missing ctors")
+ }
};
UsefulWithWitness(new_witnesses)
}
)?;
}
} else {
- // Uh, that shouln't happen... the function did not intend to return
+ // Uh, that shouldn't happen... the function did not intend to return
return err!(Unreachable);
}
}
}
-// FIXME: Really we shouldnt clone memory, ever. Snapshot machinery should instad
+// FIXME: Really we shouldn't clone memory, ever. Snapshot machinery should instead
// carefully copy only the reachable parts.
impl<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>>
Clone for Memory<'a, 'mir, 'tcx, M>
}
/// It is the caller's responsibility to handle undefined and pointer bytes.
- /// However, this still checks that there are no relocations on the *egdes*.
+ /// However, this still checks that there are no relocations on the *edges*.
#[inline]
fn get_bytes_with_undef_and_ptr(
&self,
Ok(())
}
- /// Error if there are relocations overlapping with the egdes of the
+ /// Error if there are relocations overlapping with the edges of the
/// given memory range.
#[inline]
fn check_relocation_edges(&self, ptr: Pointer<M::PointerTag>, size: Size) -> EvalResult<'tcx> {
}
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
- /// Try reading a value in memory; this is interesting particularily for ScalarPair.
+ /// Try reading a value in memory; this is interesting particularly for ScalarPair.
/// Return None if the layout does not permit loading this as a value.
pub(super) fn try_read_value_from_mplace(
&self,
mplace: MPlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx, Option<Value<M::PointerTag>>> {
if mplace.layout.is_unsized() {
- // Dont touch unsized
+ // Don't touch unsized
return Ok(None);
}
let (ptr, ptr_align) = mplace.to_scalar_ptr_align();
// it is not used by the general miri engine, just by CTFE.
use std::hash::{Hash, Hasher};
-use std::mem;
-use rustc::ich::{StableHashingContext, StableHashingContextProvider};
+use rustc::ich::StableHashingContextProvider;
use rustc::mir;
use rustc::mir::interpret::{
AllocId, Pointer, Scalar,
use rustc::ty::layout::Align;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::indexed_vec::IndexVec;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use syntax::ast::Mutability;
use syntax::source_map::Span;
align -> *align, // just copy alignment verbatim
});
-// Can't use the macro here because that does not support named enum fields.
-impl<'a> HashStable<StableHashingContext<'a>> for Place {
- fn hash_stable<W: StableHasherResult>(
- &self, hcx: &mut StableHashingContext<'a>,
- hasher: &mut StableHasher<W>)
- {
- mem::discriminant(self).hash_stable(hcx, hasher);
- match self {
- Place::Ptr(mem_place) => mem_place.hash_stable(hcx, hasher),
-
- Place::Local { frame, local } => {
- frame.hash_stable(hcx, hasher);
- local.hash_stable(hcx, hasher);
- },
- }
- }
-}
+impl_stable_hash_for!(enum ::interpret::Place {
+ Ptr(mem_place),
+ Local { frame, local },
+});
impl<'a, Ctx> Snapshot<'a, Ctx> for Place
where Ctx: SnapshotContext<'a>,
{
}
}
-// Can't use the macro here because that does not support named enum fields.
-impl<'a> HashStable<StableHashingContext<'a>> for StackPopCleanup {
- fn hash_stable<W: StableHasherResult>(
- &self,
- hcx: &mut StableHashingContext<'a>,
- hasher: &mut StableHasher<W>)
- {
- mem::discriminant(self).hash_stable(hcx, hasher);
- match self {
- StackPopCleanup::Goto(ref block) => block.hash_stable(hcx, hasher),
- StackPopCleanup::None { cleanup } => cleanup.hash_stable(hcx, hasher),
- }
- }
-}
+impl_stable_hash_for!(enum ::interpret::eval_context::StackPopCleanup {
+ Goto(block),
+ None { cleanup },
+});
#[derive(Eq, PartialEq)]
struct FrameSnapshot<'a, 'tcx: 'a> {
stmt: usize,
}
-// Not using the macro because that does not support types depending on two lifetimes
-impl<'a, 'mir, 'tcx: 'mir> HashStable<StableHashingContext<'a>> for Frame<'mir, 'tcx> {
- fn hash_stable<W: StableHasherResult>(
- &self,
- hcx: &mut StableHashingContext<'a>,
- hasher: &mut StableHasher<W>) {
-
- let Frame {
- mir,
- instance,
- span,
- return_to_block,
- return_place,
- locals,
- block,
- stmt,
- } = self;
+impl_stable_hash_for!(impl<'tcx, 'mir: 'tcx> for struct Frame<'mir, 'tcx> {
+ mir,
+ instance,
+ span,
+ return_to_block,
+ return_place -> (return_place.as_ref().map(|r| &**r)),
+ locals,
+ block,
+ stmt,
+});
- (mir, instance, span, return_to_block).hash_stable(hcx, hasher);
- (return_place.as_ref().map(|r| &**r), locals, block, stmt).hash_stable(hcx, hasher);
- }
-}
impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx>
where Ctx: SnapshotContext<'a>,
{
}
}
-// Not using the macro because we need special handling for `memory`, which the macro
-// does not support at the same time as the extra bounds on the type.
-impl<'a, 'b, 'mir, 'tcx> HashStable<StableHashingContext<'b>>
- for EvalSnapshot<'a, 'mir, 'tcx>
-{
- fn hash_stable<W: StableHasherResult>(
- &self,
- hcx: &mut StableHashingContext<'b>,
- hasher: &mut StableHasher<W>)
- {
- // Not hashing memory: Avoid hashing memory all the time during execution
- let EvalSnapshot{ memory: _, stack } = self;
- stack.hash_stable(hcx, hasher);
- }
-}
+impl_stable_hash_for!(impl<'tcx, 'b, 'mir> for struct EvalSnapshot<'b, 'mir, 'tcx> {
+ // Not hashing memory: Avoid hashing memory all the time during execution
+ memory -> _,
+ stack,
+});
impl<'a, 'mir, 'tcx> Eq for EvalSnapshot<'a, 'mir, 'tcx>
{}
),
}
}
- // non-ZST also have to be dereferencable
+ // non-ZST also have to be dereferenceable
if size != Size::ZERO {
let ptr = try_validation!(place.ptr.to_ptr(),
"integer pointer in non-ZST reference", path);
// FIXME: Check if the signature matches
}
// This should be all the primitive types
- ty::Never => bug!("Uninhabited type should have been catched earlier"),
+ ty::Never => bug!("Uninhabited type should have been caught earlier"),
_ => bug!("Unexpected primitive type {}", value.layout.ty)
}
Ok(())
mod build;
mod dataflow;
mod hair;
+mod lints;
mod shim;
pub mod transform;
pub mod util;
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc_data_structures::bit_set::BitSet;
+use rustc::hir::def_id::DefId;
+use rustc::hir::intravisit::FnKind;
+use rustc::hir::map::blocks::FnLikeNode;
+use rustc::lint::builtin::UNCONDITIONAL_RECURSION;
+use rustc::mir::{self, Mir, TerminatorKind};
+use rustc::ty::{AssociatedItem, AssociatedItemContainer, Instance, TyCtxt, TyKind};
+use rustc::ty::subst::Substs;
+
+pub fn check(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ mir: &Mir<'tcx>,
+ def_id: DefId) {
+ let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+
+ if let Some(fn_like_node) = FnLikeNode::from_node(tcx.hir.get(node_id)) {
+ check_fn_for_unconditional_recursion(tcx, fn_like_node.kind(), mir, def_id);
+ }
+}
+
+fn check_fn_for_unconditional_recursion(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ fn_kind: FnKind,
+ mir: &Mir<'tcx>,
+ def_id: DefId) {
+ if let FnKind::Closure(_) = fn_kind {
+ // closures can't recur, so they don't matter.
+ return;
+ }
+
+ //FIXME(#54444) rewrite this lint to use the dataflow framework
+
+ // Walk through this function (say `f`) looking to see if
+ // every possible path references itself, i.e. the function is
+ // called recursively unconditionally. This is done by trying
+ // to find a path from the entry node to the exit node that
+ // *doesn't* call `f` by traversing from the entry while
+ // pretending that calls of `f` are sinks (i.e. ignoring any
+ // exit edges from them).
+ //
+ // NB. this has an edge case with non-returning statements,
+ // like `loop {}` or `panic!()`: control flow never reaches
+ // the exit node through these, so one can have a function
+ // that never actually calls itself but is still picked up by
+ // this lint:
+ //
+ // fn f(cond: bool) {
+ // if !cond { panic!() } // could come from `assert!(cond)`
+ // f(false)
+ // }
+ //
+ // In general, functions of that form may be able to call
+ // itself a finite number of times and then diverge. The lint
+ // considers this to be an error for two reasons, (a) it is
+ // easier to implement, and (b) it seems rare to actually want
+ // to have behaviour like the above, rather than
+ // e.g. accidentally recursing after an assert.
+
+ let basic_blocks = mir.basic_blocks();
+ let mut reachable_without_self_call_queue = vec![mir::START_BLOCK];
+ let mut reached_exit_without_self_call = false;
+ let mut self_call_locations = vec![];
+ let mut visited = BitSet::new_empty(basic_blocks.len());
+
+ let param_env = tcx.param_env(def_id);
+ let trait_substs_count =
+ match tcx.opt_associated_item(def_id) {
+ Some(AssociatedItem {
+ container: AssociatedItemContainer::TraitContainer(trait_def_id),
+ ..
+ }) => tcx.generics_of(trait_def_id).count(),
+ _ => 0
+ };
+ let caller_substs = &Substs::identity_for_item(tcx, def_id)[..trait_substs_count];
+
+ while let Some(bb) = reachable_without_self_call_queue.pop() {
+ if visited.contains(bb) {
+ //already done
+ continue;
+ }
+
+ visited.insert(bb);
+
+ let block = &basic_blocks[bb];
+
+ if let Some(ref terminator) = block.terminator {
+ match terminator.kind {
+ TerminatorKind::Call { ref func, .. } => {
+ let func_ty = func.ty(mir, tcx);
+
+ if let TyKind::FnDef(fn_def_id, substs) = func_ty.sty {
+ let (call_fn_id, call_substs) =
+ if let Some(instance) = Instance::resolve(tcx,
+ param_env,
+ fn_def_id,
+ substs) {
+ (instance.def_id(), instance.substs)
+ } else {
+ (fn_def_id, substs)
+ };
+
+ let is_self_call =
+ call_fn_id == def_id &&
+ &call_substs[..caller_substs.len()] == caller_substs;
+
+ if is_self_call {
+ self_call_locations.push(terminator.source_info);
+
+ //this is a self call so we shouldn't explore
+ //further down this path
+ continue;
+ }
+ }
+ },
+ TerminatorKind::Abort | TerminatorKind::Return => {
+ //found a path!
+ reached_exit_without_self_call = true;
+ break;
+ }
+ _ => {}
+ }
+
+ for successor in terminator.successors() {
+ reachable_without_self_call_queue.push(*successor);
+ }
+ }
+ }
+
+ // Check the number of self calls because a function that
+ // doesn't return (e.g. calls a `-> !` function or `loop { /*
+ // no break */ }`) shouldn't be linted unless it actually
+ // recurs.
+ if !reached_exit_without_self_call && !self_call_locations.is_empty() {
+ let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+ let sp = tcx.sess.source_map().def_span(tcx.hir.span(node_id));
+ let mut db = tcx.struct_span_lint_node(UNCONDITIONAL_RECURSION,
+ node_id,
+ sp,
+ "function cannot return without recursing");
+ db.span_label(sp, "cannot return without recursing");
+ // offer some help to the programmer.
+ for location in &self_call_locations {
+ db.span_label(location.span, "recursive call site");
+ }
+ db.help("a `loop` may express intention better if this is on purpose");
+ db.emit();
+ }
+}
let operand = Operand::Copy(promoted_place(ty, span));
mem::replace(&mut args[index], operand)
}
+ // We expected a `TerminatorKind::Call` for which we'd like to promote an
+ // argument. `qualify_consts` saw a `TerminatorKind::Call` here, but
+ // we are seeing a `Goto`. That means that the `promote_temps` method
+ // already promoted this call away entirely. This case occurs when calling
+ // a function requiring a constant argument and as that constant value
+ // providing a value whose computation contains another call to a function
+ // requiring a constant argument.
+ TerminatorKind::Goto { .. } => return,
_ => bug!()
}
}
let fn_ty = func.ty(self.mir, self.tcx);
let mut callee_def_id = None;
- let (mut is_shuffle, mut is_const_fn) = (false, false);
+ let mut is_shuffle = false;
+ let mut is_const_fn = false;
+ let mut is_promotable_const_fn = false;
if let ty::FnDef(def_id, _) = fn_ty.sty {
callee_def_id = Some(def_id);
match self.tcx.fn_sig(def_id).abi() {
// functions without #[rustc_promotable]
if self.tcx.is_promotable_const_fn(def_id) {
is_const_fn = true;
+ is_promotable_const_fn = true;
+ } else if self.tcx.is_const_fn(def_id) {
+ is_const_fn = true;
}
} else {
// stable const fn or unstable const fns with their feature gate
if !constant_arguments.contains(&i) {
return
}
- if this.qualif.is_empty() {
+ // Since the argument is required to be constant,
+ // we care about constness, not promotability.
+ // If we checked for promotability, we'd miss out on
+ // the results of function calls (which are never promoted
+ // in runtime code)
+ // This is not a problem, because the argument explicitly
+ // requests constness, in contrast to regular promotion
+ // which happens even without the user requesting it.
+ // We can error out with a hard error if the argument is not
+ // constant here.
+ if (this.qualif - Qualif::NOT_PROMOTABLE).is_empty() {
this.promotion_candidates.push(candidate);
} else {
this.tcx.sess.span_err(this.span,
// Be conservative about the returned value of a const fn.
let tcx = self.tcx;
let ty = dest.ty(self.mir, tcx).to_ty(tcx);
- self.qualif = Qualif::empty();
+ if is_const_fn && !is_promotable_const_fn && self.mode == Mode::Fn {
+ self.qualif = Qualif::NOT_PROMOTABLE;
+ } else {
+ self.qualif = Qualif::empty();
+ }
self.add_type(ty);
}
self.assign(dest, location);
}
}
- /// With eRFC 2497, we need to check whether an expression is ambigious and warn or error
+ /// With eRFC 2497, we need to check whether an expression is ambiguous and warn or error
/// depending on the edition, this function handles that.
fn while_if_let_ambiguity(&self, expr: &P<Expr>) {
if let Some((span, op_kind)) = self.while_if_let_expr_ambiguity(&expr) {
let mut err = self.err_handler().struct_span_err(
- span, &format!("ambigious use of `{}`", op_kind.to_string())
+ span, &format!("ambiguous use of `{}`", op_kind.to_string())
);
err.note(
}
/// With eRFC 2497 adding if-let chains, there is a requirement that the parsing of
- /// `&&` and `||` in a if-let statement be unambigious. This function returns a span and
- /// a `BinOpKind` (either `&&` or `||` depending on what was ambigious) if it is determined
- /// that the current expression parsed is ambigious and will break in future.
+ /// `&&` and `||` in a if-let statement be unambiguous. This function returns a span and
+ /// a `BinOpKind` (either `&&` or `||` depending on what was ambiguous) if it is determined
+ /// that the current expression parsed is ambiguous and will break in future.
fn while_if_let_expr_ambiguity(&self, expr: &P<Expr>) -> Option<(Span, BinOpKind)> {
debug!("while_if_let_expr_ambiguity: expr.node: {:?}", expr.node);
match &expr.node {
Some((expr.span, op.node))
},
ExprKind::Range(ref lhs, ref rhs, _) => {
- let lhs_ambigious = lhs.as_ref()
+ let lhs_ambiguous = lhs.as_ref()
.and_then(|lhs| self.while_if_let_expr_ambiguity(lhs));
- let rhs_ambigious = rhs.as_ref()
+ let rhs_ambiguous = rhs.as_ref()
.and_then(|rhs| self.while_if_let_expr_ambiguity(rhs));
- lhs_ambigious.or(rhs_ambigious)
+ lhs_ambiguous.or(rhs_ambiguous)
}
_ => None,
}
use macros::{InvocationData, ParentScope, LegacyScope};
use resolve_imports::ImportDirective;
use resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport};
-use {Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, ToNameBinding};
-use {ModuleOrUniformRoot, PerNS, Resolver, ResolverArenas};
+use {Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding};
+use {ModuleOrUniformRoot, PerNS, Resolver, ResolverArenas, ExternPreludeEntry};
use Namespace::{self, TypeNS, ValueNS, MacroNS};
use {resolve_error, resolve_struct_error, ResolutionError};
use rustc_metadata::cstore::LoadedMacro;
use std::cell::Cell;
+use std::ptr;
use rustc_data_structures::sync::Lrc;
use syntax::ast::{Name, Ident};
use_tree: &ast::UseTree,
id: NodeId,
vis: ty::Visibility,
- parent_prefix: &[Ident],
+ parent_prefix: &[Segment],
mut uniform_paths_canary_emitted: bool,
nested: bool,
item: &Item,
self.session.features_untracked().uniform_paths;
let prefix_iter = || parent_prefix.iter().cloned()
- .chain(use_tree.prefix.segments.iter().map(|seg| seg.ident));
+ .chain(use_tree.prefix.segments.iter().map(|seg| seg.into()));
let prefix_start = prefix_iter().next();
- let starts_with_non_keyword = prefix_start.map_or(false, |ident| {
- !ident.is_path_segment_keyword()
+ let starts_with_non_keyword = prefix_start.map_or(false, |seg| {
+ !seg.ident.is_path_segment_keyword()
});
// Imports are resolved as global by default, prepend `CrateRoot`,
};
let root = if inject_crate_root {
let span = use_tree.prefix.span.shrink_to_lo();
- Some(Ident::new(keywords::CrateRoot.name(), span))
+ Some(Segment::from_ident(Ident::new(keywords::CrateRoot.name(), span)))
} else {
None
};
let source = prefix_start.unwrap();
// Helper closure to emit a canary with the given base path.
- let emit = |this: &mut Self, base: Option<Ident>| {
+ let emit = |this: &mut Self, base: Option<Segment>| {
let subclass = SingleImport {
target: Ident {
name: keywords::Underscore.name().gensymed(),
- span: source.span,
+ span: source.ident.span,
},
- source,
+ source: source.ident,
result: PerNS {
type_ns: Cell::new(Err(Undetermined)),
value_ns: Cell::new(Err(Undetermined)),
this.add_import_directive(
base.into_iter().collect(),
subclass.clone(),
- source.span,
+ source.ident.span,
id,
root_use_tree.span,
root_id,
};
// A single simple `self::x` canary.
- emit(self, Some(Ident {
- name: keywords::SelfValue.name(),
- span: source.span,
+ emit(self, Some(Segment {
+ ident: Ident {
+ name: keywords::SelfValue.name(),
+ span: source.ident.span,
+ },
+ id: source.id
}));
// One special unprefixed canary per block scope around
// the import, to detect items unreachable by `self::x`.
let orig_current_module = self.current_module;
- let mut span = source.span.modern();
+ let mut span = source.ident.span.modern();
loop {
match self.current_module.kind {
ModuleKind::Block(..) => emit(self, None),
if nested {
// Correctly handle `self`
- if source.name == keywords::SelfValue.name() {
+ if source.ident.name == keywords::SelfValue.name() {
type_ns_only = true;
- let empty_prefix = module_path.last().map_or(true, |ident| {
- ident.name == keywords::CrateRoot.name()
+ let empty_prefix = module_path.last().map_or(true, |seg| {
+ seg.ident.name == keywords::CrateRoot.name()
});
if empty_prefix {
resolve_error(
// Replace `use foo::self;` with `use foo;`
source = module_path.pop().unwrap();
if rename.is_none() {
- ident = source;
+ ident = source.ident;
}
}
} else {
// Disallow `self`
- if source.name == keywords::SelfValue.name() {
+ if source.ident.name == keywords::SelfValue.name() {
resolve_error(self,
use_tree.span,
ResolutionError::SelfImportsOnlyAllowedWithin);
}
// Disallow `use $crate;`
- if source.name == keywords::DollarCrate.name() && module_path.is_empty() {
- let crate_root = self.resolve_crate_root(source);
+ if source.ident.name == keywords::DollarCrate.name() && module_path.is_empty() {
+ let crate_root = self.resolve_crate_root(source.ident);
let crate_name = match crate_root.kind {
ModuleKind::Def(_, name) => name,
ModuleKind::Block(..) => unreachable!(),
// while the current crate doesn't have a valid `crate_name`.
if crate_name != keywords::Invalid.name() {
// `crate_name` should not be interpreted as relative.
- module_path.push(Ident {
- name: keywords::CrateRoot.name(),
- span: source.span,
+ module_path.push(Segment {
+ ident: Ident {
+ name: keywords::CrateRoot.name(),
+ span: source.ident.span,
+ },
+ id: Some(self.session.next_node_id()),
});
- source.name = crate_name;
+ source.ident.name = crate_name;
}
if rename.is_none() {
ident.name = crate_name;
let subclass = SingleImport {
target: ident,
- source,
+ source: source.ident,
result: PerNS {
type_ns: Cell::new(Err(Undetermined)),
value_ns: Cell::new(Err(Undetermined)),
let module =
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
self.populate_module_if_necessary(module);
- if injected_crate_name().map_or(false, |name| item.ident.name == name) {
+ if injected_crate_name().map_or(false, |name| ident.name == name) {
self.injected_crate = Some(module);
}
let used = self.process_legacy_macro_imports(item, module, expansion);
let binding =
(module, ty::Visibility::Public, sp, expansion).to_name_binding(self.arenas);
+ if ptr::eq(self.current_module, self.graph_root) {
+ if let Some(entry) = self.extern_prelude.get(&ident.modern()) {
+ if expansion != Mark::root() && orig_name.is_some() &&
+ entry.extern_crate_item.is_none() {
+ self.session.span_err(item.span, "macro-expanded `extern crate` items \
+ cannot shadow names passed with \
+ `--extern`");
+ }
+ }
+ let entry = self.extern_prelude.entry(ident.modern())
+ .or_insert(ExternPreludeEntry {
+ extern_crate_item: None,
+ introduced_by_item: true,
+ });
+ entry.extern_crate_item = Some(binding);
+ if orig_name.is_some() {
+ entry.introduced_by_item = true;
+ }
+ }
let directive = self.arenas.alloc_import_directive(ImportDirective {
root_id: item.id,
id: item.id,
ItemKind::GlobalAsm(..) => {}
- ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root
+ ItemKind::Mod(..) if ident == keywords::Invalid.ident() => {} // Crate root
ItemKind::Mod(..) => {
let def_id = self.definitions.local_def_id(item.id);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use {CrateLint, PathResult};
+use {CrateLint, PathResult, Segment};
use std::collections::BTreeSet;
pub(crate) fn make_path_suggestion(
&mut self,
span: Span,
- path: Vec<Ident>
- ) -> Option<Vec<Ident>> {
+ path: Vec<Segment>
+ ) -> Option<Vec<Segment>> {
debug!("make_path_suggestion: span={:?} path={:?}", span, path);
// If we don't have a path to suggest changes to, then return.
if path.is_empty() {
match (path.get(0), path.get(1)) {
// Make suggestions that require at least two non-special path segments.
- (Some(fst), Some(snd)) if !is_special(*fst) && !is_special(*snd) => {
+ (Some(fst), Some(snd)) if !is_special(fst.ident) && !is_special(snd.ident) => {
debug!("make_path_suggestion: fst={:?} snd={:?}", fst, snd);
self.make_missing_self_suggestion(span, path.clone())
.or_else(|| self.make_missing_crate_suggestion(span, path.clone()))
.or_else(|| self.make_missing_super_suggestion(span, path.clone()))
- .or_else(|| self.make_external_crate_suggestion(span, path.clone()))
+ .or_else(|| self.make_external_crate_suggestion(span, path))
},
_ => None,
}
fn make_missing_self_suggestion(
&mut self,
span: Span,
- mut path: Vec<Ident>
- ) -> Option<Vec<Ident>> {
+ mut path: Vec<Segment>
+ ) -> Option<Vec<Segment>> {
// Replace first ident with `self` and check if that is valid.
- path[0].name = keywords::SelfValue.name();
+ path[0].ident.name = keywords::SelfValue.name();
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
if let PathResult::Module(..) = result {
fn make_missing_crate_suggestion(
&mut self,
span: Span,
- mut path: Vec<Ident>
- ) -> Option<Vec<Ident>> {
+ mut path: Vec<Segment>
+ ) -> Option<Vec<Segment>> {
// Replace first ident with `crate` and check if that is valid.
- path[0].name = keywords::Crate.name();
+ path[0].ident.name = keywords::Crate.name();
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result);
if let PathResult::Module(..) = result {
fn make_missing_super_suggestion(
&mut self,
span: Span,
- mut path: Vec<Ident>
- ) -> Option<Vec<Ident>> {
+ mut path: Vec<Segment>
+ ) -> Option<Vec<Segment>> {
// Replace first ident with `crate` and check if that is valid.
- path[0].name = keywords::Super.name();
+ path[0].ident.name = keywords::Super.name();
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result);
if let PathResult::Module(..) = result {
fn make_external_crate_suggestion(
&mut self,
span: Span,
- mut path: Vec<Ident>
- ) -> Option<Vec<Ident>> {
+ mut path: Vec<Segment>
+ ) -> Option<Vec<Segment>> {
// Need to clone else we can't call `resolve_path` without a borrow error. We also store
// into a `BTreeMap` so we can get consistent ordering (and therefore the same diagnostic)
// each time.
let external_crate_names: BTreeSet<Symbol> = self.resolver.extern_prelude
- .clone().drain().collect();
+ .iter().map(|(ident, _)| ident.name).collect();
// Insert a new path segment that we can replace.
let new_path_segment = path[0].clone();
// Iterate in reverse so that we start with crates at the end of the alphabet. This means
// that we'll always get `std` before `core`.
for name in external_crate_names.iter().rev() {
- let ident = Ident::with_empty_ctxt(*name);
- // Calling `maybe_process_path_extern` ensures that we're only running `resolve_path`
- // on a crate name that won't ICE.
- if let Some(_) = self.crate_loader.maybe_process_path_extern(*name, ident.span) {
- // Replace the first after root (a placeholder we inserted) with a crate name
- // and check if that is valid.
- path[1].name = *name;
- let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
- debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
- name, path, result);
- if let PathResult::Module(..) = result {
- return Some(path)
- }
+ // Replace the first after root (a placeholder we inserted) with a crate name
+ // and check if that is valid.
+ path[1].ident.name = *name;
+ let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
+ debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
+ name, path, result);
+ if let PathResult::Module(..) = result {
+ return Some(path)
}
}
- // Remove our placeholder segment.
- path.remove(1);
None
}
}
use syntax::ext::base::SyntaxExtension;
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
use syntax::ext::base::MacroKind;
+use syntax::feature_gate::{emit_feature_err, GateIssue};
use syntax::symbol::{Symbol, keywords};
use syntax::util::lev_distance::find_best_match_for_name;
}
}
+// A minimal representation of a path segment. We use this in resolve because
+// we synthesize 'path segments' which don't have the rest of an AST or HIR
+// PathSegment.
+#[derive(Clone, Copy, Debug)]
+pub struct Segment {
+ ident: Ident,
+ id: Option<NodeId>,
+}
+
+impl Segment {
+ fn from_path(path: &Path) -> Vec<Segment> {
+ path.segments.iter().map(|s| s.into()).collect()
+ }
+
+ fn from_ident(ident: Ident) -> Segment {
+ Segment {
+ ident,
+ id: None,
+ }
+ }
+
+ fn names_to_string(segments: &[Segment]) -> String {
+ names_to_string(&segments.iter()
+ .map(|seg| seg.ident)
+ .collect::<Vec<_>>())
+ }
+}
+
+impl<'a> From<&'a ast::PathSegment> for Segment {
+ fn from(seg: &'a ast::PathSegment) -> Segment {
+ Segment {
+ ident: seg.ident,
+ id: Some(seg.id),
+ }
+ }
+}
+
struct UsePlacementFinder {
target_module: NodeId,
span: Option<Span>,
}
}
+#[derive(Default, Clone)]
+pub struct ExternPreludeEntry<'a> {
+ extern_crate_item: Option<&'a NameBinding<'a>>,
+ pub introduced_by_item: bool,
+}
+
/// The main resolver class.
///
/// This is the visitor that walks the whole crate.
graph_root: Module<'a>,
prelude: Option<Module<'a>>,
- pub extern_prelude: FxHashSet<Name>,
+ pub extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'a>>,
/// n.b. This is used only for better diagnostics, not name resolution itself.
has_self: FxHashSet<DefId>,
/// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that
/// the resolver is no longer needed as all the relevant information is inline.
impl<'a, 'cl> hir::lowering::Resolver for Resolver<'a, 'cl> {
- fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool) {
+ fn resolve_hir_path(
+ &mut self,
+ path: &ast::Path,
+ is_value: bool,
+ ) -> hir::Path {
self.resolve_hir_path_cb(path, is_value,
|resolver, span, error| resolve_error(resolver, span, error))
}
span: Span,
crate_root: Option<&str>,
components: &[&str],
- args: Option<P<hir::GenericArgs>>,
is_value: bool
) -> hir::Path {
- let mut segments = iter::once(keywords::CrateRoot.ident())
+ let segments = iter::once(keywords::CrateRoot.ident())
.chain(
crate_root.into_iter()
.chain(components.iter().cloned())
.map(Ident::from_str)
- ).map(hir::PathSegment::from_ident).collect::<Vec<_>>();
+ ).map(|i| self.new_ast_path_segment(i)).collect::<Vec<_>>();
- if let Some(args) = args {
- let ident = segments.last().unwrap().ident;
- *segments.last_mut().unwrap() = hir::PathSegment {
- ident,
- args: Some(args),
- infer_types: true,
- };
- }
- let mut path = hir::Path {
+ let path = ast::Path {
span,
- def: Def::Err,
- segments: segments.into(),
+ segments,
};
- self.resolve_hir_path(&mut path, is_value);
- path
+ self.resolve_hir_path(&path, is_value)
}
fn get_resolution(&mut self, id: NodeId) -> Option<PathResolution> {
use std::iter;
let mut errored = false;
- let mut path = if path_str.starts_with("::") {
- hir::Path {
+ let path = if path_str.starts_with("::") {
+ ast::Path {
span,
- def: Def::Err,
- segments: iter::once(keywords::CrateRoot.ident()).chain({
- path_str.split("::").skip(1).map(Ident::from_str)
- }).map(hir::PathSegment::from_ident).collect(),
+ segments: iter::once(keywords::CrateRoot.ident())
+ .chain({
+ path_str.split("::").skip(1).map(Ident::from_str)
+ })
+ .map(|i| self.new_ast_path_segment(i))
+ .collect(),
}
} else {
- hir::Path {
+ ast::Path {
span,
- def: Def::Err,
- segments: path_str.split("::").map(Ident::from_str)
- .map(hir::PathSegment::from_ident).collect(),
+ segments: path_str
+ .split("::")
+ .map(Ident::from_str)
+ .map(|i| self.new_ast_path_segment(i))
+ .collect(),
}
};
- self.resolve_hir_path_cb(&mut path, is_value, |_, _, _| errored = true);
+ let path = self.resolve_hir_path_cb(&path, is_value, |_, _, _| errored = true);
if errored || path.def == Def::Err {
Err(())
} else {
}
/// resolve_hir_path, but takes a callback in case there was an error
- fn resolve_hir_path_cb<F>(&mut self, path: &mut hir::Path, is_value: bool, error_callback: F)
+ fn resolve_hir_path_cb<F>(
+ &mut self,
+ path: &ast::Path,
+ is_value: bool,
+ error_callback: F,
+ ) -> hir::Path
where F: for<'c, 'b> FnOnce(&'c mut Resolver, Span, ResolutionError<'b>)
{
let namespace = if is_value { ValueNS } else { TypeNS };
- let hir::Path { ref segments, span, ref mut def } = *path;
- let path: Vec<_> = segments.iter().map(|seg| seg.ident).collect();
+ let span = path.span;
+ let segments = &path.segments;
+ let path = Segment::from_path(&path);
// FIXME (Manishearth): Intra doc links won't get warned of epoch changes
- match self.resolve_path(None, &path, Some(namespace), true, span, CrateLint::No) {
+ let def = match self.resolve_path(None, &path, Some(namespace), true, span, CrateLint::No) {
PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
- *def = module.def().unwrap(),
+ module.def().unwrap(),
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 =>
- *def = path_res.base_def(),
- PathResult::NonModule(..) =>
+ path_res.base_def(),
+ PathResult::NonModule(..) => {
if let PathResult::Failed(span, msg, _) = self.resolve_path(
None,
&path,
CrateLint::No,
) {
error_callback(self, span, ResolutionError::FailedToResolve(&msg));
- },
+ }
+ Def::Err
+ }
PathResult::Module(ModuleOrUniformRoot::UniformRoot(_)) |
PathResult::Indeterminate => unreachable!(),
PathResult::Failed(span, msg, _) => {
error_callback(self, span, ResolutionError::FailedToResolve(&msg));
+ Def::Err
}
+ };
+
+ let segments: Vec<_> = segments.iter().map(|seg| {
+ let mut hir_seg = hir::PathSegment::from_ident(seg.ident);
+ hir_seg.def = Some(self.def_map.get(&seg.id).map_or(Def::Err, |p| p.base_def()));
+ hir_seg
+ }).collect();
+ hir::Path {
+ span,
+ def,
+ segments: segments.into(),
}
}
+
+ fn new_ast_path_segment(&self, ident: Ident) -> ast::PathSegment {
+ let mut seg = ast::PathSegment::from_ident(ident);
+ seg.id = self.session.next_node_id();
+ seg
+ }
}
impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
DefCollector::new(&mut definitions, Mark::root())
.collect_root(crate_name, session.local_crate_disambiguator());
- let mut extern_prelude: FxHashSet<Name> =
- session.opts.externs.iter().map(|kv| Symbol::intern(kv.0)).collect();
+ let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry> =
+ session.opts.externs.iter().map(|kv| (Ident::from_str(kv.0), Default::default()))
+ .collect();
if !attr::contains_name(&krate.attrs, "no_core") {
- extern_prelude.insert(Symbol::intern("core"));
+ extern_prelude.insert(Ident::from_str("core"), Default::default());
if !attr::contains_name(&krate.attrs, "no_std") {
- extern_prelude.insert(Symbol::intern("std"));
+ extern_prelude.insert(Ident::from_str("std"), Default::default());
if session.rust_2018() {
- extern_prelude.insert(Symbol::intern("meta"));
+ extern_prelude.insert(Ident::from_str("meta"), Default::default());
}
}
}
}
if !module.no_implicit_prelude {
- if ns == TypeNS && self.extern_prelude.contains(&ident.name) {
- let crate_id = if record_used {
- self.crate_loader.process_path_extern(ident.name, ident.span)
- } else if let Some(crate_id) =
- self.crate_loader.maybe_process_path_extern(ident.name, ident.span) {
- crate_id
- } else {
- return None;
- };
- let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
- self.populate_module_if_necessary(&crate_root);
-
- let binding = (crate_root, ty::Visibility::Public,
- ident.span, Mark::root()).to_name_binding(self.arenas);
- return Some(LexicalScopeBinding::Item(binding));
+ if ns == TypeNS {
+ if let Some(binding) = self.extern_prelude_get(ident, !record_used, false) {
+ return Some(LexicalScopeBinding::Item(binding));
+ }
}
if ns == TypeNS && is_known_tool(ident.name) {
let binding = (Def::ToolMod, ty::Visibility::Public,
let mut new_val = None;
let mut new_id = None;
if let Some(trait_ref) = opt_trait_ref {
- let path: Vec<_> = trait_ref.path.segments.iter()
- .map(|seg| seg.ident)
- .collect();
+ let path: Vec<_> = Segment::from_path(&trait_ref.path);
let def = self.smart_resolve_path_fragment(
trait_ref.ref_id,
None,
source: PathSource,
crate_lint: CrateLint
) -> PathResolution {
- let segments = &path.segments.iter()
- .map(|seg| seg.ident)
- .collect::<Vec<_>>();
- self.smart_resolve_path_fragment(id, qself, segments, path.span, source, crate_lint)
+ self.smart_resolve_path_fragment(
+ id,
+ qself,
+ &Segment::from_path(path),
+ path.span,
+ source,
+ crate_lint,
+ )
}
fn smart_resolve_path_fragment(&mut self,
id: NodeId,
qself: Option<&QSelf>,
- path: &[Ident],
+ path: &[Segment],
span: Span,
source: PathSource,
crate_lint: CrateLint)
-> PathResolution {
- let ident_span = path.last().map_or(span, |ident| ident.span);
+ let ident_span = path.last().map_or(span, |ident| ident.ident.span);
let ns = source.namespace();
let is_expected = &|def| source.is_expected(def);
let is_enum_variant = &|def| if let Def::Variant(..) = def { true } else { false };
let report_errors = |this: &mut Self, def: Option<Def>| {
// Make the base error.
let expected = source.descr_expected();
- let path_str = names_to_string(path);
- let item_str = path.last().unwrap();
+ let path_str = Segment::names_to_string(path);
+ let item_str = path.last().unwrap().ident;
let code = source.error_code(def.is_some());
let (base_msg, fallback_label, base_span) = if let Some(def) = def {
(format!("expected {}, found {} `{}`", expected, def.kind_name(), path_str),
format!("not a {}", expected),
span)
} else {
- let item_span = path.last().unwrap().span;
+ let item_span = path.last().unwrap().ident.span;
let (mod_prefix, mod_str) = if path.len() == 1 {
(String::new(), "this scope".to_string())
- } else if path.len() == 2 && path[0].name == keywords::CrateRoot.name() {
+ } else if path.len() == 2 && path[0].ident.name == keywords::CrateRoot.name() {
(String::new(), "the crate root".to_string())
} else {
let mod_path = &path[..path.len() - 1];
module.def(),
_ => None,
}.map_or(String::new(), |def| format!("{} ", def.kind_name()));
- (mod_prefix, format!("`{}`", names_to_string(mod_path)))
+ (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)))
};
(format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
format!("not found in {}", mod_str),
// Emit help message for fake-self from other languages like `this`(javascript)
if ["this", "my"].contains(&&*item_str.as_str())
- && this.self_value_is_available(path[0].span, span) {
+ && this.self_value_is_available(path[0].ident.span, span) {
err.span_suggestion_with_applicability(
span,
"did you mean",
}
// Try to lookup the name in more relaxed fashion for better error reporting.
- let ident = *path.last().unwrap();
+ let ident = path.last().unwrap().ident;
let candidates = this.lookup_import_candidates(ident.name, ns, is_expected);
if candidates.is_empty() && is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) {
let enum_candidates =
}
if path.len() == 1 && this.self_type_is_available(span) {
if let Some(candidate) = this.lookup_assoc_candidate(ident, ns, is_expected) {
- let self_is_available = this.self_value_is_available(path[0].span, span);
+ let self_is_available = this.self_value_is_available(path[0].ident.span, span);
match candidate {
AssocSuggestion::Field => {
err.span_suggestion_with_applicability(
// or `<T>::A::B`. If `B` should be resolved in value namespace then
// it needs to be added to the trait map.
if ns == ValueNS {
- let item_name = *path.last().unwrap();
+ let item_name = path.last().unwrap().ident;
let traits = self.get_traits_containing_item(item_name, ns);
self.trait_map.insert(id, traits);
}
fn resolve_qpath_anywhere(&mut self,
id: NodeId,
qself: Option<&QSelf>,
- path: &[Ident],
+ path: &[Segment],
primary_ns: Namespace,
span: Span,
defer_to_typeck: bool,
}
}
if primary_ns != MacroNS &&
- (self.macro_names.contains(&path[0].modern()) ||
- self.builtin_macros.get(&path[0].name).cloned()
+ (self.macro_names.contains(&path[0].ident.modern()) ||
+ self.builtin_macros.get(&path[0].ident.name).cloned()
.and_then(NameBinding::macro_kind) == Some(MacroKind::Bang) ||
- self.macro_use_prelude.get(&path[0].name).cloned()
+ self.macro_use_prelude.get(&path[0].ident.name).cloned()
.and_then(NameBinding::macro_kind) == Some(MacroKind::Bang)) {
// Return some dummy definition, it's enough for error reporting.
return Some(
fn resolve_qpath(&mut self,
id: NodeId,
qself: Option<&QSelf>,
- path: &[Ident],
+ path: &[Segment],
ns: Namespace,
span: Span,
global_by_default: bool,
PathResult::Failed(..)
if (ns == TypeNS || path.len() > 1) &&
self.primitive_type_table.primitive_types
- .contains_key(&path[0].name) => {
- let prim = self.primitive_type_table.primitive_types[&path[0].name];
+ .contains_key(&path[0].ident.name) => {
+ let prim = self.primitive_type_table.primitive_types[&path[0].ident.name];
PathResolution::with_unresolved_segments(Def::PrimTy(prim), path.len() - 1)
}
PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
};
if path.len() > 1 && !global_by_default && result.base_def() != Def::Err &&
- path[0].name != keywords::CrateRoot.name() &&
- path[0].name != keywords::DollarCrate.name() {
+ path[0].ident.name != keywords::CrateRoot.name() &&
+ path[0].ident.name != keywords::DollarCrate.name() {
let unqualified_result = {
match self.resolve_path(
None,
fn resolve_path(
&mut self,
base_module: Option<ModuleOrUniformRoot<'a>>,
- path: &[Ident],
+ path: &[Segment],
opt_ns: Option<Namespace>, // `None` indicates a module path
record_used: bool,
path_span: Span,
fn resolve_path_with_parent_scope(
&mut self,
base_module: Option<ModuleOrUniformRoot<'a>>,
- path: &[Ident],
+ path: &[Segment],
opt_ns: Option<Namespace>, // `None` indicates a module path
parent_scope: &ParentScope<'a>,
record_used: bool,
crate_lint,
);
- for (i, &ident) in path.iter().enumerate() {
+ for (i, &Segment { ident, id }) in path.iter().enumerate() {
debug!("resolve_path ident {} {:?}", i, ident);
+
let is_last = i == path.len() - 1;
let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
let name = ident.name;
} else {
format!("`{}`", name)
};
- let msg = if i == 1 && path[0].name == keywords::CrateRoot.name() {
+ let msg = if i == 1 && path[0].ident.name == keywords::CrateRoot.name() {
format!("global paths cannot start with {}", name_str)
} else {
format!("{} in paths can only be used in start position", name_str)
let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(def);
if let Some(next_module) = binding.module() {
module = Some(ModuleOrUniformRoot::Module(next_module));
+ if record_used {
+ if let Some(id) = id {
+ if !self.def_map.contains_key(&id) {
+ assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id");
+ self.record_def(id, PathResolution::new(def));
+ }
+ }
+ }
} else if def == Def::ToolMod && i + 1 != path.len() {
let def = Def::NonMacroAttr(NonMacroAttrKind::Tool);
return PathResult::NonModule(PathResolution::new(def));
} else if i == 0 {
format!("Use of undeclared type or module `{}`", ident)
} else {
- format!("Could not find `{}` in `{}`", ident, path[i - 1])
+ format!("Could not find `{}` in `{}`", ident, path[i - 1].ident)
};
return PathResult::Failed(ident.span, msg, is_last);
}
fn lint_if_path_starts_with_module(
&self,
crate_lint: CrateLint,
- path: &[Ident],
+ path: &[Segment],
path_span: Span,
second_binding: Option<&NameBinding>,
) {
};
let first_name = match path.get(0) {
- Some(ident) => ident.name,
+ Some(ident) => ident.ident.name,
None => return,
};
match path.get(1) {
// If this import looks like `crate::...` it's already good
- Some(ident) if ident.name == keywords::Crate.name() => return,
+ Some(Segment { ident, .. }) if ident.name == keywords::Crate.name() => return,
// Otherwise go below to see if it's an extern crate
Some(_) => {}
// If the path has length one (and it's `CrateRoot` most likely)
}
fn lookup_typo_candidate<FilterFn>(&mut self,
- path: &[Ident],
+ path: &[Segment],
ns: Namespace,
filter_fn: FilterFn,
span: Span)
} else {
// Items from the prelude
if !module.no_implicit_prelude {
- names.extend(self.extern_prelude.iter().cloned());
+ names.extend(self.extern_prelude.iter().map(|(ident, _)| ident.name));
if let Some(prelude) = self.prelude {
add_module_candidates(prelude, &mut names);
}
}
}
- let name = path[path.len() - 1].name;
+ let name = path[path.len() - 1].ident.name;
// Make sure error reporting is deterministic.
names.sort_by_cached_key(|name| name.as_str());
match find_best_match_for_name(names.iter(), &name.as_str(), None) {
if self.session.rust_2018() {
let extern_prelude_names = self.extern_prelude.clone();
- for &name in extern_prelude_names.iter() {
- let ident = Ident::with_empty_ctxt(name);
- if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(name,
- ident.span)
- {
+ for (ident, _) in extern_prelude_names.into_iter() {
+ if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name,
+ ident.span) {
let crate_root = self.get_module(DefId {
krate: crate_id,
index: CRATE_DEF_INDEX,
ast::VisibilityKind::Restricted { ref path, id, .. } => {
// Visibilities are resolved as global by default, add starting root segment.
let segments = path.make_root().iter().chain(path.segments.iter())
- .map(|seg| seg.ident)
+ .map(|seg| Segment { ident: seg.ident, id: Some(seg.id) })
.collect::<Vec<_>>();
let def = self.smart_resolve_path_fragment(
id,
err.emit();
self.name_already_seen.insert(name, span);
}
+
+ fn extern_prelude_get(&mut self, ident: Ident, speculative: bool, skip_feature_gate: bool)
+ -> Option<&'a NameBinding<'a>> {
+ self.extern_prelude.get(&ident.modern()).cloned().and_then(|entry| {
+ if let Some(binding) = entry.extern_crate_item {
+ if !speculative && !skip_feature_gate && entry.introduced_by_item &&
+ !self.session.features_untracked().extern_crate_item_prelude {
+ emit_feature_err(&self.session.parse_sess, "extern_crate_item_prelude",
+ ident.span, GateIssue::Language,
+ "use of extern prelude names introduced \
+ with `extern crate` items is unstable");
+ }
+ Some(binding)
+ } else {
+ let crate_id = if !speculative {
+ self.crate_loader.process_path_extern(ident.name, ident.span)
+ } else if let Some(crate_id) =
+ self.crate_loader.maybe_process_path_extern(ident.name, ident.span) {
+ crate_id
+ } else {
+ return None;
+ };
+ let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
+ self.populate_module_if_necessary(&crate_root);
+ Some((crate_root, ty::Visibility::Public, ident.span, Mark::root())
+ .to_name_binding(self.arenas))
+ }
+ })
+ }
}
-fn is_self_type(path: &[Ident], namespace: Namespace) -> bool {
- namespace == TypeNS && path.len() == 1 && path[0].name == keywords::SelfType.name()
+fn is_self_type(path: &[Segment], namespace: Namespace) -> bool {
+ namespace == TypeNS && path.len() == 1 && path[0].ident.name == keywords::SelfType.name()
}
-fn is_self_value(path: &[Ident], namespace: Namespace) -> bool {
- namespace == ValueNS && path.len() == 1 && path[0].name == keywords::SelfValue.name()
+fn is_self_value(path: &[Segment], namespace: Namespace) -> bool {
+ namespace == ValueNS && path.len() == 1 && path[0].ident.name == keywords::SelfValue.name()
}
fn names_to_string(idents: &[Ident]) -> String {
// except according to those terms.
use {AmbiguityError, CrateLint, Resolver, ResolutionError, is_known_tool, resolve_error};
-use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, ToNameBinding};
+use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, Segment, ToNameBinding};
use ModuleOrUniformRoot;
use Namespace::{self, *};
use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
parent_scope: &ParentScope<'a>,
force: bool,
) -> Result<Def, Determinacy> {
- let ast::Path { ref segments, span } = *path;
- let mut path: Vec<_> = segments.iter().map(|seg| seg.ident).collect();
+ let span = path.span;
+ let mut path = Segment::from_path(path);
// Possibly apply the macro helper hack
if kind == MacroKind::Bang && path.len() == 1 &&
- path[0].span.ctxt().outer().expn_info().map_or(false, |info| info.local_inner_macros) {
- let root = Ident::new(keywords::DollarCrate.name(), path[0].span);
- path.insert(0, root);
+ path[0].ident.span.ctxt().outer().expn_info()
+ .map_or(false, |info| info.local_inner_macros) {
+ let root = Ident::new(keywords::DollarCrate.name(), path[0].ident.span);
+ path.insert(0, Segment::from_ident(root));
}
if path.len() > 1 {
};
parent_scope.module.macro_resolutions.borrow_mut()
- .push((path.into_boxed_slice(), span));
+ .push((path
+ .iter()
+ .map(|seg| seg.ident)
+ .collect::<Vec<Ident>>()
+ .into_boxed_slice(), span));
def
} else {
let binding = self.early_resolve_ident_in_lexical_scope(
- path[0], MacroNS, Some(kind), parent_scope, false, force, span
+ path[0].ident, MacroNS, Some(kind), parent_scope, false, force, span
);
match binding {
Ok(..) => {}
}
parent_scope.module.legacy_macro_resolutions.borrow_mut()
- .push((path[0], kind, parent_scope.clone(), binding.ok()));
+ .push((path[0].ident, kind, parent_scope.clone(), binding.ok()));
binding.map(|binding| binding.def_ignoring_ambiguity())
}
}
}
WhereToResolve::ExternPrelude => {
- if use_prelude && self.extern_prelude.contains(&ident.name) {
- let crate_id =
- self.crate_loader.process_path_extern(ident.name, ident.span);
- let crate_root =
- self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
- self.populate_module_if_necessary(crate_root);
-
- let binding = (crate_root, ty::Visibility::Public,
- ident.span, Mark::root()).to_name_binding(self.arenas);
- Ok((binding, Flags::PRELUDE, Flags::empty()))
- } else {
- Err(Determinacy::Determined)
+ let mut result = Err(Determinacy::Determined);
+ if use_prelude {
+ if let Some(binding) = self.extern_prelude_get(ident, !record_used,
+ innermost_result.is_some()) {
+ result = Ok((binding, Flags::PRELUDE, Flags::empty()));
+ }
}
+ result
}
WhereToResolve::ToolPrelude => {
if use_prelude && is_known_tool(ident.name) {
pub fn finalize_current_module_macro_resolutions(&mut self) {
let module = self.current_module;
for &(ref path, span) in module.macro_resolutions.borrow().iter() {
+ let path: Vec<_> = path.iter().map(|&ident| Segment::from_ident(ident)).collect();
match self.resolve_path(None, &path, Some(MacroNS), true, span, CrateLint::No) {
PathResult::NonModule(_) => {},
PathResult::Failed(span, msg, _) => {
}
};
let ident = Ident::new(Symbol::intern(name), span);
- self.lookup_typo_candidate(&[ident], MacroNS, is_macro, span)
+ self.lookup_typo_candidate(&[Segment::from_ident(ident)], MacroNS, is_macro, span)
});
if let Some(suggestion) = suggestion {
use {AmbiguityError, CrateLint, Module, ModuleOrUniformRoot, PerNS};
use Namespace::{self, TypeNS, MacroNS};
use {NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError};
-use Resolver;
+use {Resolver, Segment};
use {names_to_string, module_to_string};
use {resolve_error, ResolutionError};
use rustc::ty;
use rustc::lint::builtin::BuiltinLintDiagnostics;
use rustc::lint::builtin::{DUPLICATE_MACRO_EXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE};
-use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
+use rustc::hir::def_id::DefId;
use rustc::hir::def::*;
use rustc::session::DiagnosticMessageId;
use rustc::util::nodemap::FxHashSet;
pub root_span: Span,
pub parent: Module<'a>,
- pub module_path: Vec<Ident>,
+ pub module_path: Vec<Segment>,
/// The resolution of `module_path`.
pub imported_module: Cell<Option<ModuleOrUniformRoot<'a>>>,
pub subclass: ImportDirectiveSubclass<'a>,
if !(
ns == TypeNS &&
!ident.is_path_segment_keyword() &&
- self.extern_prelude.contains(&ident.name)
+ self.extern_prelude.contains_key(&ident.modern())
) {
// ... unless the crate name is not in the `extern_prelude`.
return binding;
self.resolve_crate_root(ident)
} else if
ns == TypeNS &&
- !ident.is_path_segment_keyword() &&
- self.extern_prelude.contains(&ident.name)
+ !ident.is_path_segment_keyword()
{
- let crate_id =
- self.crate_loader.process_path_extern(ident.name, ident.span);
- self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
+ if let Some(binding) = self.extern_prelude_get(ident, !record_used, false) {
+ let module = self.get_module(binding.def().def_id());
+ self.populate_module_if_necessary(module);
+ return Ok(binding);
+ } else {
+ return Err(Determined);
+ }
} else {
return Err(Determined);
};
// Add an import directive to the current module.
pub fn add_import_directive(&mut self,
- module_path: Vec<Ident>,
+ module_path: Vec<Segment>,
subclass: ImportDirectiveSubclass<'a>,
span: Span,
id: NodeId,
let has_explicit_self =
!import.module_path.is_empty() &&
- import.module_path[0].name == keywords::SelfValue.name();
+ import.module_path[0].ident.name == keywords::SelfValue.name();
self.per_ns(|_, ns| {
if let Some(result) = result[ns].get().ok() {
self.throw_unresolved_import_error(empty_vec, None);
}
if !seen_spans.contains(&span) {
- let path = import_path_to_string(&import.module_path[..],
- &import.subclass,
- span);
+ let path = import_path_to_string(
+ &import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
+ &import.subclass,
+ span,
+ );
error_vec.push((span, path, err));
seen_spans.insert(span);
prev_root_id = import.root_id;
let uniform_paths_feature = self.session.features_untracked().uniform_paths;
for ((span, _, ns), results) in uniform_paths_canaries {
let name = results.name;
- let external_crate = if ns == TypeNS && self.extern_prelude.contains(&name) {
- let crate_id =
- self.crate_loader.process_path_extern(name, span);
- Some(Def::Mod(DefId { krate: crate_id, index: CRATE_DEF_INDEX }))
+ let external_crate = if ns == TypeNS {
+ self.extern_prelude_get(Ident::with_empty_ctxt(name), true, false)
+ .map(|binding| binding.def())
} else {
None
};
/// If successful, the resolved bindings are written into the module.
fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
debug!("(resolving import for module) resolving import `{}::...` in `{}`",
- names_to_string(&directive.module_path[..]),
+ Segment::names_to_string(&directive.module_path[..]),
module_to_string(self.current_module).unwrap_or_else(|| "???".to_string()));
+
self.current_module = directive.parent;
let module = if let Some(module) = directive.imported_module.get() {
) {
Some((
span,
- format!("Did you mean `{}`?", names_to_string(&suggested_path[..]))
+ format!("Did you mean `{}`?", Segment::names_to_string(&suggested_path))
))
} else {
Some((span, msg))
// HACK(eddyb) `lint_if_path_starts_with_module` needs at least
// 2 segments, so the `resolve_path` above won't trigger it.
let mut full_path = module_path.clone();
- full_path.push(keywords::Invalid.ident());
+ full_path.push(Segment::from_ident(keywords::Invalid.ident()));
self.lint_if_path_starts_with_module(
directive.crate_lint(),
&full_path,
Some(this.dummy_binding);
}
}
+ if record_used && ns == TypeNS {
+ if let ModuleOrUniformRoot::UniformRoot(..) = module {
+ // Make sure single-segment import is resolved non-speculatively
+ // at least once to report the feature error.
+ this.extern_prelude_get(ident, false, false);
+ }
+ }
}
});
// HACK(eddyb) `lint_if_path_starts_with_module` needs at least
// 2 segments, so the `resolve_path` above won't trigger it.
let mut full_path = module_path.clone();
- full_path.push(ident);
+ full_path.push(Segment::from_ident(ident));
self.per_ns(|this, ns| {
if let Ok(binding) = result[ns].get() {
this.lint_if_path_starts_with_module(
let resolutions = imported_module.parent.expect("parent should exist")
.resolutions.borrow();
let enum_path_segment_index = directive.module_path.len() - 1;
- let enum_ident = directive.module_path[enum_path_segment_index];
+ let enum_ident = directive.module_path[enum_path_segment_index].ident;
let enum_resolution = resolutions.get(&(enum_ident, TypeNS))
.expect("resolution should exist");
use syntax::ast::{self, Attribute, NodeId, PatKind, CRATE_NODE_ID};
use syntax::parse::token;
-use syntax::symbol::keywords;
use syntax::visit::{self, Visitor};
use syntax::print::pprust::{
bounds_to_string,
generic_params_to_string,
- path_to_string,
ty_to_string
};
use syntax::ptr::P;
self.dumper.compilation_opts(data);
}
- // Return all non-empty prefixes of a path.
- // For each prefix, we return the span for the last segment in the prefix and
- // a str representation of the entire prefix.
- fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> {
- let segments = &path.segments[if path.is_global() { 1 } else { 0 }..];
-
- let mut result = Vec::with_capacity(segments.len());
- let mut segs = Vec::with_capacity(segments.len());
-
- for (i, seg) in segments.iter().enumerate() {
- segs.push(seg.clone());
- let sub_path = ast::Path {
- span: seg.ident.span, // span for the last segment
- segments: segs,
- };
- let qualname = if i == 0 && path.is_global() {
- format!("::{}", path_to_string(&sub_path))
- } else {
- path_to_string(&sub_path)
- };
- result.push((seg.ident.span, qualname));
- segs = sub_path.segments;
- }
-
- result
- }
-
fn write_sub_paths(&mut self, path: &ast::Path) {
- let sub_paths = self.process_path_prefixes(path);
- for (span, _) in sub_paths {
- let span = self.span_from_span(span);
- self.dumper.dump_ref(Ref {
- kind: RefKind::Mod,
- span,
- ref_id: ::null_id(),
- });
+ for seg in &path.segments {
+ if let Some(data) = self.save_ctxt.get_path_segment_data(seg) {
+ self.dumper.dump_ref(data);
+ }
}
}
// As write_sub_paths, but does not process the last ident in the path (assuming it
// will be processed elsewhere). See note on write_sub_paths about global.
fn write_sub_paths_truncated(&mut self, path: &ast::Path) {
- let sub_paths = self.process_path_prefixes(path);
- let len = sub_paths.len();
- if len <= 1 {
- return;
- }
-
- for (span, _) in sub_paths.into_iter().take(len - 1) {
- let span = self.span_from_span(span);
- self.dumper.dump_ref(Ref {
- kind: RefKind::Mod,
- span,
- ref_id: ::null_id(),
- });
- }
- }
-
- // As write_sub_paths, but expects a path of the form module_path::trait::method
- // Where trait could actually be a struct too.
- fn write_sub_path_trait_truncated(&mut self, path: &ast::Path) {
- let sub_paths = self.process_path_prefixes(path);
- let len = sub_paths.len();
- if len <= 1 {
- return;
- }
- let sub_paths = &sub_paths[..(len - 1)];
-
- // write the trait part of the sub-path
- let (ref span, _) = sub_paths[len - 2];
- let span = self.span_from_span(*span);
- self.dumper.dump_ref(Ref {
- kind: RefKind::Type,
- ref_id: ::null_id(),
- span,
- });
-
- // write the other sub-paths
- if len <= 2 {
- return;
- }
- let sub_paths = &sub_paths[..len - 2];
- for &(ref span, _) in sub_paths {
- let span = self.span_from_span(*span);
- self.dumper.dump_ref(Ref {
- kind: RefKind::Mod,
- span,
- ref_id: ::null_id(),
- });
+ for seg in &path.segments[..path.segments.len() - 1] {
+ if let Some(data) = self.save_ctxt.get_path_segment_data(seg) {
+ self.dumper.dump_ref(data);
+ }
}
}
self.visit_pat(&arg.pat);
let mut collector = PathCollector::new();
collector.visit_pat(&arg.pat);
- let span_utils = self.span.clone();
for (id, ident, ..) in collector.collected_idents {
let hir_id = self.tcx.hir.node_to_hir_id(id);
Some(s) => s.to_string(),
None => continue,
};
- let sub_span = span_utils.span_for_last_ident(ident.span);
- if !self.span.filter_generated(sub_span, ident.span) {
+ if !self.span.filter_generated(ident.span) {
let id = ::id_from_node_id(id, &self.save_ctxt);
- let span = self.span_from_span(sub_span.expect("No span found for variable"));
+ let span = self.span_from_span(ident.span);
self.dumper.dump_def(
&Access {
) {
debug!("process_method: {}:{}", id, ident);
- if let Some(mut method_data) = self.save_ctxt.get_method_data(id, ident.name, span) {
+ if let Some(mut method_data) = self.save_ctxt.get_method_data(id, ident, span) {
let sig_str = ::make_signature(&sig.decl, &generics);
if body.is_some() {
self.nest_tables(
);
}
- self.process_generic_params(&generics, span, &method_data.qualname, id);
+ self.process_generic_params(&generics, &method_data.qualname, id);
method_data.value = sig_str;
method_data.sig = sig::method_signature(id, ident, generics, sig, &self.save_ctxt);
fn process_generic_params(
&mut self,
generics: &'l ast::Generics,
- full_span: Span,
prefix: &str,
id: NodeId,
) {
let name = escape(self.span.snippet(param_ss));
// Append $id to name to make sure each one is unique.
let qualname = format!("{}::{}${}", prefix, name, id);
- if !self.span.filter_generated(Some(param_ss), full_span) {
+ if !self.span.filter_generated(param_ss) {
let id = ::id_from_node_id(param.id, &self.save_ctxt);
let span = self.span_from_span(param_ss);
item.id,
|v| v.process_formals(&decl.inputs, &fn_data.qualname),
);
- self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id);
+ self.process_generic_params(ty_params, &fn_data.qualname, item.id);
self.dumper.dump_def(&access_from!(self.save_ctxt, item), fn_data);
}
fn process_assoc_const(
&mut self,
id: ast::NodeId,
- name: ast::Name,
- span: Span,
+ ident: ast::Ident,
typ: &'l ast::Ty,
expr: Option<&'l ast::Expr>,
parent_id: DefId,
) {
let qualname = format!("::{}", self.tcx.node_path_str(id));
- let sub_span = self.span.sub_span_after_keyword(span, keywords::Const);
-
- if !self.span.filter_generated(sub_span, span) {
- let sig = sig::assoc_const_signature(id, name, typ, expr, &self.save_ctxt);
- let span = self.span_from_span(sub_span.expect("No span found for variable"));
+ if !self.span.filter_generated(ident.span) {
+ let sig = sig::assoc_const_signature(id, ident.name, typ, expr, &self.save_ctxt);
+ let span = self.span_from_span(ident.span);
self.dumper.dump_def(
&access_from!(self.save_ctxt, vis, id),
kind: DefKind::Const,
id: ::id_from_node_id(id, &self.save_ctxt),
span,
- name: name.to_string(),
+ name: ident.name.to_string(),
qualname,
value: ty_to_string(&typ),
parent: Some(::id_from_def_id(parent_id)),
let name = item.ident.to_string();
let qualname = format!("::{}", self.tcx.node_path_str(item.id));
- let (kind, keyword) = match item.node {
- ast::ItemKind::Struct(_, _) => (DefKind::Struct, keywords::Struct),
- ast::ItemKind::Union(_, _) => (DefKind::Union, keywords::Union),
+ let kind = match item.node {
+ ast::ItemKind::Struct(_, _) => DefKind::Struct,
+ ast::ItemKind::Union(_, _) => DefKind::Union,
_ => unreachable!(),
};
- let sub_span = self.span.sub_span_after_keyword(item.span, keyword);
let (value, fields) = match item.node {
ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) |
ast::ItemKind::Union(ast::VariantData::Struct(ref fields, _), _) => {
_ => (String::new(), vec![]),
};
- if !self.span.filter_generated(sub_span, item.span) {
- let span = self.span_from_span(sub_span.expect("No span found for struct"));
+ if !self.span.filter_generated(item.ident.span) {
+ let span = self.span_from_span(item.ident.span);
self.dumper.dump_def(
&access_from!(self.save_ctxt, item),
Def {
self.visit_ty(&field.ty);
}
- self.process_generic_params(ty_params, item.span, &qualname, item.id);
+ self.process_generic_params(ty_params, &qualname, item.id);
}
fn process_enum(
for variant in &enum_definition.variants {
let name = variant.node.ident.name.to_string();
let qualname = format!("{}::{}", enum_data.qualname, name);
+ let name_span = variant.node.ident.span;
match variant.node.data {
ast::VariantData::Struct(ref fields, _) => {
- let sub_span = self.span.span_for_first_ident(variant.span);
let fields_str = fields
.iter()
.enumerate()
.collect::<Vec<_>>()
.join(", ");
let value = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str);
- if !self.span.filter_generated(sub_span, variant.span) {
- let span = self
- .span_from_span(sub_span.expect("No span found for struct variant"));
+ if !self.span.filter_generated(name_span) {
+ let span = self.span_from_span(name_span);
let id = ::id_from_node_id(variant.node.data.id(), &self.save_ctxt);
let parent = Some(::id_from_node_id(item.id, &self.save_ctxt));
}
}
ref v => {
- let sub_span = self.span.span_for_first_ident(variant.span);
let mut value = format!("{}::{}", enum_data.name, name);
if let &ast::VariantData::Tuple(ref fields, _) = v {
value.push('(');
.join(", "));
value.push(')');
}
- if !self.span.filter_generated(sub_span, variant.span) {
- let span =
- self.span_from_span(sub_span.expect("No span found for tuple variant"));
+ if !self.span.filter_generated(name_span) {
+ let span = self.span_from_span(name_span);
let id = ::id_from_node_id(variant.node.data.id(), &self.save_ctxt);
let parent = Some(::id_from_node_id(item.id, &self.save_ctxt));
self.visit_ty(&field.ty);
}
}
- self.process_generic_params(ty_params, item.span, &enum_data.qualname, item.id);
+ self.process_generic_params(ty_params, &enum_data.qualname, item.id);
self.dumper.dump_def(&access, enum_data);
}
if let &Some(ref trait_ref) = trait_ref {
self.process_path(trait_ref.ref_id, &trait_ref.path);
}
- self.process_generic_params(type_parameters, item.span, "", item.id);
+ self.process_generic_params(type_parameters, "", item.id);
for impl_item in impl_items {
let map = &self.tcx.hir;
self.process_impl_item(impl_item, map.local_def_id(item.id));
val.push_str(": ");
val.push_str(&bounds_to_string(trait_refs));
}
- let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait);
- if !self.span.filter_generated(sub_span, item.span) {
+ if !self.span.filter_generated(item.ident.span) {
let id = ::id_from_node_id(item.id, &self.save_ctxt);
- let span = self.span_from_span(sub_span.expect("No span found for trait"));
+ let span = self.span_from_span(item.ident.span);
let children = methods
.iter()
.map(|i| ::id_from_node_id(i.id, &self.save_ctxt))
let trait_ref = &trait_ref.trait_ref;
if let Some(id) = self.lookup_def_id(trait_ref.ref_id) {
- let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
- if !self.span.filter_generated(sub_span, trait_ref.path.span) {
- let span = self.span_from_span(sub_span.expect("No span found for trait ref"));
+ let sub_span = trait_ref.path.segments.last().unwrap().ident.span;
+ if !self.span.filter_generated(sub_span) {
+ let span = self.span_from_span(sub_span);
self.dumper.dump_ref(Ref {
kind: RefKind::Type,
- span,
+ span: span.clone(),
ref_id: ::id_from_def_id(id),
});
- }
- if !self.span.filter_generated(sub_span, trait_ref.path.span) {
- let sub_span = self.span_from_span(sub_span.expect("No span for inheritance"));
self.dumper.dump_relation(Relation {
kind: RelationKind::SuperTrait,
- span: sub_span,
+ span,
from: ::id_from_def_id(id),
to: ::id_from_node_id(item.id, &self.save_ctxt),
});
}
// walk generics and methods
- self.process_generic_params(generics, item.span, &qualname, item.id);
+ self.process_generic_params(generics, &qualname, item.id);
for method in methods {
let map = &self.tcx.hir;
self.process_trait_item(method, map.local_def_id(item.id))
}
}
- // Modules or types in the path prefix.
- match self.save_ctxt.get_path_def(id) {
- HirDef::Method(did) => {
- let ti = self.tcx.associated_item(did);
- if ti.kind == ty::AssociatedKind::Method && ti.method_has_self_argument {
- self.write_sub_path_trait_truncated(path);
- }
- }
- HirDef::Fn(..) |
- HirDef::Const(..) |
- HirDef::Static(..) |
- HirDef::StructCtor(..) |
- HirDef::VariantCtor(..) |
- HirDef::AssociatedConst(..) |
- HirDef::Local(..) |
- HirDef::Upvar(..) |
- HirDef::Struct(..) |
- HirDef::Union(..) |
- HirDef::Variant(..) |
- HirDef::TyAlias(..) |
- HirDef::AssociatedTy(..) => self.write_sub_paths_truncated(path),
- _ => {}
- }
+ self.write_sub_paths_truncated(path);
}
fn process_struct_lit(
variant: &'l ty::VariantDef,
base: &'l Option<P<ast::Expr>>,
) {
- self.write_sub_paths_truncated(path);
-
if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) {
+ self.write_sub_paths_truncated(path);
down_cast_data!(struct_lit_data, RefData, ex.span);
if !generated_code(ex.span) {
self.dumper.dump_ref(struct_lit_data);
};
let variant = adt.variant_of_def(self.save_ctxt.get_path_def(p.id));
- for &Spanned { node: ref field, span } in fields {
- let sub_span = self.span.span_for_first_ident(span);
+ for &Spanned { node: ref field, .. } in fields {
if let Some(index) = self.tcx.find_field_index(field.ident, variant) {
- if !self.span.filter_generated(sub_span, span) {
- let span =
- self.span_from_span(sub_span.expect("No span fund for var ref"));
+ if !self.span.filter_generated(field.ident.span) {
+ let span = self.span_from_span(field.ident.span);
self.dumper.dump_ref(Ref {
kind: RefKind::Variable,
span,
value.push_str(": ");
value.push_str(&typ);
- if !self.span.filter_generated(Some(ident.span), ident.span) {
+ if !self.span.filter_generated(ident.span) {
let qualname = format!("{}${}", ident.to_string(), id);
let id = ::id_from_node_id(id, &self.save_ctxt);
let span = self.span_from_span(ident.span);
None => String::new(),
};
- // Get the span only for the name of the variable (I hope the path
- // is only ever a variable name, but who knows?).
- let sub_span = self.span.span_for_last_ident(ident.span);
// Rust uses the id of the pattern for var lookups, so we'll use it too.
- if !self.span.filter_generated(sub_span, ident.span) {
+ if !self.span.filter_generated(ident.span) {
let qualname = format!("{}${}", ident.to_string(), id);
let id = ::id_from_node_id(id, &self.save_ctxt);
- let span = self.span_from_span(sub_span.expect("No span found for variable"));
+ let span = self.span_from_span(ident.span);
self.dumper.dump_def(
&Access {
ast::TraitItemKind::Const(ref ty, ref expr) => {
self.process_assoc_const(
trait_item.id,
- trait_item.ident.name,
- trait_item.span,
+ trait_item.ident,
&ty,
expr.as_ref().map(|e| &**e),
trait_id,
// FIXME do something with _bounds (for type refs)
let name = trait_item.ident.name.to_string();
let qualname = format!("::{}", self.tcx.node_path_str(trait_item.id));
- let sub_span = self.span
- .sub_span_after_keyword(trait_item.span, keywords::Type);
- if !self.span.filter_generated(sub_span, trait_item.span) {
- let span = self.span_from_span(sub_span.expect("No span found for assoc type"));
+ if !self.span.filter_generated(trait_item.ident.span) {
+ let span = self.span_from_span(trait_item.ident.span);
let id = ::id_from_node_id(trait_item.id, &self.save_ctxt);
self.dumper.dump_def(
ast::ImplItemKind::Const(ref ty, ref expr) => {
self.process_assoc_const(
impl_item.id,
- impl_item.ident.name,
- impl_item.span,
+ impl_item.ident,
&ty,
Some(expr),
impl_id,
.map(::id_from_def_id);
match use_tree.kind {
- ast::UseTreeKind::Simple(..) => {
+ ast::UseTreeKind::Simple(alias, ..) => {
let ident = use_tree.ident();
let path = ast::Path {
segments: prefix.segments
span: path.span,
};
- let sub_span = self.span.span_for_last_ident(path.span);
- let alias_span = self.span.sub_span_after_keyword(use_tree.span, keywords::As);
- let ref_id = self.lookup_def_id(id);
-
- if !self.span.filter_generated(sub_span, path.span) {
- let span = self.span_from_span(sub_span.expect("No span found for use"));
- let alias_span = alias_span.map(|sp| self.span_from_span(sp));
+ let sub_span = path.segments.last().unwrap().ident.span;
+ if !self.span.filter_generated(sub_span) {
+ let ref_id = self.lookup_def_id(id).map(|id| ::id_from_def_id(id));
+ let alias_span = alias.map(|i| self.span_from_span(i.span));
+ let span = self.span_from_span(sub_span);
self.dumper.import(&access, Import {
kind: ImportKind::Use,
- ref_id: ref_id.map(|id| ::id_from_def_id(id)),
+ ref_id,
span,
alias_span,
name: ident.to_string(),
value: String::new(),
parent,
});
+ self.write_sub_paths_truncated(&path);
}
- self.write_sub_paths_truncated(&path);
}
ast::UseTreeKind::Glob => {
let path = ast::Path {
Vec::new()
};
- let sub_span = self.span.sub_span_of_token(use_tree.span,
- token::BinOp(token::Star));
- if !self.span.filter_generated(sub_span, use_tree.span) {
+ let sub_span =
+ self.span.sub_span_of_token(use_tree.span, token::BinOp(token::Star));
+ if !self.span.filter_generated(use_tree.span) {
let span =
self.span_from_span(sub_span.expect("No span found for use glob"));
self.dumper.import(&access, Import {
value: names.join(", "),
parent,
});
+ self.write_sub_paths(&path);
}
- self.write_sub_paths(&path);
}
ast::UseTreeKind::Nested(ref nested_items) => {
let prefix = ast::Path {
self.process_use_tree(use_tree, item.id, item, &prefix);
}
ExternCrate(_) => {
- let alias_span = self.span.span_for_last_ident(item.span);
-
- if !self.span.filter_generated(alias_span, item.span) {
- let span =
- self.span_from_span(alias_span.expect("No span found for extern crate"));
+ let name_span = item.ident.span;
+ if !self.span.filter_generated(name_span) {
+ let span = self.span_from_span(name_span);
let parent = self.save_ctxt.tcx.hir.opt_local_def_id(item.id)
.and_then(|id| self.save_ctxt.tcx.parent_def_id(id))
.map(::id_from_def_id);
Ty(ref ty, ref ty_params) => {
let qualname = format!("::{}", self.tcx.node_path_str(item.id));
let value = ty_to_string(&ty);
- let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type);
- if !self.span.filter_generated(sub_span, item.span) {
- let span = self.span_from_span(sub_span.expect("No span found for typedef"));
+ if !self.span.filter_generated(item.ident.span) {
+ let span = self.span_from_span(item.ident.span);
let id = ::id_from_node_id(item.id, &self.save_ctxt);
self.dumper.dump_def(
}
self.visit_ty(&ty);
- self.process_generic_params(ty_params, item.span, &qualname, item.id);
+ self.process_generic_params(ty_params, &qualname, item.id);
}
Existential(ref _bounds, ref ty_params) => {
let qualname = format!("::{}", self.tcx.node_path_str(item.id));
// FIXME do something with _bounds
let value = String::new();
- let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type);
- if !self.span.filter_generated(sub_span, item.span) {
- let span = self.span_from_span(sub_span.expect("No span found for typedef"));
+ if !self.span.filter_generated(item.ident.span) {
+ let span = self.span_from_span(item.ident.span);
let id = ::id_from_node_id(item.id, &self.save_ctxt);
self.dumper.dump_def(
);
}
- self.process_generic_params(ty_params, item.span, &qualname, item.id);
+ self.process_generic_params(ty_params, &qualname, item.id);
}
Mac(_) => (),
_ => visit::walk_item(self, item),
}
if let Some(id) = self.lookup_def_id(t.id) {
- if let Some(sub_span) = self.span.sub_span_for_type_name(t.span) {
- let span = self.span_from_span(sub_span);
- self.dumper.dump_ref(Ref {
- kind: RefKind::Type,
- span,
- ref_id: ::id_from_def_id(id),
- });
- }
+ let sub_span = path.segments.last().unwrap().ident.span;
+ let span = self.span_from_span(sub_span);
+ self.dumper.dump_ref(Ref {
+ kind: RefKind::Type,
+ span,
+ ref_id: ::id_from_def_id(id),
+ });
}
self.write_sub_paths_truncated(path);
if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) {
down_cast_data!(fn_data, DefData, item.span);
- self.nest_tables(
- item.id,
- |v| v.process_formals(&decl.inputs, &fn_data.qualname),
- );
- self.process_generic_params(generics, item.span, &fn_data.qualname, item.id);
+ self.process_generic_params(generics, &fn_data.qualname, item.id);
self.dumper.dump_def(&access, fn_data);
}
use std::fs::File;
use std::path::{Path, PathBuf};
-use syntax::ast::{self, Attribute, NodeId, PatKind};
+use syntax::ast::{self, Attribute, DUMMY_NODE_ID, NodeId, PatKind};
use syntax::source_map::Spanned;
use syntax::parse::lexer::comments::strip_doc_comment_decoration;
-use syntax::parse::token;
use syntax::print::pprust;
-use syntax::symbol::keywords;
use syntax::visit::{self, Visitor};
use syntax::print::pprust::{arg_to_string, ty_to_string};
use syntax::source_map::MacroAttribute;
let qualname = format!("::{}", self.tcx.node_path_str(item.id));
match item.node {
ast::ForeignItemKind::Fn(ref decl, ref generics) => {
- let sub_span = self.span_utils
- .sub_span_after_keyword(item.span, keywords::Fn);
- filter!(self.span_utils, sub_span, item.span, None);
+ filter!(self.span_utils, item.ident.span);
Some(Data::DefData(Def {
kind: DefKind::ForeignFunction,
id: id_from_node_id(item.id, self),
- span: self.span_from_span(sub_span.unwrap()),
+ span: self.span_from_span(item.ident.span),
name: item.ident.to_string(),
qualname,
value: make_signature(decl, generics),
attributes: lower_attributes(item.attrs.clone(), self),
}))
}
- ast::ForeignItemKind::Static(ref ty, m) => {
- let keyword = if m { keywords::Mut } else { keywords::Static };
- let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword);
- filter!(self.span_utils, sub_span, item.span, None);
+ ast::ForeignItemKind::Static(ref ty, _) => {
+ filter!(self.span_utils, item.ident.span);
let id = ::id_from_node_id(item.id, self);
- let span = self.span_from_span(sub_span.unwrap());
+ let span = self.span_from_span(item.ident.span);
Some(Data::DefData(Def {
kind: DefKind::ForeignStatic,
match item.node {
ast::ItemKind::Fn(ref decl, .., ref generics, _) => {
let qualname = format!("::{}", self.tcx.node_path_str(item.id));
- let sub_span = self.span_utils
- .sub_span_after_keyword(item.span, keywords::Fn);
- filter!(self.span_utils, sub_span, item.span, None);
+ filter!(self.span_utils, item.ident.span);
Some(Data::DefData(Def {
kind: DefKind::Function,
id: id_from_node_id(item.id, self),
- span: self.span_from_span(sub_span.unwrap()),
+ span: self.span_from_span(item.ident.span),
name: item.ident.to_string(),
qualname,
value: make_signature(decl, generics),
attributes: lower_attributes(item.attrs.clone(), self),
}))
}
- ast::ItemKind::Static(ref typ, mt, _) => {
+ ast::ItemKind::Static(ref typ, ..) => {
let qualname = format!("::{}", self.tcx.node_path_str(item.id));
- let keyword = match mt {
- ast::Mutability::Mutable => keywords::Mut,
- ast::Mutability::Immutable => keywords::Static,
- };
-
- let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword);
- filter!(self.span_utils, sub_span, item.span, None);
+ filter!(self.span_utils, item.ident.span);
let id = id_from_node_id(item.id, self);
- let span = self.span_from_span(sub_span.unwrap());
+ let span = self.span_from_span(item.ident.span);
Some(Data::DefData(Def {
kind: DefKind::Static,
}
ast::ItemKind::Const(ref typ, _) => {
let qualname = format!("::{}", self.tcx.node_path_str(item.id));
- let sub_span = self.span_utils
- .sub_span_after_keyword(item.span, keywords::Const);
- filter!(self.span_utils, sub_span, item.span, None);
+ filter!(self.span_utils, item.ident.span);
let id = id_from_node_id(item.id, self);
- let span = self.span_from_span(sub_span.unwrap());
+ let span = self.span_from_span(item.ident.span);
Some(Data::DefData(Def {
kind: DefKind::Const,
let cm = self.tcx.sess.source_map();
let filename = cm.span_to_filename(m.inner);
- let sub_span = self.span_utils
- .sub_span_after_keyword(item.span, keywords::Mod);
- filter!(self.span_utils, sub_span, item.span, None);
+ filter!(self.span_utils, item.ident.span);
Some(Data::DefData(Def {
kind: DefKind::Mod,
id: id_from_node_id(item.id, self),
name: item.ident.to_string(),
qualname,
- span: self.span_from_span(sub_span.unwrap()),
+ span: self.span_from_span(item.ident.span),
value: filename.to_string(),
parent: None,
children: m.items
ast::ItemKind::Enum(ref def, _) => {
let name = item.ident.to_string();
let qualname = format!("::{}", self.tcx.node_path_str(item.id));
- let sub_span = self.span_utils
- .sub_span_after_keyword(item.span, keywords::Enum);
- filter!(self.span_utils, sub_span, item.span, None);
+ filter!(self.span_utils, item.ident.span);
let variants_str = def.variants
.iter()
.map(|v| v.node.ident.to_string())
Some(Data::DefData(Def {
kind: DefKind::Enum,
id: id_from_node_id(item.id, self),
- span: self.span_from_span(sub_span.unwrap()),
+ span: self.span_from_span(item.ident.span),
name,
qualname,
value,
if generated_code(path.span) {
return None;
}
- let sub_span = self.span_utils.sub_span_for_type_name(path.span);
- filter!(self.span_utils, sub_span, typ.span, None);
+ let sub_span = path.segments.last().unwrap().ident.span;
+ filter!(self.span_utils, sub_span);
let impl_id = self.next_impl_id();
- let span = self.span_from_span(sub_span.unwrap());
+ let span = self.span_from_span(sub_span);
let type_data = self.lookup_ref_id(typ.id);
type_data.map(|type_data| {
if let Some(ident) = field.ident {
let name = ident.to_string();
let qualname = format!("::{}::{}", self.tcx.node_path_str(scope), ident);
- let sub_span = self.span_utils
- .sub_span_before_token(field.span, token::Colon);
- filter!(self.span_utils, sub_span, field.span, None);
+ filter!(self.span_utils, ident.span);
let def_id = self.tcx.hir.local_def_id(field.id);
let typ = self.tcx.type_of(def_id).to_string();
let id = id_from_node_id(field.id, self);
- let span = self.span_from_span(sub_span.unwrap());
+ let span = self.span_from_span(ident.span);
Some(Def {
kind: DefKind::Field,
// FIXME would be nice to take a MethodItem here, but the ast provides both
// trait and impl flavours, so the caller must do the disassembly.
- pub fn get_method_data(&self, id: ast::NodeId, name: ast::Name, span: Span) -> Option<Def> {
+ pub fn get_method_data(&self, id: ast::NodeId, ident: ast::Ident, span: Span) -> Option<Def> {
// The qualname for a method is the trait name or name of the struct in an impl in
// which the method is declared in, followed by the method's name.
let (qualname, parent_scope, decl_id, docs, attributes) =
qualname.push_str(&self.tcx.item_path_str(def_id));
self.tcx
.associated_items(def_id)
- .find(|item| item.ident.name == name)
+ .find(|item| item.ident.name == ident.name)
.map(|item| decl_id = Some(item.def_id));
}
qualname.push_str(">");
},
};
- let qualname = format!("{}::{}", qualname, name);
+ let qualname = format!("{}::{}", qualname, ident.name);
- let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn);
- filter!(self.span_utils, sub_span, span, None);
+ filter!(self.span_utils, ident.span);
Some(Def {
kind: DefKind::Method,
id: id_from_node_id(id, self),
- span: self.span_from_span(sub_span.unwrap()),
- name: name.to_string(),
+ span: self.span_from_span(ident.span),
+ name: ident.name.to_string(),
qualname,
// FIXME you get better data here by using the visitor.
value: String::new(),
if generated_code(span) {
return None;
}
- let sub_span = self.span_utils.sub_span_for_type_name(span).or(Some(span));
- filter!(self.span_utils, sub_span, span, None);
- let span = self.span_from_span(sub_span.unwrap());
+ let sub_span = trait_ref.path.segments.last().unwrap().ident.span;
+ filter!(self.span_utils, sub_span);
+ let span = self.span_from_span(sub_span);
Some(Ref {
kind: RefKind::Type,
span,
ty::Adt(def, _) if !def.is_enum() => {
let variant = &def.non_enum_variant();
let index = self.tcx.find_field_index(ident, variant).unwrap();
- let sub_span = self.span_utils.span_for_last_ident(expr.span);
- filter!(self.span_utils, sub_span, expr.span, None);
- let span = self.span_from_span(sub_span.unwrap());
+ filter!(self.span_utils, ident.span);
+ let span = self.span_from_span(ident.span);
return Some(Data::RefData(Ref {
kind: RefKind::Variable,
span,
ast::ExprKind::Struct(ref path, ..) => {
match self.tables.expr_ty_adjusted(&hir_node).sty {
ty::Adt(def, _) if !def.is_enum() => {
- let sub_span = self.span_utils.span_for_last_ident(path.span);
- filter!(self.span_utils, sub_span, path.span, None);
- let span = self.span_from_span(sub_span.unwrap());
+ let sub_span = path.segments.last().unwrap().ident.span;
+ filter!(self.span_utils, sub_span);
+ let span = self.span_from_span(sub_span);
Some(Data::RefData(Ref {
kind: RefKind::Type,
span,
ty::TraitContainer(_) => (None, Some(method_id)),
};
let sub_span = seg.ident.span;
- filter!(self.span_utils, Some(sub_span), expr.span, None);
+ filter!(self.span_utils, sub_span);
let span = self.span_from_span(sub_span);
Some(Data::RefData(Ref {
kind: RefKind::Function,
Node::Visibility(&Spanned {
node: hir::VisibilityKind::Restricted { ref path, .. }, .. }) => path.def,
+ Node::PathSegment(seg) => match seg.def {
+ Some(def) => def,
+ None => HirDef::Err,
+ },
Node::Expr(&hir::Expr {
node: hir::ExprKind::Struct(ref qpath, ..),
..
}
}
- pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option<Ref> {
+ pub fn get_path_data(&self, _id: NodeId, path: &ast::Path) -> Option<Ref> {
+ path.segments.last().and_then(|seg| self.get_path_segment_data(seg))
+ }
+
+ pub fn get_path_segment_data(&self, path_seg: &ast::PathSegment) -> Option<Ref> {
// Returns true if the path is function type sugar, e.g., `Fn(A) -> B`.
- fn fn_type(path: &ast::Path) -> bool {
- if path.segments.len() != 1 {
- return false;
- }
- if let Some(ref generic_args) = path.segments[0].args {
+ fn fn_type(seg: &ast::PathSegment) -> bool {
+ if let Some(ref generic_args) = seg.args {
if let ast::GenericArgs::Parenthesized(_) = **generic_args {
return true;
}
false
}
- if path.segments.is_empty() {
+ if path_seg.id == DUMMY_NODE_ID {
return None;
}
- let def = self.get_path_def(id);
- let last_seg = &path.segments[path.segments.len() - 1];
- let sub_span = last_seg.ident.span;
- filter!(self.span_utils, Some(sub_span), path.span, None);
+ let def = self.get_path_def(path_seg.id);
+ let span = path_seg.ident.span;
+ filter!(self.span_utils, span);
+ let span = self.span_from_span(span);
+
match def {
HirDef::Upvar(id, ..) | HirDef::Local(id) => {
- let span = self.span_from_span(sub_span);
Some(Ref {
kind: RefKind::Variable,
span,
HirDef::Const(..) |
HirDef::AssociatedConst(..) |
HirDef::VariantCtor(..) => {
- let span = self.span_from_span(sub_span);
Some(Ref {
kind: RefKind::Variable,
span,
ref_id: id_from_def_id(def.def_id()),
})
}
- HirDef::Trait(def_id) if fn_type(path) => {
- // Function type bounds are desugared in the parser, so we have to
- // special case them here.
- let fn_span = self.span_utils.span_for_first_ident(path.span);
- fn_span.map(|span| {
- Ref {
- kind: RefKind::Type,
- span: self.span_from_span(span),
- ref_id: id_from_def_id(def_id),
- }
+ HirDef::Trait(def_id) if fn_type(path_seg) => {
+ Some(Ref {
+ kind: RefKind::Type,
+ span,
+ ref_id: id_from_def_id(def_id),
})
}
HirDef::Struct(def_id) |
HirDef::Trait(def_id) |
HirDef::Existential(def_id) |
HirDef::TyParam(def_id) => {
- let span = self.span_from_span(sub_span);
Some(Ref {
kind: RefKind::Type,
span,
// This is a reference to a tuple struct where the def_id points
// to an invisible constructor function. That is not a very useful
// def, so adjust to point to the tuple struct itself.
- let span = self.span_from_span(sub_span);
let parent_def_id = self.tcx.parent_def_id(def_id).unwrap();
Some(Ref {
kind: RefKind::Type,
} else {
None
};
- let span = self.span_from_span(sub_span);
Some(Ref {
kind: RefKind::Function,
span,
})
}
HirDef::Fn(def_id) => {
- let span = self.span_from_span(sub_span);
Some(Ref {
kind: RefKind::Function,
span,
})
}
HirDef::Mod(def_id) => {
- let span = self.span_from_span(sub_span);
Some(Ref {
kind: RefKind::Mod,
span,
field_ref: &ast::Field,
variant: &ty::VariantDef,
) -> Option<Ref> {
- let index = self.tcx.find_field_index(field_ref.ident, variant).unwrap();
- // We don't really need a sub-span here, but no harm done
- let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span);
- filter!(self.span_utils, sub_span, field_ref.ident.span, None);
- let span = self.span_from_span(sub_span.unwrap());
- Some(Ref {
- kind: RefKind::Variable,
- span,
- ref_id: id_from_def_id(variant.fields[index].did),
+ filter!(self.span_utils, field_ref.ident.span);
+ self.tcx.find_field_index(field_ref.ident, variant).map(|index| {
+ let span = self.span_from_span(field_ref.ident.span);
+ Ref {
+ kind: RefKind::Variable,
+ span,
+ ref_id: id_from_def_id(variant.fields[index].did),
+ }
})
}
use syntax::parse::lexer::{self, StringReader};
use syntax::parse::token::{self, Token};
-use syntax::symbol::keywords;
use syntax_pos::*;
#[derive(Clone)]
lexer::StringReader::retokenize(&self.sess.parse_sess, span)
}
- // Re-parses a path and returns the span for the last identifier in the path
- pub fn span_for_last_ident(&self, span: Span) -> Option<Span> {
- let mut result = None;
-
- let mut toks = self.retokenise_span(span);
- let mut bracket_count = 0;
- loop {
- let ts = toks.real_token();
- if ts.tok == token::Eof {
- return result;
- }
- if bracket_count == 0 && (ts.tok.is_ident() || ts.tok.is_keyword(keywords::SelfValue)) {
- result = Some(ts.sp);
- }
-
- bracket_count += match ts.tok {
- token::Lt => 1,
- token::Gt => -1,
- token::BinOp(token::Shr) => -2,
- _ => 0,
- }
- }
- }
-
- // Return the span for the first identifier in the path.
- pub fn span_for_first_ident(&self, span: Span) -> Option<Span> {
- let mut toks = self.retokenise_span(span);
- let mut bracket_count = 0;
- loop {
- let ts = toks.real_token();
- if ts.tok == token::Eof {
- return None;
- }
- if bracket_count == 0 && (ts.tok.is_ident() || ts.tok.is_keyword(keywords::SelfValue)) {
- return Some(ts.sp);
- }
-
- bracket_count += match ts.tok {
- token::Lt => 1,
- token::Gt => -1,
- token::BinOp(token::Shr) => -2,
- _ => 0,
- }
- }
- }
-
- // Return the span for the last ident before a `<` and outside any
- // angle brackets, or the last span.
- pub fn sub_span_for_type_name(&self, span: Span) -> Option<Span> {
- let mut toks = self.retokenise_span(span);
- let mut prev = toks.real_token();
- let mut result = None;
-
- // We keep track of the following two counts - the depth of nesting of
- // angle brackets, and the depth of nesting of square brackets. For the
- // angle bracket count, we only count tokens which occur outside of any
- // square brackets (i.e. bracket_count == 0). The intuition here is
- // that we want to count angle brackets in the type, but not any which
- // could be in expression context (because these could mean 'less than',
- // etc.).
- let mut angle_count = 0;
- let mut bracket_count = 0;
- loop {
- let next = toks.real_token();
-
- if (next.tok == token::Lt || next.tok == token::Colon) && angle_count == 0
- && bracket_count == 0 && prev.tok.is_ident()
- {
- result = Some(prev.sp);
- }
-
- if bracket_count == 0 {
- angle_count += match prev.tok {
- token::Lt => 1,
- token::Gt => -1,
- token::BinOp(token::Shl) => 2,
- token::BinOp(token::Shr) => -2,
- _ => 0,
- };
- }
-
- bracket_count += match prev.tok {
- token::OpenDelim(token::Bracket) => 1,
- token::CloseDelim(token::Bracket) => -1,
- _ => 0,
- };
-
- if next.tok == token::Eof {
- break;
- }
- prev = next;
- }
- #[cfg(debug_assertions)] {
- if angle_count != 0 || bracket_count != 0 {
- let loc = self.sess.source_map().lookup_char_pos(span.lo());
- span_bug!(
- span,
- "Mis-counted brackets when breaking path? Parsing '{}' in {}, line {}",
- self.snippet(span),
- loc.file.name,
- loc.line
- );
- }
- }
- if result.is_none() && prev.tok.is_ident() {
- return Some(prev.sp);
- }
- result
- }
-
- pub fn sub_span_before_token(&self, span: Span, tok: Token) -> Option<Span> {
- let mut toks = self.retokenise_span(span);
- let mut prev = toks.real_token();
- loop {
- if prev.tok == token::Eof {
- return None;
- }
- let next = toks.real_token();
- if next.tok == tok {
- return Some(prev.sp);
- }
- prev = next;
- }
- }
-
pub fn sub_span_of_token(&self, span: Span, tok: Token) -> Option<Span> {
let mut toks = self.retokenise_span(span);
loop {
}
}
- pub fn sub_span_after_keyword(&self, span: Span, keyword: keywords::Keyword) -> Option<Span> {
- self.sub_span_after(span, |t| t.is_keyword(keyword))
- }
-
- fn sub_span_after<F: Fn(Token) -> bool>(&self, span: Span, f: F) -> Option<Span> {
- let mut toks = self.retokenise_span(span);
- loop {
- let ts = toks.real_token();
- if ts.tok == token::Eof {
- return None;
- }
- if f(ts.tok) {
- let ts = toks.real_token();
- if ts.tok == token::Eof {
- return None;
- } else {
- return Some(ts.sp);
- }
- }
- }
- }
-
// // Return the name for a macro definition (identifier after first `!`)
// pub fn span_for_macro_def_name(&self, span: Span) -> Option<Span> {
// let mut toks = self.retokenise_span(span);
///
/// Used to filter out spans of minimal value,
/// such as references to macro internal variables.
- pub fn filter_generated(&self, sub_span: Option<Span>, parent: Span) -> bool {
- if !generated_code(parent) {
- // Edge case - this occurs on generated code with incorrect expansion info.
- return sub_span.is_none()
+ pub fn filter_generated(&self, span: Span) -> bool {
+ if span.is_dummy() {
+ return true;
+ }
+
+ if !generated_code(span) {
+ return false;
}
- // If sub_span is none, filter out generated code.
- let sub_span = match sub_span {
- Some(ss) => ss,
- None => return true,
- };
//If the span comes from a fake source_file, filter it.
- if !self.sess
+ !self.sess
.source_map()
- .lookup_char_pos(parent.lo())
+ .lookup_char_pos(span.lo())
.file
.is_real_file()
- {
- return true;
- }
-
- // Otherwise, a generated span is deemed invalid if it is not a sub-span of the root
- // callsite. This filters out macro internal variables and most malformed spans.
- !parent.source_callsite().contains(sub_span)
}
}
macro_rules! filter {
- ($util: expr, $span: expr, $parent: expr, None) => {
- if $util.filter_generated($span, $parent) {
+ ($util: expr, $parent: expr) => {
+ if $util.filter_generated($parent) {
return None;
}
};
- ($util: expr, $span: ident, $parent: expr) => {
- if $util.filter_generated($span, $parent) {
- return;
- }
- };
}
}
/// Lower the alignment, if necessary, such that the given offset
- /// is aligned to it (the offset is a multiple of the aligment).
+ /// is aligned to it (the offset is a multiple of the alignment).
pub fn restrict_for_offset(self, offset: Size) -> Align {
self.min(Align::max_for_offset(offset))
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use rustc::infer::at::ToTrace;
use rustc::infer::canonical::{Canonical, QueryResponse};
use rustc::infer::InferCtxt;
+use rustc::hir::def_id::DefId;
+use rustc::traits::query::type_op::ascribe_user_type::AscribeUserType;
use rustc::traits::query::type_op::eq::Eq;
use rustc::traits::query::type_op::normalize::Normalize;
use rustc::traits::query::type_op::prove_predicate::ProvePredicate;
use rustc::traits::query::type_op::subtype::Subtype;
use rustc::traits::query::{Fallible, NoSolution};
-use rustc::traits::{FulfillmentContext, Normalized, Obligation, ObligationCause, TraitEngine,
- TraitEngineExt};
+use rustc::traits::{
+ FulfillmentContext, Normalized, Obligation, ObligationCause, TraitEngine, TraitEngineExt,
+};
use rustc::ty::query::Providers;
-use rustc::ty::{FnSig, Lift, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::subst::{Kind, Subst, UserSelfTy, UserSubsts};
+use rustc::ty::{
+ FnSig, Lift, ParamEnv, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable, Variance,
+};
use rustc_data_structures::sync::Lrc;
use std::fmt;
+use syntax::ast;
+use syntax_pos::DUMMY_SP;
crate fn provide(p: &mut Providers) {
*p = Providers {
+ type_op_ascribe_user_type,
type_op_eq,
type_op_prove_predicate,
type_op_subtype,
};
}
+fn type_op_ascribe_user_type<'tcx>(
+ tcx: TyCtxt<'_, 'tcx, 'tcx>,
+ canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, AscribeUserType<'tcx>>>,
+) -> Result<Lrc<Canonical<'tcx, QueryResponse<'tcx, ()>>>, NoSolution> {
+ tcx.infer_ctxt()
+ .enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
+ let (
+ param_env,
+ AscribeUserType {
+ mir_ty,
+ variance,
+ def_id,
+ user_substs,
+ },
+ ) = key.into_parts();
+
+ debug!(
+ "type_op_ascribe_user_type(\
+ mir_ty={:?}, variance={:?}, def_id={:?}, user_substs={:?}\
+ )",
+ mir_ty, variance, def_id, user_substs,
+ );
+
+ let mut cx = AscribeUserTypeCx {
+ infcx,
+ param_env,
+ fulfill_cx,
+ };
+ cx.relate_mir_and_user_ty(mir_ty, variance, def_id, user_substs)?;
+
+ Ok(())
+ })
+}
+
+struct AscribeUserTypeCx<'me, 'gcx: 'tcx, 'tcx: 'me> {
+ infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
+ param_env: ParamEnv<'tcx>,
+ fulfill_cx: &'me mut FulfillmentContext<'tcx>,
+}
+
+impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
+ fn normalize<T>(&mut self, value: T) -> T
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ self.infcx
+ .partially_normalize_associated_types_in(
+ DUMMY_SP,
+ ast::CRATE_NODE_ID,
+ self.param_env,
+ &value,
+ )
+ .into_value_registering_obligations(self.infcx, self.fulfill_cx)
+ }
+
+ fn relate<T>(&mut self, a: T, variance: Variance, b: T) -> Result<(), NoSolution>
+ where
+ T: ToTrace<'tcx>,
+ {
+ Ok(self.infcx
+ .at(&ObligationCause::dummy(), self.param_env)
+ .relate(a, variance, b)?
+ .into_value_registering_obligations(self.infcx, self.fulfill_cx))
+ }
+
+ fn prove_predicate(&mut self, predicate: Predicate<'tcx>) {
+ self.fulfill_cx.register_predicate_obligation(
+ self.infcx,
+ Obligation::new(ObligationCause::dummy(), self.param_env, predicate),
+ );
+ }
+
+ fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
+ self.infcx.tcx
+ }
+
+ fn subst<T>(&self, value: T, substs: &[Kind<'tcx>]) -> T
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ value.subst(self.tcx(), substs)
+ }
+
+ fn relate_mir_and_user_ty(
+ &mut self,
+ mir_ty: Ty<'tcx>,
+ variance: Variance,
+ def_id: DefId,
+ user_substs: UserSubsts<'tcx>,
+ ) -> Result<(), NoSolution> {
+ let UserSubsts {
+ substs,
+ user_self_ty,
+ } = user_substs;
+
+ let ty = self.tcx().type_of(def_id);
+ let ty = self.subst(ty, substs);
+ debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
+ let ty = self.normalize(ty);
+
+ self.relate(mir_ty, variance, ty)?;
+
+ if let Some(UserSelfTy {
+ impl_def_id,
+ self_ty,
+ }) = user_self_ty
+ {
+ let impl_self_ty = self.tcx().type_of(impl_def_id);
+ let impl_self_ty = self.subst(impl_self_ty, &substs);
+ let impl_self_ty = self.normalize(impl_self_ty);
+
+ self.relate(self_ty, Variance::Invariant, impl_self_ty)?;
+
+ self.prove_predicate(Predicate::WellFormed(impl_self_ty));
+ }
+
+ // Prove the predicates coming along with `def_id`.
+ //
+ // Also, normalize the `instantiated_predicates`
+ // because otherwise we wind up with duplicate "type
+ // outlives" error messages.
+ let instantiated_predicates = self.tcx()
+ .predicates_of(def_id)
+ .instantiate(self.tcx(), substs);
+ for instantiated_predicate in instantiated_predicates.predicates {
+ let instantiated_predicate = self.normalize(instantiated_predicate);
+ self.prove_predicate(instantiated_predicate);
+ }
+
+ // In addition to proving the predicates, we have to
+ // prove that `ty` is well-formed -- this is because
+ // the WF of `ty` is predicated on the substs being
+ // well-formed, and we haven't proven *that*. We don't
+ // want to prove the WF of types from `substs` directly because they
+ // haven't been normalized.
+ //
+ // FIXME(nmatsakis): Well, perhaps we should normalize
+ // them? This would only be relevant if some input
+ // type were ill-formed but did not appear in `ty`,
+ // which...could happen with normalization...
+ self.prove_predicate(Predicate::WellFormed(ty));
+
+ Ok(())
+ }
+}
+
fn type_op_eq<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>,
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
- // If the expected type is an enum with any variants whose sole
- // field is of the found type, suggest such variants. See Issue
- // #42764.
+ // If the expected type is an enum (Issue #55250) with any variants whose
+ // sole field is of the found type, suggest such variants. (Issue #42764)
if let ty::Adt(expected_adt, substs) = expected.sty {
- let mut compatible_variants = expected_adt.variants
- .iter()
- .filter(|variant| variant.fields.len() == 1)
- .filter_map(|variant| {
- let sole_field = &variant.fields[0];
- let sole_field_ty = sole_field.ty(self.tcx, substs);
- if self.can_coerce(expr_ty, sole_field_ty) {
- let variant_path = self.tcx.item_path_str(variant.did);
- Some(variant_path.trim_left_matches("std::prelude::v1::").to_string())
- } else {
- None
+ if expected_adt.is_enum() {
+ let mut compatible_variants = expected_adt.variants
+ .iter()
+ .filter(|variant| variant.fields.len() == 1)
+ .filter_map(|variant| {
+ let sole_field = &variant.fields[0];
+ let sole_field_ty = sole_field.ty(self.tcx, substs);
+ if self.can_coerce(expr_ty, sole_field_ty) {
+ let variant_path = self.tcx.item_path_str(variant.did);
+ Some(variant_path.trim_left_matches("std::prelude::v1::").to_string())
+ } else {
+ None
+ }
+ }).peekable();
+
+ if compatible_variants.peek().is_some() {
+ let expr_text = print::to_string(print::NO_ANN, |s| s.print_expr(expr));
+ let suggestions = compatible_variants
+ .map(|v| format!("{}({})", v, expr_text)).collect::<Vec<_>>();
+ err.span_suggestions_with_applicability(
+ expr.span,
+ "try using a variant of the expected type",
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
}
- }).peekable();
-
- if compatible_variants.peek().is_some() {
- let expr_text = print::to_string(print::NO_ANN, |s| s.print_expr(expr));
- let suggestions = compatible_variants.map(|v|
- format!("{}({})", v, expr_text)).collect::<Vec<_>>();
- err.span_suggestions_with_applicability(
- expr.span,
- "try using a variant of the expected type",
- suggestions,
- Applicability::MaybeIncorrect,
- );
}
}
} else {
// If no type arguments were provided, we have to infer them.
// This case also occurs as a result of some malformed input, e.g.
- // a lifetime argument being given instead of a type paramter.
+ // a lifetime argument being given instead of a type parameter.
// Using inference instead of `Error` gives better error messages.
self.var_for_def(span, param)
}
} // if may_define_existential_type
// now register the bounds on the parameters of the existential type
- // so the parameters given by the function need to fulfil them
+ // so the parameters given by the function need to fulfill them
// ```rust
// existential type Foo<T: Bar>: 'static;
// fn foo<U>() -> Foo<U> { .. *}
// If the extern crate isn't in the extern prelude,
// there is no way it can be written as an `use`.
let orig_name = extern_crate.orig_name.unwrap_or(item.name);
- if !tcx.extern_prelude.contains(&orig_name) {
+ if !tcx.extern_prelude.get(&orig_name).map_or(false, |from_item| !from_item) {
continue;
}
// exactly one (non-phantom) field has changed its
// type, which we will expect to be the pointer that
// is becoming fat (we could probably generalize this
- // to mutiple thin pointers of the same type becoming
+ // to multiple thin pointers of the same type becoming
// fat, but we don't). In this case:
//
// - `extra` has type `T` before and type `T` after
name: Option<String>,
) -> Vec<Item>
where F: Fn(DefId) -> Def {
+ debug!("get_blanket_impls(def_id={:?}, ...)", def_id);
let mut impls = Vec::new();
if self.cx
.tcx
}
self.cx.tcx.for_each_relevant_impl(trait_def_id, ty, |impl_def_id| {
self.cx.tcx.infer_ctxt().enter(|infcx| {
+ debug!("get_blanet_impls: Considering impl for trait '{:?}' {:?}",
+ trait_def_id, impl_def_id);
let t_generics = infcx.tcx.generics_of(impl_def_id);
let trait_ref = infcx.tcx.impl_trait_ref(impl_def_id)
.expect("Cannot get impl trait");
drop(obligations);
debug!(
- "invoking predicate_may_hold: {:?}",
- trait_ref,
+ "invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}",
+ param_env, trait_ref, ty
);
let may_apply = match infcx.evaluate_obligation(
&traits::Obligation::new(
Ok(eval_result) => eval_result.may_apply(),
Err(traits::OverflowError) => true, // overflow doesn't mean yes *or* no
};
+ debug!("get_blanket_impls: found applicable impl: {}\
+ for trait_ref={:?}, ty={:?}",
+ may_apply, trait_ref, ty);
+
if !may_apply {
return
}
fields.iter().map(|&Spanned { node: ref fp, .. }|
format!("{}: {}", fp.ident, name_from_pat(&*fp.pat)))
.collect::<Vec<String>>().join(", "),
- if etc { ", ..." } else { "" }
+ if etc { ", .." } else { "" }
)
}
PatKind::Tuple(ref elts, _) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
def: def_ctor(def_id),
segments: hir::HirVec::from_vec(apb.names.iter().map(|s| hir::PathSegment {
ident: ast::Ident::from_str(&s),
+ id: None,
+ def: None,
args: None,
infer_types: false,
}).collect())
segments.push(hir::PathSegment::new(
real_name.unwrap_or(last.ident),
+ None,
+ None,
self.generics_to_path_params(generics.clone()),
false,
));
trait_map: resolver.trait_map.clone(),
maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(),
maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(),
- extern_prelude: resolver.extern_prelude.clone(),
+ extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| {
+ (ident.name, entry.introduced_by_item)
+ }).collect(),
};
let analysis = ty::CrateAnalysis {
access_levels: Lrc::new(AccessLevels::default()),
use syntax_pos::{Span, FileName};
/// Highlights `src`, returning the HTML output.
-pub fn render_with_highlighting(src: &str, class: Option<&str>,
- extension: Option<&str>,
- tooltip: Option<(&str, &str)>) -> String {
+pub fn render_with_highlighting(
+ src: &str,
+ class: Option<&str>,
+ extension: Option<&str>,
+ tooltip: Option<(&str, &str)>,
+) -> String {
debug!("highlighting: ================\n{}\n==============", src);
let sess = parse::ParseSess::new(FilePathMapping::empty());
let fm = sess.source_map().new_source_file(FileName::Custom("stdin".to_string()),
}
fn write_header(class: Option<&str>, out: &mut dyn Write) -> io::Result<()> {
- write!(out, "<pre class=\"rust {}\">\n", class.unwrap_or(""))
+ write!(out, "<div class=\"example-wrap\"><pre class=\"rust {}\">\n", class.unwrap_or(""))
}
fn write_footer(out: &mut dyn Write) -> io::Result<()> {
- write!(out, "</pre>\n")
+ write!(out, "</pre></div>\n")
}
("method-docs", "Auto-hide item methods' documentation", false),
("go-to-only-result", "Directly go to item in search if there is only one result",
false),
+ ("line-numbers", "Show line numbers on code examples", false),
],
root_path,
suffix,
return wrapper;
}
+ var hideItemDeclarations = getCurrentValue('rustdoc-item-declarations') === "false";
onEach(document.getElementsByClassName('docblock'), function(e) {
if (hasClass(e, 'autohide')) {
var wrap = e.previousElementSibling;
}
}
if (e.parentNode.id === "main") {
- var otherMessage;
+ var otherMessage = '';
var fontSize;
var extraClass;
- var show = true;
if (hasClass(e, "type-decl")) {
fontSize = "20px";
otherMessage = ' Show declaration';
- show = getCurrentValue('rustdoc-item-declarations') === "false";
- if (!show) {
+ if (hideItemDeclarations === false) {
extraClass = 'collapsed';
}
} else if (hasClass(e, "non-exhaustive")) {
extraClass = "marg-left";
}
- e.parentNode.insertBefore(createToggle(otherMessage, fontSize, extraClass, show), e);
- if (otherMessage && show) {
+ e.parentNode.insertBefore(createToggle(otherMessage,
+ fontSize,
+ extraClass,
+ hideItemDeclarations),
+ e);
+ if (otherMessage.length > 0 && hideItemDeclarations === true) {
collapseDocs(e.previousSibling.childNodes[0], "toggle");
}
}
});
}
+ // To avoid checking on "rustdoc-item-attributes" value on every loop...
+ var itemAttributesFunc = function() {};
+ if (getCurrentValue("rustdoc-item-attributes") !== "false") {
+ itemAttributesFunc = function(x) {
+ collapseDocs(x.previousSibling.childNodes[0], "toggle");
+ };
+ }
onEach(document.getElementById('main').getElementsByClassName('attributes'), function(i_e) {
i_e.parentNode.insertBefore(createToggleWrapper(toggle.cloneNode(true)), i_e);
- if (getCurrentValue("rustdoc-item-attributes") !== "false") {
- collapseDocs(i_e.previousSibling.childNodes[0], "toggle");
- }
+ itemAttributesFunc(i_e);
});
+ // To avoid checking on "rustdoc-line-numbers" value on every loop...
+ var lineNumbersFunc = function() {};
+ if (getCurrentValue("rustdoc-line-numbers") === "true") {
+ lineNumbersFunc = function(x) {
+ var count = x.textContent.split('\n').length;
+ var elems = [];
+ for (var i = 0; i < count; ++i) {
+ elems.push(i + 1);
+ }
+ var node = document.createElement('pre');
+ addClass(node, 'line-number');
+ node.innerHTML = elems.join('\n');
+ x.parentNode.insertBefore(node, x);
+ };
+ }
onEach(document.getElementsByClassName('rust-example-rendered'), function(e) {
if (hasClass(e, 'compile_fail')) {
e.addEventListener("mouseover", function(event) {
e.previousElementSibling.childNodes[0].style.color = '';
});
}
+ lineNumbersFunc(e);
});
function showModal(content) {
padding-left: 0;
}
+.example-wrap {
+ display: inline-flex;
+ width: 100%;
+}
+
+.example-wrap > pre.line-number {
+ overflow: initial;
+ border: 1px solid;
+ border-top-left-radius: 5px;
+ border-bottom-left-radius: 5px;
+ padding: 13px 8px;
+ text-align: right;
+}
+
+.example-wrap > pre.rust {
+ width: 100%;
+}
+
#search {
margin-left: 230px;
position: relative;
color: #ff9011;
}
+.example-wrap > pre.line-number {
+ border-color: #4a4949;
+}
+
a.test-arrow {
background-color: rgba(78, 139, 202, 0.2);
}
color: #ff9011;
}
+.example-wrap > pre.line-number {
+ border-color: #c7c7c7;
+}
+
a.test-arrow {
background-color: rgba(78, 139, 202, 0.2);
}
}
}
- /// Returns a number composed of the magnitude of one number and the sign of
- /// another.
+ /// Returns a number composed of the magnitude of `self` and the sign of
+ /// `y`.
///
/// Equal to `self` if the sign of `self` and `y` are the same, otherwise
- /// equal to `-y`. If `self` is a `NAN`, then a `NAN` with the sign of `y`
- /// is returned.
+ /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of
+ /// `y` is returned.
///
/// # Examples
///
}
}
- /// Returns a number composed of the magnitude of one number and the sign of
- /// another.
+ /// Returns a number composed of the magnitude of `self` and the sign of
+ /// `y`.
///
/// Equal to `self` if the sign of `self` and `y` are the same, otherwise
- /// equal to `-y`. If `self` is a `NAN`, then a `NAN` with the sign of `y`
- /// is returned.
+ /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of
+ /// `y` is returned.
///
/// # Examples
///
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[doc(keyword = "as")]
+//
+/// The keyword for casting a value to a type.
+///
+/// `as` is most commonly used to turn primitive types into other primitive types, but it has other
+/// uses that include turning pointers into addresses, addresses into pointers, and pointers into
+/// other pointers.
+///
+/// ```rust
+/// let thing1: u8 = 89.0 as u8;
+/// assert_eq!('B' as u32, 66);
+/// assert_eq!(thing1 as char, 'Y');
+/// let thing2: f32 = thing1 as f32 + 10.5;
+/// assert_eq!(true as u8 + thing2 as u8, 100);
+/// ```
+///
+/// In general, any cast that can be performed via ascribing the type can also be done using `as`,
+/// so instead of writing `let x: u32 = 123`, you can write `let x = 123 as u32` (Note: `let x: u32
+/// = 123` would be best in that situation). The same is not true in the other direction, however,
+/// explicitly using `as` allows a few more coercions that aren't allowed implicitly, such as
+/// changing the type of a raw pointer or turning closures into raw pointers.
+///
+/// Other places `as` is used include as extra syntax for [`crate`] and `use`, to change the name
+/// something is imported as.
+///
+/// For more information on what `as` is capable of, see the [Reference]
+///
+/// [Reference]:
+/// https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions
+/// [`crate`]: keyword.crate.html
+mod as_keyword { }
+
+#[doc(keyword = "const")]
+//
+/// The keyword for defining constants.
+///
+/// Sometimes a certain value is used many times throughout a program, and it can become
+/// inconvenient to copy it over and over. What's more, it's not always possible or desirable to
+/// make it a variable that gets carried around to each function that needs it. In these cases, the
+/// `const` keyword provides a convenient alternative to code duplication.
+///
+/// ```rust
+/// const THING: u32 = 0xABAD1DEA;
+///
+/// let foo = 123 + THING;
+/// ```
+///
+/// Constants must be explicitly typed, unlike with `let` you can't ignore its type and let the
+/// compiler figure it out. Any constant value can be defined in a const, which in practice happens
+/// to be most things that would be reasonable to have a constant (barring `const fn`s, coming
+/// soon). For example, you can't have a File as a `const`.
+///
+/// The only lifetime allowed in a constant is `'static`, which is the lifetime that encompasses
+/// all others in a Rust program. For example, if you wanted to define a constant string, it would
+/// look like this:
+///
+/// ```rust
+/// const WORDS: &'static str = "hello rust!";
+/// ```
+///
+/// Thanks to static lifetime elision, you usually don't have to explicitly use 'static:
+///
+/// ```rust
+/// const WORDS: &str = "hello convenience!";
+/// ```
+///
+/// `const` items looks remarkably similar to `static` items, which introduces some confusion as
+/// to which one should be used at which times. To put it simply, constants are inlined wherever
+/// they're used, making using them identical to simply replacing the name of the const with its
+/// value. Static variables on the other hand point to a single location in memory, which all
+/// accesses share. This means that, unlike with constants, they can't have destructors, and act as
+/// a single value across the entire codebase.
+///
+/// Constants, as with statics, should always be in SCREAMING_SNAKE_CASE.
+///
+/// The `const` keyword is also used in raw pointers in combination with `mut`, as seen in `*const
+/// T` and `*mut T`. More about that can be read at the [pointer] primitive part of the Rust docs.
+///
+/// For more detail on `const`, see the [Rust Book] or the [Reference]
+///
+/// [pointer]: primitive.pointer.html
+/// [Rust Book]:
+/// https://doc.rust-lang.org/stable/book/2018-edition/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants
+/// [Reference]: https://doc.rust-lang.org/reference/items/constant-items.html
+mod const_keyword { }
+
+#[doc(keyword = "crate")]
+//
+/// The `crate` keyword.
+///
+/// The primary use of the `crate` keyword is as a part of `extern crate` declarations, which are
+/// used to specify a dependency on a crate external to the one it's declared in. Crates are the
+/// fundamental compilation unit of Rust code, and can be seen as libraries or projects. More can
+/// be read about crates in the [Reference].
+///
+/// ```rust ignore
+/// extern crate rand;
+/// extern crate my_crate as thing;
+/// extern crate std; // implicitly added to the root of every Rust project
+/// ```
+///
+/// The `as` keyword can be used to change what the crate is referred to as in your project. If a
+/// crate name includes a dash, it is implicitly imported with the dashes replaced by underscores.
+///
+/// `crate` is also used as in conjunction with `pub` to signify that the item it's attached to
+/// is public only to other members of the same crate it's in.
+///
+/// ```rust
+/// # #[allow(unused_imports)]
+/// pub(crate) use std::io::Error as IoError;
+/// pub(crate) enum CoolMarkerType { }
+/// pub struct PublicThing {
+/// pub(crate) semi_secret_thing: bool,
+/// }
+/// ```
+///
+/// [Reference]: https://doc.rust-lang.org/reference/items/extern-crates.html
+mod crate_keyword { }
+
+#[doc(keyword = "enum")]
+//
+/// For defining enumerations.
+///
+/// Enums in Rust are similar to those of other compiled languages like C, but have important
+/// differences that make them considerably more powerful. What Rust calls enums are more commonly
+/// known as [Algebraic Data Types] if you're coming from a functional programming background. The
+/// important detail is that each enum variant can have data to go along with it.
+///
+/// ```rust
+/// # struct Coord;
+/// enum SimpleEnum {
+/// FirstVariant,
+/// SecondVariant,
+/// ThirdVariant,
+/// }
+///
+/// enum Location {
+/// Unknown,
+/// Anonymous,
+/// Known(Coord),
+/// }
+///
+/// enum ComplexEnum {
+/// Nothing,
+/// Something(u32),
+/// LotsOfThings {
+/// usual_struct_stuff: bool,
+/// blah: String,
+/// }
+/// }
+///
+/// enum EmptyEnum { }
+/// ```
+///
+/// The first enum shown is the usual kind of enum you'd find in a C-style language. The second
+/// shows off a hypothetical example of something storing location data, with `Coord` being any
+/// other type that's needed, for example a struct. The third example demonstrates the kind of
+/// data a variant can store, ranging from nothing, to a tuple, to an anonymous struct.
+///
+/// Instantiating enum variants involves explicitly using the enum's name as its namespace,
+/// followed by one of its variants. `SimpleEnum::SecondVariant` would be an example from above.
+/// When data follows along with a variant, such as with rust's built-in [`Option`] type, the data
+/// is added as the type describes, for example `Option::Some(123)`. The same follows with
+/// struct-like variants, with things looking like `ComplexEnum::LotsOfThings { usual_struct_stuff:
+/// true, blah: "hello!".to_string(), }`. Empty Enums are similar to () in that they cannot be
+/// instantiated at all, and are used mainly to mess with the type system in interesting ways.
+///
+/// For more information, take a look at the [Rust Book] or the [Reference]
+///
+/// [Algebraic Data Types]: https://en.wikipedia.org/wiki/Algebraic_data_type
+/// [`Option`]: option/enum.Option.html
+/// [Rust Book]: https://doc.rust-lang.org/book/second-edition/ch06-01-defining-an-enum.html
+/// [Reference]: https://doc.rust-lang.org/reference/items/enumerations.html
+mod enum_keyword { }
+
+#[doc(keyword = "extern")]
+//
+/// For external connections in Rust code.
+///
+/// The `extern` keyword is used in two places in Rust. One is in conjunction with the [`crate`]
+/// keyword to make your Rust code aware of other Rust crates in your project, i.e. `extern crate
+/// lazy_static;`. The other use is in foreign function interfaces (FFI).
+///
+/// `extern` is used in two different contexts within FFI. The first is in the form of external
+/// blocks, for declaring function interfaces that Rust code can call foreign code by.
+///
+/// ```rust ignore
+/// #[link(name = "my_c_library")]
+/// extern "C" {
+/// fn my_c_function(x: i32) -> bool;
+/// }
+/// ```
+///
+/// This code would attempt to link with `libmy_c_library.so` on unix-like systems and
+/// `my_c_library.dll` on Windows at runtime, and panic if it can't find something to link to. Rust
+/// code could then use `my_c_function` as if it were any other unsafe Rust function. Working with
+/// non-Rust languages and FFI is inherently unsafe, so wrappers are usually built around C APIs.
+///
+/// The mirror use case of FFI is also done via the `extern` keyword:
+///
+/// ```rust
+/// #[no_mangle]
+/// pub extern fn callable_from_c(x: i32) -> bool {
+/// x % 3 == 0
+/// }
+/// ```
+///
+/// If compiled as a dylib, the resulting .so could then be linked to from a C library, and the
+/// function could be used as if it was from any other library.
+///
+/// For more information on FFI, check the [Rust book] or the [Reference].
+///
+/// [Rust book]:
+/// https://doc.rust-lang.org/book/second-edition/ch19-01-unsafe-rust.html#using-extern-functions-to-call-external-code
+/// [Reference]: https://doc.rust-lang.org/reference/items/external-blocks.html
+mod extern_keyword { }
+
#[doc(keyword = "fn")]
//
-/// The `fn` keyword.
+/// The keyword for defining functions.
///
-/// The `fn` keyword is used to declare a function.
+/// Functions are the primary way code is executed within Rust. Function blocks, usually just
+/// called functions, can be defined in a variety of different places and be assigned many
+/// different attributes and modifiers.
///
-/// Example:
+/// Standalone functions that just sit within a module not attached to anything else are common,
+/// but most functions will end up being inside [`impl`] blocks, either on another type itself, or
+/// as a trait impl for that type.
///
/// ```rust
-/// fn some_function() {
-/// // code goes in here
+/// fn standalone_function() {
+/// // code
+/// }
+///
+/// pub fn public_thing(argument: bool) -> String {
+/// // code
+/// # "".to_string()
+/// }
+///
+/// struct Thing {
+/// foo: i32,
+/// }
+///
+/// impl Thing {
+/// pub fn new() -> Self {
+/// Self {
+/// foo: 42,
+/// }
+/// }
/// }
/// ```
///
-/// For more information about functions, take a look at the [Rust Book][book].
+/// In addition to presenting fixed types in the form of `fn name(arg: type, ..) -> return_type`,
+/// functions can also declare a list of type parameters along with trait bounds that they fall
+/// into.
///
-/// [book]: https://doc.rust-lang.org/book/second-edition/ch03-03-how-functions-work.html
+/// ```rust
+/// fn generic_function<T: Clone>(x: T) -> (T, T, T) {
+/// (x.clone(), x.clone(), x.clone())
+/// }
+///
+/// fn generic_where<T>(x: T) -> T
+/// where T: std::ops::Add<Output=T> + Copy
+/// {
+/// x + x + x
+/// }
+/// ```
+///
+/// Declaring trait bounds in the angle brackets is functionally identical to using a `where`
+/// clause. It's up to the programmer to decide which works better in each situation, but `where`
+/// tends to be better when things get longer than one line.
+///
+/// Along with being made public via `pub`, `fn` can also have an [`extern`] added for use in
+/// FFI.
+///
+/// For more information on the various types of functions and how they're used, consult the [Rust
+/// book] or the [Reference].
+///
+/// [`impl`]: keyword.impl.html
+/// [`extern`]: keyword.extern.html
+/// [Rust book]: https://doc.rust-lang.org/book/second-edition/ch03-03-how-functions-work.html
+/// [Reference]: https://doc.rust-lang.org/reference/items/functions.html
mod fn_keyword { }
-#[doc(keyword = "let")]
+#[doc(keyword = "for")]
//
-/// The `let` keyword.
+/// The `for` keyword.
+///
+/// `for` is primarily used in for-in-loops, but it has a few other pieces of syntactic uses such as
+/// `impl Trait for Type` (see [`impl`] for more info on that). for-in-loops, or to be more
+/// precise, iterator loops, are a simple syntactic sugar over an exceedingly common practice
+/// within Rust, which is to loop over an iterator until that iterator returns None (or `break`
+/// is called).
+///
+/// ```rust
+/// for i in 0..5 {
+/// println!("{}", i * 2);
+/// }
///
-/// The `let` keyword is used to declare a variable.
+/// for i in std::iter::repeat(5) {
+/// println!("turns out {} never stops being 5", i);
+/// break; // would loop forever otherwise
+/// }
///
-/// Example:
+/// 'outer: for x in 5..50 {
+/// for y in 0..10 {
+/// if x == y {
+/// break 'outer;
+/// }
+/// }
+/// }
+/// ```
+///
+/// As shown in the example above, `for` loops (along with all other loops) can be tagged, using
+/// similar syntax to lifetimes (only visually similar, entirely distinct in practice). Giving the
+/// same tag to `break` breaks the tagged loop, which is useful for inner loops. It is definitely
+/// not a goto.
+///
+/// A `for` loop expands as shown:
///
/// ```rust
-/// # #![allow(unused_assignments)]
-/// let x = 3; // We create a variable named `x` with the value `3`.
+/// # fn code() { }
+/// # let iterator = 0..2;
+/// for loop_variable in iterator {
+/// code()
+/// }
+/// ```
+///
+/// ```rust
+/// # fn code() { }
+/// # let iterator = 0..2;
+/// {
+/// let mut _iter = std::iter::IntoIterator::into_iter(iterator);
+/// loop {
+/// match _iter.next() {
+/// Some(loop_variable) => {
+/// code()
+/// },
+/// None => break,
+/// }
+/// }
+/// }
+/// ```
+///
+/// More details on the functionality shown can be seen at the [`IntoIterator`] docs.
+///
+/// For more information on for-loops, see the [Rust book] or the [Reference].
+///
+/// [`impl`]: keyword.impl.html
+/// [`IntoIterator`]: iter/trait.IntoIterator.html
+/// [Rust book]:
+/// https://doc.rust-lang.org/book/2018-edition/ch03-05-control-flow.html#looping-through-a-collection-with-for
+/// [Reference]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#iterator-loops
+mod for_keyword { }
+
+#[doc(keyword = "if")]
+//
+/// If statements and expressions.
+///
+/// `if` is a familiar construct to most programmers, and is the main way you'll often do logic in
+/// your code. However, unlike in most languages, `if` blocks can also act as expressions.
+///
+/// ```rust
+/// # let rude = true;
+/// if 1 == 2 {
+/// println!("whoops, mathematics broke");
+/// } else {
+/// println!("everything's fine!");
+/// }
+///
+/// let greeting = if rude {
+/// "sup nerd."
+/// } else {
+/// "hello, friend!"
+/// };
+///
+/// if let Ok(x) = "123".parse::<i32>() {
+/// println!("{} double that and you get {}!", greeting, x * 2);
+/// }
+/// ```
+///
+/// Shown above are the three typical forms an `if` block comes in. First is the usual kind of
+/// thing you'd see in many languages, with an optional `else` block. Second uses `if` as an
+/// expression, which is only possible if all branches return the same type. An `if` expression can
+/// be used everywhere you'd expect. The third kind of `if` block is an `if let` block, which
+/// behaves similarly to using a `match` expression:
+///
+/// ```rust
+/// if let Some(x) = Some(123) {
+/// // code
+/// # let _ = x;
+/// } else {
+/// // something else
+/// }
+///
+/// match Some(123) {
+/// Some(x) => {
+/// // code
+/// # let _ = x;
+/// },
+/// _ => {
+/// // something else
+/// },
+/// }
+/// ```
+///
+/// Each kind of `if` expression can be mixed and matched as needed.
+///
+/// ```rust
+/// if true == false {
+/// println!("oh no");
+/// } else if "something" == "other thing" {
+/// println!("oh dear");
+/// } else if let Some(200) = "blarg".parse::<i32>().ok() {
+/// println!("uh oh");
+/// } else {
+/// println!("phew, nothing's broken");
+/// }
+/// ```
+///
+/// The `if` keyword is used in one other place in Rust, namely as a part of pattern matching
+/// itself, allowing patterns such as `Some(x) if x > 200` to be used.
+///
+/// For more information on `if` expressions, see the [Rust book] or the [Reference].
+///
+/// [Rust book]:
+/// https://doc.rust-lang.org/stable/book/2018-edition/ch03-05-control-flow.html#if-expressions
+/// [Reference]: https://doc.rust-lang.org/reference/expressions/if-expr.html
+mod if_keyword { }
+
+#[doc(keyword = "impl")]
+//
+/// The implementation-defining keyword.
+///
+/// The `impl` keyword is primarily used to define implementations on types. Inherent
+/// implementations are standalone, while trait implementations are used to implement traits for
+/// types, or other traits.
+///
+/// Functions and consts can both be defined in an implementation. A function defined in an
+/// `impl` block can be standalone, meaning it would be called like `Foo::bar()`. If the function
+/// takes `self`, `&self`, or `&mut self` as its first argument, it can also be called using
+/// method-call syntax, a familiar feature to any object oriented programmer, like `foo.bar()`.
+///
+/// ```rust
+/// struct Example {
+/// number: i32,
+/// }
+///
+/// impl Example {
+/// fn boo() {
+/// println!("boo! Example::boo() was called!");
+/// }
+///
+/// fn answer(&mut self) {
+/// self.number += 42;
+/// }
+///
+/// fn get_number(&self) -> i32 {
+/// self.number
+/// }
+/// }
+///
+/// trait Thingy {
+/// fn do_thingy(&self);
+/// }
+///
+/// impl Thingy for Example {
+/// fn do_thingy(&self) {
+/// println!("doing a thing! also, number is {}!", self.number);
+/// }
+/// }
/// ```
///
-/// By default, all variables are **not** mutable. If you want a mutable variable,
-/// you'll have to use the `mut` keyword.
+/// For more information on implementations, see the [Rust book][book1] or the [Reference].
///
-/// Example:
+/// The other use of the `impl` keyword is in `impl Trait` syntax, which can be seen as a shorthand
+/// for "a concrete type that implements this trait". Its primary use is working with closures,
+/// which have type definitions generated at compile time that can't be simply typed out.
+///
+/// ```rust
+/// fn thing_returning_closure() -> impl Fn(i32) -> bool {
+/// println!("here's a closure for you!");
+/// |x: i32| x % 3 == 0
+/// }
+/// ```
+///
+/// For more information on `impl Trait` syntax, see the [Rust book][book2].
+///
+/// [book1]: https://doc.rust-lang.org/stable/book/2018-edition/ch05-03-method-syntax.html
+/// [Reference]: https://doc.rust-lang.org/reference/items/implementations.html
+/// [book2]:
+/// https://doc.rust-lang.org/stable/book/2018-edition/ch10-02-traits.html#returning-traits
+mod impl_keyword { }
+
+#[doc(keyword = "let")]
+//
+/// The variable binding keyword.
+///
+/// The primary use for the `let` keyword is in `let` statements, which are used to introduce a new
+/// set of variables into the current scope, as given by a pattern.
///
/// ```rust
/// # #![allow(unused_assignments)]
-/// let mut x = 3; // We create a mutable variable named `x` with the value `3`.
+/// let thing1: i32 = 100;
+/// let thing2 = 200 + thing1;
+///
+/// let mut changing_thing = true;
+/// changing_thing = false;
///
-/// x += 4; // `x` is now equal to `7`.
+/// let (part1, part2) = ("first", "second");
+///
+/// struct Example {
+/// a: bool,
+/// b: u64,
+/// }
+///
+/// let Example { a, b: _ } = Example {
+/// a: true,
+/// b: 10004,
+/// };
+/// assert!(a);
+/// ```
+///
+/// The pattern is most commonly a single variable, which means no pattern matching is done and
+/// the expression given is bound to the variable. Apart from that, patterns used in `let` bindings
+/// can be as complicated as needed, given that the pattern is exhaustive. See the [Rust
+/// book][book1] for more information on pattern matching. The type of the pattern is optionally
+/// given afterwards, but if left blank is automatically inferred by the compiler if possible.
+///
+/// Variables in Rust are immutable by default, and require the `mut` keyword to be made mutable.
+///
+/// Multiple variables can be defined with the same name, known as shadowing. This doesn't affect
+/// the original variable in any way beyond being unable to directly access it beyond the point of
+/// shadowing. It continues to remain in scope, getting dropped only when it falls out of scope.
+/// Shadowed variables don't need to have the same type as the variables shadowing them.
+///
+/// ```rust
+/// let shadowing_example = true;
+/// let shadowing_example = 123.4;
+/// let shadowing_example = shadowing_example as u32;
+/// let mut shadowing_example = format!("cool! {}", shadowing_example);
+/// shadowing_example += " something else!"; // not shadowing
/// ```
///
-/// For more information about the `let` keyword, take a look at the [Rust Book][book].
+/// Other places the `let` keyword is used include along with [`if`], in the form of `if let`
+/// expressions. They're useful if the pattern being matched isn't exhaustive, such as with
+/// enumerations. `while let` also exists, which runs a loop with a pattern matched value until
+/// that pattern can't be matched.
///
-/// [book]: https://doc.rust-lang.org/book/second-edition/ch03-01-variables-and-mutability.html
+/// For more information on the `let` keyword, see the [Rust book] or the [Reference]
+///
+/// [book1]: https://doc.rust-lang.org/stable/book/2018-edition/ch06-02-match.html
+/// [`if`]: keyword.if.html
+/// [book2]:
+/// https://doc.rust-lang.org/stable/book/2018-edition/ch18-01-all-the-places-for-patterns.html#let-statements
+/// [Reference]: https://doc.rust-lang.org/reference/statements.html#let-statements
mod let_keyword { }
-#[doc(keyword = "struct")]
+#[doc(keyword = "loop")]
//
-/// The `struct` keyword.
+/// The loop-defining keyword.
///
-/// The `struct` keyword is used to define a struct type.
+/// `loop` is used to define the simplest kind of loop supported in Rust. It runs the code inside
+/// it until the code uses `break` or the program exits.
///
-/// Example:
+/// ```rust
+/// loop {
+/// println!("hello world forever!");
+/// # break;
+/// }
///
+/// let mut i = 0;
+/// loop {
+/// println!("i is {}", i);
+/// if i > 10 {
+/// break;
+/// }
+/// i += 1;
+/// }
/// ```
-/// struct Foo {
-/// field1: u32,
+///
+/// Unlike the other kinds of loops in Rust (`while`, `while let`, and `for`), loops can be used as
+/// expressions that return values via `break`.
+///
+/// ```rust
+/// let mut i = 1;
+/// let something = loop {
+/// i *= 2;
+/// if i > 100 {
+/// break i;
+/// }
+/// };
+/// assert_eq!(something, 128);
+/// ```
+///
+/// Every `break` in a loop has to have the same type. When it's not explicitly giving something,
+/// `break;` returns `()`.
+///
+/// For more information on `loop` and loops in general, see the [Reference].
+///
+/// [Reference]: https://doc.rust-lang.org/reference/expressions/loop-expr.html
+mod loop_keyword { }
+
+#[doc(keyword = "struct")]
+//
+/// The keyword used to define structs.
+///
+/// Structs in Rust come in three flavours: Structs with named fields, tuple structs, and unit
+/// structs.
+///
+/// ```rust
+/// struct Regular {
+/// field1: f32,
/// field2: String,
+/// pub field3: bool
+/// }
+///
+/// struct Tuple(u32, String);
+///
+/// struct Unit;
+/// ```
+///
+/// Regular structs are the most commonly used. Each field defined within them has a name and a
+/// type, and once defined can be accessed using `example_struct.field` syntax. The fields of a
+/// struct share its mutability, so `foo.bar = 2;` would only be valid if `foo` was mutable. Adding
+/// `pub` to a field makes it visible to code in other modules, as well as allowing it to be
+/// directly accessed and modified.
+///
+/// Tuple structs are similar to regular structs, but its fields have no names. They are used like
+/// tuples, with deconstruction possible via `let TupleStruct(x, y) = foo;` syntax. For accessing
+/// individual variables, the same syntax is used as with regular tuples, namely `foo.0`, `foo.1`,
+/// etc, starting at zero.
+///
+/// Unit structs are most commonly used as marker. They have a size of zero bytes, but unlike empty
+/// enums they can be instantiated, making them isomorphic to the unit type `()`. Unit structs are
+/// useful when you need to implement a trait on something, but don't need to store any data inside
+/// it.
+///
+/// # Instantiation
+///
+/// Structs can be instantiated in different ways, all of which can be mixed and
+/// matched as needed. The most common way to make a new struct is via a constructor method such as
+/// `new()`, but when that isn't available (or you're writing the constructor itself), struct
+/// literal syntax is used:
+///
+/// ```rust
+/// # struct Foo { field1: f32, field2: String, etc: bool }
+/// let example = Foo {
+/// field1: 42.0,
+/// field2: "blah".to_string(),
+/// etc: true,
+/// };
+/// ```
+///
+/// It's only possible to directly instantiate a struct using struct literal syntax when all of its
+/// fields are visible to you.
+///
+/// There are a handful of shortcuts provided to make writing constructors more convenient, most
+/// common of which is the Field Init shorthand. When there is a variable and a field of the same
+/// name, the assignment can be simplified from `field: field` into simply `field`. The following
+/// example of a hypothetical constructor demonstrates this:
+///
+/// ```rust
+/// struct User {
+/// name: String,
+/// admin: bool,
+/// }
+///
+/// impl User {
+/// pub fn new(name: String) -> Self {
+/// Self {
+/// name,
+/// admin: false,
+/// }
+/// }
/// }
/// ```
///
-/// There are different kinds of structs. For more information, take a look at the
-/// [Rust Book][book].
+/// Another shortcut for struct instantiation is available, used when you need to make a new
+/// struct that has the same values as most of a previous struct of the same type, called struct
+/// update syntax:
+///
+/// ```rust
+/// # struct Foo { field1: String, field2: () }
+/// # let thing = Foo { field1: "".to_string(), field2: () };
+/// let updated_thing = Foo {
+/// field1: "a new value".to_string(),
+/// ..thing
+/// };
+/// ```
+///
+/// Tuple structs are instantiated in the same way as tuples themselves, except with the struct's
+/// name as a prefix: `Foo(123, false, 0.1)`.
+///
+/// Empty structs are instantiated with just their name, and don't need anything else. `let thing =
+/// EmptyStruct;`
+///
+/// # Style conventions
+///
+/// Structs are always written in CamelCase, with few exceptions. While the trailing comma on a
+/// struct's list of fields can be omitted, it's usually kept for convenience in adding and
+/// removing fields down the line.
+///
+/// For more information on structs, take a look at the [Rust Book][book] or the
+/// [Reference][reference].
///
+/// [`PhantomData`]: marker/struct.PhantomData.html
/// [book]: https://doc.rust-lang.org/book/second-edition/ch05-01-defining-structs.html
+/// [reference]: https://doc.rust-lang.org/reference/items/structs.html
mod struct_keyword { }
/// use std::io::prelude::*;
/// use std::net::TcpStream;
///
-/// {
-/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap();
+/// fn main() -> std::io::Result<()> {
+/// let mut stream = TcpStream::connect("127.0.0.1:34254")?;
///
-/// // ignore the Result
-/// let _ = stream.write(&[1]);
-/// let _ = stream.read(&mut [0; 128]); // ignore here too
+/// stream.write(&[1])?;
+/// stream.read(&mut [0; 128])?;
+/// Ok(())
/// } // the stream is closed here
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
/// let s = String::from("love: ❤️");
/// let v: Vec<char> = s.chars().collect();
///
-/// assert_eq!(12, s.len() * std::mem::size_of::<u8>());
-/// assert_eq!(32, v.len() * std::mem::size_of::<char>());
+/// assert_eq!(12, std::mem::size_of_val(&s[..]));
+/// assert_eq!(32, std::mem::size_of_val(&v[..]));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_char { }
#[stable(feature = "stdio_from", since = "1.20.0")]
impl From<ChildStdin> for Stdio {
+ /// Converts a `ChildStdin` into a `Stdio`
+ ///
+ /// # Examples
+ ///
+ /// `ChildStdin` will be converted to `Stdio` using `Stdio::from` under the hood.
+ ///
+ /// ```rust
+ /// use std::process::{Command, Stdio};
+ ///
+ /// let reverse = Command::new("rev")
+ /// .stdin(Stdio::piped())
+ /// .spawn()
+ /// .expect("failed reverse command");
+ ///
+ /// let _echo = Command::new("echo")
+ /// .arg("Hello, world!")
+ /// .stdout(reverse.stdin.unwrap()) // Converted into a Stdio here
+ /// .output()
+ /// .expect("failed echo command");
+ ///
+ /// // "!dlrow ,olleH" echoed to console
+ /// ```
fn from(child: ChildStdin) -> Stdio {
Stdio::from_inner(child.into_inner().into())
}
#[stable(feature = "stdio_from", since = "1.20.0")]
impl From<ChildStdout> for Stdio {
+ /// Converts a `ChildStdout` into a `Stdio`
+ ///
+ /// # Examples
+ ///
+ /// `ChildStdout` will be converted to `Stdio` using `Stdio::from` under the hood.
+ ///
+ /// ```rust
+ /// use std::process::{Command, Stdio};
+ ///
+ /// let hello = Command::new("echo")
+ /// .arg("Hello, world!")
+ /// .stdout(Stdio::piped())
+ /// .spawn()
+ /// .expect("failed echo command");
+ ///
+ /// let reverse = Command::new("rev")
+ /// .stdin(hello.stdout.unwrap()) // Converted into a Stdio here
+ /// .output()
+ /// .expect("failed reverse command");
+ ///
+ /// assert_eq!(reverse.stdout, b"!dlrow ,olleH\n");
+ /// ```
fn from(child: ChildStdout) -> Stdio {
Stdio::from_inner(child.into_inner().into())
}
#[stable(feature = "stdio_from", since = "1.20.0")]
impl From<ChildStderr> for Stdio {
+ /// Converts a `ChildStderr` into a `Stdio`
+ ///
+ /// # Examples
+ ///
+ /// ```rust,no_run
+ /// use std::process::{Command, Stdio};
+ ///
+ /// let reverse = Command::new("rev")
+ /// .arg("non_existing_file.txt")
+ /// .stderr(Stdio::piped())
+ /// .spawn()
+ /// .expect("failed reverse command");
+ ///
+ /// let cat = Command::new("cat")
+ /// .arg("-")
+ /// .stdin(reverse.stderr.unwrap()) // Converted into a Stdio here
+ /// .output()
+ /// .expect("failed echo command");
+ ///
+ /// assert_eq!(
+ /// String::from_utf8_lossy(&cat.stdout),
+ /// "rev: cannot open non_existing_file.txt: No such file or directory\n"
+ /// );
+ /// ```
fn from(child: ChildStderr) -> Stdio {
Stdio::from_inner(child.into_inner().into())
}
#[stable(feature = "stdio_from", since = "1.20.0")]
impl From<fs::File> for Stdio {
+ /// Converts a `File` into a `Stdio`
+ ///
+ /// # Examples
+ ///
+ /// `File` will be converted to `Stdio` using `Stdio::from` under the hood.
+ ///
+ /// ```rust,no_run
+ /// use std::fs::File;
+ /// use std::process::Command;
+ ///
+ /// // With the `foo.txt` file containing `Hello, world!"
+ /// let file = File::open("foo.txt").unwrap();
+ ///
+ /// let reverse = Command::new("rev")
+ /// .stdin(file) // Implicit File convertion into a Stdio
+ /// .output()
+ /// .expect("failed reverse command");
+ ///
+ /// assert_eq!(reverse.stdout, b"!dlrow ,olleH");
+ /// ```
fn from(file: fs::File) -> Stdio {
Stdio::from_inner(file.into_inner().into())
}
//! - A **multiprocessor** system executing multiple hardware threads
//! at the same time: In multi-threaded scenarios, you can use two
//! kinds of primitives to deal with synchronization:
-//! - [memory fences] to ensure memory accesses are made visibile to
+//! - [memory fences] to ensure memory accesses are made visible to
//! other CPUs in the right order.
//! - [atomic operations] to ensure simultaneous access to the same
//! memory location doesn't lead to undefined behavior.
}
/// Returns true if some `call_once` call has completed
- /// successfuly. Specifically, `is_completed` will return false in
- /// the following situtations:
+ /// successfully. Specifically, `is_completed` will return false in
+ /// the following situations:
/// * `call_once` was not called at all,
/// * `call_once` was called, but has not yet completed,
/// * the `Once` instance is poisoned
/// The identifier portion of this path segment.
pub ident: Ident,
+ pub id: NodeId,
+
/// Type/lifetime parameters attached to this path. They come in
/// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`.
/// `None` means that no parameter list is supplied (`Path`),
impl PathSegment {
pub fn from_ident(ident: Ident) -> Self {
- PathSegment { ident, args: None }
+ PathSegment { ident, id: DUMMY_NODE_ID, args: None }
}
pub fn crate_root(span: Span) -> Self {
PathSegment::from_ident(Ident::new(keywords::CrateRoot.name(), span))
/// when the configuration predicate is true, or otherwise expand into an
/// empty list of attributes.
///
- /// Gives a compiler warning when the `cfg_attr` contains no attribtes and
+ /// Gives a compiler warning when the `cfg_attr` contains no attributes and
/// is in the original source file. Gives a compiler error if the syntax of
/// the attribute is incorrect
fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec<ast::Attribute> {
};
// Check feature gate and lint on zero attributes in source. Even if the feature is gated,
- // we still compute as if it wasn't, since the emitted error will stop compilation futher
+ // we still compute as if it wasn't, since the emitted error will stop compilation further
// along the compilation.
match (expanded_attrs.len(), gate_cfg_attr_multi) {
(0, false) => {
/// Represents a thing that maps token trees to Macro Results
pub trait TTMacroExpander {
- fn expand<'cx>(&self, ecx: &'cx mut ExtCtxt, span: Span, input: TokenStream)
- -> Box<dyn MacResult+'cx>;
+ fn expand<'cx>(
+ &self,
+ ecx: &'cx mut ExtCtxt,
+ span: Span,
+ input: TokenStream,
+ def_span: Option<Span>,
+ ) -> Box<dyn MacResult+'cx>;
}
pub type MacroExpanderFn =
where F: for<'cx> Fn(&'cx mut ExtCtxt, Span, &[tokenstream::TokenTree])
-> Box<dyn MacResult+'cx>
{
- fn expand<'cx>(&self, ecx: &'cx mut ExtCtxt, span: Span, input: TokenStream)
- -> Box<dyn MacResult+'cx> {
+ fn expand<'cx>(
+ &self,
+ ecx: &'cx mut ExtCtxt,
+ span: Span,
+ input: TokenStream,
+ _def_span: Option<Span>,
+ ) -> Box<dyn MacResult+'cx> {
struct AvoidInterpolatedIdents;
impl Folder for AvoidInterpolatedIdents {
} else {
None
};
- segments.push(ast::PathSegment { ident: last_ident.with_span_pos(span), args });
+ segments.push(ast::PathSegment {
+ ident: last_ident.with_span_pos(span),
+ id: ast::DUMMY_NODE_ID,
+ args,
+ });
let mut path = ast::Path { span, segments };
if global {
if let Some(seg) = path.make_root() {
} else {
None
};
- path.segments.push(ast::PathSegment { ident, args });
+ path.segments.push(ast::PathSegment { ident, id: ast::DUMMY_NODE_ID, args });
(ast::QSelf {
ty: self_type,
edition) {
dummy_span
} else {
- kind.make_from(expander.expand(self.cx, span, mac.node.stream()))
+ kind.make_from(expander.expand(self.cx, span, mac.node.stream(), None))
}
}
edition) {
dummy_span
} else {
- kind.make_from(expander.expand(self.cx, span, mac.node.stream()))
+ kind.make_from(expander.expand(
+ self.cx,
+ span,
+ mac.node.stream(),
+ def_info.map(|(_, s)| s),
+ ))
}
}
// Avoid emitting backtrace info twice.
let def_site_span = self.span.with_ctxt(SyntaxContext::empty());
let mut err = self.diagnostic().struct_span_err(def_site_span, &msg);
- let msg = format!("caused by the macro expansion here; the usage \
- of `{}!` is likely invalid in {} context",
- macro_path, kind_name);
- err.span_note(span, &msg).emit();
+ err.span_label(span, "caused by the macro expansion here");
+ let msg = format!(
+ "the usage of `{}!` is likely invalid in {} context",
+ macro_path,
+ kind_name,
+ );
+ err.note(&msg);
+ let semi_span = self.sess.source_map().next_point(span);
+
+ let semi_full_span = semi_span.to(self.sess.source_map().next_point(semi_span));
+ match self.sess.source_map().span_to_snippet(semi_full_span) {
+ Ok(ref snippet) if &snippet[..] != ";" && kind_name == "expression" => {
+ err.span_suggestion_with_applicability(
+ semi_span,
+ "you might be missing a semicolon here",
+ ";".to_owned(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ _ => {}
+ }
+ err.emit();
}
}
}
impl<'a> ParserAnyMacro<'a> {
pub fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
let ParserAnyMacro { site_span, macro_ident, ref mut parser } = *self;
- let fragment = panictry!(parser.parse_ast_fragment(kind, true));
+ let fragment = panictry!(parser.parse_ast_fragment(kind, true).map_err(|mut e| {
+ if e.span.is_dummy() { // Get around lack of span in error (#30128)
+ e.set_span(site_span);
+ }
+ e
+ }));
// We allow semicolons at the end of expressions -- e.g. the semicolon in
// `macro_rules! m { () => { panic!(); } }` isn't parsed by `.parse_expr()`,
}
impl TTMacroExpander for MacroRulesMacroExpander {
- fn expand<'cx>(&self,
- cx: &'cx mut ExtCtxt,
- sp: Span,
- input: TokenStream)
- -> Box<dyn MacResult+'cx> {
+ fn expand<'cx>(
+ &self,
+ cx: &'cx mut ExtCtxt,
+ sp: Span,
+ input: TokenStream,
+ def_span: Option<Span>,
+ ) -> Box<dyn MacResult+'cx> {
if !self.valid {
return DummyResult::any(sp);
}
generic_extension(cx,
sp,
+ def_span,
self.name,
input,
&self.lhses,
/// Given `lhses` and `rhses`, this is the new macro we create
fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
sp: Span,
+ def_span: Option<Span>,
name: ast::Ident,
arg: TokenStream,
lhses: &[quoted::TokenTree],
}
let best_fail_msg = parse_failure_msg(best_fail_tok.expect("ran no matchers"));
- let mut err = cx.struct_span_err(best_fail_spot.substitute_dummy(sp), &best_fail_msg);
+ let span = best_fail_spot.substitute_dummy(sp);
+ let mut err = cx.struct_span_err(span, &best_fail_msg);
+ err.span_label(span, best_fail_msg);
+ if let Some(sp) = def_span {
+ if cx.source_map().span_to_filename(sp).is_real() && !sp.is_dummy() {
+ err.span_label(cx.source_map().def_span(sp), "when calling this macro");
+ }
+ }
// Check whether there's a missing comma in this macro call, like `println!("{}" a);`
if let Some((arg, comma_span)) = arg.add_comma() {
};
match TokenTree::parse(cx, lhs_tt, arg.clone()) {
Success(_) => {
- if comma_span == DUMMY_SP {
+ if comma_span.is_dummy() {
err.note("you might be missing a comma");
} else {
err.span_suggestion_short_with_applicability(
if let TokenTree::MetaVarDecl(_, ref name, ref frag_spec) = *token {
for next_token in &suffix_first.tokens {
match is_in_follow(next_token, &frag_spec.as_str()) {
- Err((msg, help)) => {
+ IsInFollow::Invalid(msg, help) => {
sess.span_diagnostic.struct_span_err(next_token.span(), &msg)
.help(help).emit();
// don't bother reporting every source of
// conflict for a particular element of `last`.
continue 'each_last;
}
- Ok(true) => {}
- Ok(false) => {
+ IsInFollow::Yes => {}
+ IsInFollow::No(ref possible) => {
let may_be = if last.tokens.len() == 1 &&
suffix_first.tokens.len() == 1
{
"may be"
};
- sess.span_diagnostic.span_err(
- next_token.span(),
+ let sp = next_token.span();
+ let mut err = sess.span_diagnostic.struct_span_err(
+ sp,
&format!("`${name}:{frag}` {may_be} followed by `{next}`, which \
is not allowed for `{frag}` fragments",
name=name,
frag=frag_spec,
next=quoted_tt_to_string(next_token),
- may_be=may_be)
+ may_be=may_be),
);
+ err.span_label(
+ sp,
+ format!("not allowed after `{}` fragments", frag_spec),
+ );
+ let msg = "allowed there are: ";
+ match &possible[..] {
+ &[] => {}
+ &[t] => {
+ err.note(&format!(
+ "only {} is allowed after `{}` fragments",
+ t,
+ frag_spec,
+ ));
+ }
+ ts => {
+ err.note(&format!(
+ "{}{} or {}",
+ msg,
+ ts[..ts.len() - 1].iter().map(|s| *s)
+ .collect::<Vec<_>>().join(", "),
+ ts[ts.len() - 1],
+ ));
+ }
+ }
+ err.emit();
}
}
}
}
}
+enum IsInFollow {
+ Yes,
+ No(Vec<&'static str>),
+ Invalid(String, &'static str),
+}
+
/// True if `frag` can legally be followed by the token `tok`. For
/// fragments that can consume an unbounded number of tokens, `tok`
/// must be within a well-defined follow set. This is intended to
/// 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: "ed::TokenTree, frag: &str) -> Result<bool, (String, &'static str)> {
+fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> IsInFollow {
use self::quoted::TokenTree;
if let TokenTree::Token(_, token::CloseDelim(_)) = *tok {
// closing a token tree can never be matched by any fragment;
// iow, we always require that `(` and `)` match, etc.
- Ok(true)
+ IsInFollow::Yes
} else {
match frag {
"item" => {
// since items *must* be followed by either a `;` or a `}`, we can
// accept anything after them
- Ok(true)
+ IsInFollow::Yes
},
"block" => {
// anything can follow block, the braces provide an easy boundary to
// maintain
- Ok(true)
+ IsInFollow::Yes
},
- "stmt" | "expr" => match *tok {
- TokenTree::Token(_, ref tok) => match *tok {
- FatArrow | Comma | Semi => Ok(true),
- _ => Ok(false)
- },
- _ => Ok(false),
+ "stmt" | "expr" => {
+ let tokens = vec!["`=>`", "`,`", "`;`"];
+ match *tok {
+ TokenTree::Token(_, ref tok) => match *tok {
+ FatArrow | Comma | Semi => IsInFollow::Yes,
+ _ => IsInFollow::No(tokens),
+ },
+ _ => IsInFollow::No(tokens),
+ }
},
- "pat" => match *tok {
- TokenTree::Token(_, ref tok) => match *tok {
- FatArrow | Comma | Eq | BinOp(token::Or) => Ok(true),
- Ident(i, false) if i.name == "if" || i.name == "in" => Ok(true),
- _ => Ok(false)
- },
- _ => Ok(false),
+ "pat" => {
+ let tokens = vec!["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"];
+ match *tok {
+ TokenTree::Token(_, ref tok) => match *tok {
+ FatArrow | Comma | Eq | BinOp(token::Or) => IsInFollow::Yes,
+ Ident(i, false) if i.name == "if" || i.name == "in" => IsInFollow::Yes,
+ _ => IsInFollow::No(tokens),
+ },
+ _ => IsInFollow::No(tokens),
+ }
},
- "path" | "ty" => match *tok {
- TokenTree::Token(_, ref tok) => match *tok {
- OpenDelim(token::DelimToken::Brace) | OpenDelim(token::DelimToken::Bracket) |
- Comma | FatArrow | Colon | Eq | Gt | Semi | BinOp(token::Or) => Ok(true),
- Ident(i, false) if i.name == "as" || i.name == "where" => Ok(true),
- _ => Ok(false)
- },
- TokenTree::MetaVarDecl(_, _, frag) if frag.name == "block" => Ok(true),
- _ => Ok(false),
+ "path" | "ty" => {
+ let tokens = vec![
+ "`{`", "`[`", "`=>`", "`,`", "`>`","`=`", "`:`", "`;`", "`|`", "`as`",
+ "`where`",
+ ];
+ match *tok {
+ TokenTree::Token(_, ref tok) => match *tok {
+ OpenDelim(token::DelimToken::Brace) |
+ OpenDelim(token::DelimToken::Bracket) |
+ Comma | FatArrow | Colon | Eq | Gt | BinOp(token::Shr) | Semi |
+ BinOp(token::Or) => IsInFollow::Yes,
+ Ident(i, false) if i.name == "as" || i.name == "where" => IsInFollow::Yes,
+ _ => IsInFollow::No(tokens),
+ },
+ TokenTree::MetaVarDecl(_, _, frag) if frag.name == "block" => IsInFollow::Yes,
+ _ => IsInFollow::No(tokens),
+ }
},
"ident" | "lifetime" => {
// being a single token, idents and lifetimes are harmless
- Ok(true)
+ IsInFollow::Yes
},
"literal" => {
// literals may be of a single token, or two tokens (negative numbers)
- Ok(true)
+ IsInFollow::Yes
},
"meta" | "tt" => {
// being either a single token or a delimited sequence, tt is
// harmless
- Ok(true)
+ IsInFollow::Yes
},
"vis" => {
// Explicitly disallow `priv`, on the off chance it comes back.
+ let tokens = vec!["`,`", "an ident", "a type"];
match *tok {
TokenTree::Token(_, ref tok) => match *tok {
- Comma => Ok(true),
- Ident(i, is_raw) if is_raw || i.name != "priv" => Ok(true),
- ref tok => Ok(tok.can_begin_type())
+ Comma => IsInFollow::Yes,
+ Ident(i, is_raw) if is_raw || i.name != "priv" => IsInFollow::Yes,
+ ref tok => if tok.can_begin_type() {
+ IsInFollow::Yes
+ } else {
+ IsInFollow::No(tokens)
+ }
},
TokenTree::MetaVarDecl(_, _, frag) if frag.name == "ident"
|| frag.name == "ty"
- || frag.name == "path" => Ok(true),
- _ => Ok(false)
+ || frag.name == "path" => IsInFollow::Yes,
+ _ => IsInFollow::No(tokens),
}
},
- "" => Ok(true), // keywords::Invalid
- _ => Err((format!("invalid fragment specifier `{}`", frag),
- VALID_FRAGMENT_NAMES_MSG))
+ "" => IsInFollow::Yes, // keywords::Invalid
+ _ => IsInFollow::Invalid(format!("invalid fragment specifier `{}`", frag),
+ VALID_FRAGMENT_NAMES_MSG),
}
}
}
// Allows `const _: TYPE = VALUE`
(active, underscore_const_names, "1.31.0", Some(54912), None),
+
+ // `extern crate foo as bar;` puts `bar` into extern prelude.
+ (active, extern_crate_item_prelude, "1.31.0", Some(54658), None),
);
declare_features! (
pub fn noop_fold_path<T: Folder>(Path { segments, span }: Path, fld: &mut T) -> Path {
Path {
- segments: segments.move_map(|PathSegment { ident, args }| PathSegment {
+ segments: segments.move_map(|PathSegment { ident, id, args }| PathSegment {
ident: fld.fold_ident(ident),
+ id: fld.new_id(id),
args: args.map(|args| args.map(|args| fld.fold_generic_args(args))),
}),
span: fld.new_span(span)
polarity,
defaultness,
folder.fold_generics(generics),
- ifce.map(|trait_ref| folder.fold_trait_ref(trait_ref.clone())),
+ ifce.map(|trait_ref| folder.fold_trait_ref(trait_ref)),
folder.fold_ty(ty),
impl_items.move_flat_map(|item| folder.fold_impl_item(item)),
),
ExprKind::MethodCall(
PathSegment {
ident: folder.fold_ident(seg.ident),
+ id: folder.new_id(seg.id),
args: seg.args.map(|args| {
args.map(|args| folder.fold_generic_args(args))
}),
ParenthesisedArgs { inputs, output, span }.into()
};
- PathSegment { ident, args }
+ PathSegment { ident, args, id: ast::DUMMY_NODE_ID }
} else {
// Generic arguments are not found.
PathSegment::from_ident(ident)
&self.primary_spans
}
+ /// Returns `true` if this contains only a dummy primary span with any hygienic context.
+ pub fn is_dummy(&self) -> bool {
+ let mut is_dummy = true;
+ for span in &self.primary_spans {
+ if !span.is_dummy() {
+ is_dummy = false;
+ }
+ }
+ is_dummy
+ }
+
/// Replaces all occurrences of one Span with another. Used to move Spans in areas that don't
/// display well (like std macros). Returns true if replacements occurred.
pub fn replace(&mut self, before: Span, after: Span) -> bool {
-Subproject commit 307650500de5b44dc1047dc9d15e449e09d92b57
+Subproject commit 431766a3fbcfb6dafb2d5a3866c1609bf44ee554
}
#[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="HirBody, TypeckTables")]
+#[rustc_clean(cfg="cfail2", except="HirBody, MirValidated, TypeckTables")]
#[rustc_clean(cfg="cfail3")]
pub fn add_type_ascription_to_parameter() {
let closure = |x: u32| x + 1u32;
// START rustc.main.SimplifyCfg-qualify-consts.after.mir
// let mut _0: ();
// ...
-// let _2: &'10_1rs i32;
+// let _2: &'11_1rs i32;
// ...
// let _1: i32;
// ...
// _1 = const 3i32;
// FakeRead(ForLet, _1);
// StorageLive(_2);
-// _2 = &'10_1rs _1;
+// _2 = &'11_1rs _1;
// FakeRead(ForLet, _2);
// _0 = ();
-// EndRegion('10_1rs);
+// EndRegion('11_1rs);
// StorageDead(_2);
// StorageDead(_1);
// return;
// START rustc.main.SimplifyCfg-qualify-consts.after.mir
// let mut _0: ();
// ...
-// let _7: &'23_3rs bool;
+// let _7: &'26_3rs bool;
// ...
-// let _3: &'23_1rs bool;
+// let _3: &'26_1rs bool;
// ...
// let _2: bool;
// ...
// _2 = const true;
// FakeRead(ForLet, _2);
// StorageLive(_3);
-// _3 = &'23_1rs _2;
+// _3 = &'26_1rs _2;
// FakeRead(ForLet, _3);
// StorageLive(_5);
// _5 = _2;
// bb4: {
// _0 = ();
// StorageDead(_5);
-// EndRegion('23_1rs);
+// EndRegion('26_1rs);
// StorageDead(_3);
// StorageDead(_2);
// return;
// _4 = ();
// StorageDead(_5);
// StorageLive(_7);
-// _7 = &'23_3rs _2;
+// _7 = &'26_3rs _2;
// FakeRead(ForLet, _7);
// _1 = ();
-// EndRegion('23_3rs);
+// EndRegion('26_3rs);
// StorageDead(_7);
-// EndRegion('23_1rs);
+// EndRegion('26_1rs);
// StorageDead(_3);
// StorageDead(_2);
// goto -> bb1;
// START rustc.main.SimplifyCfg-qualify-consts.after.mir
// let mut _0: ();
// ...
-// let _7: &'26_3rs bool;
+// let _7: &'30_3rs bool;
// ...
-// let _3: &'26_1rs bool;
+// let _3: &'30_1rs bool;
// ...
// let mut _1: bool;
// ...
// bb2: {
// _1 = const true;
// StorageLive(_3);
-// _3 = &'26_1rs _1;
+// _3 = &'30_1rs _1;
// FakeRead(ForLet, _3);
// StorageLive(_5);
// _5 = _1;
// bb4: {
// _0 = ();
// StorageDead(_5);
-// EndRegion('26_1rs);
+// EndRegion('30_1rs);
// StorageDead(_3);
// StorageDead(_1);
// return;
// _4 = ();
// StorageDead(_5);
// StorageLive(_7);
-// _7 = &'26_3rs _1;
+// _7 = &'30_3rs _1;
// FakeRead(ForLet, _7);
// _2 = ();
-// EndRegion('26_3rs);
+// EndRegion('30_3rs);
// StorageDead(_7);
-// EndRegion('26_1rs);
+// EndRegion('30_1rs);
// StorageDead(_3);
// goto -> bb1;
// }
// START rustc.main.SimplifyCfg-qualify-consts.after.mir
// let mut _0: ();
// ...
-// let _6: &'26_4rs i32;
+// let _6: &'31_4rs i32;
// ...
-// let _3: &'26_2rs i32;
+// let _3: &'31_2rs i32;
// ...
// let _2: i32;
// ...
// _2 = const 0i32;
// FakeRead(ForLet, _2);
// StorageLive(_3);
-// _3 = &'26_2rs _2;
+// _3 = &'31_2rs _2;
// FakeRead(ForLet, _3);
// StorageLive(_5);
// _5 = (*_3);
// bb2: {
// StorageDead(_5);
// StorageLive(_6);
-// _6 = &'26_4rs _2;
+// _6 = &'31_4rs _2;
// FakeRead(ForLet, _6);
// _0 = ();
-// EndRegion('26_4rs);
+// EndRegion('31_4rs);
// StorageDead(_6);
-// EndRegion('26_2rs);
+// EndRegion('31_2rs);
// StorageDead(_3);
// StorageDead(_2);
// drop(_1) -> [return: bb4, unwind: bb1];
// }
// bb3: {
-// EndRegion('26_2rs);
+// EndRegion('31_2rs);
// drop(_1) -> bb1;
// }
// bb4: {
// let _1: D;
// ...
// let mut _2: ();
-// let mut _3: [closure@NodeId(18) d:&'14s D];
-// let mut _4: &'14s D;
+// let mut _3: [closure@NodeId(28) d:&'18s D];
+// let mut _4: &'18s D;
// bb0: {
// StorageLive(_1);
// _1 = D::{{constructor}}(const 0i32,);
// FakeRead(ForLet, _1);
// StorageLive(_3);
// StorageLive(_4);
-// _4 = &'14s _1;
-// _3 = [closure@NodeId(18)] { d: move _4 };
+// _4 = &'18s _1;
+// _3 = [closure@NodeId(28)] { d: move _4 };
// StorageDead(_4);
// _2 = const foo(move _3) -> [return: bb2, unwind: bb3];
// }
// resume;
// }
// bb2: {
-// EndRegion('14s);
+// EndRegion('18s);
// StorageDead(_3);
// _0 = ();
// drop(_1) -> [return: bb4, unwind: bb1];
// }
// bb3: {
-// EndRegion('14s);
+// EndRegion('18s);
// drop(_1) -> bb1;
// }
// bb4: {
// END rustc.main.SimplifyCfg-qualify-consts.after.mir
// START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir
-// fn main::{{closure}}(_1: [closure@NodeId(18) d:&'14s D]) -> i32 {
+// fn main::{{closure}}(_1: [closure@NodeId(28) d:&'18s D]) -> i32 {
// let mut _0: i32;
//
// bb0: {
-// _0 = ((*(_1.0: &'14s D)).0: i32);
+// _0 = ((*(_1.0: &'18s D)).0: i32);
// return;
// }
// END rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir
// let _1: D;
// ...
// let mut _2: ();
-// let mut _3: [closure@NodeId(22) d:&'19s D];
-// let mut _4: &'19s D;
+// let mut _3: [closure@NodeId(33) d:&'24s D];
+// let mut _4: &'24s D;
// bb0: {
// StorageLive(_1);
// _1 = D::{{constructor}}(const 0i32,);
// FakeRead(ForLet, _1);
// StorageLive(_3);
// StorageLive(_4);
-// _4 = &'19s _1;
-// _3 = [closure@NodeId(22)] { d: move _4 };
+// _4 = &'24s _1;
+// _3 = [closure@NodeId(33)] { d: move _4 };
// StorageDead(_4);
// _2 = const foo(move _3) -> [return: bb2, unwind: bb3];
// }
// resume;
// }
// bb2: {
-// EndRegion('19s);
+// EndRegion('24s);
// StorageDead(_3);
// _0 = ();
// drop(_1) -> [return: bb4, unwind: bb1];
// }
// bb3: {
-// EndRegion('19s);
+// EndRegion('24s);
// drop(_1) -> bb1;
// }
// bb4: {
// END rustc.main.SimplifyCfg-qualify-consts.after.mir
// START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir
-// fn main::{{closure}}(_1: [closure@NodeId(22) d:&'19s D]) -> i32 {
+// fn main::{{closure}}(_1: [closure@NodeId(33) d:&'24s D]) -> i32 {
// let mut _0: i32;
// ...
-// let _2: &'16_0rs D;
+// let _2: &'21_0rs D;
// ...
// bb0: {
// StorageLive(_2);
-// _2 = &'16_0rs (*(_1.0: &'19s D));
+// _2 = &'21_0rs (*(_1.0: &'24s D));
// FakeRead(ForLet, _2);
// _0 = ((*_2).0: i32);
-// EndRegion('16_0rs);
+// EndRegion('21_0rs);
// StorageDead(_2);
// return;
// }
// let _1: D;
// ...
// let mut _2: ();
-// let mut _3: [closure@NodeId(22) d:D];
+// let mut _3: [closure@NodeId(33) d:D];
// bb0: {
// StorageLive(_1);
// _1 = D::{{constructor}}(const 0i32,);
// FakeRead(ForLet, _1);
// StorageLive(_3);
-// _3 = [closure@NodeId(22)] { d: move _1 };
+// _3 = [closure@NodeId(33)] { d: move _1 };
// _2 = const foo(move _3) -> [return: bb2, unwind: bb4];
// }
// bb1: {
// END rustc.main.SimplifyCfg-qualify-consts.after.mir
// START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir
-// fn main::{{closure}}(_1: [closure@NodeId(22) d:D]) -> i32 {
+// fn main::{{closure}}(_1: [closure@NodeId(33) d:D]) -> i32 {
// let mut _0: i32;
// ...
-// let _2: &'16_0rs D;
+// let _2: &'21_0rs D;
// ...
// bb0: {
// StorageLive(_2);
-// _2 = &'16_0rs (_1.0: D);
+// _2 = &'21_0rs (_1.0: D);
// FakeRead(ForLet, _2);
// _0 = ((*_2).0: i32);
-// EndRegion('16_0rs);
+// EndRegion('21_0rs);
// StorageDead(_2);
// drop(_1) -> [return: bb2, unwind: bb1];
// }
// fn main() -> () {
// let mut _0: ();
// ...
-// let _2: &'21_1rs D;
+// let _2: &'26_1rs D;
// ...
// let _1: D;
// ...
// let mut _3: ();
-// let mut _4: [closure@NodeId(22) r:&'19s D];
+// let mut _4: [closure@NodeId(33) r:&'24s D];
// bb0: {
// StorageLive(_1);
// _1 = D::{{constructor}}(const 0i32,);
// FakeRead(ForLet, _1);
// StorageLive(_2);
-// _2 = &'21_1rs _1;
+// _2 = &'26_1rs _1;
// FakeRead(ForLet, _2);
// StorageLive(_4);
-// _4 = [closure@NodeId(22)] { r: _2 };
+// _4 = [closure@NodeId(33)] { r: _2 };
// _3 = const foo(move _4) -> [return: bb2, unwind: bb3];
// }
// bb1: {
// resume;
// }
// bb2: {
-// EndRegion('19s);
+// EndRegion('24s);
// StorageDead(_4);
// _0 = ();
-// EndRegion('21_1rs);
+// EndRegion('26_1rs);
// StorageDead(_2);
// drop(_1) -> [return: bb4, unwind: bb1];
// }
// bb3: {
-// EndRegion('19s);
-// EndRegion('21_1rs);
+// EndRegion('24s);
+// EndRegion('26_1rs);
// drop(_1) -> bb1;
// }
// bb4: {
// END rustc.main.SimplifyCfg-qualify-consts.after.mir
// START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir
-// fn main::{{closure}}(_1: [closure@NodeId(22) r:&'19s D]) -> i32 {
+// fn main::{{closure}}(_1: [closure@NodeId(33) r:&'24s D]) -> i32 {
// let mut _0: i32;
//
// bb0: {
-// _0 = ((*(_1.0: &'21_1rs D)).0: i32);
+// _0 = ((*(_1.0: &'26_1rs D)).0: i32);
// return;
// }
// }
// fn main() -> () {
// let mut _0: ();
// ...
-// let mut _4: &'33_0rs i32;
+// let mut _4: &'37_0rs i32;
// ...
// let _2: i32;
// ...
// bb5: {
// _0 = ();
// StorageDead(_7);
-// EndRegion('33_0rs);
+// EndRegion('37_0rs);
// StorageDead(_4);
// StorageDead(_2);
// StorageDead(_1);
// return;
// }
// bb6: {
-// _4 = &'33_0rs _2;
+// _4 = &'37_0rs _2;
// _6 = ();
// StorageDead(_7);
// _1 = const true;
// scope 1 {
// }
// scope 2 {
-// let _2: S<'36_0rs>;
+// let _2: S<'49_0rs>;
// }
// let mut _1: ();
-// let mut _3: std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>;
-// let mut _4: std::option::Option<&'36_0rs S<'36_0rs>>;
+// let mut _3: std::cell::Cell<std::option::Option<&'49_0rs S<'49_0rs>>>;
+// let mut _4: std::option::Option<&'49_0rs S<'49_0rs>>;
// let mut _5: ();
-// let mut _6: &'17s std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>;
-// let mut _7: std::option::Option<&'36_0rs S<'36_0rs>>;
-// let mut _8: &'36_0rs S<'36_0rs>;
-// let mut _9: &'36_0rs S<'36_0rs>;
+// let mut _6: &'25s std::cell::Cell<std::option::Option<&'49_0rs S<'49_0rs>>>;
+// let mut _7: std::option::Option<&'49_0rs S<'49_0rs>>;
+// let mut _8: &'49_0rs S<'49_0rs>;
+// let mut _9: &'49_0rs S<'49_0rs>;
// let mut _10: ();
// let mut _11: bool;
// let mut _12: !;
// let mut _13: ();
-// let mut _14: &'34s std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>;
-// let mut _15: std::option::Option<&'36_0rs S<'36_0rs>>;
-// let mut _16: &'36_0rs S<'36_0rs>;
-// let mut _17: &'36_0rs S<'36_0rs>;
+// let mut _14: &'47s std::cell::Cell<std::option::Option<&'49_0rs S<'49_0rs>>>;
+// let mut _15: std::option::Option<&'49_0rs S<'49_0rs>>;
+// let mut _16: &'49_0rs S<'49_0rs>;
+// let mut _17: &'49_0rs S<'49_0rs>;
// bb0: {
// goto -> bb1;
// }
// StorageLive(_2);
// StorageLive(_3);
// StorageLive(_4);
-// _4 = std::option::Option<&'36_0rs S<'36_0rs>>::None;
+// _4 = std::option::Option<&'49_0rs S<'49_0rs>>::None;
// _3 = const <std::cell::Cell<T>>::new(move _4) -> [return: bb4, unwind: bb3];
// }
// bb3: {
// }
// bb4: {
// StorageDead(_4);
-// _2 = S<'36_0rs> { r: move _3 };
+// _2 = S<'49_0rs> { r: move _3 };
// StorageDead(_3);
// FakeRead(ForLet, _2);
// StorageLive(_6);
-// _6 = &'17s (_2.0: std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>);
+// _6 = &'25s (_2.0: std::cell::Cell<std::option::Option<&'49_0rs S<'49_0rs>>>);
// StorageLive(_7);
// StorageLive(_8);
// StorageLive(_9);
-// _9 = &'36_0rs _2;
-// _8 = &'36_0rs (*_9);
-// _7 = std::option::Option<&'36_0rs S<'36_0rs>>::Some(move _8,);
+// _9 = &'49_0rs _2;
+// _8 = &'49_0rs (*_9);
+// _7 = std::option::Option<&'49_0rs S<'49_0rs>>::Some(move _8,);
// StorageDead(_8);
// _5 = const <std::cell::Cell<T>>::set(move _6, move _7) -> [return: bb5, unwind: bb3];
// }
// bb5: {
-// EndRegion('17s);
+// EndRegion('25s);
// StorageDead(_7);
// StorageDead(_6);
// StorageDead(_9);
// bb7: {
// _0 = ();
// StorageDead(_11);
-// EndRegion('36_0rs);
+// EndRegion('49_0rs);
// StorageDead(_2);
// return;
// }
// _10 = ();
// StorageDead(_11);
// StorageLive(_14);
-// _14 = &'34s (_2.0: std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>);
+// _14 = &'47s (_2.0: std::cell::Cell<std::option::Option<&'49_0rs S<'49_0rs>>>);
// StorageLive(_15);
// StorageLive(_16);
// StorageLive(_17);
-// _17 = &'36_0rs _2;
-// _16 = &'36_0rs (*_17);
-// _15 = std::option::Option<&'36_0rs S<'36_0rs>>::Some(move _16,);
+// _17 = &'49_0rs _2;
+// _16 = &'49_0rs (*_17);
+// _15 = std::option::Option<&'49_0rs S<'49_0rs>>::Some(move _16,);
// StorageDead(_16);
// _13 = const <std::cell::Cell<T>>::set(move _14, move _15) -> [return: bb9, unwind: bb3];
// }
// bb9: {
-// EndRegion('34s);
+// EndRegion('47s);
// StorageDead(_15);
// StorageDead(_14);
// StorageDead(_17);
// _1 = ();
-// EndRegion('36_0rs);
+// EndRegion('49_0rs);
// StorageDead(_2);
// goto -> bb1;
// }
// Notes on the MIR output below:
//
-// 1. The `EndRegion('10s)` is allowed to precede the `drop(_3)`
+// 1. The `EndRegion('13s)` is allowed to precede the `drop(_3)`
// solely because of the #[may_dangle] mentioned above.
//
-// 2. Regarding the occurrence of `EndRegion('12ds)` *after* `StorageDead(_6)`
-// (where we have borrows `&'12ds _6`): Eventually:
+// 2. Regarding the occurrence of `EndRegion('15ds)` *after* `StorageDead(_6)`
+// (where we have borrows `&'15ds _6`): Eventually:
//
// i. this code should be rejected (by mir-borrowck), or
//
// ii. the MIR code generation should be changed so that the
-// EndRegion('12ds)` precedes `StorageDead(_6)` in the
+// EndRegion('15ds)` precedes `StorageDead(_6)` in the
// control-flow. (Note: arielb1 views drop+storagedead as one
// unit, and does not see this option as a useful avenue to
// explore.), or
// START rustc.main.QualifyAndPromoteConstants.before.mir
// fn main() -> () {
// let mut _0: ();
-// let mut _1: &'12ds S1;
-// let mut _2: D1<'12ds, '10s>;
-// let mut _3: &'12ds S1;
-// let mut _4: &'12ds S1;
+// let mut _1: &'15ds S1;
+// let mut _2: D1<'15ds, '13s>;
+// let mut _3: &'15ds S1;
+// let mut _4: &'15ds S1;
// let _5: S1;
-// let mut _6: &'10s S1;
-// let mut _7: &'10s S1;
+// let mut _6: &'13s S1;
+// let mut _7: &'13s S1;
// let _8: S1;
// bb0: {
// StorageLive(_2);
// StorageLive(_4);
// StorageLive(_5);
// _5 = S1::{{constructor}}(const "ex1",);
-// _4 = &'12ds _5;
-// _3 = &'12ds (*_4);
+// _4 = &'15ds _5;
+// _3 = &'15ds (*_4);
// StorageLive(_6);
// StorageLive(_7);
// StorageLive(_8);
// _8 = S1::{{constructor}}(const "dang1",);
-// _7 = &'10s _8;
-// _6 = &'10s (*_7);
-// _2 = D1<'12ds, '10s>::{{constructor}}(move _3, move _6);
-// EndRegion('10s);
+// _7 = &'13s _8;
+// _6 = &'13s (*_7);
+// _2 = D1<'15ds, '13s>::{{constructor}}(move _3, move _6);
+// EndRegion('13s);
// StorageDead(_6);
// StorageDead(_3);
-// _1 = (_2.0: &'12ds S1);
+// _1 = (_2.0: &'15ds S1);
// drop(_2) -> [return: bb2, unwind: bb1];
// }
// bb1: {
// StorageDead(_8);
// StorageDead(_4);
// StorageDead(_5);
-// EndRegion('12ds);
+// EndRegion('15ds);
// _0 = ();
// return;
// }
// START rustc.main.QualifyAndPromoteConstants.after.mir
// fn main() -> (){
// let mut _0: ();
-// let mut _1: &'12ds S1;
-// let mut _2: D1<'12ds, '10s>;
-// let mut _3: &'12ds S1;
-// let mut _4: &'12ds S1;
+// let mut _1: &'15ds S1;
+// let mut _2: D1<'15ds, '13s>;
+// let mut _3: &'15ds S1;
+// let mut _4: &'15ds S1;
// let _5: S1;
-// let mut _6: &'10s S1;
-// let mut _7: &'10s S1;
+// let mut _6: &'13s S1;
+// let mut _7: &'13s S1;
// let _8: S1;
// bb0: {
// StorageLive(_2);
// StorageLive(_3);
// StorageLive(_4);
-// _4 = &'12ds (promoted[1]: S1);
-// _3 = &'12ds (*_4);
+// _4 = &'15ds (promoted[1]: S1);
+// _3 = &'15ds (*_4);
// StorageLive(_6);
// StorageLive(_7);
-// _7 = &'10s (promoted[0]: S1);
-// _6 = &'10s (*_7);
-// _2 = D1<'12ds, '10s>::{{constructor}}(move _3, move _6);
-// EndRegion('10s);
+// _7 = &'13s (promoted[0]: S1);
+// _6 = &'13s (*_7);
+// _2 = D1<'15ds, '13s>::{{constructor}}(move _3, move _6);
+// EndRegion('13s);
// StorageDead(_6);
// StorageDead(_3);
-// _1 = (_2.0: &'12ds S1);
+// _1 = (_2.0: &'15ds S1);
// drop(_2) -> [return: bb2, unwind: bb1];
// }
// bb1: {
// StorageDead(_2);
// StorageDead(_7);
// StorageDead(_4);
-// EndRegion('12ds);
+// EndRegion('15ds);
// _0 = ();
// return;
// }
// ...
// bb0: {
// ...
-// _3 = [closure@NodeId(39)];
+// _3 = [closure@NodeId(53)];
// ...
// _4 = &_3;
// ...
// ...
// bb0: {
// ...
-// _3 = [closure@NodeId(28)];
+// _3 = [closure@NodeId(39)];
// ...
// _4 = &_3;
// ...
// ...
// bb0: {
// ...
-// Validate(Suspend(ReScope(Node(ItemLocalId(10)))), [_1: i32]);
+// Validate(Suspend(ReScope(Node(ItemLocalId(13)))), [_1: i32]);
// _6 = &ReErased mut _1;
-// Validate(Acquire, [(*_6): i32/ReScope(Node(ItemLocalId(10)))]);
-// Validate(Suspend(ReScope(Node(ItemLocalId(10)))), [(*_6): i32/ReScope(Node(ItemLocalId(10)))]);
+// Validate(Acquire, [(*_6): i32/ReScope(Node(ItemLocalId(13)))]);
+// Validate(Suspend(ReScope(Node(ItemLocalId(13)))), [(*_6): i32/ReScope(Node(ItemLocalId(13)))]);
// _5 = &ReErased mut (*_6);
-// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(10)))]);
-// Validate(Release, [_2: (), _3: &ReScope(Node(ItemLocalId(10))) Test, _5: &ReScope(Node(ItemLocalId(10))) mut i32]);
+// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(13)))]);
+// Validate(Release, [_2: (), _3: &ReScope(Node(ItemLocalId(13))) Test, _5: &ReScope(Node(ItemLocalId(13))) mut i32]);
// _2 = const Test::foo(move _3, move _5) -> bb1;
// }
//
// bb1: {
// Validate(Acquire, [_2: ()]);
-// EndRegion(ReScope(Node(ItemLocalId(10))));
+// EndRegion(ReScope(Node(ItemLocalId(13))));
// ...
// return;
// }
// }
// END rustc.main.EraseRegions.after.mir
// START rustc.main-{{closure}}.EraseRegions.after.mir
-// fn main::{{closure}}(_1: &ReErased [closure@NodeId(50)], _2: &ReErased mut i32) -> i32 {
+// fn main::{{closure}}(_1: &ReErased [closure@NodeId(65)], _2: &ReErased mut i32) -> i32 {
// ...
// bb0: {
-// Validate(Acquire, [_1: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(50)], _2: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
+// Validate(Acquire, [_1: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(65)], _2: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
// StorageLive(_3);
-// Validate(Suspend(ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 })), [(*_2): i32]);
+// Validate(Suspend(ReScope(Remainder { block: ItemLocalId(31), first_statement_index: 0 })), [(*_2): i32]);
// _3 = &ReErased (*_2);
-// Validate(Acquire, [(*_3): i32/ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 }) (imm)]);
+// Validate(Acquire, [(*_3): i32/ReScope(Remainder { block: ItemLocalId(31), first_statement_index: 0 }) (imm)]);
// _0 = (*_3);
-// EndRegion(ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 }));
+// EndRegion(ReScope(Remainder { block: ItemLocalId(31), first_statement_index: 0 }));
// StorageDead(_3);
// return;
// }
// StorageLive(_1);
// _1 = Test { x: const 0i32 };
// StorageLive(_2);
-// Validate(Suspend(ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 })), [_1: Test]);
+// Validate(Suspend(ReScope(Remainder { block: ItemLocalId(24), first_statement_index: 3 })), [_1: Test]);
// _2 = &ReErased _1;
-// Validate(Acquire, [(*_2): Test/ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }) (imm)]);
+// Validate(Acquire, [(*_2): Test/ReScope(Remainder { block: ItemLocalId(24), first_statement_index: 3 }) (imm)]);
// StorageLive(_4);
// StorageLive(_5);
-// Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [((*_2).0: i32): i32/ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }) (imm)]);
+// Validate(Suspend(ReScope(Node(ItemLocalId(22)))), [((*_2).0: i32): i32/ReScope(Remainder { block: ItemLocalId(24), first_statement_index: 3 }) (imm)]);
// _5 = &ReErased ((*_2).0: i32);
-// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(18))) (imm)]);
-// Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [(*_5): i32/ReScope(Node(ItemLocalId(18))) (imm)]);
+// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(22))) (imm)]);
+// Validate(Suspend(ReScope(Node(ItemLocalId(22)))), [(*_5): i32/ReScope(Node(ItemLocalId(22))) (imm)]);
// _4 = &ReErased (*_5);
-// Validate(Acquire, [(*_4): i32/ReScope(Node(ItemLocalId(18))) (imm)]);
-// Validate(Release, [_3: (), _4: &ReScope(Node(ItemLocalId(18))) i32]);
+// Validate(Acquire, [(*_4): i32/ReScope(Node(ItemLocalId(22))) (imm)]);
+// Validate(Release, [_3: (), _4: &ReScope(Node(ItemLocalId(22))) i32]);
// _3 = const foo(move _4) -> bb1;
// }
// bb1: {
// Validate(Acquire, [_3: ()]);
-// EndRegion(ReScope(Node(ItemLocalId(18))));
+// EndRegion(ReScope(Node(ItemLocalId(22))));
// StorageDead(_4);
// StorageDead(_5);
// _0 = ();
-// EndRegion(ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }));
+// EndRegion(ReScope(Remainder { block: ItemLocalId(24), first_statement_index: 3 }));
// StorageDead(_2);
// StorageDead(_1);
// return;
// }
// END rustc.write_42.EraseRegions.after.mir
// START rustc.write_42-{{closure}}.EraseRegions.after.mir
-// fn write_42::{{closure}}(_1: &ReErased [closure@NodeId(22)], _2: *mut i32) -> () {
+// fn write_42::{{closure}}(_1: &ReErased [closure@NodeId(32)], _2: *mut i32) -> () {
// ...
// bb0: {
-// Validate(Acquire, [_1: &ReFree(DefId(0/1:9 ~ validate_4[317d]::write_42[0]::{{closure}}[0]), BrEnv) [closure@NodeId(22)], _2: *mut i32]);
-// Validate(Release, [_1: &ReFree(DefId(0/1:9 ~ validate_4[317d]::write_42[0]::{{closure}}[0]), BrEnv) [closure@NodeId(22)], _2: *mut i32]);
+// Validate(Acquire, [_1: &ReFree(DefId(0/1:9 ~ validate_4[317d]::write_42[0]::{{closure}}[0]), BrEnv) [closure@NodeId(32)], _2: *mut i32]);
+// Validate(Release, [_1: &ReFree(DefId(0/1:9 ~ validate_4[317d]::write_42[0]::{{closure}}[0]), BrEnv) [closure@NodeId(32)], _2: *mut i32]);
// (*_2) = const 23i32;
// _0 = ();
// return;
// }
// END rustc.test.EraseRegions.after.mir
// START rustc.main-{{closure}}.EraseRegions.after.mir
-// fn main::{{closure}}(_1: &ReErased [closure@NodeId(60)], _2: &ReErased mut i32) -> bool {
+// fn main::{{closure}}(_1: &ReErased [closure@NodeId(80)], _2: &ReErased mut i32) -> bool {
// ...
// bb0: {
-// Validate(Acquire, [_1: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
-// Validate(Release, [_1: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
+// Validate(Acquire, [_1: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(80)], _2: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
+// Validate(Release, [_1: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(80)], _2: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
// StorageLive(_3);
// ...
// _0 = const write_42(move _3) -> bb1;
// }
// END rustc.test.EraseRegions.after.mir
// START rustc.main-{{closure}}.EraseRegions.after.mir
-// fn main::{{closure}}(_1: &ReErased [closure@NodeId(46)], _2: &ReErased mut i32) -> bool {
+// fn main::{{closure}}(_1: &ReErased [closure@NodeId(62)], _2: &ReErased mut i32) -> bool {
// ...
// bb0: {
-// Validate(Acquire, [_1: &ReFree(DefId(0/1:9 ~ validate_5[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(46)], _2: &ReFree(DefId(0/1:9 ~ validate_5[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
+// Validate(Acquire, [_1: &ReFree(DefId(0/1:9 ~ validate_5[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(62)], _2: &ReFree(DefId(0/1:9 ~ validate_5[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
// StorageLive(_3);
// StorageLive(_4);
// StorageLive(_5);
-// Validate(Suspend(ReScope(Node(ItemLocalId(12)))), [(*_2): i32]);
+// Validate(Suspend(ReScope(Node(ItemLocalId(16)))), [(*_2): i32]);
// _5 = &ReErased mut (*_2);
-// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(12)))]);
+// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(16)))]);
// _4 = move _5 as *mut i32 (Misc);
// _3 = move _4;
-// EndRegion(ReScope(Node(ItemLocalId(12))));
+// EndRegion(ReScope(Node(ItemLocalId(16))));
// StorageDead(_4);
// StorageDead(_5);
// Validate(Release, [_0: bool, _3: *mut i32]);
fn expand<'cx>(&self,
ecx: &'cx mut ExtCtxt,
sp: Span,
- _: TokenStream) -> Box<MacResult+'cx> {
+ _: TokenStream,
+ _: Option<Span>) -> Box<MacResult+'cx> {
let args = self.args.iter().map(|i| pprust::meta_list_item_to_string(i))
.collect::<Vec<_>>().join(", ");
MacEager::expr(ecx.expr_str(sp, Symbol::intern(&args)))
// except according to those terms.
// run-pass
-// Test for issue #18804, #[linkage] does not propagate thorugh generic
+// Test for issue #18804, #[linkage] does not propagate through generic
// functions. Failure results in a linker error.
// ignore-asmjs no weak symbol support
--- /dev/null
+macro_rules! test {
+ (
+ fn fun() -> Option<Box<$t:ty>>;
+ ) => {
+ fn fun(x: $t) -> Option<Box<$t>>
+ { Some(Box::new(x)) }
+ }
+}
+
+test! {
+ fn fun() -> Option<Box<i32>>;
+}
+
+fn main() {
+ println!("{}", fun(0).unwrap());
+}
// compile-flags:--test
// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
// failure-status: 101
+// rustc-env:RUST_BACKTRACE=0
// doctest fails at runtime
/// ```
running 2 tests
-test $DIR/failed-doctest-output.rs - OtherStruct (line 26) ... FAILED
-test $DIR/failed-doctest-output.rs - SomeStruct (line 20) ... FAILED
+test $DIR/failed-doctest-output.rs - OtherStruct (line 27) ... FAILED
+test $DIR/failed-doctest-output.rs - SomeStruct (line 21) ... FAILED
failures:
----- $DIR/failed-doctest-output.rs - OtherStruct (line 26) stdout ----
+---- $DIR/failed-doctest-output.rs - OtherStruct (line 27) stdout ----
error[E0425]: cannot find value `no` in this scope
- --> $DIR/failed-doctest-output.rs:27:1
+ --> $DIR/failed-doctest-output.rs:28:1
|
3 | no
| ^^ not found in this scope
-thread '$DIR/failed-doctest-output.rs - OtherStruct (line 26)' panicked at 'couldn't compile the test', librustdoc/test.rs:332:13
+thread '$DIR/failed-doctest-output.rs - OtherStruct (line 27)' panicked at 'couldn't compile the test', librustdoc/test.rs:332:13
note: Run with `RUST_BACKTRACE=1` for a backtrace.
----- $DIR/failed-doctest-output.rs - SomeStruct (line 20) stdout ----
-thread '$DIR/failed-doctest-output.rs - SomeStruct (line 20)' panicked at 'test executable failed:
+---- $DIR/failed-doctest-output.rs - SomeStruct (line 21) stdout ----
+thread '$DIR/failed-doctest-output.rs - SomeStruct (line 21)' panicked at 'test executable failed:
thread 'main' panicked at 'oh no', $DIR/failed-doctest-output.rs:3:1
note: Run with `RUST_BACKTRACE=1` for a backtrace.
failures:
- $DIR/failed-doctest-output.rs - OtherStruct (line 26)
- $DIR/failed-doctest-output.rs - SomeStruct (line 20)
+ $DIR/failed-doctest-output.rs - OtherStruct (line 27)
+ $DIR/failed-doctest-output.rs - SomeStruct (line 21)
test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out
// @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.5: fn_def_with_doc'
// @has - 'fn_def_with_doc short'
- // @!has - 'fn_def_with full'
+ // @!has - 'fn_def_with_doc full'
fn fn_def_with_doc() {}
// @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.6: fn_def_without_doc'
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the contents of constants are not displayed as part of the
+// documentation.
+
+// @!has dont_show_const_contents/constant.CONST_S.html 'dont show this'
+pub const CONST_S: &'static str = "dont show this";
pub struct Foo;
// @has foo/struct.Foo.html
-// @!has - '//*[@class="synthetic-implementations"]' 'Auto Trait Implementations'
+// @!has - 'Auto Trait Implementations'
impl !Send for Foo {}
impl !Sync for Foo {}
+++ /dev/null
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Test that we HTML-escape Rust expressions, where HTML special chars
-// can occur, and we know it's definitely not markup.
-
-// @!has escape_rust_expr/constant.CONST_S.html '//pre[@class="rust const"]' '"<script>"'
-pub const CONST_S: &'static str = "<script>";
// @has foo/struct.Foo.html
// @!has - 'Methods'
-// @!has - 'impl Foo'
+// @!has - '//code' 'impl Foo'
// @!has - 'this_should_be_hidden'
pub use hidden::Foo;
// @has foo/struct.Bar.html
// @!has - 'Methods'
-// @!has - 'impl Bar'
+// @!has - '//code' 'impl Bar'
// @!has - 'this_should_be_hidden'
pub use hidden::Bar;
fn bar(&self) {}
}
-// @!has issue_13698/struct.Foo.html '//*[@id="method.foo"]' 'fn bar'
+// @!has issue_13698/struct.Foo.html '//*[@id="method.bar"]' 'fn bar'
impl Bar for Foo {}
}
pub use self::private::Enum::*;
-// @!has foo/index.html '//a/@href' './private/index.html'
+// @!has-dir foo/private
+// @!has foo/index.html '//a/@href' 'private/index.html'
--- /dev/null
+// Issue #54478: regression test showing that we can demonstrate
+// `#[global_allocator]` in code blocks built by `rustdoc`.
+//
+// ## Background
+//
+// Changes in lang-item visibility injected failures that were only
+// exposed when compiling with `-C prefer-dynamic`. But `rustdoc` used
+// `-C prefer-dynamic` (and had done so for years, for reasons we did
+// not document at that time).
+//
+// Rather than try to revise the visbility semanics, we instead
+// decided to change `rustdoc` to behave more like the compiler's
+// default setting, by leaving off `-C prefer-dynamic`.
+
+// compile-flags:--test
+
+//! This is a doc comment
+//!
+//! ```rust
+//! use std::alloc::*;
+//!
+//! #[global_allocator]
+//! static ALLOC: A = A;
+//!
+//! static mut HIT: bool = false;
+//!
+//! struct A;
+//!
+//! unsafe impl GlobalAlloc for A {
+//! unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+//! HIT = true;
+//! System.alloc(layout)
+//! }
+//! unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+//! System.dealloc(ptr, layout);
+//! }
+//! }
+//!
+//! fn main() {
+//! assert!(unsafe { HIT });
+//! }
+//! ```
--- /dev/null
+// Regression test for issue #55001. Previously, we would incorrectly
+// cache certain trait selection results when checking for blanket impls,
+// resulting in an ICE when we tried to confirm the cached ParamCandidate
+// against an obligation.
+
+pub struct DefaultAllocator;
+pub struct Standard;
+pub struct Inner;
+
+pub trait Rand {}
+
+pub trait Distribution<T> {}
+pub trait Allocator<N> {}
+
+impl<T> Rand for T where Standard: Distribution<T> {}
+
+impl<A> Distribution<Point<A>> for Standard
+where
+DefaultAllocator: Allocator<A>,
+Standard: Distribution<A> {}
+
+impl Distribution<Inner> for Standard {}
+
+
+pub struct Point<N>
+where DefaultAllocator: Allocator<N>
+{
+ field: N
+}
+
+fn main() {}
// @has - '//*[@class="docblock"]' 'Docs associated with the S1 trait a_method implementation.'
// @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.'
// @has - '//*[@class="docblock"]' 'Docs associated with the trait b_method definition.'
-// @has - '//*[@class="docblock"]' 'Docs associated with the trait b_method definition.'
// @has - '//*[@class="docblock"]' 'Docs associated with the trait c_method definition.'
// @!has - '//*[@class="docblock"]' 'There is another line'
// @has - '//*[@class="docblock"]' 'Read more'
#![doc(html_playground_url = "")]
+// compile-flags:-Z unstable-options --playground-url https://play.rust-lang.org/
+
//! module docs
//!
//! ```
// @has redirect/index.html
// @has - '//code' 'pub use private_no_inline::Qux'
-// @!has - '//code/a' 'Qux'
+// @!has - '//a' 'Qux'
+// @!has redirect/struct.Qux.html
#[doc(no_inline)]
pub use private_no_inline::Qux;
pub struct Bar;
-// @!has foo/struct.Bar.html '//*[@id="implementations"]'
+// @count foo/struct.Bar.html '//*[@id="implementations"]' 0
--- /dev/null
+// compile-pass
+// edition:2018
+
+#![feature(extern_crate_item_prelude)]
+
+extern crate proc_macro;
+use proc_macro::TokenStream; // OK
+
+fn main() {}
--> $DIR/resolve-error.rs:54:10
|
LL | #[derive(attr_proc_macra)]
- | ^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^ help: try: `attr_proc_macro`
error: cannot find macro `FooWithLongNama!` in this scope
--> $DIR/resolve-error.rs:59:5
--> $DIR/bound-lifetime-in-binding-only.rs:62:23
|
LL | fn elision<T: Fn() -> &i32>() {
- | ^ expected lifetime parameter
+ | ^ help: consider giving it a 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
- = help: consider giving it a 'static lifetime
error: aborting due to previous error
--> $DIR/bound-lifetime-in-return-only.rs:44:23
|
LL | fn elision(_: fn() -> &i32) {
- | ^ expected lifetime parameter
+ | ^ help: consider giving it a 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
- = help: consider giving it a 'static lifetime
error: aborting due to previous error
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Test that we do some basic error correcton in the tokeniser (and don't spew
+// Test that we do some basic error correction in the tokeniser (and don't spew
// too many bogus errors).
fn foo() -> usize {
// Test that cfg_attr doesn't emit any attributes when the
-// configuation variable is false. This mirrors `cfg-attr-multi-true.rs`
+// configuration variable is false. This mirrors `cfg-attr-multi-true.rs`
// compile-pass
--- /dev/null
+// compile-pass
+
+#![feature(const_fn, rustc_attrs)]
+
+#[rustc_args_required_const(0)]
+pub const fn a(value: u8) -> u8 {
+ value
+}
+
+#[rustc_args_required_const(0)]
+pub fn b(_: u8) {
+ unimplemented!()
+}
+
+fn main() {
+ let _ = b(a(0));
+}
| cannot borrow as mutable
| try removing `&mut` here
+warning: function cannot return without recursing
+ --> $DIR/issue-31424.rs:22:5
+ |
+LL | fn bar(self: &mut Self) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL | //~^ WARN function cannot return without recursing
+LL | (&mut self).bar(); //~ ERROR cannot borrow
+ | ----------------- recursive call site
+ |
+ = note: #[warn(unconditional_recursion)] on by default
+ = help: a `loop` may express intention better if this is on purpose
+
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
- --> $DIR/issue-31424.rs:23:9
+ --> $DIR/issue-31424.rs:24:9
|
LL | (&mut self).bar(); //~ ERROR cannot borrow
| ^^^^^^^^^^^
// In this case we could keep the suggestion, but to distinguish the
// two cases is pretty hard. It's an obscure case anyway.
fn bar(self: &mut Self) {
+ //~^ WARN function cannot return without recursing
(&mut self).bar(); //~ ERROR cannot borrow
}
}
| cannot reborrow mutably
| try removing `&mut` here
+warning: function cannot return without recursing
+ --> $DIR/issue-31424.rs:22:5
+ |
+LL | fn bar(self: &mut Self) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL | //~^ WARN function cannot return without recursing
+LL | (&mut self).bar(); //~ ERROR cannot borrow
+ | ----------------- recursive call site
+ |
+ = note: #[warn(unconditional_recursion)] on by default
+ = help: a `loop` may express intention better if this is on purpose
+
error[E0596]: cannot borrow immutable argument `self` as mutable
- --> $DIR/issue-31424.rs:23:15
+ --> $DIR/issue-31424.rs:24:15
|
LL | (&mut self).bar(); //~ ERROR cannot borrow
| ^^^^ cannot borrow mutably
let n: usize = 42;
this_function_expects_a_double_option(n);
//~^ ERROR mismatched types
+ //~| HELP try using a variant of the expected type
+}
+
+
+// But don't issue the "try using a variant" help if the one-"variant" ADT is
+// actually a one-field struct.
+
+struct Payload;
+
+struct Wrapper { payload: Payload }
+
+struct Context { wrapper: Wrapper }
+
+fn overton() {
+ let _c = Context { wrapper: Payload{} };
+ //~^ ERROR mismatched types
}
LL | this_function_expects_a_double_option(DoubleOption::AlternativeSome(n));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to previous error
+error[E0308]: mismatched types
+ --> $DIR/issue-42764.rs:37:33
+ |
+LL | let _c = Context { wrapper: Payload{} };
+ | ^^^^^^^^^ expected struct `Wrapper`, found struct `Payload`
+ |
+ = note: expected type `Wrapper`
+ found type `Payload`
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.
--> $DIR/edition-keywords-2015-2015-parsing.rs:22:31
|
LL | r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
- | ^^^^^^^
+ | ^^^^^^^ no rules expected the token `r#async`
error: no rules expected the token `async`
--> $DIR/edition-keywords-2015-2015-parsing.rs:23:35
|
LL | r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
- | ^^^^^
+ | ^^^^^ no rules expected the token `async`
error: aborting due to 2 previous errors
--> $DIR/edition-keywords-2015-2018-parsing.rs:22:31
|
LL | r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
- | ^^^^^^^
+ | ^^^^^^^ no rules expected the token `r#async`
error: no rules expected the token `async`
--> $DIR/edition-keywords-2015-2018-parsing.rs:23:35
|
LL | r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
- | ^^^^^
+ | ^^^^^ no rules expected the token `async`
error: aborting due to 2 previous errors
--> $DIR/edition-keywords-2018-2015-parsing.rs:22:31
|
LL | r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
- | ^^^^^^^
+ | ^^^^^^^ no rules expected the token `r#async`
error: no rules expected the token `async`
--> $DIR/edition-keywords-2018-2015-parsing.rs:23:35
|
LL | r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
- | ^^^^^
+ | ^^^^^ no rules expected the token `async`
error: expected one of `move`, `|`, or `||`, found `<eof>`
--> <::edition_kw_macro_2015::passes_ident macros>:1:22
--> $DIR/edition-keywords-2018-2018-parsing.rs:22:31
|
LL | r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
- | ^^^^^^^
+ | ^^^^^^^ no rules expected the token `r#async`
error: no rules expected the token `async`
--> $DIR/edition-keywords-2018-2018-parsing.rs:23:35
|
LL | r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
- | ^^^^^
+ | ^^^^^ no rules expected the token `async`
error: expected one of `move`, `|`, or `||`, found `<eof>`
--> <::edition_kw_macro_2018::passes_ident macros>:1:22
error: unexpected end of macro invocation
--> $DIR/empty-comment.rs:20:5
|
+LL | macro_rules! one_arg_macro {
+ | -------------------------- when calling this macro
+...
LL | one_arg_macro!(/**/); //~ ERROR unexpected end
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^ unexpected end of macro invocation
error: aborting due to previous error
--> $DIR/fail-simple.rs:12:12
|
LL | panic!(@); //~ ERROR no rules expected the token `@`
- | ^
+ | ^ no rules expected the token `@`
error: aborting due to previous error
--- /dev/null
+// edition:2018
+
+#![feature(alloc)]
+
+extern crate alloc;
+
+mod in_scope {
+ fn check() {
+ let v = alloc::vec![0];
+ //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable
+ type A = alloc::boxed::Box<u8>;
+ //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable
+ }
+}
+
+mod absolute {
+ fn check() {
+ let v = ::alloc::vec![0];
+ //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable
+ type A = ::alloc::boxed::Box<u8>;
+ //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable
+ }
+}
+
+mod import_in_scope {
+ use alloc;
+ //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable
+ use alloc::boxed;
+ //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable
+}
+
+mod import_absolute {
+ use ::alloc;
+ //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable
+ use ::alloc::boxed;
+ //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable
+}
+
+extern crate alloc as core;
+
+mod unrelated_crate_renamed {
+ type A = core::boxed::Box<u8>;
+ //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable
+}
+
+fn main() {}
--- /dev/null
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+ --> $DIR/feature-gate-extern_crate_item_prelude.rs:26:9
+ |
+LL | use alloc;
+ | ^^^^^
+ |
+ = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
+
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+ --> $DIR/feature-gate-extern_crate_item_prelude.rs:28:9
+ |
+LL | use alloc::boxed;
+ | ^^^^^
+ |
+ = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
+
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+ --> $DIR/feature-gate-extern_crate_item_prelude.rs:33:11
+ |
+LL | use ::alloc;
+ | ^^^^^
+ |
+ = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
+
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+ --> $DIR/feature-gate-extern_crate_item_prelude.rs:35:11
+ |
+LL | use ::alloc::boxed;
+ | ^^^^^
+ |
+ = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
+
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+ --> $DIR/feature-gate-extern_crate_item_prelude.rs:9:17
+ |
+LL | let v = alloc::vec![0];
+ | ^^^^^
+ |
+ = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
+
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+ --> $DIR/feature-gate-extern_crate_item_prelude.rs:11:18
+ |
+LL | type A = alloc::boxed::Box<u8>;
+ | ^^^^^
+ |
+ = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
+
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+ --> $DIR/feature-gate-extern_crate_item_prelude.rs:18:19
+ |
+LL | let v = ::alloc::vec![0];
+ | ^^^^^
+ |
+ = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
+
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+ --> $DIR/feature-gate-extern_crate_item_prelude.rs:20:20
+ |
+LL | type A = ::alloc::boxed::Box<u8>;
+ | ^^^^^
+ |
+ = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
+
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+ --> $DIR/feature-gate-extern_crate_item_prelude.rs:42:14
+ |
+LL | type A = core::boxed::Box<u8>;
+ | ^^^^
+ |
+ = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-rustfix
+
+extern "C" {
+ pub fn g(_: &u8) -> &u8; // OK
+ pub fn f() -> &'static u8; //~ ERROR missing lifetime specifier
+}
+
+fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// run-rustfix
+
extern "C" {
- fn g(_: &u8) -> &u8; // OK
- fn f() -> &u8; //~ ERROR missing lifetime specifier
+ pub fn g(_: &u8) -> &u8; // OK
+ pub fn f() -> &u8; //~ ERROR missing lifetime specifier
}
fn main() {}
error[E0106]: missing lifetime specifier
- --> $DIR/foreign-fn-return-lifetime.rs:13:15
+ --> $DIR/foreign-fn-return-lifetime.rs:15:19
|
-LL | fn f() -> &u8; //~ ERROR missing lifetime specifier
- | ^ expected lifetime parameter
+LL | pub fn f() -> &u8; //~ ERROR missing lifetime specifier
+ | ^ help: consider giving it a 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
- = help: consider giving it a 'static lifetime
error: aborting due to previous error
--- /dev/null
+// compile-pass
+// compile-flags:--cfg my_feature
+
+#![feature(extern_crate_item_prelude)]
+#![no_std]
+
+#[cfg(my_feature)]
+extern crate std;
+
+mod m {
+ #[cfg(my_feature)]
+ fn conditional() {
+ std::vec::Vec::<u8>::new(); // OK
+ }
+}
+
+fn main() {}
--- /dev/null
+// aux-build:two_macros.rs
+// compile-flags:--extern non_existent
+
+mod n {
+ extern crate two_macros;
+}
+
+mod m {
+ fn check() {
+ two_macros::m!(); //~ ERROR failed to resolve. Use of undeclared type or module `two_macros`
+ }
+}
+
+macro_rules! define_std_as_non_existent {
+ () => {
+ extern crate std as non_existent;
+ //~^ ERROR `extern crate` items cannot shadow names passed with `--extern`
+ }
+}
+define_std_as_non_existent!();
+
+fn main() {}
--- /dev/null
+error: macro-expanded `extern crate` items cannot shadow names passed with `--extern`
+ --> $DIR/extern-prelude-extern-crate-fail.rs:16:9
+ |
+LL | extern crate std as non_existent;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | define_std_as_non_existent!();
+ | ------------------------------ in this macro invocation
+
+error[E0433]: failed to resolve. Use of undeclared type or module `two_macros`
+ --> $DIR/extern-prelude-extern-crate-fail.rs:10:9
+ |
+LL | two_macros::m!(); //~ ERROR failed to resolve. Use of undeclared type or module `two_macros`
+ | ^^^^^^^^^^ Use of undeclared type or module `two_macros`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
--- /dev/null
+// compile-pass
+// aux-build:two_macros.rs
+
+#![feature(extern_crate_item_prelude)]
+
+extern crate two_macros;
+
+mod m {
+ fn check() {
+ two_macros::m!(); // OK
+ }
+}
+
+fn main() {}
--- /dev/null
+// aux-build:two_macros.rs
+
+#![feature(extern_crate_item_prelude)]
+
+macro_rules! define_vec {
+ () => {
+ extern crate std as Vec;
+ }
+}
+
+define_vec!();
+
+mod m {
+ fn check() {
+ Vec::panic!(); //~ ERROR `Vec` is ambiguous
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0659]: `Vec` is ambiguous
+ --> $DIR/extern-prelude-extern-crate-restricted-shadowing.rs:15:9
+ |
+LL | Vec::panic!(); //~ ERROR `Vec` is ambiguous
+ | ^^^ ambiguous name
+ |
+note: `Vec` could refer to the name defined here
+ --> $DIR/extern-prelude-extern-crate-restricted-shadowing.rs:7:9
+ |
+LL | extern crate std as Vec;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | define_vec!();
+ | -------------- in this macro invocation
+note: `Vec` could also refer to the name defined here
+ = note: macro-expanded items do not shadow when used in a macro invocation path
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0659`.
--> $DIR/issue-13497.rs:12:5
|
LL | &str //~ ERROR missing lifetime specifier
- | ^ expected lifetime parameter
+ | ^ help: consider giving it a 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
- = help: consider giving it a 'static lifetime
error: aborting due to previous error
--> $DIR/issue-26638.rs:14:40
|
LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
- | ^ expected lifetime parameter
+ | ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
- = help: consider giving it an explicit bounded or 'static lifetime
error[E0106]: missing lifetime specifier
--> $DIR/issue-26638.rs:17:22
|
LL | fn parse_type_3() -> &str { unimplemented!() }
- | ^ expected lifetime parameter
+ | ^ help: consider giving it a 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
- = help: consider giving it a 'static lifetime
error: aborting due to 3 previous errors
|
LL | () => ( String ; ); //~ ERROR macro expansion ignores token `;`
| ^
- |
-note: caused by the macro expansion here; the usage of `t!` is likely invalid in type context
- --> $DIR/issue-30007.rs:16:16
- |
+...
LL | let i: Vec<t!()>;
- | ^^^^
+ | ---- caused by the macro expansion here
+ |
+ = note: the usage of `t!` is likely invalid in type context
error: aborting due to previous error
error: unexpected end of macro invocation
--> $DIR/issue-7970a.rs:16:5
|
+LL | macro_rules! one_arg_macro {
+ | -------------------------- when calling this macro
+...
LL | one_arg_macro!();
- | ^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^ unexpected end of macro invocation
error: aborting due to previous error
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:12:11
|
LL | fn f() -> &isize { //~ ERROR missing lifetime specifier
- | ^ expected lifetime parameter
+ | ^ help: consider giving it a 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
- = help: consider giving it a 'static lifetime
error[E0106]: missing lifetime specifier
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:17:33
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:31:20
|
LL | fn i(_x: isize) -> &isize { //~ ERROR missing lifetime specifier
- | ^ expected lifetime parameter
+ | ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
- = help: consider giving it an explicit bounded or 'static lifetime
error[E0106]: missing lifetime specifier
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:44:24
|
LL | fn j(_x: StaticStr) -> &isize { //~ ERROR missing lifetime specifier
- | ^ expected lifetime parameter
+ | ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
- = help: consider giving it an explicit bounded or 'static lifetime
error[E0106]: missing lifetime specifier
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:50:49
|
LL | fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &isize {
- | ^ expected lifetime parameter
+ | ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
- = help: consider giving it an explicit bounded or 'static lifetime
error: aborting due to 6 previous errors
--- /dev/null
+trait Future {
+ type Item;
+ type Error;
+}
+
+use std::error::Error;
+
+fn foo() -> impl Future<Item=(), Error=Box<Error>> {
+ Ok(())
+}
+
+fn main() {}
--- /dev/null
+error[E0106]: missing lifetime specifier
+ --> $DIR/lifetime-elision-return-type-trait.rs:8:44
+ |
+LL | fn foo() -> impl Future<Item=(), Error=Box<Error>> {
+ | ^^^^^ help: consider giving it a 'static lifetime: `Error + 'static`
+ |
+ = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0106`.
while true {
//~^ WARN denote infinite loops
//~| HELP use `loop`
- let mut a = (1);
+ let mut registry_no = (format!("NX-{}", 74205));
//~^ WARN does not need to be mutable
//~| HELP remove this `mut`
//~| WARN unnecessary parentheses
//~^ WARN this pattern is redundant
//~| HELP remove this
}
- println!("{} {}", a, b);
+ println!("{} {}", registry_no, b);
}
}
warning: unnecessary parentheses around assigned value
- --> $DIR/suggestions.rs:59:21
+ --> $DIR/suggestions.rs:59:31
|
-LL | let mut a = (1);
- | ^^^ help: remove these parentheses
+LL | let mut registry_no = (format!("NX-{}", 74205));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses
|
note: lint level defined here
--> $DIR/suggestions.rs:13:21
warning: variable does not need to be mutable
--> $DIR/suggestions.rs:59:13
|
-LL | let mut a = (1);
- | ----^
+LL | let mut registry_no = (format!("NX-{}", 74205));
+ | ----^^^^^^^^^^^
| |
| help: remove this `mut`
|
error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-2018-feature-gate.rs:41:11
|
+LL | macro_rules! foo {
+ | ---------------- when calling this macro
+...
LL | foo!(a?); //~ ERROR no rules expected the token `?`
- | ^
+ | ^ no rules expected the token `?`
error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-2018-feature-gate.rs:42:11
|
+LL | macro_rules! foo {
+ | ---------------- when calling this macro
+...
LL | foo!(a?a); //~ ERROR no rules expected the token `?`
- | ^
+ | ^ no rules expected the token `?`
error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-2018-feature-gate.rs:43:11
|
+LL | macro_rules! foo {
+ | ---------------- when calling this macro
+...
LL | foo!(a?a?a); //~ ERROR no rules expected the token `?`
- | ^
+ | ^ no rules expected the token `?`
error: aborting due to 10 previous errors
error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-2018.rs:36:11
|
+LL | macro_rules! foo {
+ | ---------------- when calling this macro
+...
LL | foo!(a?); //~ ERROR no rules expected the token `?`
- | ^
+ | ^ no rules expected the token `?`
error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-2018.rs:37:11
|
+LL | macro_rules! foo {
+ | ---------------- when calling this macro
+...
LL | foo!(a?a); //~ ERROR no rules expected the token `?`
- | ^
+ | ^ no rules expected the token `?`
error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-2018.rs:38:11
|
+LL | macro_rules! foo {
+ | ---------------- when calling this macro
+...
LL | foo!(a?a?a); //~ ERROR no rules expected the token `?`
- | ^
+ | ^ no rules expected the token `?`
error: unexpected end of macro invocation
--> $DIR/macro-at-most-once-rep-2018.rs:40:5
|
+LL | macro_rules! barplus {
+ | -------------------- when calling this macro
+...
LL | barplus!(); //~ERROR unexpected end of macro invocation
- | ^^^^^^^^^^^
+ | ^^^^^^^^^^^ unexpected end of macro invocation
error: unexpected end of macro invocation
--> $DIR/macro-at-most-once-rep-2018.rs:41:14
|
+LL | macro_rules! barplus {
+ | -------------------- when calling this macro
+...
LL | barplus!(a); //~ERROR unexpected end of macro invocation
- | ^
+ | ^ unexpected end of macro invocation
error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-2018.rs:42:15
|
+LL | macro_rules! barplus {
+ | -------------------- when calling this macro
+...
LL | barplus!(a?); //~ ERROR no rules expected the token `?`
- | ^
+ | ^ no rules expected the token `?`
error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-2018.rs:43:15
|
+LL | macro_rules! barplus {
+ | -------------------- when calling this macro
+...
LL | barplus!(a?a); //~ ERROR no rules expected the token `?`
- | ^
+ | ^ no rules expected the token `?`
error: unexpected end of macro invocation
--> $DIR/macro-at-most-once-rep-2018.rs:47:5
|
+LL | macro_rules! barstar {
+ | -------------------- when calling this macro
+...
LL | barstar!(); //~ERROR unexpected end of macro invocation
- | ^^^^^^^^^^^
+ | ^^^^^^^^^^^ unexpected end of macro invocation
error: unexpected end of macro invocation
--> $DIR/macro-at-most-once-rep-2018.rs:48:14
|
+LL | macro_rules! barstar {
+ | -------------------- when calling this macro
+...
LL | barstar!(a); //~ERROR unexpected end of macro invocation
- | ^
+ | ^ unexpected end of macro invocation
error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-2018.rs:49:15
|
+LL | macro_rules! barstar {
+ | -------------------- when calling this macro
+...
LL | barstar!(a?); //~ ERROR no rules expected the token `?`
- | ^
+ | ^ no rules expected the token `?`
error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-2018.rs:50:15
|
+LL | macro_rules! barstar {
+ | -------------------- when calling this macro
+...
LL | barstar!(a?a); //~ ERROR no rules expected the token `?`
- | ^
+ | ^ no rules expected the token `?`
error: aborting due to 12 previous errors
|
LL | () => ( i ; typeof ); //~ ERROR expected expression, found reserved keyword `typeof`
| ^
- |
-note: caused by the macro expansion here; the usage of `m!` is likely invalid in type context
- --> $DIR/macro-context.rs:20:12
- |
+...
LL | let a: m!();
- | ^^^^
+ | ---- caused by the macro expansion here
+ |
+ = note: the usage of `m!` is likely invalid in type context
error: macro expansion ignores token `typeof` and any following
--> $DIR/macro-context.rs:13:17
|
LL | () => ( i ; typeof ); //~ ERROR expected expression, found reserved keyword `typeof`
| ^^^^^^
- |
-note: caused by the macro expansion here; the usage of `m!` is likely invalid in expression context
- --> $DIR/macro-context.rs:21:13
- |
+...
LL | let i = m!();
- | ^^^^
+ | ---- caused by the macro expansion here
+ |
+ = note: the usage of `m!` is likely invalid in expression context
error: macro expansion ignores token `;` and any following
--> $DIR/macro-context.rs:13:15
|
LL | () => ( i ; typeof ); //~ ERROR expected expression, found reserved keyword `typeof`
| ^
- |
-note: caused by the macro expansion here; the usage of `m!` is likely invalid in pattern context
- --> $DIR/macro-context.rs:23:9
- |
+...
LL | m!() => {}
- | ^^^^
+ | ---- caused by the macro expansion here
+ |
+ = note: the usage of `m!` is likely invalid in pattern context
error: expected expression, found reserved keyword `typeof`
--> $DIR/macro-context.rs:13:17
--> $DIR/macro-follow.rs:17:14
|
LL | ($p:pat ()) => {}; //~ERROR `$p:pat` is followed by `(`
- | ^
+ | ^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
error: `$p:pat` is followed by `[`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:18:14
|
LL | ($p:pat []) => {}; //~ERROR `$p:pat` is followed by `[`
- | ^
+ | ^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
error: `$p:pat` is followed by `{`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:19:14
|
LL | ($p:pat {}) => {}; //~ERROR `$p:pat` is followed by `{`
- | ^
+ | ^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
error: `$p:pat` is followed by `:`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:20:13
|
LL | ($p:pat :) => {}; //~ERROR `$p:pat` is followed by `:`
- | ^
+ | ^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
error: `$p:pat` is followed by `>`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:21:13
|
LL | ($p:pat >) => {}; //~ERROR `$p:pat` is followed by `>`
- | ^
+ | ^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
error: `$p:pat` is followed by `+`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:22:13
|
LL | ($p:pat +) => {}; //~ERROR `$p:pat` is followed by `+`
- | ^
+ | ^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
error: `$p:pat` is followed by `ident`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:23:13
|
LL | ($p:pat ident) => {}; //~ERROR `$p:pat` is followed by `ident`
- | ^^^^^
+ | ^^^^^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
error: `$p:pat` is followed by `$p:pat`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:24:13
|
LL | ($p:pat $p:pat) => {}; //~ERROR `$p:pat` is followed by `$p:pat`
- | ^^^^^^
+ | ^^^^^^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
error: `$p:pat` is followed by `$e:expr`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:25:13
|
LL | ($p:pat $e:expr) => {}; //~ERROR `$p:pat` is followed by `$e:expr`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
error: `$p:pat` is followed by `$t:ty`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:26:13
|
LL | ($p:pat $t:ty) => {}; //~ERROR `$p:pat` is followed by `$t:ty`
- | ^^^^^
+ | ^^^^^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
error: `$p:pat` is followed by `$s:stmt`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:27:13
|
LL | ($p:pat $s:stmt) => {}; //~ERROR `$p:pat` is followed by `$s:stmt`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
error: `$p:pat` is followed by `$p:path`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:28:13
|
LL | ($p:pat $p:path) => {}; //~ERROR `$p:pat` is followed by `$p:path`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
error: `$p:pat` is followed by `$b:block`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:29:13
|
LL | ($p:pat $b:block) => {}; //~ERROR `$p:pat` is followed by `$b:block`
- | ^^^^^^^^
+ | ^^^^^^^^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
error: `$p:pat` is followed by `$i:ident`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:30:13
|
LL | ($p:pat $i:ident) => {}; //~ERROR `$p:pat` is followed by `$i:ident`
- | ^^^^^^^^
+ | ^^^^^^^^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
error: `$p:pat` is followed by `$t:tt`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:31:13
|
LL | ($p:pat $t:tt) => {}; //~ERROR `$p:pat` is followed by `$t:tt`
- | ^^^^^
+ | ^^^^^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
error: `$p:pat` is followed by `$i:item`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:32:13
|
LL | ($p:pat $i:item) => {}; //~ERROR `$p:pat` is followed by `$i:item`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
error: `$p:pat` is followed by `$m:meta`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:33:13
|
LL | ($p:pat $m:meta) => {}; //~ERROR `$p:pat` is followed by `$m:meta`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
error: `$e:expr` is followed by `(`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:37:15
|
LL | ($e:expr ()) => {}; //~ERROR `$e:expr` is followed by `(`
- | ^
+ | ^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `[`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:38:15
|
LL | ($e:expr []) => {}; //~ERROR `$e:expr` is followed by `[`
- | ^
+ | ^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `{`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:39:15
|
LL | ($e:expr {}) => {}; //~ERROR `$e:expr` is followed by `{`
- | ^
+ | ^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `=`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:40:14
|
LL | ($e:expr =) => {}; //~ERROR `$e:expr` is followed by `=`
- | ^
+ | ^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `|`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:41:14
|
LL | ($e:expr |) => {}; //~ERROR `$e:expr` is followed by `|`
- | ^
+ | ^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `:`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:42:14
|
LL | ($e:expr :) => {}; //~ERROR `$e:expr` is followed by `:`
- | ^
+ | ^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `>`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:43:14
|
LL | ($e:expr >) => {}; //~ERROR `$e:expr` is followed by `>`
- | ^
+ | ^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `+`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:44:14
|
LL | ($e:expr +) => {}; //~ERROR `$e:expr` is followed by `+`
- | ^
+ | ^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `ident`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:45:14
|
LL | ($e:expr ident) => {}; //~ERROR `$e:expr` is followed by `ident`
- | ^^^^^
+ | ^^^^^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `if`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:46:14
|
LL | ($e:expr if) => {}; //~ERROR `$e:expr` is followed by `if`
- | ^^
+ | ^^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `in`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:47:14
|
LL | ($e:expr in) => {}; //~ERROR `$e:expr` is followed by `in`
- | ^^
+ | ^^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$p:pat`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:48:14
|
LL | ($e:expr $p:pat) => {}; //~ERROR `$e:expr` is followed by `$p:pat`
- | ^^^^^^
+ | ^^^^^^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$e:expr`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:49:14
|
LL | ($e:expr $e:expr) => {}; //~ERROR `$e:expr` is followed by `$e:expr`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$t:ty`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:50:14
|
LL | ($e:expr $t:ty) => {}; //~ERROR `$e:expr` is followed by `$t:ty`
- | ^^^^^
+ | ^^^^^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$s:stmt`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:51:14
|
LL | ($e:expr $s:stmt) => {}; //~ERROR `$e:expr` is followed by `$s:stmt`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$p:path`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:52:14
|
LL | ($e:expr $p:path) => {}; //~ERROR `$e:expr` is followed by `$p:path`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$b:block`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:53:14
|
LL | ($e:expr $b:block) => {}; //~ERROR `$e:expr` is followed by `$b:block`
- | ^^^^^^^^
+ | ^^^^^^^^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$i:ident`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:54:14
|
LL | ($e:expr $i:ident) => {}; //~ERROR `$e:expr` is followed by `$i:ident`
- | ^^^^^^^^
+ | ^^^^^^^^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$t:tt`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:55:14
|
LL | ($e:expr $t:tt) => {}; //~ERROR `$e:expr` is followed by `$t:tt`
- | ^^^^^
+ | ^^^^^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$i:item`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:56:14
|
LL | ($e:expr $i:item) => {}; //~ERROR `$e:expr` is followed by `$i:item`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$m:meta`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:57:14
|
LL | ($e:expr $m:meta) => {}; //~ERROR `$e:expr` is followed by `$m:meta`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$t:ty` is followed by `(`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:62:13
|
LL | ($t:ty ()) => {}; //~ERROR `$t:ty` is followed by `(`
- | ^
+ | ^ not allowed after `ty` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `+`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:64:12
|
LL | ($t:ty +) => {}; //~ERROR `$t:ty` is followed by `+`
- | ^
+ | ^ not allowed after `ty` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `ident`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:65:12
|
LL | ($t:ty ident) => {}; //~ERROR `$t:ty` is followed by `ident`
- | ^^^^^
+ | ^^^^^ not allowed after `ty` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `if`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:66:12
|
LL | ($t:ty if) => {}; //~ERROR `$t:ty` is followed by `if`
- | ^^
+ | ^^ not allowed after `ty` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `$p:pat`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:67:12
|
LL | ($t:ty $p:pat) => {}; //~ERROR `$t:ty` is followed by `$p:pat`
- | ^^^^^^
+ | ^^^^^^ not allowed after `ty` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `$e:expr`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:68:12
|
LL | ($t:ty $e:expr) => {}; //~ERROR `$t:ty` is followed by `$e:expr`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `ty` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `$t:ty`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:69:12
|
LL | ($t:ty $t:ty) => {}; //~ERROR `$t:ty` is followed by `$t:ty`
- | ^^^^^
+ | ^^^^^ not allowed after `ty` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `$s:stmt`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:70:12
|
LL | ($t:ty $s:stmt) => {}; //~ERROR `$t:ty` is followed by `$s:stmt`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `ty` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `$p:path`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:71:12
|
LL | ($t:ty $p:path) => {}; //~ERROR `$t:ty` is followed by `$p:path`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `ty` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `$i:ident`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:73:12
|
LL | ($t:ty $i:ident) => {}; //~ERROR `$t:ty` is followed by `$i:ident`
- | ^^^^^^^^
+ | ^^^^^^^^ not allowed after `ty` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `$t:tt`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:74:12
|
LL | ($t:ty $t:tt) => {}; //~ERROR `$t:ty` is followed by `$t:tt`
- | ^^^^^
+ | ^^^^^ not allowed after `ty` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `$i:item`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:75:12
|
LL | ($t:ty $i:item) => {}; //~ERROR `$t:ty` is followed by `$i:item`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `ty` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `$m:meta`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:76:12
|
LL | ($t:ty $m:meta) => {}; //~ERROR `$t:ty` is followed by `$m:meta`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `ty` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$s:stmt` is followed by `(`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:80:15
|
LL | ($s:stmt ()) => {}; //~ERROR `$s:stmt` is followed by `(`
- | ^
+ | ^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `[`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:81:15
|
LL | ($s:stmt []) => {}; //~ERROR `$s:stmt` is followed by `[`
- | ^
+ | ^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `{`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:82:15
|
LL | ($s:stmt {}) => {}; //~ERROR `$s:stmt` is followed by `{`
- | ^
+ | ^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `=`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:83:14
|
LL | ($s:stmt =) => {}; //~ERROR `$s:stmt` is followed by `=`
- | ^
+ | ^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `|`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:84:14
|
LL | ($s:stmt |) => {}; //~ERROR `$s:stmt` is followed by `|`
- | ^
+ | ^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `:`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:85:14
|
LL | ($s:stmt :) => {}; //~ERROR `$s:stmt` is followed by `:`
- | ^
+ | ^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `>`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:86:14
|
LL | ($s:stmt >) => {}; //~ERROR `$s:stmt` is followed by `>`
- | ^
+ | ^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `+`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:87:14
|
LL | ($s:stmt +) => {}; //~ERROR `$s:stmt` is followed by `+`
- | ^
+ | ^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `ident`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:88:14
|
LL | ($s:stmt ident) => {}; //~ERROR `$s:stmt` is followed by `ident`
- | ^^^^^
+ | ^^^^^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `if`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:89:14
|
LL | ($s:stmt if) => {}; //~ERROR `$s:stmt` is followed by `if`
- | ^^
+ | ^^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `in`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:90:14
|
LL | ($s:stmt in) => {}; //~ERROR `$s:stmt` is followed by `in`
- | ^^
+ | ^^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `$p:pat`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:91:14
|
LL | ($s:stmt $p:pat) => {}; //~ERROR `$s:stmt` is followed by `$p:pat`
- | ^^^^^^
+ | ^^^^^^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `$e:expr`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:92:14
|
LL | ($s:stmt $e:expr) => {}; //~ERROR `$s:stmt` is followed by `$e:expr`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `$t:ty`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:93:14
|
LL | ($s:stmt $t:ty) => {}; //~ERROR `$s:stmt` is followed by `$t:ty`
- | ^^^^^
+ | ^^^^^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `$s:stmt`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:94:14
|
LL | ($s:stmt $s:stmt) => {}; //~ERROR `$s:stmt` is followed by `$s:stmt`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `$p:path`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:95:14
|
LL | ($s:stmt $p:path) => {}; //~ERROR `$s:stmt` is followed by `$p:path`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `$b:block`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:96:14
|
LL | ($s:stmt $b:block) => {}; //~ERROR `$s:stmt` is followed by `$b:block`
- | ^^^^^^^^
+ | ^^^^^^^^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `$i:ident`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:97:14
|
LL | ($s:stmt $i:ident) => {}; //~ERROR `$s:stmt` is followed by `$i:ident`
- | ^^^^^^^^
+ | ^^^^^^^^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `$t:tt`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:98:14
|
LL | ($s:stmt $t:tt) => {}; //~ERROR `$s:stmt` is followed by `$t:tt`
- | ^^^^^
+ | ^^^^^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `$i:item`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:99:14
|
LL | ($s:stmt $i:item) => {}; //~ERROR `$s:stmt` is followed by `$i:item`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `$m:meta`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:100:14
|
LL | ($s:stmt $m:meta) => {}; //~ERROR `$s:stmt` is followed by `$m:meta`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `stmt` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$p:path` is followed by `(`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:104:15
|
LL | ($p:path ()) => {}; //~ERROR `$p:path` is followed by `(`
- | ^
+ | ^ not allowed after `path` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `+`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:106:14
|
LL | ($p:path +) => {}; //~ERROR `$p:path` is followed by `+`
- | ^
+ | ^ not allowed after `path` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `ident`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:107:14
|
LL | ($p:path ident) => {}; //~ERROR `$p:path` is followed by `ident`
- | ^^^^^
+ | ^^^^^ not allowed after `path` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `if`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:108:14
|
LL | ($p:path if) => {}; //~ERROR `$p:path` is followed by `if`
- | ^^
+ | ^^ not allowed after `path` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `$p:pat`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:109:14
|
LL | ($p:path $p:pat) => {}; //~ERROR `$p:path` is followed by `$p:pat`
- | ^^^^^^
+ | ^^^^^^ not allowed after `path` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `$e:expr`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:110:14
|
LL | ($p:path $e:expr) => {}; //~ERROR `$p:path` is followed by `$e:expr`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `path` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `$t:ty`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:111:14
|
LL | ($p:path $t:ty) => {}; //~ERROR `$p:path` is followed by `$t:ty`
- | ^^^^^
+ | ^^^^^ not allowed after `path` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `$s:stmt`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:112:14
|
LL | ($p:path $s:stmt) => {}; //~ERROR `$p:path` is followed by `$s:stmt`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `path` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `$p:path`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:113:14
|
LL | ($p:path $p:path) => {}; //~ERROR `$p:path` is followed by `$p:path`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `path` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `$i:ident`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:115:14
|
LL | ($p:path $i:ident) => {}; //~ERROR `$p:path` is followed by `$i:ident`
- | ^^^^^^^^
+ | ^^^^^^^^ not allowed after `path` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `$t:tt`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:116:14
|
LL | ($p:path $t:tt) => {}; //~ERROR `$p:path` is followed by `$t:tt`
- | ^^^^^
+ | ^^^^^ not allowed after `path` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `$i:item`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:117:14
|
LL | ($p:path $i:item) => {}; //~ERROR `$p:path` is followed by `$i:item`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `path` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `$m:meta`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:118:14
|
LL | ($p:path $m:meta) => {}; //~ERROR `$p:path` is followed by `$m:meta`
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `path` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: aborting due to 85 previous errors
--> $DIR/macro-followed-by-seq-bad.rs:17:15
|
LL | ( $a:expr $($b:tt)* ) => { }; //~ ERROR not allowed for `expr` fragments
- | ^^^^^
+ | ^^^^^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: `$a:ty` is followed by `$b:tt`, which is not allowed for `ty` fragments
--> $DIR/macro-followed-by-seq-bad.rs:18:13
|
LL | ( $a:ty $($b:tt)* ) => { }; //~ ERROR not allowed for `ty` fragments
- | ^^^^^
+ | ^^^^^ not allowed after `ty` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: aborting due to 2 previous errors
--- /dev/null
+macro_rules! empty { () => () }
+
+fn main() {
+ match 42 {
+ _ => { empty!() }
+ };
+}
--- /dev/null
+error: expected expression, found `<eof>`
+ --> $DIR/macro-in-expression-context-2.rs:5:16
+ |
+LL | _ => { empty!() }
+ | ^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// run-rustfix
+
+macro_rules! foo {
+ () => {
+ assert_eq!("A", "A");
+ assert_eq!("B", "B");
+ }
+ //~^^ ERROR macro expansion ignores token `assert_eq` and any following
+ //~| NOTE the usage of `foo!` is likely invalid in expression context
+}
+
+fn main() {
+ foo!();
+ //~^ NOTE caused by the macro expansion here
+}
--- /dev/null
+// run-rustfix
+
+macro_rules! foo {
+ () => {
+ assert_eq!("A", "A");
+ assert_eq!("B", "B");
+ }
+ //~^^ ERROR macro expansion ignores token `assert_eq` and any following
+ //~| NOTE the usage of `foo!` is likely invalid in expression context
+}
+
+fn main() {
+ foo!()
+ //~^ NOTE caused by the macro expansion here
+}
--- /dev/null
+error: macro expansion ignores token `assert_eq` and any following
+ --> $DIR/macro-in-expression-context.rs:6:9
+ |
+LL | assert_eq!("B", "B");
+ | ^^^^^^^^^
+...
+LL | foo!()
+ | ------- help: you might be missing a semicolon here: `;`
+ | |
+ | caused by the macro expansion here
+ |
+ = note: the usage of `foo!` is likely invalid in expression context
+
+error: aborting due to previous error
+
--> $DIR/macro-input-future-proofing.rs:14:13
|
LL | ($ty:ty <) => (); //~ ERROR `$ty:ty` is followed by `<`, which is not allowed for `ty`
- | ^
+ | ^ not allowed after `ty` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$ty:ty` is followed by `<`, which is not allowed for `ty` fragments
--> $DIR/macro-input-future-proofing.rs:15:13
|
LL | ($ty:ty < foo ,) => (); //~ ERROR `$ty:ty` is followed by `<`, which is not allowed for `ty`
- | ^
+ | ^ not allowed after `ty` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$pa:pat` is followed by `>`, which is not allowed for `pat` fragments
--> $DIR/macro-input-future-proofing.rs:21:14
|
LL | ($pa:pat >) => (); //~ ERROR `$pa:pat` is followed by `>`, which is not allowed for `pat`
- | ^
+ | ^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
error: `$pa:pat` is followed by `$pb:pat`, which is not allowed for `pat` fragments
--> $DIR/macro-input-future-proofing.rs:23:14
|
LL | ($pa:pat $pb:pat $ty:ty ,) => ();
- | ^^^^^^^
+ | ^^^^^^^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
error: `$pb:pat` is followed by `$ty:ty`, which is not allowed for `pat` fragments
--> $DIR/macro-input-future-proofing.rs:23:22
|
LL | ($pa:pat $pb:pat $ty:ty ,) => ();
- | ^^^^^^
+ | ^^^^^^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
error: `$ty:ty` is followed by `-`, which is not allowed for `ty` fragments
--> $DIR/macro-input-future-proofing.rs:26:17
|
LL | ($($ty:ty)* -) => (); //~ ERROR `$ty:ty` is followed by `-`
- | ^
+ | ^ not allowed after `ty` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$b:ty` is followed by `-`, which is not allowed for `ty` fragments
--> $DIR/macro-input-future-proofing.rs:27:23
|
LL | ($($a:ty, $b:ty)* -) => (); //~ ERROR `$b:ty` is followed by `-`
- | ^
+ | ^ not allowed after `ty` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$ty:ty` is followed by `-`, which is not allowed for `ty` fragments
--> $DIR/macro-input-future-proofing.rs:28:7
|
LL | ($($ty:ty)-+) => (); //~ ERROR `$ty:ty` is followed by `-`, which is not allowed for `ty`
- | ^^^^^^^^
+ | ^^^^^^^^ not allowed after `ty` fragments
+ |
+ = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$a:expr` is followed by `$b:tt`, which is not allowed for `expr` fragments
--> $DIR/macro-input-future-proofing.rs:29:21
|
LL | ( $($a:expr)* $($b:tt)* ) => { };
- | ^^^^^
+ | ^^^^^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: aborting due to 9 previous errors
error: no rules expected the token `a`
--> $DIR/macro-non-lifetime.rs:18:8
|
+LL | macro_rules! m { ($x:lifetime) => { } }
+ | -------------- when calling this macro
+...
LL | m!(a);
- | ^
+ | ^ no rules expected the token `a`
error: aborting due to previous error
LL | use m2::*; // glob-import user-defined `std`
| ^^^^^
note: `std` could also refer to the name defined here
- --> $DIR/macro-path-prelude-shadowing.rs:39:9
- |
-LL | std::panic!(); //~ ERROR `std` is ambiguous
- | ^^^
= note: consider adding an explicit import of `std` to disambiguate
error: aborting due to previous error
error: no rules expected the token `b`
--> $DIR/missing-comma.rs:22:12
|
+LL | macro_rules! foo {
+ | ---------------- when calling this macro
+...
LL | foo!(a b);
- | -^
+ | -^ no rules expected the token `b`
| |
| help: missing comma here
error: no rules expected the token `e`
--> $DIR/missing-comma.rs:24:21
|
+LL | macro_rules! foo {
+ | ---------------- when calling this macro
+...
LL | foo!(a, b, c, d e);
- | -^
+ | -^ no rules expected the token `e`
| |
| help: missing comma here
error: no rules expected the token `d`
--> $DIR/missing-comma.rs:26:18
|
+LL | macro_rules! foo {
+ | ---------------- when calling this macro
+...
LL | foo!(a, b, c d, e);
- | -^
+ | -^ no rules expected the token `d`
| |
| help: missing comma here
error: no rules expected the token `d`
--> $DIR/missing-comma.rs:28:18
|
+LL | macro_rules! foo {
+ | ---------------- when calling this macro
+...
LL | foo!(a, b, c d e);
- | ^
+ | ^ no rules expected the token `d`
error: aborting due to 5 previous errors
--> $DIR/nonterminal-matching.rs:29:10
|
LL | n!(a $nt_item b); //~ ERROR no rules expected the token `enum E { }`
- | ^^^^^^^^
+ | ^^^^^^^^ no rules expected the token `enum E { }`
...
LL | complex_nonterminal!(enum E {});
| -------------------------------- in this macro invocation
error: no rules expected the token `bcd`
--> $DIR/trace_faulty_macros.rs:17:26
|
+LL | macro_rules! my_faulty_macro {
+ | ---------------------------- when calling this macro
+LL | () => {
LL | my_faulty_macro!(bcd); //~ ERROR no rules
- | ^^^
+ | ^^^ no rules expected the token `bcd`
...
LL | my_faulty_macro!();
| ------------------- in this macro invocation
// It got pretty monotonous writing the same code over and over, and I
// feared I would forget details. So I abstracted some desiderata into
// macros. But I left the initialization code inline, because that's
-// where the errors for #54986 will be emited.
+// where the errors for #54986 will be emitted.
macro_rules! use_fully {
(struct $s:expr) => { {
impl Struct {
fn bar(self: &mut Self) {
+ //~^ WARN function cannot return without recursing
(&mut self).bar();
//~^ ERROR cannot borrow `self` as mutable, as it is not declared as mutable [E0596]
}
+warning: function cannot return without recursing
+ --> $DIR/issue-51191.rs:16:5
+ |
+LL | fn bar(self: &mut Self) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL | //~^ WARN function cannot return without recursing
+LL | (&mut self).bar();
+ | ----------------- recursive call site
+ |
+ = note: #[warn(unconditional_recursion)] on by default
+ = help: a `loop` may express intention better if this is on purpose
+
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
- --> $DIR/issue-51191.rs:17:9
+ --> $DIR/issue-51191.rs:18:9
|
LL | (&mut self).bar();
| ^^^^^^^^^^^
| try removing `&mut` here
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
- --> $DIR/issue-51191.rs:22:9
+ --> $DIR/issue-51191.rs:23:9
|
LL | fn imm(self) {
| ---- help: consider changing this to be mutable: `mut self`
| ^^^^^^^^^^^ cannot borrow as mutable
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
- --> $DIR/issue-51191.rs:31:9
+ --> $DIR/issue-51191.rs:32:9
|
LL | (&mut self).bar();
| ^^^^^^^^^^^ cannot borrow as mutable
error[E0596]: cannot borrow data in a `&` reference as mutable
- --> $DIR/issue-51191.rs:31:9
+ --> $DIR/issue-51191.rs:32:9
|
LL | (&mut self).bar();
| ^^^^^^^^^^^ cannot borrow as mutable
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
- --> $DIR/issue-51191.rs:37:9
+ --> $DIR/issue-51191.rs:38:9
|
LL | (&mut self).bar();
| ^^^^^^^^^^^
// rust-lang/rust#52059: Regardless of whether you are moving out of a
-// Drop type or just introducing an inadvertant alias via a borrow of
+// Drop type or just introducing an inadvertent alias via a borrow of
// one of its fields, it is useful to be reminded of the significance
// of the fact that the type implements Drop.
--- /dev/null
+// Regression test for #55219:
+//
+// The `Self::HASH_LEN` here expands to a "self-type" where `T` is not
+// known. This unbound inference variable was causing an ICE.
+//
+// run-pass
+
+#![feature(nll)]
+
+pub struct Foo<T>(T);
+
+impl<T> Foo<T> {
+ const HASH_LEN: usize = 20;
+
+ fn stuff() {
+ let _ = Self::HASH_LEN;
+ }
+}
+
+fn main() { }
--- /dev/null
+// Regression test for #55241:
+//
+// The reference to `C::HASHED_NULL_NODE` resulted in a type like `<C
+// as NodeCodec<_>>::Out`; normalizing this type requires knowing the
+// value of `_`; solving that requires having normalized, so we can
+// test against `C: NodeCodec<H>` in the environment.
+//
+// run-pass
+
+#![feature(nll)]
+
+pub trait Hasher {
+ type Out: Eq;
+}
+
+pub trait NodeCodec<H: Hasher> {
+ const HASHED_NULL_NODE: H::Out;
+}
+
+pub trait Trie<H: Hasher, C: NodeCodec<H>> {
+ /// Return the root of the trie.
+ fn root(&self) -> &H::Out;
+
+ /// Is the trie empty?
+ fn is_empty(&self) -> bool { *self.root() == C::HASHED_NULL_NODE }
+}
+
+fn main() { }
error: no rules expected the token `!`
--> $DIR/macro-doc-comments-1.rs:16:5
|
+LL | macro_rules! outer {
+ | ------------------ when calling this macro
+...
LL | //! Inner
- | ^^^^^^^^^
+ | ^^^^^^^^^ no rules expected the token `!`
error: aborting due to previous error
error: no rules expected the token `[`
--> $DIR/macro-doc-comments-2.rs:16:5
|
+LL | macro_rules! inner {
+ | ------------------ when calling this macro
+...
LL | /// Outer
- | ^
+ | ^ no rules expected the token `[`
error: aborting due to previous error
|
LL | , //~ ERROR macro expansion ignores token `,`
| ^
- |
-note: caused by the macro expansion here; the usage of `ignored_item!` is likely invalid in item context
- --> $DIR/macro-incomplete-parse.rs:31:1
- |
+...
LL | ignored_item!();
- | ^^^^^^^^^^^^^^^^
+ | ---------------- caused by the macro expansion here
+ |
+ = note: the usage of `ignored_item!` is likely invalid in item context
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,`
--> $DIR/macro-incomplete-parse.rs:22:14
|
LL | () => ( 1, 2 ) //~ ERROR macro expansion ignores token `,`
| ^
- |
-note: caused by the macro expansion here; the usage of `ignored_pat!` is likely invalid in pattern context
- --> $DIR/macro-incomplete-parse.rs:36:9
- |
+...
LL | ignored_pat!() => (),
- | ^^^^^^^^^^^^^^
+ | -------------- caused by the macro expansion here
+ |
+ = note: the usage of `ignored_pat!` is likely invalid in pattern context
error: aborting due to 3 previous errors
+warning: function cannot return without recursing
+ --> $DIR/region-bound-on-closure-outlives-call.rs:11:1
+ |
+LL | fn call_rec<F>(mut f: F) -> usize where F: FnMut(usize) -> usize {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL | //~^ WARN function cannot return without recursing
+LL | (|x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f`
+ | ----------- recursive call site
+ |
+ = note: #[warn(unconditional_recursion)] on by default
+ = help: a `loop` may express intention better if this is on purpose
+
error[E0505]: cannot move out of `f` because it is borrowed
- --> $DIR/region-bound-on-closure-outlives-call.rs:12:25
+ --> $DIR/region-bound-on-closure-outlives-call.rs:13:25
|
LL | (|x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f`
| ---------- ^ move out of `f` occurs here
// except according to those terms.
fn call_rec<F>(mut f: F) -> usize where F: FnMut(usize) -> usize {
+ //~^ WARN function cannot return without recursing
(|x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f`
}
+warning: function cannot return without recursing
+ --> $DIR/region-bound-on-closure-outlives-call.rs:11:1
+ |
+LL | fn call_rec<F>(mut f: F) -> usize where F: FnMut(usize) -> usize {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL | //~^ WARN function cannot return without recursing
+LL | (|x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f`
+ | ----------- recursive call site
+ |
+ = note: #[warn(unconditional_recursion)] on by default
+ = help: a `loop` may express intention better if this is on purpose
+
error[E0505]: cannot move out of `f` because it is borrowed
- --> $DIR/region-bound-on-closure-outlives-call.rs:12:25
+ --> $DIR/region-bound-on-closure-outlives-call.rs:13:25
|
LL | (|x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f`
| --- ^ move out of `f` occurs here
LL | }
| - temporary value is freed at the end of this statement
-error[E0597]: `y` does not live long enough
- --> $DIR/regions-free-region-ordering-caller1.rs:19:27
- |
-LL | fn call1<'a>(x: &'a usize) {
- | -- lifetime `'a` defined here
-...
-LL | let z: &'a & usize = &(&y);
- | ----------- ^^^^ borrowed value does not live long enough
- | |
- | type annotation requires that `y` is borrowed for `'a`
-...
-LL | }
- | - `y` dropped here while still borrowed
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors occurred: E0597, E0716.
-For more information about an error, try `rustc --explain E0597`.
+For more information about this error, try `rustc --explain E0716`.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Test that we do some basic error correcton in the tokeniser (and don't ICE).
+// Test that we do some basic error correction in the tokeniser (and don't ICE).
fn main() {
if foo {
// ignore-cloudabi no std::fs support
-// Test that we do some basic error correcton in the tokeniser (and don't spew
+// Test that we do some basic error correction in the tokeniser (and don't spew
// too many bogus errors).
pub mod raw {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Test that we do some basic error correcton in the tokeniser.
+// Test that we do some basic error correction in the tokeniser.
fn main() {
foo(bar(;
use std::ops::Range;
if let Range { start: _, end: _ } = true..true && false { }
- //~^ ERROR ambigious use of `&&`
+ //~^ ERROR ambiguous use of `&&`
if let Range { start: _, end: _ } = true..true || false { }
- //~^ ERROR ambigious use of `||`
+ //~^ ERROR ambiguous use of `||`
while let Range { start: _, end: _ } = true..true && false { }
- //~^ ERROR ambigious use of `&&`
+ //~^ ERROR ambiguous use of `&&`
while let Range { start: _, end: _ } = true..true || false { }
- //~^ ERROR ambigious use of `||`
+ //~^ ERROR ambiguous use of `||`
if let true = false && false { }
- //~^ ERROR ambigious use of `&&`
+ //~^ ERROR ambiguous use of `&&`
while let true = (1 == 2) && false { }
- //~^ ERROR ambigious use of `&&`
+ //~^ ERROR ambiguous use of `&&`
// The following cases are not an error as parenthesis are used to
// clarify intent:
-error: ambigious use of `&&`
+error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2015.rs:21:47
|
LL | if let Range { start: _, end: _ } = true..true && false { }
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
-error: ambigious use of `||`
+error: ambiguous use of `||`
--> $DIR/syntax-ambiguity-2015.rs:24:47
|
LL | if let Range { start: _, end: _ } = true..true || false { }
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
-error: ambigious use of `&&`
+error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2015.rs:27:50
|
LL | while let Range { start: _, end: _ } = true..true && false { }
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
-error: ambigious use of `||`
+error: ambiguous use of `||`
--> $DIR/syntax-ambiguity-2015.rs:30:50
|
LL | while let Range { start: _, end: _ } = true..true || false { }
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
-error: ambigious use of `&&`
+error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2015.rs:33:19
|
LL | if let true = false && false { }
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
-error: ambigious use of `&&`
+error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2015.rs:36:22
|
LL | while let true = (1 == 2) && false { }
use std::ops::Range;
if let Range { start: _, end: _ } = true..true && false { }
- //~^ ERROR ambigious use of `&&`
+ //~^ ERROR ambiguous use of `&&`
if let Range { start: _, end: _ } = true..true || false { }
- //~^ ERROR ambigious use of `||`
+ //~^ ERROR ambiguous use of `||`
while let Range { start: _, end: _ } = true..true && false { }
- //~^ ERROR ambigious use of `&&`
+ //~^ ERROR ambiguous use of `&&`
while let Range { start: _, end: _ } = true..true || false { }
- //~^ ERROR ambigious use of `||`
+ //~^ ERROR ambiguous use of `||`
if let true = false && false { }
- //~^ ERROR ambigious use of `&&`
+ //~^ ERROR ambiguous use of `&&`
while let true = (1 == 2) && false { }
- //~^ ERROR ambigious use of `&&`
+ //~^ ERROR ambiguous use of `&&`
// The following cases are not an error as parenthesis are used to
// clarify intent:
-error: ambigious use of `&&`
+error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2018.rs:21:47
|
LL | if let Range { start: _, end: _ } = true..true && false { }
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
-error: ambigious use of `||`
+error: ambiguous use of `||`
--> $DIR/syntax-ambiguity-2018.rs:24:47
|
LL | if let Range { start: _, end: _ } = true..true || false { }
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
-error: ambigious use of `&&`
+error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2018.rs:27:50
|
LL | while let Range { start: _, end: _ } = true..true && false { }
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
-error: ambigious use of `||`
+error: ambiguous use of `||`
--> $DIR/syntax-ambiguity-2018.rs:30:50
|
LL | while let Range { start: _, end: _ } = true..true || false { }
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
-error: ambigious use of `&&`
+error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2018.rs:33:19
|
LL | if let true = false && false { }
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
-error: ambigious use of `&&`
+error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2018.rs:36:22
|
LL | while let true = (1 == 2) && false { }
// • one generic parameter (T) bound inline
// • one parameter (T) with a where clause
// • two parameters (T and U), both bound inline
-// • two paramters (T and U), one bound inline, one with a where clause
+// • two parameters (T and U), one bound inline, one with a where clause
// • two parameters (T and U), both with where clauses
//
// —and for every permutation of 0, 1, or 2 lifetimes to outlive and 0 or 1
// • one generic parameter (T) bound inline
// • one parameter (T) with a where clause
// • two parameters (T and U), both bound inline
-// • two paramters (T and U), one bound inline, one with a where clause
+// • two parameters (T and U), one bound inline, one with a where clause
// • two parameters (T and U), both with where clauses
//
// —and for every permutation of 0, 1, or 2 lifetimes to outlive and 0 or 1
// Regression test for #52050: when inserting the blanket impl `I`
// into the tree, we had to replace the child node for `Foo`, which
-// led to the struture of the tree being messed up.
+// led to the structure of the tree being messed up.
use std::iter::Iterator;
error: no rules expected the token `_`
--> $DIR/underscore-ident-matcher.rs:18:19
|
+LL | macro_rules! identity {
+ | --------------------- when calling this macro
+...
LL | let identity!(_) = 10; //~ ERROR no rules expected the token `_`
- | ^
+ | ^ no rules expected the token `_`
error: aborting due to previous error
--> $DIR/underscore-lifetime-binders.rs:20:29
|
LL | fn meh() -> Box<for<'_> Meh<'_>> //~ ERROR cannot be used here
- | ^^ expected lifetime parameter
+ | ^^ help: consider giving it a 'static lifetime: `'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
- = help: consider giving it a 'static lifetime
error[E0106]: missing lifetime specifier
--> $DIR/underscore-lifetime-binders.rs:26:35
--> $DIR/unused-macro-with-follow-violation.rs:14:14
|
LL | ($e:expr +) => () //~ ERROR not allowed for `expr` fragments
- | ^
+ | ^ not allowed after `expr` fragments
+ |
+ = note: allowed there are: `=>`, `,` or `;`
error: aborting due to previous error
--> $DIR/vec-macro-with-comma-only.rs:12:10
|
LL | vec![,]; //~ ERROR no rules expected the token `,`
- | ^
+ | ^ no rules expected the token `,`
error: aborting due to previous error
-Subproject commit 5afdf8b78507ddf015d192858aef56e72c17de16
+Subproject commit b1d0343749bdc87e5cbbe7f1aeaa9d2a2c9dbc5b
fn find_test_mod(contents: &str) -> usize {
if let Some(mod_tests_idx) = contents.find("mod tests") {
- // Also capture a previos line indicating "mod tests" in cfg-ed out
+ // Also capture a previous line indicating "mod tests" in cfg-ed out
let prev_newline_idx = contents[..mod_tests_idx].rfind('\n').unwrap_or(mod_tests_idx);
let prev_newline_idx = contents[..prev_newline_idx].rfind('\n');
if let Some(nl) = prev_newline_idx {