Auto merge of #51448 - Mark-Simulacrum:rollup, r=Mark-Simulacrum
Rollup of 13 pull requests Successful merges: - #50143 (Add deprecation lint for duplicated `macro_export`s) - #51099 (Fix Issue 38777) - #51276 (Dedup auto traits in trait objects.) - #51298 (Stabilize unit tests with non-`()` return type) - #51360 (Suggest parentheses when a struct literal needs them) - #51391 (Use spans pointing at the inside of a rustdoc attribute) - #51394 (Use scope tree depths to speed up `nearest_common_ancestor`.) - #51396 (Make the size of Option<NonZero*> a documented guarantee.) - #51401 (Warn on `repr` without hints) - #51412 (Avoid useless Vec clones in pending_obligations().) - #51427 (compiletest: autoremove duplicate .nll.* files (#51204)) - #51436 (Do not require stage 2 compiler for rustdoc) - #51437 (rustbuild: generate full list of dependencies for metadata) Failed merges:
This commit is contained in:
commit
cf91e9b9ba
54 changed files with 1108 additions and 457 deletions
|
@ -800,10 +800,7 @@ impl<'a> Builder<'a> {
|
||||||
cargo.env("RUSTC_ERROR_FORMAT", error_format);
|
cargo.env("RUSTC_ERROR_FORMAT", error_format);
|
||||||
}
|
}
|
||||||
if cmd != "build" && cmd != "check" && want_rustdoc {
|
if cmd != "build" && cmd != "check" && want_rustdoc {
|
||||||
cargo.env(
|
cargo.env("RUSTDOC_LIBDIR", self.sysroot_libdir(compiler, self.config.build));
|
||||||
"RUSTDOC_LIBDIR",
|
|
||||||
self.rustc_libdir(self.compiler(2, self.config.build)),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if mode.is_tool() {
|
if mode.is_tool() {
|
||||||
|
|
|
@ -280,7 +280,8 @@ pub struct Build {
|
||||||
struct Crate {
|
struct Crate {
|
||||||
name: Interned<String>,
|
name: Interned<String>,
|
||||||
version: String,
|
version: String,
|
||||||
deps: Vec<Interned<String>>,
|
deps: HashSet<Interned<String>>,
|
||||||
|
id: String,
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
doc_step: String,
|
doc_step: String,
|
||||||
build_step: String,
|
build_step: String,
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use build_helper::output;
|
use build_helper::output;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
@ -45,45 +46,17 @@ struct ResolveNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(build: &mut Build) {
|
pub fn build(build: &mut Build) {
|
||||||
build_krate(build, "src/libstd");
|
let mut resolves = Vec::new();
|
||||||
build_krate(build, "src/libtest");
|
build_krate(&build.std_features(), build, &mut resolves, "src/libstd");
|
||||||
build_krate(build, "src/rustc");
|
build_krate("", build, &mut resolves, "src/libtest");
|
||||||
}
|
build_krate(&build.rustc_features(), build, &mut resolves, "src/rustc");
|
||||||
|
|
||||||
fn build_krate(build: &mut Build, krate: &str) {
|
|
||||||
// Run `cargo metadata` to figure out what crates we're testing.
|
|
||||||
//
|
|
||||||
// Down below we're going to call `cargo test`, but to test the right set
|
|
||||||
// of packages we're going to have to know what `-p` arguments to pass it
|
|
||||||
// to know what crates to test. Here we run `cargo metadata` to learn about
|
|
||||||
// the dependency graph and what `-p` arguments there are.
|
|
||||||
let mut cargo = Command::new(&build.initial_cargo);
|
|
||||||
cargo.arg("metadata")
|
|
||||||
.arg("--format-version").arg("1")
|
|
||||||
.arg("--manifest-path").arg(build.src.join(krate).join("Cargo.toml"));
|
|
||||||
let output = output(&mut cargo);
|
|
||||||
let output: Output = serde_json::from_str(&output).unwrap();
|
|
||||||
let mut id2name = HashMap::new();
|
let mut id2name = HashMap::new();
|
||||||
for package in output.packages {
|
for (name, krate) in build.crates.iter() {
|
||||||
if package.source.is_none() {
|
id2name.insert(krate.id.clone(), name.clone());
|
||||||
let name = INTERNER.intern_string(package.name);
|
|
||||||
id2name.insert(package.id, name);
|
|
||||||
let mut path = PathBuf::from(package.manifest_path);
|
|
||||||
path.pop();
|
|
||||||
build.crates.insert(name, Crate {
|
|
||||||
build_step: format!("build-crate-{}", name),
|
|
||||||
doc_step: format!("doc-crate-{}", name),
|
|
||||||
test_step: format!("test-crate-{}", name),
|
|
||||||
bench_step: format!("bench-crate-{}", name),
|
|
||||||
name,
|
|
||||||
version: package.version,
|
|
||||||
deps: Vec::new(),
|
|
||||||
path,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for node in output.resolve.nodes {
|
for node in resolves {
|
||||||
let name = match id2name.get(&node.id) {
|
let name = match id2name.get(&node.id) {
|
||||||
Some(name) => name,
|
Some(name) => name,
|
||||||
None => continue,
|
None => continue,
|
||||||
|
@ -95,7 +68,42 @@ fn build_krate(build: &mut Build, krate: &str) {
|
||||||
Some(dep) => dep,
|
Some(dep) => dep,
|
||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
krate.deps.push(*dep);
|
krate.deps.insert(*dep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_krate(features: &str, build: &mut Build, resolves: &mut Vec<ResolveNode>, krate: &str) {
|
||||||
|
// Run `cargo metadata` to figure out what crates we're testing.
|
||||||
|
//
|
||||||
|
// Down below we're going to call `cargo test`, but to test the right set
|
||||||
|
// of packages we're going to have to know what `-p` arguments to pass it
|
||||||
|
// to know what crates to test. Here we run `cargo metadata` to learn about
|
||||||
|
// the dependency graph and what `-p` arguments there are.
|
||||||
|
let mut cargo = Command::new(&build.initial_cargo);
|
||||||
|
cargo.arg("metadata")
|
||||||
|
.arg("--format-version").arg("1")
|
||||||
|
.arg("--features").arg(features)
|
||||||
|
.arg("--manifest-path").arg(build.src.join(krate).join("Cargo.toml"));
|
||||||
|
let output = output(&mut cargo);
|
||||||
|
let output: Output = serde_json::from_str(&output).unwrap();
|
||||||
|
for package in output.packages {
|
||||||
|
if package.source.is_none() {
|
||||||
|
let name = INTERNER.intern_string(package.name);
|
||||||
|
let mut path = PathBuf::from(package.manifest_path);
|
||||||
|
path.pop();
|
||||||
|
build.crates.insert(name, Crate {
|
||||||
|
build_step: format!("build-crate-{}", name),
|
||||||
|
doc_step: format!("doc-crate-{}", name),
|
||||||
|
test_step: format!("test-crate-{}", name),
|
||||||
|
bench_step: format!("bench-crate-{}", name),
|
||||||
|
name,
|
||||||
|
version: package.version,
|
||||||
|
id: package.id,
|
||||||
|
deps: HashSet::new(),
|
||||||
|
path,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resolves.extend(output.resolve.nodes);
|
||||||
|
}
|
||||||
|
|
|
@ -39,10 +39,10 @@ macro_rules! nonzero_integers {
|
||||||
$(
|
$(
|
||||||
/// An integer that is known not to equal zero.
|
/// An integer that is known not to equal zero.
|
||||||
///
|
///
|
||||||
/// This may enable some memory layout optimization such as:
|
/// This enables some memory layout optimization.
|
||||||
|
/// For example, `Option<NonZeroU32>` is the same size as `u32`:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # #![feature(nonzero)]
|
|
||||||
/// use std::mem::size_of;
|
/// use std::mem::size_of;
|
||||||
/// assert_eq!(size_of::<Option<std::num::NonZeroU32>>(), size_of::<u32>());
|
/// assert_eq!(size_of::<Option<std::num::NonZeroU32>>(), size_of::<u32>());
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
use errors::{Applicability, DiagnosticBuilder};
|
use errors::{Applicability, DiagnosticBuilder};
|
||||||
use lint::{LintPass, LateLintPass, LintArray};
|
use lint::{LintPass, LateLintPass, LintArray};
|
||||||
use session::Session;
|
use session::Session;
|
||||||
|
use syntax::ast;
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
|
@ -206,6 +207,12 @@ declare_lint! {
|
||||||
"potentially-conflicting impls were erroneously allowed"
|
"potentially-conflicting impls were erroneously allowed"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
pub BAD_REPR,
|
||||||
|
Warn,
|
||||||
|
"detects incorrect use of `repr` attribute"
|
||||||
|
}
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
pub DEPRECATED,
|
pub DEPRECATED,
|
||||||
Warn,
|
Warn,
|
||||||
|
@ -285,6 +292,12 @@ declare_lint! {
|
||||||
"warns about duplicate associated type bindings in generics"
|
"warns about duplicate associated type bindings in generics"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
pub DUPLICATE_MACRO_EXPORTS,
|
||||||
|
Deny,
|
||||||
|
"detects duplicate macro exports"
|
||||||
|
}
|
||||||
|
|
||||||
/// Does nothing as a lint pass, but registers some `Lint`s
|
/// Does nothing as a lint pass, but registers some `Lint`s
|
||||||
/// which are used by other parts of the compiler.
|
/// which are used by other parts of the compiler.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
@ -337,6 +350,7 @@ impl LintPass for HardwiredLints {
|
||||||
ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
|
ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
|
||||||
UNSTABLE_NAME_COLLISIONS,
|
UNSTABLE_NAME_COLLISIONS,
|
||||||
DUPLICATE_ASSOCIATED_TYPE_BINDINGS,
|
DUPLICATE_ASSOCIATED_TYPE_BINDINGS,
|
||||||
|
DUPLICATE_MACRO_EXPORTS,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -348,6 +362,7 @@ pub enum BuiltinLintDiagnostics {
|
||||||
Normal,
|
Normal,
|
||||||
BareTraitObject(Span, /* is_global */ bool),
|
BareTraitObject(Span, /* is_global */ bool),
|
||||||
AbsPathWithModule(Span),
|
AbsPathWithModule(Span),
|
||||||
|
DuplicatedMacroExports(ast::Ident, Span, Span),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuiltinLintDiagnostics {
|
impl BuiltinLintDiagnostics {
|
||||||
|
@ -380,6 +395,10 @@ impl BuiltinLintDiagnostics {
|
||||||
};
|
};
|
||||||
db.span_suggestion_with_applicability(span, "use `crate`", sugg, app);
|
db.span_suggestion_with_applicability(span, "use `crate`", sugg, app);
|
||||||
}
|
}
|
||||||
|
BuiltinLintDiagnostics::DuplicatedMacroExports(ident, earlier_span, later_span) => {
|
||||||
|
db.span_label(later_span, format!("`{}` already exported", ident));
|
||||||
|
db.span_note(earlier_span, "previous macro export is now shadowed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ use ty;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use rustc_data_structures::small_vec::SmallVec;
|
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use syntax::codemap;
|
use syntax::codemap;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
@ -280,6 +279,8 @@ impl Scope {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type ScopeDepth = u32;
|
||||||
|
|
||||||
/// The region scope tree encodes information about region relationships.
|
/// The region scope tree encodes information about region relationships.
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct ScopeTree {
|
pub struct ScopeTree {
|
||||||
|
@ -297,7 +298,7 @@ pub struct ScopeTree {
|
||||||
/// conditional expression or repeating block. (Note that the
|
/// conditional expression or repeating block. (Note that the
|
||||||
/// enclosing scope id for the block associated with a closure is
|
/// enclosing scope id for the block associated with a closure is
|
||||||
/// the closure itself.)
|
/// the closure itself.)
|
||||||
parent_map: FxHashMap<Scope, Scope>,
|
parent_map: FxHashMap<Scope, (Scope, ScopeDepth)>,
|
||||||
|
|
||||||
/// `var_map` maps from a variable or binding id to the block in
|
/// `var_map` maps from a variable or binding id to the block in
|
||||||
/// which that variable is declared.
|
/// which that variable is declared.
|
||||||
|
@ -415,11 +416,12 @@ pub struct Context {
|
||||||
/// details.
|
/// details.
|
||||||
root_id: Option<hir::ItemLocalId>,
|
root_id: Option<hir::ItemLocalId>,
|
||||||
|
|
||||||
/// the scope that contains any new variables declared
|
/// The scope that contains any new variables declared, plus its depth in
|
||||||
var_parent: Option<Scope>,
|
/// the scope tree.
|
||||||
|
var_parent: Option<(Scope, ScopeDepth)>,
|
||||||
|
|
||||||
/// region parent of expressions etc
|
/// Region parent of expressions, etc., plus its depth in the scope tree.
|
||||||
parent: Option<Scope>,
|
parent: Option<(Scope, ScopeDepth)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RegionResolutionVisitor<'a, 'tcx: 'a> {
|
struct RegionResolutionVisitor<'a, 'tcx: 'a> {
|
||||||
|
@ -499,7 +501,7 @@ impl<'tcx> Visitor<'tcx> for ExprLocatorVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ScopeTree {
|
impl<'tcx> ScopeTree {
|
||||||
pub fn record_scope_parent(&mut self, child: Scope, parent: Option<Scope>) {
|
pub fn record_scope_parent(&mut self, child: Scope, parent: Option<(Scope, ScopeDepth)>) {
|
||||||
debug!("{:?}.parent = {:?}", child, parent);
|
debug!("{:?}.parent = {:?}", child, parent);
|
||||||
|
|
||||||
if let Some(p) = parent {
|
if let Some(p) = parent {
|
||||||
|
@ -515,7 +517,7 @@ impl<'tcx> ScopeTree {
|
||||||
|
|
||||||
pub fn each_encl_scope<E>(&self, mut e:E) where E: FnMut(Scope, Scope) {
|
pub fn each_encl_scope<E>(&self, mut e:E) where E: FnMut(Scope, Scope) {
|
||||||
for (&child, &parent) in &self.parent_map {
|
for (&child, &parent) in &self.parent_map {
|
||||||
e(child, parent)
|
e(child, parent.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,7 +560,7 @@ impl<'tcx> ScopeTree {
|
||||||
|
|
||||||
pub fn opt_encl_scope(&self, id: Scope) -> Option<Scope> {
|
pub fn opt_encl_scope(&self, id: Scope) -> Option<Scope> {
|
||||||
//! Returns the narrowest scope that encloses `id`, if any.
|
//! Returns the narrowest scope that encloses `id`, if any.
|
||||||
self.parent_map.get(&id).cloned()
|
self.parent_map.get(&id).cloned().map(|(p, _)| p)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)] // used in cfg
|
#[allow(dead_code)] // used in cfg
|
||||||
|
@ -590,7 +592,7 @@ impl<'tcx> ScopeTree {
|
||||||
// returned.
|
// returned.
|
||||||
let mut id = Scope::Node(expr_id);
|
let mut id = Scope::Node(expr_id);
|
||||||
|
|
||||||
while let Some(&p) = self.parent_map.get(&id) {
|
while let Some(&(p, _)) = self.parent_map.get(&id) {
|
||||||
match p.data() {
|
match p.data() {
|
||||||
ScopeData::Destruction(..) => {
|
ScopeData::Destruction(..) => {
|
||||||
debug!("temporary_scope({:?}) = {:?} [enclosing]",
|
debug!("temporary_scope({:?}) = {:?} [enclosing]",
|
||||||
|
@ -658,57 +660,61 @@ impl<'tcx> ScopeTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finds the nearest common ancestor (if any) of two scopes. That is, finds the smallest
|
/// Finds the nearest common ancestor of two scopes. That is, finds the
|
||||||
/// scope which is greater than or equal to both `scope_a` and `scope_b`.
|
/// smallest scope which is greater than or equal to both `scope_a` and
|
||||||
pub fn nearest_common_ancestor(&self,
|
/// `scope_b`.
|
||||||
scope_a: Scope,
|
pub fn nearest_common_ancestor(&self, scope_a: Scope, scope_b: Scope) -> Scope {
|
||||||
scope_b: Scope)
|
|
||||||
-> Scope {
|
|
||||||
if scope_a == scope_b { return scope_a; }
|
if scope_a == scope_b { return scope_a; }
|
||||||
|
|
||||||
// Process the lists in tandem from the innermost scope, recording the
|
let mut a = scope_a;
|
||||||
// scopes seen so far. The first scope that comes up for a second time
|
let mut b = scope_b;
|
||||||
// is the nearest common ancestor.
|
|
||||||
//
|
|
||||||
// Note: another way to compute the nearest common ancestor is to get
|
|
||||||
// the full scope chain for both scopes and then compare the chains to
|
|
||||||
// find the first scope in a common tail. But getting a parent scope
|
|
||||||
// requires a hash table lookup, and we often have very long scope
|
|
||||||
// chains (10s or 100s of scopes) that only differ by a few elements at
|
|
||||||
// the start. So this algorithm is faster.
|
|
||||||
|
|
||||||
let mut ma = Some(&scope_a);
|
// Get the depth of each scope's parent. If either scope has no parent,
|
||||||
let mut mb = Some(&scope_b);
|
// it must be the root, which means we can stop immediately because the
|
||||||
|
// root must be the nearest common ancestor. (In practice, this is
|
||||||
|
// moderately common.)
|
||||||
|
let (parent_a, parent_a_depth) = match self.parent_map.get(&a) {
|
||||||
|
Some(pd) => *pd,
|
||||||
|
None => return a,
|
||||||
|
};
|
||||||
|
let (parent_b, parent_b_depth) = match self.parent_map.get(&b) {
|
||||||
|
Some(pd) => *pd,
|
||||||
|
None => return b,
|
||||||
|
};
|
||||||
|
|
||||||
// A HashSet<Scope> is a more obvious choice for these, but SmallVec is
|
if parent_a_depth > parent_b_depth {
|
||||||
// faster because the set size is normally small so linear search is
|
// `a` is lower than `b`. Move `a` up until it's at the same depth
|
||||||
// as good or better than a hash table lookup, plus the size is usually
|
// as `b`. The first move up is trivial because we already found
|
||||||
// small enough to avoid a heap allocation.
|
// `parent_a` above; the loop does the remaining N-1 moves.
|
||||||
let mut seen_a: SmallVec<[&Scope; 32]> = SmallVec::new();
|
a = parent_a;
|
||||||
let mut seen_b: SmallVec<[&Scope; 32]> = SmallVec::new();
|
for _ in 0..(parent_a_depth - parent_b_depth - 1) {
|
||||||
|
a = self.parent_map.get(&a).unwrap().0;
|
||||||
loop {
|
|
||||||
if let Some(a) = ma {
|
|
||||||
if seen_b.iter().any(|s| *s == a) {
|
|
||||||
return *a;
|
|
||||||
}
|
}
|
||||||
seen_a.push(a);
|
} else if parent_b_depth > parent_a_depth {
|
||||||
ma = self.parent_map.get(&a);
|
// `b` is lower than `a`.
|
||||||
|
b = parent_b;
|
||||||
|
for _ in 0..(parent_b_depth - parent_a_depth - 1) {
|
||||||
|
b = self.parent_map.get(&b).unwrap().0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Both scopes are at the same depth, and we know they're not equal
|
||||||
|
// because that case was tested for at the top of this function. So
|
||||||
|
// we can trivially move them both up one level now.
|
||||||
|
assert!(parent_a_depth != 0);
|
||||||
|
a = parent_a;
|
||||||
|
b = parent_b;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(b) = mb {
|
// Now both scopes are at the same level. We move upwards in lockstep
|
||||||
if seen_a.iter().any(|s| *s == b) {
|
// until they match. In practice, this loop is almost always executed
|
||||||
return *b;
|
// zero times because `a` is almost always a direct ancestor of `b` or
|
||||||
}
|
// vice versa.
|
||||||
seen_b.push(b);
|
while a != b {
|
||||||
mb = self.parent_map.get(&b);
|
a = self.parent_map.get(&a).unwrap().0;
|
||||||
}
|
b = self.parent_map.get(&b).unwrap().0;
|
||||||
|
};
|
||||||
|
|
||||||
if ma.is_none() && mb.is_none() {
|
a
|
||||||
// No nearest common ancestor found.
|
|
||||||
bug!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assuming that the provided region was defined within this `ScopeTree`,
|
/// Assuming that the provided region was defined within this `ScopeTree`,
|
||||||
|
@ -807,7 +813,7 @@ fn record_var_lifetime(visitor: &mut RegionResolutionVisitor,
|
||||||
//
|
//
|
||||||
// extern fn isalnum(c: c_int) -> c_int
|
// extern fn isalnum(c: c_int) -> c_int
|
||||||
}
|
}
|
||||||
Some(parent_scope) =>
|
Some((parent_scope, _)) =>
|
||||||
visitor.scope_tree.record_var_scope(var_id, parent_scope),
|
visitor.scope_tree.record_var_scope(var_id, parent_scope),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1019,7 +1025,7 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
|
||||||
// Keep traversing up while we can.
|
// Keep traversing up while we can.
|
||||||
match visitor.scope_tree.parent_map.get(&scope) {
|
match visitor.scope_tree.parent_map.get(&scope) {
|
||||||
// Don't cross from closure bodies to their parent.
|
// Don't cross from closure bodies to their parent.
|
||||||
Some(&superscope) => match superscope.data() {
|
Some(&(superscope, _)) => match superscope.data() {
|
||||||
ScopeData::CallSite(_) => break,
|
ScopeData::CallSite(_) => break,
|
||||||
_ => scope = superscope
|
_ => scope = superscope
|
||||||
},
|
},
|
||||||
|
@ -1036,7 +1042,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
|
||||||
init: Option<&'tcx hir::Expr>) {
|
init: Option<&'tcx hir::Expr>) {
|
||||||
debug!("resolve_local(pat={:?}, init={:?})", pat, init);
|
debug!("resolve_local(pat={:?}, init={:?})", pat, init);
|
||||||
|
|
||||||
let blk_scope = visitor.cx.var_parent;
|
let blk_scope = visitor.cx.var_parent.map(|(p, _)| p);
|
||||||
|
|
||||||
// As an exception to the normal rules governing temporary
|
// As an exception to the normal rules governing temporary
|
||||||
// lifetimes, initializers in a let have a temporary lifetime
|
// lifetimes, initializers in a let have a temporary lifetime
|
||||||
|
@ -1261,16 +1267,20 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
|
||||||
|
|
||||||
impl<'a, 'tcx> RegionResolutionVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> RegionResolutionVisitor<'a, 'tcx> {
|
||||||
/// Records the current parent (if any) as the parent of `child_scope`.
|
/// Records the current parent (if any) as the parent of `child_scope`.
|
||||||
fn record_child_scope(&mut self, child_scope: Scope) {
|
/// Returns the depth of `child_scope`.
|
||||||
|
fn record_child_scope(&mut self, child_scope: Scope) -> ScopeDepth {
|
||||||
let parent = self.cx.parent;
|
let parent = self.cx.parent;
|
||||||
self.scope_tree.record_scope_parent(child_scope, parent);
|
self.scope_tree.record_scope_parent(child_scope, parent);
|
||||||
|
// If `child_scope` has no parent, it must be the root node, and so has
|
||||||
|
// a depth of 1. Otherwise, its depth is one more than its parent's.
|
||||||
|
parent.map_or(1, |(_p, d)| d + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Records the current parent (if any) as the parent of `child_scope`,
|
/// Records the current parent (if any) as the parent of `child_scope`,
|
||||||
/// and sets `child_scope` as the new current parent.
|
/// and sets `child_scope` as the new current parent.
|
||||||
fn enter_scope(&mut self, child_scope: Scope) {
|
fn enter_scope(&mut self, child_scope: Scope) {
|
||||||
self.record_child_scope(child_scope);
|
let child_depth = self.record_child_scope(child_scope);
|
||||||
self.cx.parent = Some(child_scope);
|
self.cx.parent = Some((child_scope, child_depth));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enter_node_scope_with_dtor(&mut self, id: hir::ItemLocalId) {
|
fn enter_node_scope_with_dtor(&mut self, id: hir::ItemLocalId) {
|
||||||
|
|
|
@ -13,7 +13,7 @@ use ty::{self, Ty, TyCtxt};
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
|
|
||||||
use super::{FulfillmentContext, FulfillmentError};
|
use super::{FulfillmentContext, FulfillmentError};
|
||||||
use super::{ObligationCause, PendingPredicateObligation, PredicateObligation};
|
use super::{ObligationCause, PredicateObligation};
|
||||||
|
|
||||||
pub trait TraitEngine<'tcx>: 'tcx {
|
pub trait TraitEngine<'tcx>: 'tcx {
|
||||||
fn normalize_projection_type<'a, 'gcx>(
|
fn normalize_projection_type<'a, 'gcx>(
|
||||||
|
@ -49,7 +49,7 @@ pub trait TraitEngine<'tcx>: 'tcx {
|
||||||
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||||
) -> Result<(), Vec<FulfillmentError<'tcx>>>;
|
) -> Result<(), Vec<FulfillmentError<'tcx>>>;
|
||||||
|
|
||||||
fn pending_obligations(&self) -> Vec<PendingPredicateObligation<'tcx>>;
|
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> dyn TraitEngine<'tcx> {
|
impl<'a, 'gcx, 'tcx> dyn TraitEngine<'tcx> {
|
||||||
|
|
|
@ -241,8 +241,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
|
||||||
self.select(&mut selcx)
|
self.select(&mut selcx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_obligations(&self) -> Vec<PendingPredicateObligation<'tcx>> {
|
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
|
||||||
self.predicates.pending_obligations()
|
self.predicates.map_pending_obligations(|o| o.obligation.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -229,13 +229,13 @@ impl<O: ForestObligation> ObligationForest<O> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the set of obligations that are in a pending state.
|
/// Returns the set of obligations that are in a pending state.
|
||||||
pub fn pending_obligations(&self) -> Vec<O>
|
pub fn map_pending_obligations<P, F>(&self, f: F) -> Vec<P>
|
||||||
where O: Clone
|
where F: Fn(&O) -> P
|
||||||
{
|
{
|
||||||
self.nodes
|
self.nodes
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|n| n.state.get() == NodeState::Pending)
|
.filter(|n| n.state.get() == NodeState::Pending)
|
||||||
.map(|n| n.obligation.clone())
|
.map(|n| f(&n.obligation))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -191,11 +191,12 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
||||||
self.infcx.tcx
|
self.infcx.tcx
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_region_hierarchy(&mut self, rh: &RH, parent: region::Scope) {
|
pub fn create_region_hierarchy(&mut self, rh: &RH,
|
||||||
|
parent: (region::Scope, region::ScopeDepth)) {
|
||||||
let me = region::Scope::Node(rh.id);
|
let me = region::Scope::Node(rh.id);
|
||||||
self.region_scope_tree.record_scope_parent(me, Some(parent));
|
self.region_scope_tree.record_scope_parent(me, Some(parent));
|
||||||
for child_rh in rh.sub {
|
for child_rh in rh.sub {
|
||||||
self.create_region_hierarchy(child_rh, me);
|
self.create_region_hierarchy(child_rh, (me, parent.1 + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +216,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
||||||
id: hir::ItemLocalId(11),
|
id: hir::ItemLocalId(11),
|
||||||
sub: &[],
|
sub: &[],
|
||||||
}],
|
}],
|
||||||
}, dscope);
|
}, (dscope, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)] // this seems like it could be useful, even if we don't use it now
|
#[allow(dead_code)] // this seems like it could be useful, even if we don't use it now
|
||||||
|
|
|
@ -673,6 +673,79 @@ impl EarlyLintPass for AnonymousParameters {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks for incorrect use use of `repr` attributes.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct BadRepr;
|
||||||
|
|
||||||
|
impl LintPass for BadRepr {
|
||||||
|
fn get_lints(&self) -> LintArray {
|
||||||
|
lint_array!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EarlyLintPass for BadRepr {
|
||||||
|
fn check_attribute(&mut self, cx: &EarlyContext, attr: &ast::Attribute) {
|
||||||
|
if attr.name() == "repr" {
|
||||||
|
let list = attr.meta_item_list();
|
||||||
|
|
||||||
|
let repr_str = |lit: &str| { format!("#[repr({})]", lit) };
|
||||||
|
|
||||||
|
// Emit warnings with `repr` either has a literal assignment (`#[repr = "C"]`) or
|
||||||
|
// no hints (``#[repr]`)
|
||||||
|
let has_hints = list.as_ref().map(|ref list| !list.is_empty()).unwrap_or(false);
|
||||||
|
if !has_hints {
|
||||||
|
let mut suggested = false;
|
||||||
|
let mut warn = if let Some(ref lit) = attr.value_str() {
|
||||||
|
// avoid warning about empty `repr` on `#[repr = "foo"]`
|
||||||
|
let mut warn = cx.struct_span_lint(
|
||||||
|
BAD_REPR,
|
||||||
|
attr.span,
|
||||||
|
"`repr` attribute isn't configurable with a literal",
|
||||||
|
);
|
||||||
|
match format!("{}", lit).as_ref() {
|
||||||
|
| "C" | "packed" | "rust" | "transparent"
|
||||||
|
| "u8" | "u16" | "u32" | "u64" | "u128" | "usize"
|
||||||
|
| "i8" | "i16" | "i32" | "i64" | "i128" | "isize" => {
|
||||||
|
// if the literal could have been a valid `repr` arg,
|
||||||
|
// suggest the correct syntax
|
||||||
|
warn.span_suggestion(
|
||||||
|
attr.span,
|
||||||
|
"give `repr` a hint",
|
||||||
|
repr_str(&lit.as_str()),
|
||||||
|
);
|
||||||
|
suggested = true;
|
||||||
|
}
|
||||||
|
_ => { // the literal wasn't a valid `repr` arg
|
||||||
|
warn.span_label(attr.span, "needs a hint");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
warn
|
||||||
|
} else {
|
||||||
|
let mut warn = cx.struct_span_lint(
|
||||||
|
BAD_REPR,
|
||||||
|
attr.span,
|
||||||
|
"`repr` attribute must have a hint",
|
||||||
|
);
|
||||||
|
warn.span_label(attr.span, "needs a hint");
|
||||||
|
warn
|
||||||
|
};
|
||||||
|
if !suggested {
|
||||||
|
warn.help(&format!(
|
||||||
|
"valid hints include `{}`, `{}`, `{}` and `{}`",
|
||||||
|
repr_str("C"),
|
||||||
|
repr_str("packed"),
|
||||||
|
repr_str("rust"),
|
||||||
|
repr_str("transparent"),
|
||||||
|
));
|
||||||
|
warn.note("for more information, visit \
|
||||||
|
<https://doc.rust-lang.org/reference/type-layout.html>");
|
||||||
|
}
|
||||||
|
warn.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks for use of attributes which have been deprecated.
|
/// Checks for use of attributes which have been deprecated.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct DeprecatedAttr {
|
pub struct DeprecatedAttr {
|
||||||
|
|
|
@ -107,6 +107,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
||||||
UnusedImportBraces,
|
UnusedImportBraces,
|
||||||
AnonymousParameters,
|
AnonymousParameters,
|
||||||
UnusedDocComment,
|
UnusedDocComment,
|
||||||
|
BadRepr,
|
||||||
);
|
);
|
||||||
|
|
||||||
add_early_builtin_with_new!(sess,
|
add_early_builtin_with_new!(sess,
|
||||||
|
@ -211,6 +212,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
||||||
reference: "issue #35203 <https://github.com/rust-lang/rust/issues/35203>",
|
reference: "issue #35203 <https://github.com/rust-lang/rust/issues/35203>",
|
||||||
edition: None,
|
edition: None,
|
||||||
},
|
},
|
||||||
|
FutureIncompatibleInfo {
|
||||||
|
id: LintId::of(DUPLICATE_MACRO_EXPORTS),
|
||||||
|
reference: "issue #35896 <https://github.com/rust-lang/rust/issues/35896>",
|
||||||
|
edition: Some(Edition::Edition2018),
|
||||||
|
},
|
||||||
FutureIncompatibleInfo {
|
FutureIncompatibleInfo {
|
||||||
id: LintId::of(SAFE_EXTERN_STATICS),
|
id: LintId::of(SAFE_EXTERN_STATICS),
|
||||||
reference: "issue #36247 <https://github.com/rust-lang/rust/issues/36247>",
|
reference: "issue #36247 <https://github.com/rust-lang/rust/issues/36247>",
|
||||||
|
|
|
@ -2934,8 +2934,38 @@ impl<'a> Resolver<'a> {
|
||||||
here due to private fields"));
|
here due to private fields"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?",
|
// HACK(estebank): find a better way to figure out that this was a
|
||||||
path_str));
|
// parser issue where a struct literal is being used on an expression
|
||||||
|
// where a brace being opened means a block is being started. Look
|
||||||
|
// ahead for the next text to see if `span` is followed by a `{`.
|
||||||
|
let cm = this.session.codemap();
|
||||||
|
let mut sp = span;
|
||||||
|
loop {
|
||||||
|
sp = cm.next_point(sp);
|
||||||
|
match cm.span_to_snippet(sp) {
|
||||||
|
Ok(ref snippet) => {
|
||||||
|
if snippet.chars().any(|c| { !c.is_whitespace() }) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let followed_by_brace = match cm.span_to_snippet(sp) {
|
||||||
|
Ok(ref snippet) if snippet == "{" => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if let (PathSource::Expr(None), true) = (source, followed_by_brace) {
|
||||||
|
err.span_label(
|
||||||
|
span,
|
||||||
|
format!("did you mean `({} {{ /* fields */ }})`?", path_str),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
err.span_label(
|
||||||
|
span,
|
||||||
|
format!("did you mean `{} {{ /* fields */ }}`?", path_str),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return (err, candidates);
|
return (err, candidates);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,13 +18,14 @@ use {names_to_string, module_to_string};
|
||||||
use {resolve_error, ResolutionError};
|
use {resolve_error, ResolutionError};
|
||||||
|
|
||||||
use rustc::ty;
|
use rustc::ty;
|
||||||
use rustc::lint::builtin::PUB_USE_OF_PRIVATE_EXTERN_CRATE;
|
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::{CRATE_DEF_INDEX, DefId};
|
||||||
use rustc::hir::def::*;
|
use rustc::hir::def::*;
|
||||||
use rustc::session::DiagnosticMessageId;
|
use rustc::session::DiagnosticMessageId;
|
||||||
use rustc::util::nodemap::{FxHashMap, FxHashSet};
|
use rustc::util::nodemap::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
use syntax::ast::{Ident, Name, NodeId};
|
use syntax::ast::{Ident, Name, NodeId, CRATE_NODE_ID};
|
||||||
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
|
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
|
||||||
use syntax::ext::hygiene::Mark;
|
use syntax::ext::hygiene::Mark;
|
||||||
use syntax::symbol::keywords;
|
use syntax::symbol::keywords;
|
||||||
|
@ -974,7 +975,16 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||||
if module as *const _ == self.graph_root as *const _ {
|
if module as *const _ == self.graph_root as *const _ {
|
||||||
let macro_exports = mem::replace(&mut self.macro_exports, Vec::new());
|
let macro_exports = mem::replace(&mut self.macro_exports, Vec::new());
|
||||||
for export in macro_exports.into_iter().rev() {
|
for export in macro_exports.into_iter().rev() {
|
||||||
if exported_macro_names.insert(export.ident.modern(), export.span).is_none() {
|
if let Some(later_span) = exported_macro_names.insert(export.ident.modern(),
|
||||||
|
export.span) {
|
||||||
|
self.session.buffer_lint_with_diagnostic(
|
||||||
|
DUPLICATE_MACRO_EXPORTS,
|
||||||
|
CRATE_NODE_ID,
|
||||||
|
later_span,
|
||||||
|
&format!("a macro named `{}` has already been exported", export.ident),
|
||||||
|
BuiltinLintDiagnostics::DuplicatedMacroExports(
|
||||||
|
export.ident, export.span, later_span));
|
||||||
|
} else {
|
||||||
reexports.push(export);
|
reexports.push(export);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ use util::common::ErrorReported;
|
||||||
use util::nodemap::{FxHashSet, FxHashMap};
|
use util::nodemap::{FxHashSet, FxHashMap};
|
||||||
use errors::FatalError;
|
use errors::FatalError;
|
||||||
|
|
||||||
|
// use std::cmp::Ordering;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::feature_gate::{GateIssue, emit_feature_err};
|
use syntax::feature_gate::{GateIssue, emit_feature_err};
|
||||||
|
@ -646,7 +647,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||||
&mut vec![]);
|
&mut vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (auto_traits, trait_bounds) = split_auto_traits(tcx, &trait_bounds[1..]);
|
let (mut auto_traits, trait_bounds) = split_auto_traits(tcx, &trait_bounds[1..]);
|
||||||
|
|
||||||
if !trait_bounds.is_empty() {
|
if !trait_bounds.is_empty() {
|
||||||
let b = &trait_bounds[0];
|
let b = &trait_bounds[0];
|
||||||
|
@ -707,6 +708,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dedup auto traits so that `dyn Trait + Send + Send` is the same as `dyn Trait + Send`.
|
||||||
|
auto_traits.sort();
|
||||||
|
auto_traits.dedup();
|
||||||
|
|
||||||
// skip_binder is okay, because the predicates are re-bound.
|
// skip_binder is okay, because the predicates are re-bound.
|
||||||
let mut v =
|
let mut v =
|
||||||
iter::once(ty::ExistentialPredicate::Trait(*existential_principal.skip_binder()))
|
iter::once(ty::ExistentialPredicate::Trait(*existential_principal.skip_binder()))
|
||||||
|
@ -1319,7 +1324,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Divides a list of general trait bounds into two groups: builtin bounds (Sync/Send) and the
|
/// Divides a list of general trait bounds into two groups: auto traits (e.g. Sync and Send) and the
|
||||||
/// remaining general trait bounds.
|
/// remaining general trait bounds.
|
||||||
fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
trait_bounds: &'b [hir::PolyTraitRef])
|
trait_bounds: &'b [hir::PolyTraitRef])
|
||||||
|
|
|
@ -225,7 +225,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
let expected_sig = fulfillment_cx
|
let expected_sig = fulfillment_cx
|
||||||
.pending_obligations()
|
.pending_obligations()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|obligation| &obligation.obligation)
|
|
||||||
.filter_map(|obligation| {
|
.filter_map(|obligation| {
|
||||||
debug!(
|
debug!(
|
||||||
"deduce_expectations_from_obligations: obligation.predicate={:?}",
|
"deduce_expectations_from_obligations: obligation.predicate={:?}",
|
||||||
|
@ -257,7 +256,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
let expected_kind = fulfillment_cx
|
let expected_kind = fulfillment_cx
|
||||||
.pending_obligations()
|
.pending_obligations()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|obligation| &obligation.obligation)
|
|
||||||
.filter_map(|obligation| {
|
.filter_map(|obligation| {
|
||||||
let opt_trait_ref = match obligation.predicate {
|
let opt_trait_ref = match obligation.predicate {
|
||||||
ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref(self.tcx)),
|
ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref(self.tcx)),
|
||||||
|
|
|
@ -1251,30 +1251,60 @@ fn resolution_failure(
|
||||||
link_range: Option<Range<usize>>,
|
link_range: Option<Range<usize>>,
|
||||||
) {
|
) {
|
||||||
let sp = span_of_attrs(attrs);
|
let sp = span_of_attrs(attrs);
|
||||||
let mut diag = cx.sess()
|
let msg = format!("`[{}]` cannot be resolved, ignoring it...", path_str);
|
||||||
.struct_span_warn(sp, &format!("[{}] cannot be resolved, ignoring it...", path_str));
|
|
||||||
|
|
||||||
if let Some(link_range) = link_range {
|
let code_dox = sp.to_src(cx);
|
||||||
|
|
||||||
|
let doc_comment_padding = 3;
|
||||||
|
let mut diag = if let Some(link_range) = link_range {
|
||||||
// blah blah blah\nblah\nblah [blah] blah blah\nblah blah
|
// blah blah blah\nblah\nblah [blah] blah blah\nblah blah
|
||||||
// ^ ~~~~~~
|
// ^ ~~~~~~
|
||||||
// | link_range
|
// | link_range
|
||||||
// last_new_line_offset
|
// last_new_line_offset
|
||||||
|
|
||||||
|
let mut diag;
|
||||||
|
if dox.lines().count() == code_dox.lines().count() {
|
||||||
|
let line_offset = dox[..link_range.start].lines().count();
|
||||||
|
// The span starts in the `///`, so we don't have to account for the leading whitespace
|
||||||
|
let code_dox_len = if line_offset <= 1 {
|
||||||
|
doc_comment_padding
|
||||||
|
} else {
|
||||||
|
// The first `///`
|
||||||
|
doc_comment_padding +
|
||||||
|
// Each subsequent leading whitespace and `///`
|
||||||
|
code_dox.lines().skip(1).take(line_offset - 1).fold(0, |sum, line| {
|
||||||
|
sum + doc_comment_padding + line.len() - line.trim().len()
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extract the specific span
|
||||||
|
let sp = sp.from_inner_byte_pos(
|
||||||
|
link_range.start + code_dox_len,
|
||||||
|
link_range.end + code_dox_len,
|
||||||
|
);
|
||||||
|
|
||||||
|
diag = cx.sess().struct_span_warn(sp, &msg);
|
||||||
|
diag.span_label(sp, "cannot be resolved, ignoring");
|
||||||
|
} else {
|
||||||
|
diag = cx.sess().struct_span_warn(sp, &msg);
|
||||||
|
|
||||||
let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
|
let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
|
||||||
let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
|
let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
|
||||||
|
|
||||||
// Print the line containing the `link_range` and manually mark it with '^'s
|
// Print the line containing the `link_range` and manually mark it with '^'s
|
||||||
diag.note(&format!(
|
diag.note(&format!(
|
||||||
"the link appears in this line:\n\n{line}\n{indicator: <before$}{indicator:^<found$}",
|
"the link appears in this line:\n\n{line}\n\
|
||||||
|
{indicator: <before$}{indicator:^<found$}",
|
||||||
line=line,
|
line=line,
|
||||||
indicator="",
|
indicator="",
|
||||||
before=link_range.start - last_new_line_offset,
|
before=link_range.start - last_new_line_offset,
|
||||||
found=link_range.len(),
|
found=link_range.len(),
|
||||||
));
|
));
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
diag
|
||||||
|
} else {
|
||||||
|
cx.sess().struct_span_warn(sp, &msg)
|
||||||
|
};
|
||||||
diag.emit();
|
diag.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -398,9 +398,6 @@ declare_features! (
|
||||||
// `foo.rs` as an alternative to `foo/mod.rs`
|
// `foo.rs` as an alternative to `foo/mod.rs`
|
||||||
(active, non_modrs_mods, "1.24.0", Some(44660), Some(Edition::Edition2018)),
|
(active, non_modrs_mods, "1.24.0", Some(44660), Some(Edition::Edition2018)),
|
||||||
|
|
||||||
// Termination trait in tests (RFC 1937)
|
|
||||||
(active, termination_trait_test, "1.24.0", Some(48854), Some(Edition::Edition2018)),
|
|
||||||
|
|
||||||
// `extern` in paths
|
// `extern` in paths
|
||||||
(active, extern_in_paths, "1.23.0", Some(44660), None),
|
(active, extern_in_paths, "1.23.0", Some(44660), None),
|
||||||
|
|
||||||
|
@ -616,6 +613,8 @@ declare_features! (
|
||||||
(accepted, fn_must_use, "1.27.0", Some(43302), None),
|
(accepted, fn_must_use, "1.27.0", Some(43302), None),
|
||||||
// Allows use of the :lifetime macro fragment specifier
|
// Allows use of the :lifetime macro fragment specifier
|
||||||
(accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None),
|
(accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None),
|
||||||
|
// Termination trait in tests (RFC 1937)
|
||||||
|
(accepted, termination_trait_test, "1.27.0", Some(48854), None),
|
||||||
);
|
);
|
||||||
|
|
||||||
// If you change this, please modify src/doc/unstable-book as well. You must
|
// If you change this, please modify src/doc/unstable-book as well. You must
|
||||||
|
|
|
@ -652,7 +652,7 @@ impl<'a> Parser<'a> {
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.expect_one_of(unsafe { slice::from_raw_parts(t, 1) }, &[])
|
self.expect_one_of(slice::from_ref(t), &[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1108,7 +1108,12 @@ impl<'a> Parser<'a> {
|
||||||
{
|
{
|
||||||
let mut first: bool = true;
|
let mut first: bool = true;
|
||||||
let mut v = vec![];
|
let mut v = vec![];
|
||||||
while !kets.contains(&&self.token) {
|
while !kets.iter().any(|k| {
|
||||||
|
match expect {
|
||||||
|
TokenExpectType::Expect => self.check(k),
|
||||||
|
TokenExpectType::NoExpect => self.token == **k,
|
||||||
|
}
|
||||||
|
}) {
|
||||||
match self.token {
|
match self.token {
|
||||||
token::CloseDelim(..) | token::Eof => break,
|
token::CloseDelim(..) | token::Eof => break,
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -335,7 +335,7 @@ enum BadTestSignature {
|
||||||
fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
|
fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
|
||||||
let has_test_attr = attr::contains_name(&i.attrs, "test");
|
let has_test_attr = attr::contains_name(&i.attrs, "test");
|
||||||
|
|
||||||
fn has_test_signature(cx: &TestCtxt, i: &ast::Item) -> HasTestSignature {
|
fn has_test_signature(_cx: &TestCtxt, i: &ast::Item) -> HasTestSignature {
|
||||||
let has_should_panic_attr = attr::contains_name(&i.attrs, "should_panic");
|
let has_should_panic_attr = attr::contains_name(&i.attrs, "should_panic");
|
||||||
match i.node {
|
match i.node {
|
||||||
ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => {
|
ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => {
|
||||||
|
@ -351,15 +351,14 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
|
||||||
return No(BadTestSignature::NoArgumentsAllowed);
|
return No(BadTestSignature::NoArgumentsAllowed);
|
||||||
}
|
}
|
||||||
|
|
||||||
match (has_output, cx.features.termination_trait_test, has_should_panic_attr) {
|
match (has_output, has_should_panic_attr) {
|
||||||
(true, true, true) => No(BadTestSignature::ShouldPanicOnlyWithNoArgs),
|
(true, true) => No(BadTestSignature::ShouldPanicOnlyWithNoArgs),
|
||||||
(true, true, false) => if generics.is_parameterized() {
|
(true, false) => if generics.is_parameterized() {
|
||||||
No(BadTestSignature::WrongTypeSignature)
|
No(BadTestSignature::WrongTypeSignature)
|
||||||
} else {
|
} else {
|
||||||
Yes
|
Yes
|
||||||
},
|
},
|
||||||
(true, false, _) => No(BadTestSignature::WrongTypeSignature),
|
(false, _) => Yes
|
||||||
(false, _, _) => Yes
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => No(BadTestSignature::NotEvenAFunction),
|
_ => No(BadTestSignature::NotEvenAFunction),
|
||||||
|
@ -395,31 +394,12 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
|
||||||
fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
|
fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
|
||||||
let has_bench_attr = attr::contains_name(&i.attrs, "bench");
|
let has_bench_attr = attr::contains_name(&i.attrs, "bench");
|
||||||
|
|
||||||
fn has_bench_signature(cx: &TestCtxt, i: &ast::Item) -> bool {
|
fn has_bench_signature(_cx: &TestCtxt, i: &ast::Item) -> bool {
|
||||||
match i.node {
|
match i.node {
|
||||||
ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => {
|
ast::ItemKind::Fn(ref decl, _, _, _, _, _) => {
|
||||||
let input_cnt = decl.inputs.len();
|
|
||||||
|
|
||||||
// If the termination trait is active, the compiler will check that the output
|
|
||||||
// type implements the `Termination` trait as `libtest` enforces that.
|
|
||||||
let output_matches = if cx.features.termination_trait_test {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
let no_output = match decl.output {
|
|
||||||
ast::FunctionRetTy::Default(..) => true,
|
|
||||||
ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true,
|
|
||||||
_ => false
|
|
||||||
};
|
|
||||||
let tparm_cnt = generics.params.iter()
|
|
||||||
.filter(|param| param.is_type_param())
|
|
||||||
.count();
|
|
||||||
|
|
||||||
no_output && tparm_cnt == 0
|
|
||||||
};
|
|
||||||
|
|
||||||
// NB: inadequate check, but we're running
|
// NB: inadequate check, but we're running
|
||||||
// well before resolve, can't get too deep.
|
// well before resolve, can't get too deep.
|
||||||
input_cnt == 1 && output_matches
|
decl.inputs.len() == 1
|
||||||
}
|
}
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
|
@ -430,13 +410,8 @@ fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
|
||||||
if has_bench_attr && !has_bench_signature {
|
if has_bench_attr && !has_bench_signature {
|
||||||
let diag = cx.span_diagnostic;
|
let diag = cx.span_diagnostic;
|
||||||
|
|
||||||
if cx.features.termination_trait_test {
|
|
||||||
diag.span_err(i.span, "functions used as benches must have signature \
|
diag.span_err(i.span, "functions used as benches must have signature \
|
||||||
`fn(&mut Bencher) -> impl Termination`");
|
`fn(&mut Bencher) -> impl Termination`");
|
||||||
} else {
|
|
||||||
diag.span_err(i.span, "functions used as benches must have signature \
|
|
||||||
`fn(&mut Bencher) -> ()`");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
has_bench_attr && has_bench_signature
|
has_bench_attr && has_bench_signature
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
fn foo(a: [0; 1]) {} //~ ERROR expected type, found `0`
|
fn foo(a: [0; 1]) {} //~ ERROR expected type, found `0`
|
||||||
//~| ERROR expected one of `->`, `where`, or `{`, found `]`
|
//~| ERROR expected one of `)`, `,`, `->`, `where`, or `{`, found `]`
|
||||||
// FIXME(jseyfried): avoid emitting the second error (preexisting)
|
// FIXME(jseyfried): avoid emitting the second error (preexisting)
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -34,6 +34,7 @@ fn main() {
|
||||||
#[repr]
|
#[repr]
|
||||||
let _y = "123";
|
let _y = "123";
|
||||||
//~^^ ERROR attribute should not be applied to a statement
|
//~^^ ERROR attribute should not be applied to a statement
|
||||||
|
//~| WARN `repr` attribute must have a hint
|
||||||
|
|
||||||
|
|
||||||
fn foo() {}
|
fn foo() {}
|
||||||
|
@ -44,5 +45,5 @@ fn main() {
|
||||||
|
|
||||||
let _z = #[repr] 1;
|
let _z = #[repr] 1;
|
||||||
//~^ ERROR attribute should not be applied to an expression
|
//~^ ERROR attribute should not be applied to an expression
|
||||||
|
//~| WARN `repr` attribute must have a hint
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![allow(duplicate_macro_exports)]
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! foo { ($i:ident) => {} }
|
macro_rules! foo { ($i:ident) => {} }
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
// file at the top-level directory of this distribution and at
|
// file at the top-level directory of this distribution and at
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
//
|
//
|
||||||
|
@ -8,15 +8,6 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-flags: --test
|
macro_rules! macro_one { ($($t:tt)*) => ($($t)*) }
|
||||||
|
|
||||||
fn main() {}
|
macro_rules! macro_two { ($($t:tt)*) => ($($t)*) }
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
#[test]
|
|
||||||
fn it_works() -> Result<(), ()> {
|
|
||||||
//~^ ERROR functions used as tests must have signature fn() -> ()
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -20,12 +20,12 @@ pub fn main() {
|
||||||
|
|
||||||
#[path = "auxiliary"]
|
#[path = "auxiliary"]
|
||||||
mod foo {
|
mod foo {
|
||||||
mod two_macros;
|
mod two_macros_2;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[path = "auxiliary"]
|
#[path = "auxiliary"]
|
||||||
mod bar {
|
mod bar {
|
||||||
macro_rules! m { () => { mod two_macros; } }
|
macro_rules! m { () => { mod two_macros_2; } }
|
||||||
m!();
|
m!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
53
src/test/run-pass/trait-object-auto-dedup.rs
Normal file
53
src/test/run-pass/trait-object-auto-dedup.rs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright 2014 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 duplicate auto trait bounds in trait objects don't create new types.
|
||||||
|
#[allow(unused_assignments)]
|
||||||
|
|
||||||
|
use std::marker::Send as SendAlias;
|
||||||
|
|
||||||
|
// A dummy trait for the non-auto trait.
|
||||||
|
trait Trait {}
|
||||||
|
|
||||||
|
// A dummy struct to implement Trait, Send, and .
|
||||||
|
struct Struct;
|
||||||
|
|
||||||
|
impl Trait for Struct {}
|
||||||
|
|
||||||
|
// These three functions should be equivalent.
|
||||||
|
fn takes_dyn_trait_send(_: Box<dyn Trait + Send>) {}
|
||||||
|
fn takes_dyn_trait_send_send(_: Box<dyn Trait + Send + Send>) {}
|
||||||
|
fn takes_dyn_trait_send_sendalias(_: Box<dyn Trait + Send + SendAlias>) {}
|
||||||
|
|
||||||
|
impl dyn Trait + Send + Send {
|
||||||
|
fn do_nothing(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// 1. Moving into a variable with more Sends and back.
|
||||||
|
let mut dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>;
|
||||||
|
let dyn_trait_send_send: Box<dyn Trait + Send + Send> = dyn_trait_send;
|
||||||
|
dyn_trait_send = dyn_trait_send_send;
|
||||||
|
|
||||||
|
// 2. Calling methods with different number of Sends.
|
||||||
|
let dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>;
|
||||||
|
takes_dyn_trait_send_send(dyn_trait_send);
|
||||||
|
|
||||||
|
let dyn_trait_send_send = Box::new(Struct) as Box<dyn Trait + Send + Send>;
|
||||||
|
takes_dyn_trait_send(dyn_trait_send_send);
|
||||||
|
|
||||||
|
// 3. Aliases to the trait are transparent.
|
||||||
|
let dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>;
|
||||||
|
takes_dyn_trait_send_sendalias(dyn_trait_send);
|
||||||
|
|
||||||
|
// 4. Calling an impl that duplicates an auto trait.
|
||||||
|
let dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>;
|
||||||
|
dyn_trait_send.do_nothing();
|
||||||
|
}
|
|
@ -10,10 +10,48 @@
|
||||||
|
|
||||||
// compile-pass
|
// compile-pass
|
||||||
|
|
||||||
//! Test with [Foo::baz], [Bar::foo], ...
|
//! Test with [Foo::baz], [Bar::foo], ...
|
||||||
//!
|
//! , [Uniooon::X] and [Qux::Z].
|
||||||
//! and [Uniooon::X].
|
//!
|
||||||
|
//! , [Uniooon::X] and [Qux::Z].
|
||||||
|
|
||||||
|
/// [Qux:Y]
|
||||||
pub struct Foo {
|
pub struct Foo {
|
||||||
pub bar: usize,
|
pub bar: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Foo
|
||||||
|
/// bar [BarA] bar
|
||||||
|
/// baz
|
||||||
|
pub fn a() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Foo
|
||||||
|
* bar [BarB] bar
|
||||||
|
* baz
|
||||||
|
*/
|
||||||
|
pub fn b() {}
|
||||||
|
|
||||||
|
/** Foo
|
||||||
|
|
||||||
|
bar [BarC] bar
|
||||||
|
baz
|
||||||
|
|
||||||
|
let bar_c_1 = 0;
|
||||||
|
let bar_c_2 = 0;
|
||||||
|
let g = [bar_c_1];
|
||||||
|
let h = g[bar_c_2];
|
||||||
|
|
||||||
|
*/
|
||||||
|
pub fn c() {}
|
||||||
|
|
||||||
|
#[doc = "Foo\nbar [BarD] bar\nbaz"]
|
||||||
|
pub fn d() {}
|
||||||
|
|
||||||
|
macro_rules! f {
|
||||||
|
($f:expr) => {
|
||||||
|
#[doc = $f]
|
||||||
|
pub fn f() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f!("Foo\nbar [BarF] bar\nbaz");
|
||||||
|
|
|
@ -1,39 +1,105 @@
|
||||||
warning: [Foo::baz] cannot be resolved, ignoring it...
|
warning: `[Foo::baz]` cannot be resolved, ignoring it...
|
||||||
--> $DIR/intra-links-warning.rs:13:1
|
--> $DIR/intra-links-warning.rs:13:23
|
||||||
|
|
|
|
||||||
13 | / //! Test with [Foo::baz], [Bar::foo], ...
|
13 | //! Test with [Foo::baz], [Bar::foo], ...
|
||||||
14 | | //!
|
| ^^^^^^^^ cannot be resolved, ignoring
|
||||||
15 | | //! and [Uniooon::X].
|
|
||||||
| |_____________________^
|
warning: `[Bar::foo]` cannot be resolved, ignoring it...
|
||||||
|
--> $DIR/intra-links-warning.rs:13:35
|
||||||
|
|
|
||||||
|
13 | //! Test with [Foo::baz], [Bar::foo], ...
|
||||||
|
| ^^^^^^^^ cannot be resolved, ignoring
|
||||||
|
|
||||||
|
warning: `[Uniooon::X]` cannot be resolved, ignoring it...
|
||||||
|
--> $DIR/intra-links-warning.rs:14:13
|
||||||
|
|
|
||||||
|
14 | //! , [Uniooon::X] and [Qux::Z].
|
||||||
|
| ^^^^^^^^^^ cannot be resolved, ignoring
|
||||||
|
|
||||||
|
warning: `[Qux::Z]` cannot be resolved, ignoring it...
|
||||||
|
--> $DIR/intra-links-warning.rs:14:30
|
||||||
|
|
|
||||||
|
14 | //! , [Uniooon::X] and [Qux::Z].
|
||||||
|
| ^^^^^^ cannot be resolved, ignoring
|
||||||
|
|
||||||
|
warning: `[Uniooon::X]` cannot be resolved, ignoring it...
|
||||||
|
--> $DIR/intra-links-warning.rs:16:14
|
||||||
|
|
|
||||||
|
16 | //! , [Uniooon::X] and [Qux::Z].
|
||||||
|
| ^^^^^^^^^^ cannot be resolved, ignoring
|
||||||
|
|
||||||
|
warning: `[Qux::Z]` cannot be resolved, ignoring it...
|
||||||
|
--> $DIR/intra-links-warning.rs:16:31
|
||||||
|
|
|
||||||
|
16 | //! , [Uniooon::X] and [Qux::Z].
|
||||||
|
| ^^^^^^ cannot be resolved, ignoring
|
||||||
|
|
||||||
|
warning: `[Qux:Y]` cannot be resolved, ignoring it...
|
||||||
|
--> $DIR/intra-links-warning.rs:18:13
|
||||||
|
|
|
||||||
|
18 | /// [Qux:Y]
|
||||||
|
| ^^^^^ cannot be resolved, ignoring
|
||||||
|
|
||||||
|
warning: `[BarA]` cannot be resolved, ignoring it...
|
||||||
|
--> $DIR/intra-links-warning.rs:24:10
|
||||||
|
|
|
||||||
|
24 | /// bar [BarA] bar
|
||||||
|
| ^^^^ cannot be resolved, ignoring
|
||||||
|
|
||||||
|
warning: `[BarB]` cannot be resolved, ignoring it...
|
||||||
|
--> $DIR/intra-links-warning.rs:28:1
|
||||||
|
|
|
||||||
|
28 | / /**
|
||||||
|
29 | | * Foo
|
||||||
|
30 | | * bar [BarB] bar
|
||||||
|
31 | | * baz
|
||||||
|
32 | | */
|
||||||
|
| |___^
|
||||||
|
|
|
|
||||||
= note: the link appears in this line:
|
= note: the link appears in this line:
|
||||||
|
|
||||||
Test with [Foo::baz], [Bar::foo], ...
|
bar [BarB] bar
|
||||||
^^^^^^^^
|
^^^^
|
||||||
|
|
||||||
warning: [Bar::foo] cannot be resolved, ignoring it...
|
warning: `[BarC]` cannot be resolved, ignoring it...
|
||||||
--> $DIR/intra-links-warning.rs:13:1
|
--> $DIR/intra-links-warning.rs:35:1
|
||||||
|
|
|
|
||||||
13 | / //! Test with [Foo::baz], [Bar::foo], ...
|
35 | / /** Foo
|
||||||
14 | | //!
|
36 | |
|
||||||
15 | | //! and [Uniooon::X].
|
37 | | bar [BarC] bar
|
||||||
| |_____________________^
|
38 | | baz
|
||||||
|
... |
|
||||||
|
44 | |
|
||||||
|
45 | | */
|
||||||
|
| |__^
|
||||||
|
|
|
|
||||||
= note: the link appears in this line:
|
= note: the link appears in this line:
|
||||||
|
|
||||||
Test with [Foo::baz], [Bar::foo], ...
|
bar [BarC] bar
|
||||||
^^^^^^^^
|
^^^^
|
||||||
|
|
||||||
warning: [Uniooon::X] cannot be resolved, ignoring it...
|
warning: `[BarD]` cannot be resolved, ignoring it...
|
||||||
--> $DIR/intra-links-warning.rs:13:1
|
--> $DIR/intra-links-warning.rs:48:1
|
||||||
|
|
|
|
||||||
13 | / //! Test with [Foo::baz], [Bar::foo], ...
|
48 | #[doc = "Foo/nbar [BarD] bar/nbaz"]
|
||||||
14 | | //!
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
15 | | //! and [Uniooon::X].
|
|
||||||
| |_____________________^
|
|
||||||
|
|
|
|
||||||
= note: the link appears in this line:
|
= note: the link appears in this line:
|
||||||
|
|
||||||
and [Uniooon::X].
|
bar [BarD] bar
|
||||||
^^^^^^^^^^
|
^^^^
|
||||||
|
|
||||||
|
warning: `[BarF]` cannot be resolved, ignoring it...
|
||||||
|
--> $DIR/intra-links-warning.rs:53:9
|
||||||
|
|
|
||||||
|
53 | #[doc = $f]
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
...
|
||||||
|
57 | f!("Foo/nbar [BarF] bar/nbaz");
|
||||||
|
| ------------------------------- in this macro invocation
|
||||||
|
|
|
||||||
|
= note: the link appears in this line:
|
||||||
|
|
||||||
|
bar [BarF] bar
|
||||||
|
^^^^
|
||||||
|
|
||||||
|
|
|
@ -13,3 +13,22 @@ fn main () {
|
||||||
|
|
||||||
let f = Foo(); //~ ERROR E0423
|
let f = Foo(); //~ ERROR E0423
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bar() {
|
||||||
|
struct S { x: i32, y: i32 }
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
struct T {}
|
||||||
|
|
||||||
|
if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); }
|
||||||
|
//~^ ERROR E0423
|
||||||
|
//~| expected type, found `1`
|
||||||
|
if T {} == T {} { println!("Ok"); }
|
||||||
|
//~^ ERROR E0423
|
||||||
|
//~| ERROR expected expression, found `==`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
for _ in std::ops::Range { start: 0, end: 10 } {}
|
||||||
|
//~^ ERROR E0423
|
||||||
|
//~| ERROR expected type, found `0`
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,48 @@
|
||||||
|
error: expected type, found `1`
|
||||||
|
--> $DIR/E0423.rs:22:39
|
||||||
|
|
|
||||||
|
LL | if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); }
|
||||||
|
| ^ expecting a type here because of type ascription
|
||||||
|
|
||||||
|
error: expected expression, found `==`
|
||||||
|
--> $DIR/E0423.rs:25:13
|
||||||
|
|
|
||||||
|
LL | if T {} == T {} { println!("Ok"); }
|
||||||
|
| ^^ expected expression
|
||||||
|
|
||||||
|
error: expected type, found `0`
|
||||||
|
--> $DIR/E0423.rs:31:39
|
||||||
|
|
|
||||||
|
LL | for _ in std::ops::Range { start: 0, end: 10 } {}
|
||||||
|
| ^ expecting a type here because of type ascription
|
||||||
|
|
||||||
error[E0423]: expected function, found struct `Foo`
|
error[E0423]: expected function, found struct `Foo`
|
||||||
--> $DIR/E0423.rs:14:13
|
--> $DIR/E0423.rs:14:13
|
||||||
|
|
|
|
||||||
LL | let f = Foo(); //~ ERROR E0423
|
LL | let f = Foo(); //~ ERROR E0423
|
||||||
| ^^^ did you mean `Foo { /* fields */ }`?
|
| ^^^
|
||||||
|
| |
|
||||||
|
| did you mean `foo`?
|
||||||
|
| did you mean `Foo { /* fields */ }`?
|
||||||
|
|
||||||
error: aborting due to previous error
|
error[E0423]: expected value, found struct `S`
|
||||||
|
--> $DIR/E0423.rs:22:32
|
||||||
|
|
|
||||||
|
LL | if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); }
|
||||||
|
| ^ did you mean `(S { /* fields */ })`?
|
||||||
|
|
||||||
|
error[E0423]: expected value, found struct `T`
|
||||||
|
--> $DIR/E0423.rs:25:8
|
||||||
|
|
|
||||||
|
LL | if T {} == T {} { println!("Ok"); }
|
||||||
|
| ^ did you mean `(T { /* fields */ })`?
|
||||||
|
|
||||||
|
error[E0423]: expected value, found struct `std::ops::Range`
|
||||||
|
--> $DIR/E0423.rs:31:14
|
||||||
|
|
|
||||||
|
LL | for _ in std::ops::Range { start: 0, end: 10 } {}
|
||||||
|
| ^^^^^^^^^^^^^^^ did you mean `(std::ops::Range { /* fields */ })`?
|
||||||
|
|
||||||
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0423`.
|
For more information about this error, try `rustc --explain E0423`.
|
||||||
|
|
|
@ -59,7 +59,9 @@
|
||||||
#![start = "x4300"] //~ WARN unused attribute
|
#![start = "x4300"] //~ WARN unused attribute
|
||||||
// see issue-43106-gating-of-test.rs for crate-level; but non crate-level is below at "4200"
|
// see issue-43106-gating-of-test.rs for crate-level; but non crate-level is below at "4200"
|
||||||
// see issue-43106-gating-of-bench.rs for crate-level; but non crate-level is below at "4100"
|
// see issue-43106-gating-of-bench.rs for crate-level; but non crate-level is below at "4100"
|
||||||
#![repr = "3900"] //~ WARN unused attribute
|
#![repr = "3900"]
|
||||||
|
//~^ WARN unused attribute
|
||||||
|
//~| WARN `repr` attribute isn't configurable with a literal
|
||||||
#![path = "3800"] //~ WARN unused attribute
|
#![path = "3800"] //~ WARN unused attribute
|
||||||
#![abi = "3700"] //~ WARN unused attribute
|
#![abi = "3700"] //~ WARN unused attribute
|
||||||
#![automatically_derived = "3600"] //~ WARN unused attribute
|
#![automatically_derived = "3600"] //~ WARN unused attribute
|
||||||
|
@ -309,20 +311,25 @@ mod bench {
|
||||||
|
|
||||||
#[repr = "3900"]
|
#[repr = "3900"]
|
||||||
//~^ WARN unused attribute
|
//~^ WARN unused attribute
|
||||||
|
//~| WARN `repr` attribute isn't configurable with a literal
|
||||||
mod repr {
|
mod repr {
|
||||||
mod inner { #![repr="3900"] }
|
mod inner { #![repr="3900"] }
|
||||||
//~^ WARN unused attribute
|
//~^ WARN unused attribute
|
||||||
|
//~| WARN `repr` attribute isn't configurable with a literal
|
||||||
|
|
||||||
#[repr = "3900"] fn f() { }
|
#[repr = "3900"] fn f() { }
|
||||||
//~^ WARN unused attribute
|
//~^ WARN unused attribute
|
||||||
|
//~| WARN `repr` attribute isn't configurable with a literal
|
||||||
|
|
||||||
struct S;
|
struct S;
|
||||||
|
|
||||||
#[repr = "3900"] type T = S;
|
#[repr = "3900"] type T = S;
|
||||||
//~^ WARN unused attribute
|
//~^ WARN unused attribute
|
||||||
|
//~| WARN `repr` attribute isn't configurable with a literal
|
||||||
|
|
||||||
#[repr = "3900"] impl S { }
|
#[repr = "3900"] impl S { }
|
||||||
//~^ WARN unused attribute
|
//~^ WARN unused attribute
|
||||||
|
//~| WARN `repr` attribute isn't configurable with a literal
|
||||||
}
|
}
|
||||||
|
|
||||||
#[path = "3800"]
|
#[path = "3800"]
|
||||||
|
|
File diff suppressed because it is too large
Load diff
16
src/test/ui/issue-38715.rs
Normal file
16
src/test/ui/issue-38715.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! foo { ($i:ident) => {} }
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! foo { () => {} } //~ ERROR a macro named `foo` has already been exported
|
||||||
|
//~| WARN this was previously accepted
|
22
src/test/ui/issue-38715.stderr
Normal file
22
src/test/ui/issue-38715.stderr
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
error: a macro named `foo` has already been exported
|
||||||
|
--> $DIR/issue-38715.rs:15:1
|
||||||
|
|
|
||||||
|
LL | macro_rules! foo { () => {} } //~ ERROR a macro named `foo` has already been exported
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `foo` already exported
|
||||||
|
|
|
||||||
|
= note: #[deny(duplicate_macro_exports)] on by default
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
|
||||||
|
= note: for more information, see issue #35896 <https://github.com/rust-lang/rust/issues/35896>
|
||||||
|
note: previous macro export is now shadowed
|
||||||
|
--> $DIR/issue-38715.rs:12:1
|
||||||
|
|
|
||||||
|
LL | macro_rules! foo { ($i:ident) => {} }
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0601]: `main` function not found in crate `issue_38715`
|
||||||
|
|
|
||||||
|
= note: consider adding a `main` function to `$DIR/issue-38715.rs`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0601`.
|
|
@ -10,11 +10,11 @@ note: unclosed delimiter
|
||||||
LL | callback(path.as_ref(); //~ ERROR expected one of
|
LL | callback(path.as_ref(); //~ ERROR expected one of
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: expected one of `,`, `.`, `?`, or an operator, found `;`
|
error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;`
|
||||||
--> $DIR/token-error-correct-3.rs:24:35
|
--> $DIR/token-error-correct-3.rs:24:35
|
||||||
|
|
|
|
||||||
LL | callback(path.as_ref(); //~ ERROR expected one of
|
LL | callback(path.as_ref(); //~ ERROR expected one of
|
||||||
| ^ expected one of `,`, `.`, `?`, or an operator here
|
| ^ expected one of `)`, `,`, `.`, `?`, or an operator here
|
||||||
|
|
||||||
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)`
|
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)`
|
||||||
--> $DIR/token-error-correct-3.rs:30:9
|
--> $DIR/token-error-correct-3.rs:30:9
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
// compile-flags: --test
|
// compile-flags: --test
|
||||||
|
|
||||||
#![feature(termination_trait_test)]
|
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
|
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: functions using `#[should_panic]` must return `()`
|
error: functions using `#[should_panic]` must return `()`
|
||||||
--> $DIR/termination-trait-in-test-should-panic.rs:22:1
|
--> $DIR/termination-trait-in-test-should-panic.rs:21:1
|
||||||
|
|
|
|
||||||
LL | / fn not_a_num() -> Result<(), ParseIntError> {
|
LL | / fn not_a_num() -> Result<(), ParseIntError> {
|
||||||
LL | | //~^ ERROR functions using `#[should_panic]` must return `()`
|
LL | | //~^ ERROR functions using `#[should_panic]` must return `()`
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
// compile-flags: --test
|
// compile-flags: --test
|
||||||
// run-pass
|
// run-pass
|
||||||
|
|
||||||
#![feature(termination_trait_test)]
|
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
|
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
|
@ -10,8 +10,6 @@
|
||||||
|
|
||||||
// compile-flags: --test
|
// compile-flags: --test
|
||||||
|
|
||||||
#![feature(termination_trait_test)]
|
|
||||||
|
|
||||||
use std::num::ParseIntError;
|
use std::num::ParseIntError;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0277]: `main` has invalid return type `std::result::Result<f32, std::num::ParseIntError>`
|
error[E0277]: `main` has invalid return type `std::result::Result<f32, std::num::ParseIntError>`
|
||||||
--> $DIR/termination-trait-test-wrong-type.rs:18:1
|
--> $DIR/termination-trait-test-wrong-type.rs:16:1
|
||||||
|
|
|
|
||||||
LL | / fn can_parse_zero_as_f32() -> Result<f32, ParseIntError> { //~ ERROR
|
LL | / fn can_parse_zero_as_f32() -> Result<f32, ParseIntError> { //~ ERROR
|
||||||
LL | | "0".parse()
|
LL | | "0".parse()
|
||||||
|
|
|
@ -14,6 +14,6 @@ mod x {
|
||||||
}
|
}
|
||||||
|
|
||||||
// `.` is similar to `,` so list parsing should continue to closing `}`
|
// `.` is similar to `,` so list parsing should continue to closing `}`
|
||||||
use x::{A. B}; //~ ERROR expected one of `,`, `::`, or `as`, found `.`
|
use x::{A. B}; //~ ERROR expected one of `,`, `::`, `as`, or `}`, found `.`
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: expected one of `,`, `::`, or `as`, found `.`
|
error: expected one of `,`, `::`, `as`, or `}`, found `.`
|
||||||
--> $DIR/similar-tokens.rs:17:10
|
--> $DIR/similar-tokens.rs:17:10
|
||||||
|
|
|
|
||||||
LL | use x::{A. B}; //~ ERROR expected one of `,`, `::`, or `as`, found `.`
|
LL | use x::{A. B}; //~ ERROR expected one of `,`, `::`, `as`, or `}`, found `.`
|
||||||
| ^ expected one of `,`, `::`, or `as` here
|
| ^ expected one of `,`, `::`, `as`, or `}` here
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
28
src/test/ui/suggestions/repr.rs
Normal file
28
src/test/ui/suggestions/repr.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// compile-pass
|
||||||
|
|
||||||
|
#[repr]
|
||||||
|
//^ WARN `repr` attribute must have a hint
|
||||||
|
struct _A {}
|
||||||
|
|
||||||
|
#[repr = "B"]
|
||||||
|
//^ WARN `repr` attribute isn't configurable with a literal
|
||||||
|
struct _B {}
|
||||||
|
|
||||||
|
#[repr = "C"]
|
||||||
|
//^ WARN `repr` attribute isn't configurable with a literal
|
||||||
|
struct _C {}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct _D {}
|
||||||
|
|
||||||
|
fn main() {}
|
25
src/test/ui/suggestions/repr.stderr
Normal file
25
src/test/ui/suggestions/repr.stderr
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
warning: `repr` attribute must have a hint
|
||||||
|
--> $DIR/repr.rs:13:1
|
||||||
|
|
|
||||||
|
LL | #[repr]
|
||||||
|
| ^^^^^^^ needs a hint
|
||||||
|
|
|
||||||
|
= note: #[warn(bad_repr)] on by default
|
||||||
|
= help: valid hints include `#[repr(C)]`, `#[repr(packed)]`, `#[repr(rust)]` and `#[repr(transparent)]`
|
||||||
|
= note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html>
|
||||||
|
|
||||||
|
warning: `repr` attribute isn't configurable with a literal
|
||||||
|
--> $DIR/repr.rs:17:1
|
||||||
|
|
|
||||||
|
LL | #[repr = "B"]
|
||||||
|
| ^^^^^^^^^^^^^ needs a hint
|
||||||
|
|
|
||||||
|
= help: valid hints include `#[repr(C)]`, `#[repr(packed)]`, `#[repr(rust)]` and `#[repr(transparent)]`
|
||||||
|
= note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html>
|
||||||
|
|
||||||
|
warning: `repr` attribute isn't configurable with a literal
|
||||||
|
--> $DIR/repr.rs:21:1
|
||||||
|
|
|
||||||
|
LL | #[repr = "C"]
|
||||||
|
| ^^^^^^^^^^^^^ help: give `repr` a hint: `#[repr(C)]`
|
||||||
|
|
|
@ -10,11 +10,11 @@ note: unclosed delimiter
|
||||||
LL | option.map(|some| 42;
|
LL | option.map(|some| 42;
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: expected one of `,`, `.`, `?`, or an operator, found `;`
|
error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;`
|
||||||
--> $DIR/issue-10636-2.rs:15:25
|
--> $DIR/issue-10636-2.rs:15:25
|
||||||
|
|
|
|
||||||
LL | option.map(|some| 42;
|
LL | option.map(|some| 42;
|
||||||
| ^ expected one of `,`, `.`, `?`, or an operator here
|
| ^ expected one of `)`, `,`, `.`, `?`, or an operator here
|
||||||
|
|
||||||
error: expected expression, found `)`
|
error: expected expression, found `)`
|
||||||
--> $DIR/issue-10636-2.rs:18:1
|
--> $DIR/issue-10636-2.rs:18:1
|
||||||
|
|
29
src/test/ui/trait-object-auto-dedup-in-impl.rs
Normal file
29
src/test/ui/trait-object-auto-dedup-in-impl.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright 2014 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.
|
||||||
|
|
||||||
|
// Checks to make sure that `dyn Trait + Send` and `dyn Trait + Send + Send` are the same type.
|
||||||
|
// Issue: #47010
|
||||||
|
|
||||||
|
struct Struct;
|
||||||
|
impl Trait for Struct {}
|
||||||
|
trait Trait {}
|
||||||
|
|
||||||
|
type Send1 = Trait + Send;
|
||||||
|
type Send2 = Trait + Send + Send;
|
||||||
|
|
||||||
|
fn main () {}
|
||||||
|
|
||||||
|
impl Trait + Send {
|
||||||
|
fn test(&self) { println!("one"); } //~ ERROR duplicate definitions with name `test`
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait + Send + Send {
|
||||||
|
fn test(&self) { println!("two"); }
|
||||||
|
}
|
12
src/test/ui/trait-object-auto-dedup-in-impl.stderr
Normal file
12
src/test/ui/trait-object-auto-dedup-in-impl.stderr
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
error[E0592]: duplicate definitions with name `test`
|
||||||
|
--> $DIR/trait-object-auto-dedup-in-impl.rs:24:5
|
||||||
|
|
|
||||||
|
LL | fn test(&self) { println!("one"); } //~ ERROR duplicate definitions with name `test`
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definitions for `test`
|
||||||
|
...
|
||||||
|
LL | fn test(&self) { println!("two"); }
|
||||||
|
| ----------------------------------- other definition for `test`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0592`.
|
|
@ -12,6 +12,6 @@ mod foo {
|
||||||
type T = ();
|
type T = ();
|
||||||
struct S1(pub(in foo) (), pub(T), pub(crate) (), pub(((), T)));
|
struct S1(pub(in foo) (), pub(T), pub(crate) (), pub(((), T)));
|
||||||
struct S2(pub((foo)) ());
|
struct S2(pub((foo)) ());
|
||||||
//~^ ERROR expected `,`, found `(`
|
//~^ ERROR expected one of `)` or `,`, found `(`
|
||||||
//~| ERROR cannot find type `foo` in this scope
|
//~| ERROR cannot find type `foo` in this scope
|
||||||
}
|
}
|
20
src/test/ui/tuple-struct-fields/test.stderr
Normal file
20
src/test/ui/tuple-struct-fields/test.stderr
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
error: expected one of `)` or `,`, found `(`
|
||||||
|
--> $DIR/test.rs:14:26
|
||||||
|
|
|
||||||
|
LL | struct S2(pub((foo)) ());
|
||||||
|
| ^ expected one of `)` or `,` here
|
||||||
|
|
||||||
|
error[E0412]: cannot find type `foo` in this scope
|
||||||
|
--> $DIR/test.rs:14:20
|
||||||
|
|
|
||||||
|
LL | struct S2(pub((foo)) ());
|
||||||
|
| ^^^ not found in this scope
|
||||||
|
|
||||||
|
error[E0601]: `main` function not found in crate `test`
|
||||||
|
|
|
||||||
|
= note: consider adding a `main` function to `$DIR/test.rs`
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
Some errors occurred: E0412, E0601.
|
||||||
|
For more information about an error, try `rustc --explain E0412`.
|
|
@ -13,7 +13,7 @@ macro_rules! define_struct {
|
||||||
struct S1(pub $t);
|
struct S1(pub $t);
|
||||||
struct S2(pub (in foo) ());
|
struct S2(pub (in foo) ());
|
||||||
struct S3(pub $t ());
|
struct S3(pub $t ());
|
||||||
//~^ ERROR expected `,`, found `(`
|
//~^ ERROR expected one of `)` or `,`, found `(`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
11
src/test/ui/tuple-struct-fields/test2.stderr
Normal file
11
src/test/ui/tuple-struct-fields/test2.stderr
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
error: expected one of `)` or `,`, found `(`
|
||||||
|
--> $DIR/test2.rs:15:26
|
||||||
|
|
|
||||||
|
LL | struct S3(pub $t ());
|
||||||
|
| ^ expected one of `)` or `,` here
|
||||||
|
...
|
||||||
|
LL | define_struct! { (foo) }
|
||||||
|
| ------------------------ in this macro invocation
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -13,7 +13,7 @@ macro_rules! define_struct {
|
||||||
struct S1(pub($t));
|
struct S1(pub($t));
|
||||||
struct S2(pub (in foo) ());
|
struct S2(pub (in foo) ());
|
||||||
struct S3(pub($t) ());
|
struct S3(pub($t) ());
|
||||||
//~^ ERROR expected `,`, found `(`
|
//~^ ERROR expected one of `)` or `,`, found `(`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
11
src/test/ui/tuple-struct-fields/test3.stderr
Normal file
11
src/test/ui/tuple-struct-fields/test3.stderr
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
error: expected one of `)` or `,`, found `(`
|
||||||
|
--> $DIR/test3.rs:15:27
|
||||||
|
|
|
||||||
|
LL | struct S3(pub($t) ());
|
||||||
|
| ^ expected one of `)` or `,` here
|
||||||
|
...
|
||||||
|
LL | define_struct! { foo }
|
||||||
|
| ---------------------- in this macro invocation
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use common::CompareMode;
|
use common::CompareMode;
|
||||||
use common::{expected_output_path, UI_FIXED, UI_STDERR, UI_STDOUT};
|
use common::{expected_output_path, UI_EXTENSIONS, UI_FIXED, UI_STDERR, UI_STDOUT};
|
||||||
use common::{output_base_dir, output_base_name, output_testname_unique};
|
use common::{output_base_dir, output_base_name, output_testname_unique};
|
||||||
use common::{Codegen, CodegenUnits, DebugInfoGdb, DebugInfoLldb, Rustdoc};
|
use common::{Codegen, CodegenUnits, DebugInfoGdb, DebugInfoLldb, Rustdoc};
|
||||||
use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind};
|
use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind};
|
||||||
|
@ -2609,6 +2609,9 @@ impl<'test> TestCx<'test> {
|
||||||
errors += self.compare_output("stdout", &normalized_stdout, &expected_stdout);
|
errors += self.compare_output("stdout", &normalized_stdout, &expected_stdout);
|
||||||
errors += self.compare_output("stderr", &normalized_stderr, &expected_stderr);
|
errors += self.compare_output("stderr", &normalized_stderr, &expected_stderr);
|
||||||
|
|
||||||
|
let modes_to_prune = vec![CompareMode::Nll];
|
||||||
|
self.prune_duplicate_outputs(&modes_to_prune);
|
||||||
|
|
||||||
if self.config.compare_mode.is_some() {
|
if self.config.compare_mode.is_some() {
|
||||||
// don't test rustfix with nll right now
|
// don't test rustfix with nll right now
|
||||||
} else if self.props.run_rustfix {
|
} else if self.props.run_rustfix {
|
||||||
|
@ -2971,6 +2974,16 @@ impl<'test> TestCx<'test> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn delete_file(&self, file: &PathBuf) {
|
||||||
|
if let Err(e) = ::std::fs::remove_file(file) {
|
||||||
|
self.fatal(&format!(
|
||||||
|
"failed to delete `{}`: {}",
|
||||||
|
file.display(),
|
||||||
|
e,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn compare_output(&self, kind: &str, actual: &str, expected: &str) -> usize {
|
fn compare_output(&self, kind: &str, actual: &str, expected: &str) -> usize {
|
||||||
if actual == expected {
|
if actual == expected {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3023,13 +3036,7 @@ impl<'test> TestCx<'test> {
|
||||||
|
|
||||||
for output_file in &files {
|
for output_file in &files {
|
||||||
if actual.is_empty() {
|
if actual.is_empty() {
|
||||||
if let Err(e) = ::std::fs::remove_file(output_file) {
|
self.delete_file(output_file);
|
||||||
self.fatal(&format!(
|
|
||||||
"failed to delete `{}`: {}",
|
|
||||||
output_file.display(),
|
|
||||||
e,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
match File::create(&output_file).and_then(|mut f| f.write_all(actual.as_bytes())) {
|
match File::create(&output_file).and_then(|mut f| f.write_all(actual.as_bytes())) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
|
@ -3054,6 +3061,42 @@ impl<'test> TestCx<'test> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn prune_duplicate_output(&self, mode: CompareMode, kind: &str, canon_content: &str) {
|
||||||
|
let examined_path = expected_output_path(
|
||||||
|
&self.testpaths,
|
||||||
|
self.revision,
|
||||||
|
&Some(mode),
|
||||||
|
kind,
|
||||||
|
);
|
||||||
|
|
||||||
|
let examined_content = self
|
||||||
|
.load_expected_output_from_path(&examined_path)
|
||||||
|
.unwrap_or_else(|_| String::new());
|
||||||
|
|
||||||
|
if examined_path.exists() && canon_content == &examined_content {
|
||||||
|
self.delete_file(&examined_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prune_duplicate_outputs(&self, modes: &[CompareMode]) {
|
||||||
|
if self.config.bless {
|
||||||
|
for kind in UI_EXTENSIONS {
|
||||||
|
let canon_comparison_path = expected_output_path(
|
||||||
|
&self.testpaths,
|
||||||
|
self.revision,
|
||||||
|
&None,
|
||||||
|
kind,
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Ok(canon) = self.load_expected_output_from_path(&canon_comparison_path) {
|
||||||
|
for mode in modes {
|
||||||
|
self.prune_duplicate_output(mode.clone(), kind, &canon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn create_stamp(&self) {
|
fn create_stamp(&self) {
|
||||||
let mut f = File::create(::stamp(&self.config, self.testpaths, self.revision)).unwrap();
|
let mut f = File::create(::stamp(&self.config, self.testpaths, self.revision)).unwrap();
|
||||||
f.write_all(compute_stamp_hash(&self.config).as_bytes())
|
f.write_all(compute_stamp_hash(&self.config).as_bytes())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue