mirror of https://github.com/rust-lang/rust.git
Auto merge of #65223 - Centril:rollup-5sdvdni, r=Centril
Rollup of 7 pull requests Successful merges: - #64284 (Warn if include macro fails to include entire file) - #65081 (Remove -Zprofile-queries) - #65133 (typeck: prohibit foreign statics w/ generics) - #65135 (Add check for missing tests for error codes) - #65141 (Replace code of conduct with link) - #65194 (Use structured suggestion for removal of `as_str()` call) - #65213 (Ignore `ExprKind::DropTemps` for some ref suggestions) Failed merges: r? @ghost
This commit is contained in:
commit
b5bd31ec6d
|
@ -1,40 +1,3 @@
|
|||
# The Rust Code of Conduct
|
||||
|
||||
A version of this document [can be found online](https://www.rust-lang.org/conduct.html).
|
||||
|
||||
## Conduct
|
||||
|
||||
**Contact**: [rust-mods@rust-lang.org](mailto:rust-mods@rust-lang.org)
|
||||
|
||||
* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic.
|
||||
* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all.
|
||||
* Please be kind and courteous. There's no need to be mean or rude.
|
||||
* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.
|
||||
* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.
|
||||
* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the <a href="http://citizencodeofconduct.org/">Citizen Code of Conduct</a>; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups.
|
||||
* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [Rust moderation team][mod_team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back.
|
||||
* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome.
|
||||
|
||||
## Moderation
|
||||
|
||||
|
||||
These are the policies for upholding our community's standards of conduct. If you feel that a thread needs moderation, please contact the [Rust moderation team][mod_team].
|
||||
|
||||
1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.)
|
||||
2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed.
|
||||
3. Moderators will first respond to such remarks with a warning.
|
||||
4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off.
|
||||
5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded.
|
||||
6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology.
|
||||
7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed.
|
||||
8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others.
|
||||
|
||||
In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely.
|
||||
|
||||
And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust.
|
||||
|
||||
The enforcement policies listed above apply to all official Rust venues; including all communication channels (Rust Discord server, Rust Zulip server); GitHub repositories under rust-lang, rust-lang-nursery, and rust-lang-deprecated; and all forums under rust-lang.org (users.rust-lang.org, internals.rust-lang.org). For other projects adopting the Rust Code of Conduct, please contact the maintainers of those projects for enforcement. If you wish to use this code of conduct for your own project, consider explicitly mentioning your moderation policy or making a copy with your own moderation policy so as to avoid confusion.
|
||||
|
||||
*Adapted from the [Node.js Policy on Trolling](https://blog.izs.me/2012/08/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).*
|
||||
|
||||
[mod_team]: https://www.rust-lang.org/team.html#Moderation-team
|
||||
The Code of Conduct for this repository [can be found online](https://www.rust-lang.org/conduct.html).
|
||||
|
|
|
@ -9,7 +9,6 @@ use std::hash::Hash;
|
|||
use std::collections::hash_map::Entry;
|
||||
use std::mem;
|
||||
use crate::ty::{self, TyCtxt};
|
||||
use crate::util::common::{ProfileQueriesMsg, profq_msg};
|
||||
use parking_lot::{Mutex, Condvar};
|
||||
|
||||
use crate::ich::{StableHashingContext, StableHashingContextProvider, Fingerprint};
|
||||
|
@ -256,10 +255,6 @@ impl DepGraph {
|
|||
// - we can get an idea of the runtime cost.
|
||||
let mut hcx = cx.get_stable_hashing_context();
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
profq_msg(hcx.sess(), ProfileQueriesMsg::TaskBegin(key.clone()))
|
||||
};
|
||||
|
||||
let result = if no_tcx {
|
||||
task(cx, arg)
|
||||
} else {
|
||||
|
@ -275,10 +270,6 @@ impl DepGraph {
|
|||
})
|
||||
};
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
profq_msg(hcx.sess(), ProfileQueriesMsg::TaskEnd)
|
||||
};
|
||||
|
||||
let current_fingerprint = hash_result(&mut hcx, &result);
|
||||
|
||||
let dep_node_index = finish_task_and_alloc_depnode(
|
||||
|
|
|
@ -466,7 +466,6 @@ fn main() {
|
|||
```
|
||||
"##,
|
||||
|
||||
|
||||
E0139: r##"
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
|
@ -1562,7 +1561,9 @@ fn transmute_lifetime<'a, T>(t: &'a (T,)) -> &'a T {
|
|||
"##,
|
||||
|
||||
E0496: r##"
|
||||
A lifetime name is shadowing another lifetime name. Erroneous code example:
|
||||
A lifetime name is shadowing another lifetime name.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0496
|
||||
struct Foo<'a> {
|
||||
|
@ -1594,8 +1595,11 @@ fn main() {
|
|||
"##,
|
||||
|
||||
E0497: r##"
|
||||
A stability attribute was used outside of the standard library. Erroneous code
|
||||
example:
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
A stability attribute was used outside of the standard library.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail
|
||||
#[stable] // error: stability attributes may not be used outside of the
|
||||
|
@ -2125,7 +2129,7 @@ rejected in your own crates.
|
|||
// E0272, // on_unimplemented #0
|
||||
// E0273, // on_unimplemented #1
|
||||
// E0274, // on_unimplemented #2
|
||||
E0278, // requirement is not satisfied
|
||||
// E0278, // requirement is not satisfied
|
||||
E0279, // requirement is not satisfied
|
||||
E0280, // requirement is not satisfied
|
||||
// E0285, // overflow evaluation builtin bounds
|
||||
|
@ -2165,10 +2169,10 @@ rejected in your own crates.
|
|||
E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax
|
||||
E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders
|
||||
E0697, // closures cannot be static
|
||||
E0707, // multiple elided lifetimes used in arguments of `async fn`
|
||||
// E0707, // multiple elided lifetimes used in arguments of `async fn`
|
||||
E0708, // `async` non-`move` closures with parameters are not currently
|
||||
// supported
|
||||
E0709, // multiple different lifetimes used in arguments of `async fn`
|
||||
// E0709, // multiple different lifetimes used in arguments of `async fn`
|
||||
E0710, // an unknown tool name found in scoped lint
|
||||
E0711, // a feature has been declared with conflicting stability attributes
|
||||
// E0702, // replaced with a generic attribute input check
|
||||
|
|
|
@ -1548,6 +1548,19 @@ impl Expr {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// If `Self.kind` is `ExprKind::DropTemps(expr)`, drill down until we get a non-`DropTemps`
|
||||
/// `Expr`. This is used in suggestions to ignore this `ExprKind` as it is semantically
|
||||
/// silent, only signaling the ownership system. By doing this, suggestions that check the
|
||||
/// `ExprKind` of any given `Expr` for presentation don't have to care about `DropTemps`
|
||||
/// beyond remembering to call this function before doing analysis on it.
|
||||
pub fn peel_drop_temps(&self) -> &Self {
|
||||
let mut expr = self;
|
||||
while let ExprKind::DropTemps(inner) = &expr.kind {
|
||||
expr = inner;
|
||||
}
|
||||
expr
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Expr {
|
||||
|
|
|
@ -368,6 +368,12 @@ pub mod parser {
|
|||
Allow,
|
||||
"possible meta-variable misuse at macro definition"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub INCOMPLETE_INCLUDE,
|
||||
Deny,
|
||||
"trailing content in included file"
|
||||
}
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
|
|
|
@ -28,6 +28,7 @@ use crate::hir::intravisit;
|
|||
use crate::hir;
|
||||
use crate::lint::builtin::BuiltinLintDiagnostics;
|
||||
use crate::lint::builtin::parser::{ILL_FORMED_ATTRIBUTE_INPUT, META_VARIABLE_MISUSE};
|
||||
use crate::lint::builtin::parser::INCOMPLETE_INCLUDE;
|
||||
use crate::session::{Session, DiagnosticMessageId};
|
||||
use crate::ty::TyCtxt;
|
||||
use crate::ty::query::Providers;
|
||||
|
@ -83,6 +84,7 @@ impl Lint {
|
|||
match lint_id {
|
||||
BufferedEarlyLintId::IllFormedAttributeInput => ILL_FORMED_ATTRIBUTE_INPUT,
|
||||
BufferedEarlyLintId::MetaVariableMisuse => META_VARIABLE_MISUSE,
|
||||
BufferedEarlyLintId::IncompleteInclude => INCOMPLETE_INCLUDE,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1316,10 +1316,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
|||
"dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
|
||||
query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
|
||||
"enable queries of the dependency graph for regression testing"),
|
||||
profile_queries: bool = (false, parse_bool, [UNTRACKED],
|
||||
"trace and profile the queries of the incremental compilation framework"),
|
||||
profile_queries_and_keys: bool = (false, parse_bool, [UNTRACKED],
|
||||
"trace and profile the queries and keys of the incremental compilation framework"),
|
||||
no_analysis: bool = (false, parse_bool, [UNTRACKED],
|
||||
"parse and expand the source, but run no analysis"),
|
||||
extra_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED],
|
||||
|
|
|
@ -11,7 +11,6 @@ use crate::session::config::{OutputType, PrintRequest, SwitchWithOptPath};
|
|||
use crate::session::search_paths::{PathKind, SearchPath};
|
||||
use crate::util::nodemap::{FxHashMap, FxHashSet};
|
||||
use crate::util::common::{duration_to_secs_str, ErrorReported};
|
||||
use crate::util::common::ProfileQueriesMsg;
|
||||
|
||||
use rustc_data_structures::base_n;
|
||||
use rustc_data_structures::sync::{
|
||||
|
@ -46,7 +45,7 @@ use std::fmt;
|
|||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
use std::sync::{Arc, mpsc};
|
||||
use std::sync::Arc;
|
||||
|
||||
mod code_stats;
|
||||
pub mod config;
|
||||
|
@ -125,9 +124,6 @@ pub struct Session {
|
|||
/// `-Zquery-dep-graph` is specified.
|
||||
pub cgu_reuse_tracker: CguReuseTracker,
|
||||
|
||||
/// Used by `-Z profile-queries` in `util::common`.
|
||||
pub profile_channel: Lock<Option<mpsc::Sender<ProfileQueriesMsg>>>,
|
||||
|
||||
/// Used by `-Z self-profile`.
|
||||
pub prof: SelfProfilerRef,
|
||||
|
||||
|
@ -509,13 +505,6 @@ impl Session {
|
|||
pub fn time_extended(&self) -> bool {
|
||||
self.opts.debugging_opts.time_passes
|
||||
}
|
||||
pub fn profile_queries(&self) -> bool {
|
||||
self.opts.debugging_opts.profile_queries
|
||||
|| self.opts.debugging_opts.profile_queries_and_keys
|
||||
}
|
||||
pub fn profile_queries_and_keys(&self) -> bool {
|
||||
self.opts.debugging_opts.profile_queries_and_keys
|
||||
}
|
||||
pub fn instrument_mcount(&self) -> bool {
|
||||
self.opts.debugging_opts.instrument_mcount
|
||||
}
|
||||
|
@ -1234,7 +1223,6 @@ fn build_session_(
|
|||
incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)),
|
||||
cgu_reuse_tracker,
|
||||
prof: SelfProfilerRef::new(self_profiler),
|
||||
profile_channel: Lock::new(None),
|
||||
perf_stats: PerfStats {
|
||||
symbol_hash_time: Lock::new(Duration::from_secs(0)),
|
||||
decode_def_path_tables_time: Lock::new(Duration::from_secs(0)),
|
||||
|
|
|
@ -1075,7 +1075,7 @@ where
|
|||
let desc = &format!("encode_query_results for {}",
|
||||
::std::any::type_name::<Q>());
|
||||
|
||||
time_ext(tcx.sess.time_extended(), Some(tcx.sess), desc, || {
|
||||
time_ext(tcx.sess.time_extended(), desc, || {
|
||||
let shards = Q::query_cache(tcx).lock_shards();
|
||||
assert!(shards.iter().all(|shard| shard.active.is_empty()));
|
||||
for (key, entry) in shards.iter().flat_map(|shard| shard.results.iter()) {
|
||||
|
|
|
@ -9,8 +9,6 @@ use crate::ty::query::Query;
|
|||
use crate::ty::query::config::{QueryConfig, QueryDescription};
|
||||
use crate::ty::query::job::{QueryJob, QueryResult, QueryInfo};
|
||||
|
||||
use crate::util::common::{profq_msg, ProfileQueriesMsg, QueryMsg};
|
||||
|
||||
use errors::DiagnosticBuilder;
|
||||
use errors::Level;
|
||||
use errors::Diagnostic;
|
||||
|
@ -62,33 +60,6 @@ impl<'tcx, M: QueryConfig<'tcx>> Default for QueryCache<'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
// If enabled, sends a message to the profile-queries thread.
|
||||
macro_rules! profq_msg {
|
||||
($tcx:expr, $msg:expr) => {
|
||||
if cfg!(debug_assertions) {
|
||||
if $tcx.sess.profile_queries() {
|
||||
profq_msg($tcx.sess, $msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If enabled, formats a key using its debug string, which can be
|
||||
// expensive to compute (in terms of time).
|
||||
macro_rules! profq_query_msg {
|
||||
($query:expr, $tcx:expr, $key:expr) => {{
|
||||
let msg = if cfg!(debug_assertions) {
|
||||
if $tcx.sess.profile_queries_and_keys() {
|
||||
Some(format!("{:?}", $key))
|
||||
} else { None }
|
||||
} else { None };
|
||||
QueryMsg {
|
||||
query: $query,
|
||||
msg,
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
/// A type representing the responsibility to execute the job in the `job` field.
|
||||
/// This will poison the relevant query if dropped.
|
||||
pub(super) struct JobOwner<'a, 'tcx, Q: QueryDescription<'tcx>> {
|
||||
|
@ -111,7 +82,6 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
|
|||
loop {
|
||||
let mut lock = cache.get_shard_by_value(key).lock();
|
||||
if let Some(value) = lock.results.get(key) {
|
||||
profq_msg!(tcx, ProfileQueriesMsg::CacheHit);
|
||||
tcx.prof.query_cache_hit(Q::NAME);
|
||||
let result = (value.value.clone(), value.index);
|
||||
#[cfg(debug_assertions)]
|
||||
|
@ -358,13 +328,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
key,
|
||||
span);
|
||||
|
||||
profq_msg!(self,
|
||||
ProfileQueriesMsg::QueryBegin(
|
||||
span.data(),
|
||||
profq_query_msg!(Q::NAME.as_str(), self, key),
|
||||
)
|
||||
);
|
||||
|
||||
let job = match JobOwner::try_get(self, span, &key) {
|
||||
TryGetJob::NotYetStarted(job) => job,
|
||||
TryGetJob::Cycle(result) => return result,
|
||||
|
@ -383,7 +346,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
|
||||
if Q::ANON {
|
||||
|
||||
profq_msg!(self, ProfileQueriesMsg::ProviderBegin);
|
||||
let prof_timer = self.prof.query_provider(Q::NAME);
|
||||
|
||||
let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
|
||||
|
@ -395,7 +357,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
});
|
||||
|
||||
drop(prof_timer);
|
||||
profq_msg!(self, ProfileQueriesMsg::ProviderEnd);
|
||||
|
||||
self.dep_graph.read_index(dep_node_index);
|
||||
|
||||
|
@ -468,7 +429,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
};
|
||||
|
||||
let result = if let Some(result) = result {
|
||||
profq_msg!(self, ProfileQueriesMsg::CacheHit);
|
||||
result
|
||||
} else {
|
||||
// We could not load a result from the on-disk cache, so
|
||||
|
@ -542,7 +502,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
- dep-node: {:?}",
|
||||
key, dep_node);
|
||||
|
||||
profq_msg!(self, ProfileQueriesMsg::ProviderBegin);
|
||||
let prof_timer = self.prof.query_provider(Q::NAME);
|
||||
|
||||
let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
|
||||
|
@ -564,7 +523,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
});
|
||||
|
||||
drop(prof_timer);
|
||||
profq_msg!(self, ProfileQueriesMsg::ProviderEnd);
|
||||
|
||||
if unlikely!(!diagnostics.is_empty()) {
|
||||
if dep_node.kind != crate::dep_graph::DepKind::Null {
|
||||
|
@ -606,19 +564,12 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
|
||||
let _ = self.get_query::<Q>(DUMMY_SP, key);
|
||||
} else {
|
||||
profq_msg!(self, ProfileQueriesMsg::CacheHit);
|
||||
self.prof.query_cache_hit(Q::NAME);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn force_query<Q: QueryDescription<'tcx>>(self, key: Q::Key, span: Span, dep_node: DepNode) {
|
||||
profq_msg!(
|
||||
self,
|
||||
ProfileQueriesMsg::QueryBegin(span.data(),
|
||||
profq_query_msg!(Q::NAME.as_str(), self, key))
|
||||
);
|
||||
|
||||
// We may be concurrently trying both execute and force a query.
|
||||
// Ensure that only one of them runs the query.
|
||||
let job = match JobOwner::try_get(self, span, &key) {
|
||||
|
|
|
@ -6,11 +6,8 @@ use std::cell::Cell;
|
|||
use std::fmt::Debug;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use std::sync::mpsc::{Sender};
|
||||
use syntax_pos::{SpanData};
|
||||
use syntax::symbol::{Symbol, sym};
|
||||
use rustc_macros::HashStable;
|
||||
use crate::dep_graph::{DepNode};
|
||||
use crate::session::Session;
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -26,17 +23,6 @@ pub struct ErrorReported;
|
|||
|
||||
thread_local!(static TIME_DEPTH: Cell<usize> = Cell::new(0));
|
||||
|
||||
/// Parameters to the `Dump` variant of type `ProfileQueriesMsg`.
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct ProfQDumpParams {
|
||||
/// A base path for the files we will dump.
|
||||
pub path:String,
|
||||
/// To ensure that the compiler waits for us to finish our dumps.
|
||||
pub ack:Sender<()>,
|
||||
/// Toggle dumping a log file with every `ProfileQueriesMsg`.
|
||||
pub dump_profq_msg_log:bool,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct QueryMsg {
|
||||
|
@ -44,53 +30,6 @@ pub struct QueryMsg {
|
|||
pub msg: Option<String>,
|
||||
}
|
||||
|
||||
/// A sequence of these messages induce a trace of query-based incremental compilation.
|
||||
// FIXME(matthewhammer): Determine whether we should include cycle detection here or not.
|
||||
#[derive(Clone,Debug)]
|
||||
pub enum ProfileQueriesMsg {
|
||||
/// Begin a timed pass.
|
||||
TimeBegin(String),
|
||||
/// End a timed pass.
|
||||
TimeEnd,
|
||||
/// Begin a task (see `dep_graph::graph::with_task`).
|
||||
TaskBegin(DepNode),
|
||||
/// End a task.
|
||||
TaskEnd,
|
||||
/// Begin a new query.
|
||||
/// Cannot use `Span` because queries are sent to other thread.
|
||||
QueryBegin(SpanData, QueryMsg),
|
||||
/// Query is satisfied by using an already-known value for the given key.
|
||||
CacheHit,
|
||||
/// Query requires running a provider; providers may nest, permitting queries to nest.
|
||||
ProviderBegin,
|
||||
/// Query is satisfied by a provider terminating with a value.
|
||||
ProviderEnd,
|
||||
/// Dump a record of the queries to the given path.
|
||||
Dump(ProfQDumpParams),
|
||||
/// Halt the profiling/monitoring background thread.
|
||||
Halt
|
||||
}
|
||||
|
||||
/// If enabled, send a message to the profile-queries thread.
|
||||
pub fn profq_msg(sess: &Session, msg: ProfileQueriesMsg) {
|
||||
if let Some(s) = sess.profile_channel.borrow().as_ref() {
|
||||
s.send(msg).unwrap()
|
||||
} else {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
/// Set channel for profile queries channel.
|
||||
pub fn profq_set_chan(sess: &Session, s: Sender<ProfileQueriesMsg>) -> bool {
|
||||
let mut channel = sess.profile_channel.borrow_mut();
|
||||
if channel.is_none() {
|
||||
*channel = Some(s);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Read the current depth of `time()` calls. This is used to
|
||||
/// encourage indentation across threads.
|
||||
pub fn time_depth() -> usize {
|
||||
|
@ -107,10 +46,10 @@ pub fn set_time_depth(depth: usize) {
|
|||
pub fn time<T, F>(sess: &Session, what: &str, f: F) -> T where
|
||||
F: FnOnce() -> T,
|
||||
{
|
||||
time_ext(sess.time_passes(), Some(sess), what, f)
|
||||
time_ext(sess.time_passes(), what, f)
|
||||
}
|
||||
|
||||
pub fn time_ext<T, F>(do_it: bool, sess: Option<&Session>, what: &str, f: F) -> T where
|
||||
pub fn time_ext<T, F>(do_it: bool, what: &str, f: F) -> T where
|
||||
F: FnOnce() -> T,
|
||||
{
|
||||
if !do_it { return f(); }
|
||||
|
@ -121,19 +60,9 @@ pub fn time_ext<T, F>(do_it: bool, sess: Option<&Session>, what: &str, f: F) ->
|
|||
r
|
||||
});
|
||||
|
||||
if let Some(sess) = sess {
|
||||
if cfg!(debug_assertions) {
|
||||
profq_msg(sess, ProfileQueriesMsg::TimeBegin(what.to_string()))
|
||||
}
|
||||
}
|
||||
let start = Instant::now();
|
||||
let rv = f();
|
||||
let dur = start.elapsed();
|
||||
if let Some(sess) = sess {
|
||||
if cfg!(debug_assertions) {
|
||||
profq_msg(sess, ProfileQueriesMsg::TimeEnd)
|
||||
}
|
||||
}
|
||||
|
||||
print_time_passes_entry(true, what, dur);
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ fn prepare_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
info!("adding bytecode {}", name);
|
||||
let bc_encoded = data.data();
|
||||
|
||||
let (bc, id) = time_ext(cgcx.time_passes, None, &format!("decode {}", name), || {
|
||||
let (bc, id) = time_ext(cgcx.time_passes, &format!("decode {}", name), || {
|
||||
match DecodedBytecode::new(bc_encoded) {
|
||||
Ok(b) => Ok((b.bytecode(), b.identifier().to_string())),
|
||||
Err(e) => Err(diag_handler.fatal(&e)),
|
||||
|
@ -295,7 +295,7 @@ fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
for (bc_decoded, name) in serialized_modules {
|
||||
let _timer = cgcx.prof.generic_activity("LLVM_fat_lto_link_module");
|
||||
info!("linking {:?}", name);
|
||||
time_ext(cgcx.time_passes, None, &format!("ll link {:?}", name), || {
|
||||
time_ext(cgcx.time_passes, &format!("ll link {:?}", name), || {
|
||||
let data = bc_decoded.data();
|
||||
linker.add(&data).map_err(|()| {
|
||||
let msg = format!("failed to load bc of {:?}", name);
|
||||
|
@ -590,7 +590,7 @@ pub(crate) fn run_pass_manager(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
llvm::LLVMRustAddPass(pm, pass.unwrap());
|
||||
}
|
||||
|
||||
time_ext(cgcx.time_passes, None, "LTO passes", ||
|
||||
time_ext(cgcx.time_passes, "LTO passes", ||
|
||||
llvm::LLVMRunPassManager(pm, module.module_llvm.llmod()));
|
||||
|
||||
llvm::LLVMDisposePassManager(pm);
|
||||
|
|
|
@ -427,7 +427,6 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
{
|
||||
let _timer = cgcx.prof.generic_activity("LLVM_module_optimize_function_passes");
|
||||
time_ext(config.time_passes,
|
||||
None,
|
||||
&format!("llvm function passes [{}]", module_name.unwrap()),
|
||||
|| {
|
||||
llvm::LLVMRustRunFunctionPassManager(fpm, llmod)
|
||||
|
@ -436,7 +435,6 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
{
|
||||
let _timer = cgcx.prof.generic_activity("LLVM_module_optimize_module_passes");
|
||||
time_ext(config.time_passes,
|
||||
None,
|
||||
&format!("llvm module passes [{}]", module_name.unwrap()),
|
||||
|| {
|
||||
llvm::LLVMRunPassManager(mpm, llmod)
|
||||
|
@ -538,7 +536,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
embed_bitcode(cgcx, llcx, llmod, None);
|
||||
}
|
||||
|
||||
time_ext(config.time_passes, None, &format!("codegen passes [{}]", module_name.unwrap()),
|
||||
time_ext(config.time_passes, &format!("codegen passes [{}]", module_name.unwrap()),
|
||||
|| -> Result<(), FatalError> {
|
||||
if config.emit_ir {
|
||||
let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_ir");
|
||||
|
|
|
@ -1535,7 +1535,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
|
|||
let name = cratepath.file_name().unwrap().to_str().unwrap();
|
||||
let name = &name[3..name.len() - 5]; // chop off lib/.rlib
|
||||
|
||||
time_ext(sess.time_extended(), Some(sess), &format!("altering {}.rlib", name), || {
|
||||
time_ext(sess.time_extended(), &format!("altering {}.rlib", name), || {
|
||||
let mut archive = <B as ArchiveBuilder>::new(sess, &dst, Some(cratepath));
|
||||
archive.update_symbols();
|
||||
|
||||
|
|
|
@ -160,7 +160,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
|
|||
}
|
||||
|
||||
MaybeAsync::Async(std::thread::spawn(move || {
|
||||
time_ext(time_passes, None, "background load prev dep-graph", move || {
|
||||
time_ext(time_passes, "background load prev dep-graph", move || {
|
||||
match load_data(report_incremental_info, &path) {
|
||||
LoadResult::DataOutOfDate => LoadResult::DataOutOfDate,
|
||||
LoadResult::Error { message } => LoadResult::Error { message },
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::queries::Queries;
|
||||
use crate::util;
|
||||
use crate::profile;
|
||||
pub use crate::passes::BoxedResolver;
|
||||
|
||||
use rustc::lint;
|
||||
|
@ -115,17 +114,7 @@ where
|
|||
compiler.sess.diagnostic().print_error_count(&util::diagnostics_registry());
|
||||
});
|
||||
|
||||
if compiler.sess.profile_queries() {
|
||||
profile::begin(&compiler.sess);
|
||||
}
|
||||
|
||||
let r = f(&compiler);
|
||||
|
||||
if compiler.sess.profile_queries() {
|
||||
profile::dump(&compiler.sess, "profile_queries".to_string())
|
||||
}
|
||||
|
||||
r
|
||||
f(&compiler)
|
||||
}
|
||||
|
||||
pub fn run_compiler<F, R>(mut config: Config, f: F) -> R
|
||||
|
|
|
@ -16,6 +16,5 @@ mod passes;
|
|||
mod queries;
|
||||
pub mod util;
|
||||
mod proc_macro_decls;
|
||||
mod profile;
|
||||
|
||||
pub use interface::{run_compiler, Config};
|
||||
|
|
|
@ -1,297 +0,0 @@
|
|||
use log::debug;
|
||||
use rustc::dep_graph::DepNode;
|
||||
use rustc::session::Session;
|
||||
use rustc::util::common::{ProfQDumpParams, ProfileQueriesMsg, profq_msg, profq_set_chan};
|
||||
use std::sync::mpsc::{Receiver};
|
||||
use std::io::{Write};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
pub mod trace;
|
||||
|
||||
/// begin a profile thread, if not already running
|
||||
pub fn begin(sess: &Session) {
|
||||
use std::thread;
|
||||
use std::sync::mpsc::{channel};
|
||||
let (tx, rx) = channel();
|
||||
if profq_set_chan(sess, tx) {
|
||||
thread::spawn(move || profile_queries_thread(rx));
|
||||
}
|
||||
}
|
||||
|
||||
/// dump files with profiling information to the given base path, and
|
||||
/// wait for this dump to complete.
|
||||
///
|
||||
/// wraps the RPC (send/recv channel logic) of requesting a dump.
|
||||
pub fn dump(sess: &Session, path: String) {
|
||||
use std::sync::mpsc::{channel};
|
||||
let (tx, rx) = channel();
|
||||
let params = ProfQDumpParams {
|
||||
path,
|
||||
ack: tx,
|
||||
// FIXME: Add another compiler flag to toggle whether this log
|
||||
// is written; false for now
|
||||
dump_profq_msg_log: true,
|
||||
};
|
||||
profq_msg(sess, ProfileQueriesMsg::Dump(params));
|
||||
let _ = rx.recv().unwrap();
|
||||
}
|
||||
|
||||
// State for parsing recursive trace structure in separate thread, via messages
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
enum ParseState {
|
||||
// No (local) parse state; may be parsing a tree, focused on a
|
||||
// sub-tree that could be anything.
|
||||
Clear,
|
||||
// Have Query information from the last message
|
||||
HaveQuery(trace::Query, Instant),
|
||||
// Have "time-begin" information from the last message (doit flag, and message)
|
||||
HaveTimeBegin(String, Instant),
|
||||
// Have "task-begin" information from the last message
|
||||
HaveTaskBegin(DepNode, Instant),
|
||||
}
|
||||
struct StackFrame {
|
||||
pub parse_st: ParseState,
|
||||
pub traces: Vec<trace::Rec>,
|
||||
}
|
||||
|
||||
fn total_duration(traces: &[trace::Rec]) -> Duration {
|
||||
Duration::new(0, 0) + traces.iter().map(|t| t.dur_total).sum()
|
||||
}
|
||||
|
||||
// profiling thread; retains state (in local variables) and dump traces, upon request.
|
||||
fn profile_queries_thread(r: Receiver<ProfileQueriesMsg>) {
|
||||
use self::trace::*;
|
||||
use std::fs::File;
|
||||
|
||||
let mut profq_msgs: Vec<ProfileQueriesMsg> = vec![];
|
||||
let mut frame: StackFrame = StackFrame { parse_st: ParseState::Clear, traces: vec![] };
|
||||
let mut stack: Vec<StackFrame> = vec![];
|
||||
loop {
|
||||
let msg = r.recv();
|
||||
if let Err(_recv_err) = msg {
|
||||
// FIXME: Perhaps do something smarter than simply quitting?
|
||||
break
|
||||
};
|
||||
let msg = msg.unwrap();
|
||||
debug!("profile_queries_thread: {:?}", msg);
|
||||
|
||||
// Meta-level versus _actual_ queries messages
|
||||
match msg {
|
||||
ProfileQueriesMsg::Halt => return,
|
||||
ProfileQueriesMsg::Dump(params) => {
|
||||
assert!(stack.is_empty());
|
||||
assert!(frame.parse_st == ParseState::Clear);
|
||||
|
||||
// write log of all messages
|
||||
if params.dump_profq_msg_log {
|
||||
let mut log_file =
|
||||
File::create(format!("{}.log.txt", params.path)).unwrap();
|
||||
for m in profq_msgs.iter() {
|
||||
writeln!(&mut log_file, "{:?}", m).unwrap()
|
||||
};
|
||||
}
|
||||
|
||||
// write HTML file, and counts file
|
||||
let html_path = format!("{}.html", params.path);
|
||||
let mut html_file = File::create(&html_path).unwrap();
|
||||
|
||||
let counts_path = format!("{}.counts.txt", params.path);
|
||||
let mut counts_file = File::create(&counts_path).unwrap();
|
||||
|
||||
writeln!(html_file,
|
||||
"<html>\n<head>\n<link rel=\"stylesheet\" type=\"text/css\" href=\"{}\">",
|
||||
"profile_queries.css").unwrap();
|
||||
writeln!(html_file, "<style>").unwrap();
|
||||
trace::write_style(&mut html_file);
|
||||
writeln!(html_file, "</style>\n</head>\n<body>").unwrap();
|
||||
trace::write_traces(&mut html_file, &mut counts_file, &frame.traces);
|
||||
writeln!(html_file, "</body>\n</html>").unwrap();
|
||||
|
||||
let ack_path = format!("{}.ack", params.path);
|
||||
let ack_file = File::create(&ack_path).unwrap();
|
||||
drop(ack_file);
|
||||
|
||||
// Tell main thread that we are done, e.g., so it can exit
|
||||
params.ack.send(()).unwrap();
|
||||
}
|
||||
// Actual query message:
|
||||
msg => {
|
||||
// Record msg in our log
|
||||
profq_msgs.push(msg.clone());
|
||||
// Respond to the message, knowing that we've already handled Halt and Dump, above.
|
||||
match (frame.parse_st.clone(), msg) {
|
||||
(_, ProfileQueriesMsg::Halt) | (_, ProfileQueriesMsg::Dump(_)) => {
|
||||
unreachable!();
|
||||
},
|
||||
// Parse State: Clear
|
||||
(ParseState::Clear,
|
||||
ProfileQueriesMsg::QueryBegin(span, querymsg)) => {
|
||||
let start = Instant::now();
|
||||
frame.parse_st = ParseState::HaveQuery
|
||||
(Query { span, msg: querymsg }, start)
|
||||
},
|
||||
(ParseState::Clear,
|
||||
ProfileQueriesMsg::CacheHit) => {
|
||||
panic!("parse error: unexpected CacheHit; expected QueryBegin")
|
||||
},
|
||||
(ParseState::Clear,
|
||||
ProfileQueriesMsg::ProviderBegin) => {
|
||||
panic!("parse error: expected QueryBegin before beginning a provider")
|
||||
},
|
||||
(ParseState::Clear,
|
||||
ProfileQueriesMsg::ProviderEnd) => {
|
||||
let provider_extent = frame.traces;
|
||||
match stack.pop() {
|
||||
None =>
|
||||
panic!("parse error: expected a stack frame; found an empty stack"),
|
||||
Some(old_frame) => {
|
||||
match old_frame.parse_st {
|
||||
ParseState::HaveQuery(q, start) => {
|
||||
let duration = start.elapsed();
|
||||
frame = StackFrame{
|
||||
parse_st: ParseState::Clear,
|
||||
traces: old_frame.traces
|
||||
};
|
||||
let dur_extent = total_duration(&provider_extent);
|
||||
let trace = Rec {
|
||||
effect: Effect::QueryBegin(q, CacheCase::Miss),
|
||||
extent: Box::new(provider_extent),
|
||||
start: start,
|
||||
dur_self: duration - dur_extent,
|
||||
dur_total: duration,
|
||||
};
|
||||
frame.traces.push( trace );
|
||||
},
|
||||
_ => panic!("internal parse error: malformed parse stack")
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
(ParseState::Clear,
|
||||
ProfileQueriesMsg::TimeBegin(msg)) => {
|
||||
let start = Instant::now();
|
||||
frame.parse_st = ParseState::HaveTimeBegin(msg, start);
|
||||
stack.push(frame);
|
||||
frame = StackFrame{parse_st: ParseState::Clear, traces: vec![]};
|
||||
},
|
||||
(_, ProfileQueriesMsg::TimeBegin(_)) => {
|
||||
panic!("parse error; did not expect time begin here");
|
||||
},
|
||||
(ParseState::Clear,
|
||||
ProfileQueriesMsg::TimeEnd) => {
|
||||
let provider_extent = frame.traces;
|
||||
match stack.pop() {
|
||||
None =>
|
||||
panic!("parse error: expected a stack frame; found an empty stack"),
|
||||
Some(old_frame) => {
|
||||
match old_frame.parse_st {
|
||||
ParseState::HaveTimeBegin(msg, start) => {
|
||||
let duration = start.elapsed();
|
||||
frame = StackFrame{
|
||||
parse_st: ParseState::Clear,
|
||||
traces: old_frame.traces
|
||||
};
|
||||
let dur_extent = total_duration(&provider_extent);
|
||||
let trace = Rec {
|
||||
effect: Effect::TimeBegin(msg),
|
||||
extent: Box::new(provider_extent),
|
||||
start: start,
|
||||
dur_total: duration,
|
||||
dur_self: duration - dur_extent,
|
||||
};
|
||||
frame.traces.push( trace );
|
||||
},
|
||||
_ => panic!("internal parse error: malformed parse stack")
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
(_, ProfileQueriesMsg::TimeEnd) => {
|
||||
panic!("parse error")
|
||||
},
|
||||
(ParseState::Clear,
|
||||
ProfileQueriesMsg::TaskBegin(key)) => {
|
||||
let start = Instant::now();
|
||||
frame.parse_st = ParseState::HaveTaskBegin(key, start);
|
||||
stack.push(frame);
|
||||
frame = StackFrame{ parse_st: ParseState::Clear, traces: vec![] };
|
||||
},
|
||||
(_, ProfileQueriesMsg::TaskBegin(_)) => {
|
||||
panic!("parse error; did not expect time begin here");
|
||||
},
|
||||
(ParseState::Clear,
|
||||
ProfileQueriesMsg::TaskEnd) => {
|
||||
let provider_extent = frame.traces;
|
||||
match stack.pop() {
|
||||
None =>
|
||||
panic!("parse error: expected a stack frame; found an empty stack"),
|
||||
Some(old_frame) => {
|
||||
match old_frame.parse_st {
|
||||
ParseState::HaveTaskBegin(key, start) => {
|
||||
let duration = start.elapsed();
|
||||
frame = StackFrame{
|
||||
parse_st: ParseState::Clear,
|
||||
traces: old_frame.traces
|
||||
};
|
||||
let dur_extent = total_duration(&provider_extent);
|
||||
let trace = Rec {
|
||||
effect: Effect::TaskBegin(key),
|
||||
extent: Box::new(provider_extent),
|
||||
start: start,
|
||||
dur_total: duration,
|
||||
dur_self: duration - dur_extent,
|
||||
};
|
||||
frame.traces.push( trace );
|
||||
},
|
||||
_ => panic!("internal parse error: malformed parse stack")
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
(_, ProfileQueriesMsg::TaskEnd) => {
|
||||
panic!("parse error")
|
||||
},
|
||||
// Parse State: HaveQuery
|
||||
(ParseState::HaveQuery(q,start),
|
||||
ProfileQueriesMsg::CacheHit) => {
|
||||
let duration = start.elapsed();
|
||||
let trace : Rec = Rec{
|
||||
effect: Effect::QueryBegin(q, CacheCase::Hit),
|
||||
extent: Box::new(vec![]),
|
||||
start: start,
|
||||
dur_self: duration,
|
||||
dur_total: duration,
|
||||
};
|
||||
frame.traces.push( trace );
|
||||
frame.parse_st = ParseState::Clear;
|
||||
},
|
||||
(ParseState::HaveQuery(_, _),
|
||||
ProfileQueriesMsg::ProviderBegin) => {
|
||||
stack.push(frame);
|
||||
frame = StackFrame{ parse_st: ParseState::Clear, traces: vec![] };
|
||||
},
|
||||
|
||||
// Parse errors:
|
||||
|
||||
(ParseState::HaveQuery(q, _),
|
||||
ProfileQueriesMsg::ProviderEnd) => {
|
||||
panic!("parse error: unexpected ProviderEnd; \
|
||||
expected something else to follow BeginQuery for {:?}", q)
|
||||
},
|
||||
(ParseState::HaveQuery(q1, _),
|
||||
ProfileQueriesMsg::QueryBegin(span2, querymsg2)) => {
|
||||
panic!("parse error: unexpected QueryBegin; \
|
||||
earlier query is unfinished: {:?} and now {:?}",
|
||||
q1, Query{span:span2, msg: querymsg2})
|
||||
},
|
||||
(ParseState::HaveTimeBegin(_, _), _) => {
|
||||
unreachable!()
|
||||
},
|
||||
(ParseState::HaveTaskBegin(_, _), _) => {
|
||||
unreachable!()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,304 +0,0 @@
|
|||
use super::*;
|
||||
use syntax_pos::SpanData;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc::util::common::QueryMsg;
|
||||
use std::fs::File;
|
||||
use std::time::{Duration, Instant};
|
||||
use rustc::dep_graph::{DepNode};
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Query {
|
||||
pub span: SpanData,
|
||||
pub msg: QueryMsg,
|
||||
}
|
||||
pub enum Effect {
|
||||
QueryBegin(Query, CacheCase),
|
||||
TimeBegin(String),
|
||||
TaskBegin(DepNode),
|
||||
}
|
||||
pub enum CacheCase {
|
||||
Hit, Miss
|
||||
}
|
||||
/// Recursive trace structure
|
||||
pub struct Rec {
|
||||
pub effect: Effect,
|
||||
pub start: Instant,
|
||||
pub dur_self: Duration,
|
||||
pub dur_total: Duration,
|
||||
pub extent: Box<Vec<Rec>>,
|
||||
}
|
||||
pub struct QueryMetric {
|
||||
pub count: usize,
|
||||
pub dur_self: Duration,
|
||||
pub dur_total: Duration,
|
||||
}
|
||||
|
||||
fn cons(s: &str) -> String {
|
||||
let first = s.split(|d| d == '(' || d == '{').next();
|
||||
assert!(first.is_some() && first != Some(""));
|
||||
first.unwrap().to_owned()
|
||||
}
|
||||
|
||||
pub fn cons_of_query_msg(q: &trace::Query) -> String {
|
||||
cons(&format!("{:?}", q.msg))
|
||||
}
|
||||
|
||||
pub fn cons_of_key(k: &DepNode) -> String {
|
||||
cons(&format!("{:?}", k))
|
||||
}
|
||||
|
||||
// First return value is text; second return value is a CSS class
|
||||
pub fn html_of_effect(eff: &Effect) -> (String, String) {
|
||||
match *eff {
|
||||
Effect::TimeBegin(ref msg) => {
|
||||
(msg.clone(),
|
||||
"time-begin".to_string())
|
||||
},
|
||||
Effect::TaskBegin(ref key) => {
|
||||
let cons = cons_of_key(key);
|
||||
(cons.clone(), format!("{} task-begin", cons))
|
||||
},
|
||||
Effect::QueryBegin(ref qmsg, ref cc) => {
|
||||
let cons = cons_of_query_msg(qmsg);
|
||||
(cons.clone(),
|
||||
format!("{} {}",
|
||||
cons,
|
||||
match *cc {
|
||||
CacheCase::Hit => "hit",
|
||||
CacheCase::Miss => "miss",
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// First return value is text; second return value is a CSS class
|
||||
fn html_of_duration(_start: &Instant, dur: &Duration) -> (String, String) {
|
||||
use rustc::util::common::duration_to_secs_str;
|
||||
(duration_to_secs_str(dur.clone()), String::new())
|
||||
}
|
||||
|
||||
fn html_of_fraction(frac: f64) -> (String, &'static str) {
|
||||
let css = {
|
||||
if frac > 0.50 { "frac-50" }
|
||||
else if frac > 0.40 { "frac-40" }
|
||||
else if frac > 0.30 { "frac-30" }
|
||||
else if frac > 0.20 { "frac-20" }
|
||||
else if frac > 0.10 { "frac-10" }
|
||||
else if frac > 0.05 { "frac-05" }
|
||||
else if frac > 0.02 { "frac-02" }
|
||||
else if frac > 0.01 { "frac-01" }
|
||||
else if frac > 0.001 { "frac-001" }
|
||||
else { "frac-0" }
|
||||
};
|
||||
let percent = frac * 100.0;
|
||||
|
||||
if percent > 0.1 {
|
||||
(format!("{:.1}%", percent), css)
|
||||
} else {
|
||||
("< 0.1%".to_string(), css)
|
||||
}
|
||||
}
|
||||
|
||||
fn total_duration(traces: &[Rec]) -> Duration {
|
||||
Duration::new(0, 0) + traces.iter().map(|t| t.dur_total).sum()
|
||||
}
|
||||
|
||||
fn duration_div(nom: Duration, den: Duration) -> f64 {
|
||||
fn to_nanos(d: Duration) -> u64 {
|
||||
d.as_secs() * 1_000_000_000 + d.subsec_nanos() as u64
|
||||
}
|
||||
|
||||
to_nanos(nom) as f64 / to_nanos(den) as f64
|
||||
}
|
||||
|
||||
fn write_traces_rec(file: &mut File, traces: &[Rec], total: Duration, depth: usize) {
|
||||
for t in traces {
|
||||
let (eff_text, eff_css_classes) = html_of_effect(&t.effect);
|
||||
let (dur_text, dur_css_classes) = html_of_duration(&t.start, &t.dur_total);
|
||||
let fraction = duration_div(t.dur_total, total);
|
||||
let percent = fraction * 100.0;
|
||||
let (frc_text, frc_css_classes) = html_of_fraction(fraction);
|
||||
writeln!(file, "<div class=\"trace depth-{} extent-{}{} {} {} {}\">",
|
||||
depth,
|
||||
t.extent.len(),
|
||||
/* Heuristic for 'important' CSS class: */
|
||||
if t.extent.len() > 5 || percent >= 1.0 { " important" } else { "" },
|
||||
eff_css_classes,
|
||||
dur_css_classes,
|
||||
frc_css_classes,
|
||||
).unwrap();
|
||||
writeln!(file, "<div class=\"eff\">{}</div>", eff_text).unwrap();
|
||||
writeln!(file, "<div class=\"dur\">{}</div>", dur_text).unwrap();
|
||||
writeln!(file, "<div class=\"frc\">{}</div>", frc_text).unwrap();
|
||||
write_traces_rec(file, &t.extent, total, depth + 1);
|
||||
writeln!(file, "</div>").unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_counts_rec(counts: &mut FxHashMap<String,QueryMetric>, traces: &[Rec]) {
|
||||
counts.reserve(traces.len());
|
||||
for t in traces.iter() {
|
||||
match t.effect {
|
||||
Effect::TimeBegin(ref msg) => {
|
||||
let qm = match counts.get(msg) {
|
||||
Some(_qm) => panic!("TimeBegin with non-unique, repeat message"),
|
||||
None => QueryMetric {
|
||||
count: 1,
|
||||
dur_self: t.dur_self,
|
||||
dur_total: t.dur_total,
|
||||
}
|
||||
};
|
||||
counts.insert(msg.clone(), qm);
|
||||
},
|
||||
Effect::TaskBegin(ref key) => {
|
||||
let cons = cons_of_key(key);
|
||||
let qm = match counts.get(&cons) {
|
||||
Some(qm) =>
|
||||
QueryMetric {
|
||||
count: qm.count + 1,
|
||||
dur_self: qm.dur_self + t.dur_self,
|
||||
dur_total: qm.dur_total + t.dur_total,
|
||||
},
|
||||
None => QueryMetric {
|
||||
count: 1,
|
||||
dur_self: t.dur_self,
|
||||
dur_total: t.dur_total,
|
||||
}
|
||||
};
|
||||
counts.insert(cons, qm);
|
||||
},
|
||||
Effect::QueryBegin(ref qmsg, ref _cc) => {
|
||||
let qcons = cons_of_query_msg(qmsg);
|
||||
let qm = match counts.get(&qcons) {
|
||||
Some(qm) =>
|
||||
QueryMetric {
|
||||
count: qm.count + 1,
|
||||
dur_total: qm.dur_total + t.dur_total,
|
||||
dur_self: qm.dur_self + t.dur_self
|
||||
},
|
||||
None => QueryMetric {
|
||||
count: 1,
|
||||
dur_total: t.dur_total,
|
||||
dur_self: t.dur_self,
|
||||
}
|
||||
};
|
||||
counts.insert(qcons, qm);
|
||||
}
|
||||
}
|
||||
compute_counts_rec(counts, &t.extent)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_counts(count_file: &mut File, counts: &mut FxHashMap<String, QueryMetric>) {
|
||||
use rustc::util::common::duration_to_secs_str;
|
||||
use std::cmp::Reverse;
|
||||
|
||||
let mut data = counts.iter().map(|(ref cons, ref qm)|
|
||||
(cons.clone(), qm.count.clone(), qm.dur_total.clone(), qm.dur_self.clone())
|
||||
).collect::<Vec<_>>();
|
||||
|
||||
data.sort_by_key(|k| Reverse(k.3));
|
||||
for (cons, count, dur_total, dur_self) in data {
|
||||
writeln!(count_file, "{}, {}, {}, {}",
|
||||
cons, count,
|
||||
duration_to_secs_str(dur_total),
|
||||
duration_to_secs_str(dur_self)
|
||||
).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_traces(html_file: &mut File, counts_file: &mut File, traces: &[Rec]) {
|
||||
let capacity = traces.iter().fold(0, |acc, t| acc + 1 + t.extent.len());
|
||||
let mut counts = FxHashMap::with_capacity_and_hasher(capacity, Default::default());
|
||||
compute_counts_rec(&mut counts, traces);
|
||||
write_counts(counts_file, &mut counts);
|
||||
|
||||
let total: Duration = total_duration(traces);
|
||||
write_traces_rec(html_file, traces, total, 0)
|
||||
}
|
||||
|
||||
pub fn write_style(html_file: &mut File) {
|
||||
write!(html_file, "{}", "
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
background: black;
|
||||
}
|
||||
.trace {
|
||||
color: black;
|
||||
display: inline-block;
|
||||
border-style: solid;
|
||||
border-color: red;
|
||||
border-width: 1px;
|
||||
border-radius: 5px;
|
||||
padding: 0px;
|
||||
margin: 1px;
|
||||
font-size: 0px;
|
||||
}
|
||||
.task-begin {
|
||||
border-width: 1px;
|
||||
color: white;
|
||||
border-color: #ff8;
|
||||
font-size: 0px;
|
||||
}
|
||||
.miss {
|
||||
border-color: red;
|
||||
border-width: 1px;
|
||||
}
|
||||
.extent-0 {
|
||||
padding: 2px;
|
||||
}
|
||||
.time-begin {
|
||||
border-width: 4px;
|
||||
font-size: 12px;
|
||||
color: white;
|
||||
border-color: #afa;
|
||||
}
|
||||
.important {
|
||||
border-width: 3px;
|
||||
font-size: 12px;
|
||||
color: white;
|
||||
border-color: #f77;
|
||||
}
|
||||
.hit {
|
||||
padding: 0px;
|
||||
border-color: blue;
|
||||
border-width: 3px;
|
||||
}
|
||||
.eff {
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
}
|
||||
.frc {
|
||||
color: #7f7;
|
||||
display: inline-block;
|
||||
}
|
||||
.dur {
|
||||
display: none
|
||||
}
|
||||
.frac-50 {
|
||||
padding: 10px;
|
||||
border-width: 10px;
|
||||
font-size: 32px;
|
||||
}
|
||||
.frac-40 {
|
||||
padding: 8px;
|
||||
border-width: 8px;
|
||||
font-size: 24px;
|
||||
}
|
||||
.frac-30 {
|
||||
padding: 6px;
|
||||
border-width: 6px;
|
||||
font-size: 18px;
|
||||
}
|
||||
.frac-20 {
|
||||
padding: 4px;
|
||||
border-width: 6px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.frac-10 {
|
||||
padding: 2px;
|
||||
border-width: 6px;
|
||||
font-size: 14px;
|
||||
}
|
||||
").unwrap();
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
syntax::register_diagnostics! {
|
||||
;
|
||||
E0721, // `await` keyword
|
||||
// E0721, // `await` keyword
|
||||
}
|
||||
|
|
|
@ -953,7 +953,7 @@ https://doc.rust-lang.org/std/cell/
|
|||
"##,
|
||||
|
||||
E0388: r##"
|
||||
E0388 was removed and is no longer issued.
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
"##,
|
||||
|
||||
E0389: r##"
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
syntax::register_diagnostics! {
|
||||
/*
|
||||
E0014: r##"
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
Constants can only be initialized by a constant value or, in a future
|
||||
version of Rust, a call to a const function. This error indicates the use
|
||||
of a path (like a::b, or x) denoting something other than one of these
|
||||
allowed items. Erroneous code xample:
|
||||
allowed items.
|
||||
|
||||
```compile_fail
|
||||
Erroneous code example:
|
||||
|
||||
```
|
||||
const FOO: i32 = { let x = 0; x }; // 'x' isn't a constant nor a function!
|
||||
```
|
||||
|
||||
|
@ -18,10 +21,10 @@ const FOO: i32 = { const X : i32 = 0; X };
|
|||
const FOO2: i32 = { 0 }; // but brackets are useless here
|
||||
```
|
||||
"##,
|
||||
*/
|
||||
|
||||
E0130: r##"
|
||||
You declared a pattern as an argument in a foreign function declaration.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail
|
||||
|
@ -57,6 +60,20 @@ extern {
|
|||
E0136: r##"
|
||||
A binary can only have one entry point, and by default that entry point is the
|
||||
function `main()`. If there are multiple such functions, please rename one.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0136
|
||||
fn main() {
|
||||
// ...
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
fn main() { // error!
|
||||
// ...
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0137: r##"
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
syntax::register_diagnostics! {
|
||||
|
||||
E0445: r##"
|
||||
A private trait was used on a public type parameter bound. Erroneous code
|
||||
examples:
|
||||
A private trait was used on a public type parameter bound.
|
||||
|
||||
Erroneous code examples:
|
||||
|
||||
```compile_fail,E0445
|
||||
#![deny(private_in_public)]
|
||||
|
@ -32,7 +33,9 @@ pub fn foo<T: Foo> (t: T) {} // ok!
|
|||
"##,
|
||||
|
||||
E0446: r##"
|
||||
A private type was used in a public type signature. Erroneous code example:
|
||||
A private type was used in a public type signature.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0446
|
||||
#![deny(private_in_public)]
|
||||
|
@ -65,7 +68,9 @@ mod Foo {
|
|||
E0447: r##"
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
The `pub` keyword was used inside a function. Erroneous code example:
|
||||
The `pub` keyword was used inside a function.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```
|
||||
fn foo() {
|
||||
|
@ -79,7 +84,11 @@ is invalid.
|
|||
"##,
|
||||
|
||||
E0448: r##"
|
||||
The `pub` keyword was used inside a public enum. Erroneous code example:
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
The `pub` keyword was used inside a public enum.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail
|
||||
pub enum Foo {
|
||||
|
@ -106,7 +115,9 @@ pub enum Foo {
|
|||
"##,
|
||||
|
||||
E0451: r##"
|
||||
A struct constructor with private fields was invoked. Erroneous code example:
|
||||
A struct constructor with private fields was invoked.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0451
|
||||
mod Bar {
|
||||
|
|
|
@ -20,7 +20,7 @@ use syntax_pos::{BytePos, Span, MultiSpan};
|
|||
|
||||
use crate::resolve_imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver};
|
||||
use crate::{path_names_to_string, KNOWN_TOOLS};
|
||||
use crate::{BindingError, CrateLint, LegacyScope, Module, ModuleOrUniformRoot};
|
||||
use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot};
|
||||
use crate::{PathResult, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Segment};
|
||||
|
||||
type Res = def::Res<ast::NodeId>;
|
||||
|
@ -102,7 +102,7 @@ impl<'a> Resolver<'a> {
|
|||
&self, span: Span, resolution_error: ResolutionError<'_>
|
||||
) -> DiagnosticBuilder<'_> {
|
||||
match resolution_error {
|
||||
ResolutionError::GenericParamsFromOuterFunction(outer_res) => {
|
||||
ResolutionError::GenericParamsFromOuterFunction(outer_res, has_generic_params) => {
|
||||
let mut err = struct_span_err!(self.session,
|
||||
span,
|
||||
E0401,
|
||||
|
@ -148,22 +148,24 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// Try to retrieve the span of the function signature and generate a new message
|
||||
// with a local type or const parameter.
|
||||
let sugg_msg = &format!("try using a local generic parameter instead");
|
||||
if let Some((sugg_span, new_snippet)) = cm.generate_local_type_param_snippet(span) {
|
||||
// Suggest the modification to the user
|
||||
err.span_suggestion(
|
||||
sugg_span,
|
||||
sugg_msg,
|
||||
new_snippet,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if let Some(sp) = cm.generate_fn_name_span(span) {
|
||||
err.span_label(sp,
|
||||
format!("try adding a local generic parameter in this method instead"));
|
||||
} else {
|
||||
err.help(&format!("try using a local generic parameter instead"));
|
||||
if has_generic_params == HasGenericParams::Yes {
|
||||
// Try to retrieve the span of the function signature and generate a new
|
||||
// message with a local type or const parameter.
|
||||
let sugg_msg = &format!("try using a local generic parameter instead");
|
||||
if let Some((sugg_span, snippet)) = cm.generate_local_type_param_snippet(span) {
|
||||
// Suggest the modification to the user
|
||||
err.span_suggestion(
|
||||
sugg_span,
|
||||
sugg_msg,
|
||||
snippet,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if let Some(sp) = cm.generate_fn_name_span(span) {
|
||||
err.span_label(sp,
|
||||
format!("try adding a local generic parameter in this method instead"));
|
||||
} else {
|
||||
err.help(&format!("try using a local generic parameter instead"));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
//! If you wonder why there's no `early.rs`, that's because it's split into three files -
|
||||
//! `build_reduced_graph.rs`, `macros.rs` and `resolve_imports.rs`.
|
||||
|
||||
use GenericParameters::*;
|
||||
use RibKind::*;
|
||||
|
||||
use crate::{path_names_to_string, BindingError, CrateLint, LexicalScopeBinding};
|
||||
|
@ -46,16 +45,6 @@ struct BindingInfo {
|
|||
binding_mode: BindingMode,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum GenericParameters<'a, 'b> {
|
||||
NoGenericParams,
|
||||
HasGenericParams(// Type parameters.
|
||||
&'b Generics,
|
||||
|
||||
// The kind of the rib used for type parameters.
|
||||
RibKind<'a>),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
enum PatternSource {
|
||||
Match,
|
||||
|
@ -85,6 +74,10 @@ enum PatBoundCtx {
|
|||
Or,
|
||||
}
|
||||
|
||||
/// Does this the item (from the item rib scope) allow generic parameters?
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
crate enum HasGenericParams { Yes, No }
|
||||
|
||||
/// The rib kind restricts certain accesses,
|
||||
/// e.g. to a `Res::Local` of an outer item.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
@ -103,7 +96,7 @@ crate enum RibKind<'a> {
|
|||
FnItemRibKind,
|
||||
|
||||
/// We passed through an item scope. Disallow upvars.
|
||||
ItemRibKind,
|
||||
ItemRibKind(HasGenericParams),
|
||||
|
||||
/// We're in a constant item. Can't refer to dynamic stuff.
|
||||
ConstantItemRibKind,
|
||||
|
@ -134,7 +127,7 @@ impl RibKind<'_> {
|
|||
| ModuleRibKind(_)
|
||||
| MacroDefinition(_) => false,
|
||||
AssocItemRibKind
|
||||
| ItemRibKind
|
||||
| ItemRibKind(_)
|
||||
| ForwardTyParamBanRibKind
|
||||
| TyParamAsConstParamTy => true,
|
||||
}
|
||||
|
@ -406,17 +399,21 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
|
|||
visit::walk_poly_trait_ref(self, tref, m);
|
||||
}
|
||||
fn visit_foreign_item(&mut self, foreign_item: &'tcx ForeignItem) {
|
||||
let generic_params = match foreign_item.kind {
|
||||
match foreign_item.kind {
|
||||
ForeignItemKind::Fn(_, ref generics) => {
|
||||
HasGenericParams(generics, ItemRibKind)
|
||||
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
|
||||
visit::walk_foreign_item(this, foreign_item);
|
||||
});
|
||||
}
|
||||
ForeignItemKind::Static(..) => NoGenericParams,
|
||||
ForeignItemKind::Ty => NoGenericParams,
|
||||
ForeignItemKind::Macro(..) => NoGenericParams,
|
||||
};
|
||||
self.with_generic_param_rib(generic_params, |this| {
|
||||
visit::walk_foreign_item(this, foreign_item);
|
||||
});
|
||||
ForeignItemKind::Static(..) => {
|
||||
self.with_item_rib(HasGenericParams::No, |this| {
|
||||
visit::walk_foreign_item(this, foreign_item);
|
||||
});
|
||||
}
|
||||
ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {
|
||||
visit::walk_foreign_item(self, foreign_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, declaration: &'tcx FnDecl, _: Span, _: NodeId) {
|
||||
debug!("(resolving function) entering function");
|
||||
|
@ -660,7 +657,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
|
|||
fn resolve_adt(&mut self, item: &Item, generics: &Generics) {
|
||||
debug!("resolve_adt");
|
||||
self.with_current_self_item(item, |this| {
|
||||
this.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
|
||||
this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
|
||||
let item_def_id = this.r.definitions.local_def_id(item.id);
|
||||
this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| {
|
||||
visit::walk_item(this, item);
|
||||
|
@ -719,10 +716,8 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
|
|||
ItemKind::TyAlias(_, ref generics) |
|
||||
ItemKind::OpaqueTy(_, ref generics) |
|
||||
ItemKind::Fn(_, _, ref generics, _) => {
|
||||
self.with_generic_param_rib(
|
||||
HasGenericParams(generics, ItemRibKind),
|
||||
|this| visit::walk_item(this, item)
|
||||
);
|
||||
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes),
|
||||
|this| visit::walk_item(this, item));
|
||||
}
|
||||
|
||||
ItemKind::Enum(_, ref generics) |
|
||||
|
@ -740,7 +735,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
|
|||
|
||||
ItemKind::Trait(.., ref generics, ref bounds, ref trait_items) => {
|
||||
// Create a new rib for the trait-wide type parameters.
|
||||
self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
|
||||
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
|
||||
let local_def_id = this.r.definitions.local_def_id(item.id);
|
||||
this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
|
||||
this.visit_generics(generics);
|
||||
|
@ -748,35 +743,32 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
|
|||
|
||||
for trait_item in trait_items {
|
||||
this.with_trait_items(trait_items, |this| {
|
||||
let generic_params = HasGenericParams(
|
||||
&trait_item.generics,
|
||||
AssocItemRibKind,
|
||||
);
|
||||
this.with_generic_param_rib(generic_params, |this| {
|
||||
match trait_item.kind {
|
||||
TraitItemKind::Const(ref ty, ref default) => {
|
||||
this.visit_ty(ty);
|
||||
this.with_generic_param_rib(&trait_item.generics, AssocItemRibKind,
|
||||
|this| {
|
||||
match trait_item.kind {
|
||||
TraitItemKind::Const(ref ty, ref default) => {
|
||||
this.visit_ty(ty);
|
||||
|
||||
// Only impose the restrictions of
|
||||
// ConstRibKind for an actual constant
|
||||
// expression in a provided default.
|
||||
if let Some(ref expr) = *default{
|
||||
this.with_constant_rib(|this| {
|
||||
this.visit_expr(expr);
|
||||
});
|
||||
// Only impose the restrictions of
|
||||
// ConstRibKind for an actual constant
|
||||
// expression in a provided default.
|
||||
if let Some(ref expr) = *default{
|
||||
this.with_constant_rib(|this| {
|
||||
this.visit_expr(expr);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
TraitItemKind::Method(_, _) => {
|
||||
visit::walk_trait_item(this, trait_item)
|
||||
}
|
||||
TraitItemKind::Type(..) => {
|
||||
visit::walk_trait_item(this, trait_item)
|
||||
}
|
||||
TraitItemKind::Macro(_) => {
|
||||
panic!("unexpanded macro in resolve!")
|
||||
}
|
||||
};
|
||||
});
|
||||
TraitItemKind::Method(_, _) => {
|
||||
visit::walk_trait_item(this, trait_item)
|
||||
}
|
||||
TraitItemKind::Type(..) => {
|
||||
visit::walk_trait_item(this, trait_item)
|
||||
}
|
||||
TraitItemKind::Macro(_) => {
|
||||
panic!("unexpanded macro in resolve!")
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -785,7 +777,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
|
|||
|
||||
ItemKind::TraitAlias(ref generics, ref bounds) => {
|
||||
// Create a new rib for the trait-wide type parameters.
|
||||
self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
|
||||
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
|
||||
let local_def_id = this.r.definitions.local_def_id(item.id);
|
||||
this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
|
||||
this.visit_generics(generics);
|
||||
|
@ -803,7 +795,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
|
|||
ItemKind::Static(ref ty, _, ref expr) |
|
||||
ItemKind::Const(ref ty, ref expr) => {
|
||||
debug!("resolve_item ItemKind::Const");
|
||||
self.with_item_rib(|this| {
|
||||
self.with_item_rib(HasGenericParams::No, |this| {
|
||||
this.visit_ty(ty);
|
||||
this.with_constant_rib(|this| {
|
||||
this.visit_expr(expr);
|
||||
|
@ -824,91 +816,75 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn with_generic_param_rib<'c, F>(&'c mut self, generic_params: GenericParameters<'a, 'c>, f: F)
|
||||
fn with_generic_param_rib<'c, F>(&'c mut self, generics: &'c Generics, kind: RibKind<'a>, f: F)
|
||||
where F: FnOnce(&mut Self)
|
||||
{
|
||||
debug!("with_generic_param_rib");
|
||||
match generic_params {
|
||||
HasGenericParams(generics, rib_kind) => {
|
||||
let mut function_type_rib = Rib::new(rib_kind);
|
||||
let mut function_value_rib = Rib::new(rib_kind);
|
||||
let mut seen_bindings = FxHashMap::default();
|
||||
// We also can't shadow bindings from the parent item
|
||||
if let AssocItemRibKind = rib_kind {
|
||||
let mut add_bindings_for_ns = |ns| {
|
||||
let parent_rib = self.ribs[ns].iter()
|
||||
.rfind(|rib| if let ItemRibKind = rib.kind { true } else { false })
|
||||
.expect("associated item outside of an item");
|
||||
seen_bindings.extend(
|
||||
parent_rib.bindings.iter().map(|(ident, _)| (*ident, ident.span)),
|
||||
);
|
||||
};
|
||||
add_bindings_for_ns(ValueNS);
|
||||
add_bindings_for_ns(TypeNS);
|
||||
}
|
||||
for param in &generics.params {
|
||||
match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => {}
|
||||
GenericParamKind::Type { .. } => {
|
||||
let ident = param.ident.modern();
|
||||
debug!("with_generic_param_rib: {}", param.id);
|
||||
let mut function_type_rib = Rib::new(kind);
|
||||
let mut function_value_rib = Rib::new(kind);
|
||||
let mut seen_bindings = FxHashMap::default();
|
||||
|
||||
if seen_bindings.contains_key(&ident) {
|
||||
let span = seen_bindings.get(&ident).unwrap();
|
||||
let err = ResolutionError::NameAlreadyUsedInParameterList(
|
||||
ident.name,
|
||||
*span,
|
||||
);
|
||||
self.r.report_error(param.ident.span, err);
|
||||
}
|
||||
seen_bindings.entry(ident).or_insert(param.ident.span);
|
||||
// We also can't shadow bindings from the parent item
|
||||
if let AssocItemRibKind = kind {
|
||||
let mut add_bindings_for_ns = |ns| {
|
||||
let parent_rib = self.ribs[ns].iter()
|
||||
.rfind(|r| if let ItemRibKind(_) = r.kind { true } else { false })
|
||||
.expect("associated item outside of an item");
|
||||
seen_bindings.extend(
|
||||
parent_rib.bindings.iter().map(|(ident, _)| (*ident, ident.span)),
|
||||
);
|
||||
};
|
||||
add_bindings_for_ns(ValueNS);
|
||||
add_bindings_for_ns(TypeNS);
|
||||
}
|
||||
|
||||
// Plain insert (no renaming).
|
||||
let res = Res::Def(
|
||||
DefKind::TyParam,
|
||||
self.r.definitions.local_def_id(param.id),
|
||||
);
|
||||
function_type_rib.bindings.insert(ident, res);
|
||||
self.r.record_partial_res(param.id, PartialRes::new(res));
|
||||
}
|
||||
GenericParamKind::Const { .. } => {
|
||||
let ident = param.ident.modern();
|
||||
debug!("with_generic_param_rib: {}", param.id);
|
||||
|
||||
if seen_bindings.contains_key(&ident) {
|
||||
let span = seen_bindings.get(&ident).unwrap();
|
||||
let err = ResolutionError::NameAlreadyUsedInParameterList(
|
||||
ident.name,
|
||||
*span,
|
||||
);
|
||||
self.r.report_error(param.ident.span, err);
|
||||
}
|
||||
seen_bindings.entry(ident).or_insert(param.ident.span);
|
||||
|
||||
let res = Res::Def(
|
||||
DefKind::ConstParam,
|
||||
self.r.definitions.local_def_id(param.id),
|
||||
);
|
||||
function_value_rib.bindings.insert(ident, res);
|
||||
self.r.record_partial_res(param.id, PartialRes::new(res));
|
||||
}
|
||||
}
|
||||
}
|
||||
self.ribs[ValueNS].push(function_value_rib);
|
||||
self.ribs[TypeNS].push(function_type_rib);
|
||||
for param in &generics.params {
|
||||
if let GenericParamKind::Lifetime { .. } = param.kind {
|
||||
continue;
|
||||
}
|
||||
|
||||
NoGenericParams => {
|
||||
// Nothing to do.
|
||||
let def_kind = match param.kind {
|
||||
GenericParamKind::Type { .. } => DefKind::TyParam,
|
||||
GenericParamKind::Const { .. } => DefKind::ConstParam,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let ident = param.ident.modern();
|
||||
debug!("with_generic_param_rib: {}", param.id);
|
||||
|
||||
if seen_bindings.contains_key(&ident) {
|
||||
let span = seen_bindings.get(&ident).unwrap();
|
||||
let err = ResolutionError::NameAlreadyUsedInParameterList(
|
||||
ident.name,
|
||||
*span,
|
||||
);
|
||||
self.r.report_error(param.ident.span, err);
|
||||
}
|
||||
seen_bindings.entry(ident).or_insert(param.ident.span);
|
||||
|
||||
// Plain insert (no renaming).
|
||||
let res = Res::Def(def_kind, self.r.definitions.local_def_id(param.id));
|
||||
|
||||
match param.kind {
|
||||
GenericParamKind::Type { .. } => {
|
||||
function_type_rib.bindings.insert(ident, res);
|
||||
self.r.record_partial_res(param.id, PartialRes::new(res));
|
||||
}
|
||||
GenericParamKind::Const { .. } => {
|
||||
function_value_rib.bindings.insert(ident, res);
|
||||
self.r.record_partial_res(param.id, PartialRes::new(res));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
self.ribs[ValueNS].push(function_value_rib);
|
||||
self.ribs[TypeNS].push(function_type_rib);
|
||||
|
||||
f(self);
|
||||
|
||||
if let HasGenericParams(..) = generic_params {
|
||||
self.ribs[TypeNS].pop();
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
self.ribs[TypeNS].pop();
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
|
||||
fn with_label_rib(&mut self, kind: RibKind<'a>, f: impl FnOnce(&mut Self)) {
|
||||
|
@ -917,8 +893,9 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
|
|||
self.label_ribs.pop();
|
||||
}
|
||||
|
||||
fn with_item_rib(&mut self, f: impl FnOnce(&mut Self)) {
|
||||
self.with_rib(ValueNS, ItemRibKind, |this| this.with_rib(TypeNS, ItemRibKind, f))
|
||||
fn with_item_rib(&mut self, has_generic_params: HasGenericParams, f: impl FnOnce(&mut Self)) {
|
||||
let kind = ItemRibKind(has_generic_params);
|
||||
self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
|
||||
}
|
||||
|
||||
fn with_constant_rib(&mut self, f: impl FnOnce(&mut Self)) {
|
||||
|
@ -1023,7 +1000,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
|
|||
impl_items: &[ImplItem]) {
|
||||
debug!("resolve_implementation");
|
||||
// If applicable, create a rib for the type parameters.
|
||||
self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
|
||||
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
|
||||
// Dummy self type for better errors if `Self` is used in the trait path.
|
||||
this.with_self_rib(Res::SelfTy(None, None), |this| {
|
||||
// Resolve the trait reference, if necessary.
|
||||
|
@ -1044,9 +1021,9 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
|
|||
debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
|
||||
for impl_item in impl_items {
|
||||
// We also need a new scope for the impl item type parameters.
|
||||
let generic_params = HasGenericParams(&impl_item.generics,
|
||||
AssocItemRibKind);
|
||||
this.with_generic_param_rib(generic_params, |this| {
|
||||
this.with_generic_param_rib(&impl_item.generics,
|
||||
AssocItemRibKind,
|
||||
|this| {
|
||||
use crate::ResolutionError::*;
|
||||
match impl_item.kind {
|
||||
ImplItemKind::Const(..) => {
|
||||
|
|
|
@ -61,7 +61,7 @@ use rustc_data_structures::fx::FxIndexMap;
|
|||
|
||||
use diagnostics::{Suggestion, ImportSuggestion};
|
||||
use diagnostics::{find_span_of_binding_until_next_binding, extend_span_to_previous_binding};
|
||||
use late::{PathSource, Rib, RibKind::*};
|
||||
use late::{HasGenericParams, PathSource, Rib, RibKind::*};
|
||||
use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver};
|
||||
use macros::{LegacyBinding, LegacyScope};
|
||||
|
||||
|
@ -178,7 +178,7 @@ impl Ord for BindingError {
|
|||
|
||||
enum ResolutionError<'a> {
|
||||
/// Error E0401: can't use type or const parameters from outer function.
|
||||
GenericParamsFromOuterFunction(Res),
|
||||
GenericParamsFromOuterFunction(Res, HasGenericParams),
|
||||
/// Error E0403: the name is already used for a type or const parameter in this generic
|
||||
/// parameter list.
|
||||
NameAlreadyUsedInParameterList(Name, Span),
|
||||
|
@ -2156,7 +2156,7 @@ impl<'a> Resolver<'a> {
|
|||
ForwardTyParamBanRibKind | TyParamAsConstParamTy => {
|
||||
// Nothing to do. Continue.
|
||||
}
|
||||
ItemRibKind | FnItemRibKind | AssocItemRibKind => {
|
||||
ItemRibKind(_) | FnItemRibKind | AssocItemRibKind => {
|
||||
// This was an attempt to access an upvar inside a
|
||||
// named function item. This is not allowed, so we
|
||||
// report an error.
|
||||
|
@ -2184,22 +2184,23 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
Res::Def(DefKind::TyParam, _) | Res::SelfTy(..) => {
|
||||
for rib in ribs {
|
||||
match rib.kind {
|
||||
let has_generic_params = match rib.kind {
|
||||
NormalRibKind | AssocItemRibKind |
|
||||
ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind |
|
||||
ConstantItemRibKind | TyParamAsConstParamTy => {
|
||||
// Nothing to do. Continue.
|
||||
continue;
|
||||
}
|
||||
ItemRibKind | FnItemRibKind => {
|
||||
// This was an attempt to use a type parameter outside its scope.
|
||||
if record_used {
|
||||
self.report_error(
|
||||
span, ResolutionError::GenericParamsFromOuterFunction(res)
|
||||
);
|
||||
}
|
||||
return Res::Err;
|
||||
}
|
||||
// This was an attempt to use a type parameter outside its scope.
|
||||
ItemRibKind(has_generic_params) => has_generic_params,
|
||||
FnItemRibKind => HasGenericParams::Yes,
|
||||
};
|
||||
|
||||
if record_used {
|
||||
self.report_error(span, ResolutionError::GenericParamsFromOuterFunction(
|
||||
res, has_generic_params));
|
||||
}
|
||||
return Res::Err;
|
||||
}
|
||||
}
|
||||
Res::Def(DefKind::ConstParam, _) => {
|
||||
|
@ -2211,15 +2212,18 @@ impl<'a> Resolver<'a> {
|
|||
ribs.next();
|
||||
}
|
||||
for rib in ribs {
|
||||
if let ItemRibKind | FnItemRibKind = rib.kind {
|
||||
// This was an attempt to use a const parameter outside its scope.
|
||||
if record_used {
|
||||
self.report_error(
|
||||
span, ResolutionError::GenericParamsFromOuterFunction(res)
|
||||
);
|
||||
}
|
||||
return Res::Err;
|
||||
let has_generic_params = match rib.kind {
|
||||
ItemRibKind(has_generic_params) => has_generic_params,
|
||||
FnItemRibKind => HasGenericParams::Yes,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
// This was an attempt to use a const parameter outside its scope.
|
||||
if record_used {
|
||||
self.report_error(span, ResolutionError::GenericParamsFromOuterFunction(
|
||||
res, has_generic_params));
|
||||
}
|
||||
return Res::Err;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
@ -115,6 +115,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
Err(e) => e
|
||||
};
|
||||
|
||||
let expr = expr.peel_drop_temps();
|
||||
let cause = self.misc(expr.span);
|
||||
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
|
||||
let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
|
||||
|
@ -355,6 +356,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
};
|
||||
let is_macro = sp.from_expansion() && !is_desugaring;
|
||||
|
||||
// `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
|
||||
let expr = expr.peel_drop_temps();
|
||||
|
||||
match (&expr.kind, &expected.kind, &checked_ty.kind) {
|
||||
(_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (&exp.kind, &check.kind) {
|
||||
(&ty::Str, &ty::Array(arr, _)) |
|
||||
|
|
|
@ -87,12 +87,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) {
|
||||
let expr = expr.peel_drop_temps();
|
||||
self.suggest_ref_or_into(&mut err, expr, expected_ty, ty);
|
||||
|
||||
let expr = match &expr.kind {
|
||||
ExprKind::DropTemps(expr) => expr,
|
||||
_ => expr,
|
||||
};
|
||||
extend_err(&mut err);
|
||||
// Error possibly reported in `check_assign` so avoid emitting error again.
|
||||
err.emit_unless(self.is_assign_to_bool(expr, expected_ty));
|
||||
|
|
|
@ -538,13 +538,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
let mut fallback_span = true;
|
||||
let msg = "remove this method call";
|
||||
if item_name.as_str() == "as_str" && actual.peel_refs().is_str() {
|
||||
// FIXME: the span is not quite correct, it should point to ".as_str()" instead
|
||||
// of just "as_str".
|
||||
err.span_label(
|
||||
span,
|
||||
"try removing `as_str`"
|
||||
);
|
||||
if let SelfSource::MethodCall(expr) = source {
|
||||
let call_expr = self.tcx.hir().expect_expr(
|
||||
self.tcx.hir().get_parent_node(expr.hir_id),
|
||||
);
|
||||
if let Some(span) = call_expr.span.trim_start(expr.span) {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
msg,
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
fallback_span = false;
|
||||
}
|
||||
}
|
||||
if fallback_span {
|
||||
err.span_label(span, msg);
|
||||
}
|
||||
} else if let Some(lev_candidate) = lev_candidate {
|
||||
let def_kind = lev_candidate.def_kind();
|
||||
err.span_suggestion(
|
||||
|
|
|
@ -4216,20 +4216,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
pub fn suggest_mismatched_types_on_tail(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
expression: &'tcx hir::Expr,
|
||||
expr: &'tcx hir::Expr,
|
||||
expected: Ty<'tcx>,
|
||||
found: Ty<'tcx>,
|
||||
cause_span: Span,
|
||||
blk_id: hir::HirId,
|
||||
) -> bool {
|
||||
self.suggest_missing_semicolon(err, expression, expected, cause_span);
|
||||
let expr = expr.peel_drop_temps();
|
||||
self.suggest_missing_semicolon(err, expr, expected, cause_span);
|
||||
let mut pointing_at_return_type = false;
|
||||
if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
|
||||
pointing_at_return_type = self.suggest_missing_return_type(
|
||||
err, &fn_decl, expected, found, can_suggest);
|
||||
}
|
||||
self.suggest_ref_or_into(err, expression, expected, found);
|
||||
self.suggest_boxing_when_appropriate(err, expression, expected, found);
|
||||
self.suggest_ref_or_into(err, expr, expected, found);
|
||||
self.suggest_boxing_when_appropriate(err, expr, expected, found);
|
||||
pointing_at_return_type
|
||||
}
|
||||
|
||||
|
|
|
@ -1873,13 +1873,14 @@ This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this
|
|||
differs from the behavior for `&T`, which is always `Copy`).
|
||||
"##,
|
||||
|
||||
/*
|
||||
E0205: r##"
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
An attempt to implement the `Copy` trait for an enum failed because one of the
|
||||
variants does not implement `Copy`. To fix this, you must implement `Copy` for
|
||||
the mentioned variant. Note that this may not be possible, as in the example of
|
||||
|
||||
```compile_fail,E0205
|
||||
```compile_fail,E0204
|
||||
enum Foo {
|
||||
Bar(Vec<u32>),
|
||||
Baz,
|
||||
|
@ -1892,7 +1893,7 @@ This fails because `Vec<T>` does not implement `Copy` for any `T`.
|
|||
|
||||
Here's another example that will fail:
|
||||
|
||||
```compile_fail,E0205
|
||||
```compile_fail,E0204
|
||||
#[derive(Copy)]
|
||||
enum Foo<'a> {
|
||||
Bar(&'a mut bool),
|
||||
|
@ -1903,7 +1904,6 @@ enum Foo<'a> {
|
|||
This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this
|
||||
differs from the behavior for `&T`, which is always `Copy`).
|
||||
"##,
|
||||
*/
|
||||
|
||||
E0206: r##"
|
||||
You can only implement `Copy` for a struct or enum. Both of the following
|
||||
|
@ -2126,8 +2126,9 @@ For information on the design of the orphan rules, see [RFC 1023].
|
|||
[RFC 1023]: https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md
|
||||
"##,
|
||||
|
||||
/*
|
||||
E0211: r##"
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
You used a function or type which doesn't fit the requirements for where it was
|
||||
used. Erroneous code examples:
|
||||
|
||||
|
@ -2174,7 +2175,7 @@ extern "rust-intrinsic" {
|
|||
}
|
||||
```
|
||||
|
||||
The second case example is a bit particular : the main function must always
|
||||
The second case example is a bit particular: the main function must always
|
||||
have this definition:
|
||||
|
||||
```compile_fail
|
||||
|
@ -2206,7 +2207,6 @@ impl Foo {
|
|||
}
|
||||
```
|
||||
"##,
|
||||
*/
|
||||
|
||||
E0220: r##"
|
||||
You used an associated type which isn't defined in the trait.
|
||||
|
@ -2727,14 +2727,9 @@ impl<T, U> CoerceUnsized<MyType<U>> for MyType<T>
|
|||
[`CoerceUnsized`]: https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html
|
||||
"##,
|
||||
|
||||
/*
|
||||
// Associated consts can now be accessed through generic type parameters, and
|
||||
// this error is no longer emitted.
|
||||
//
|
||||
// FIXME: consider whether to leave it in the error index, or remove it entirely
|
||||
// as associated consts is not stabilized yet.
|
||||
|
||||
E0329: r##"
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
An attempt was made to access an associated constant through either a generic
|
||||
type parameter or `Self`. This is not supported yet. An example causing this
|
||||
error is shown below:
|
||||
|
@ -2765,12 +2760,15 @@ trait Foo {
|
|||
|
||||
struct MyStruct;
|
||||
|
||||
impl Foo for MyStruct {
|
||||
const BAR: f64 = 0f64;
|
||||
}
|
||||
|
||||
fn get_bar_good() -> f64 {
|
||||
<MyStruct as Foo>::BAR
|
||||
}
|
||||
```
|
||||
"##,
|
||||
*/
|
||||
|
||||
E0366: r##"
|
||||
An attempt was made to implement `Drop` on a concrete specialization of a
|
||||
|
@ -4973,7 +4971,7 @@ and the pin is required to keep it in the same place in memory.
|
|||
// between structures with the same definition
|
||||
// E0558, // replaced with a generic attribute input check
|
||||
// E0563, // cannot determine a type for this `impl Trait` removed in 6383de15
|
||||
E0564, // only named lifetimes are allowed in `impl Trait`,
|
||||
// E0564, // only named lifetimes are allowed in `impl Trait`,
|
||||
// but `{}` was found in the type `{}`
|
||||
E0587, // type has conflicting packed and align representation hints
|
||||
E0588, // packed type cannot transitively contain a `[repr(align)]` type
|
||||
|
@ -4986,7 +4984,7 @@ and the pin is required to keep it in the same place in memory.
|
|||
E0634, // type has conflicting packed representaton hints
|
||||
E0640, // infer outlives requirements
|
||||
E0641, // cannot cast to/from a pointer with an unknown kind
|
||||
E0645, // trait aliases not finished
|
||||
// E0645, // trait aliases not finished
|
||||
E0719, // duplicate values for associated type binding
|
||||
E0722, // Malformed `#[optimize]` attribute
|
||||
E0724, // `#[ffi_returns_twice]` is only allowed in foreign functions
|
||||
|
|
|
@ -11,6 +11,7 @@ use syntax_pos::MultiSpan;
|
|||
pub enum BufferedEarlyLintId {
|
||||
IllFormedAttributeInput,
|
||||
MetaVariableMisuse,
|
||||
IncompleteInclude,
|
||||
}
|
||||
|
||||
/// Stores buffered lint info which can later be passed to `librustc`.
|
||||
|
|
|
@ -5,6 +5,7 @@ use syntax::print::pprust;
|
|||
use syntax::ptr::P;
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax::tokenstream::TokenStream;
|
||||
use syntax::early_buffered_lints::BufferedEarlyLintId;
|
||||
|
||||
use smallvec::SmallVec;
|
||||
use syntax_pos::{self, Pos, Span};
|
||||
|
@ -83,7 +84,16 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream)
|
|||
}
|
||||
impl<'a> base::MacResult for ExpandResult<'a> {
|
||||
fn make_expr(mut self: Box<ExpandResult<'a>>) -> Option<P<ast::Expr>> {
|
||||
Some(panictry!(self.p.parse_expr()))
|
||||
let r = panictry!(self.p.parse_expr());
|
||||
if self.p.token != token::Eof {
|
||||
self.p.sess.buffer_lint(
|
||||
BufferedEarlyLintId::IncompleteInclude,
|
||||
self.p.token.span,
|
||||
ast::CRATE_NODE_ID,
|
||||
"include macro expected single expression in source",
|
||||
);
|
||||
}
|
||||
Some(r)
|
||||
}
|
||||
|
||||
fn make_items(mut self: Box<ExpandResult<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> {
|
||||
|
|
|
@ -29,7 +29,7 @@ LL | if &true {}
|
|||
| ^^^^^
|
||||
| |
|
||||
| expected bool, found &bool
|
||||
| help: consider dereferencing the borrow: `*&true`
|
||||
| help: consider removing the borrow: `true`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found type `&bool`
|
||||
|
@ -41,7 +41,7 @@ LL | if &mut true {}
|
|||
| ^^^^^^^^^
|
||||
| |
|
||||
| expected bool, found &mut bool
|
||||
| help: consider dereferencing the borrow: `*&mut true`
|
||||
| help: consider removing the borrow: `true`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found type `&mut bool`
|
||||
|
@ -77,7 +77,7 @@ LL | while &true {}
|
|||
| ^^^^^
|
||||
| |
|
||||
| expected bool, found &bool
|
||||
| help: consider dereferencing the borrow: `*&true`
|
||||
| help: consider removing the borrow: `true`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found type `&bool`
|
||||
|
@ -89,7 +89,7 @@ LL | while &mut true {}
|
|||
| ^^^^^^^^^
|
||||
| |
|
||||
| expected bool, found &mut bool
|
||||
| help: consider dereferencing the borrow: `*&mut true`
|
||||
| help: consider removing the borrow: `true`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found type `&mut bool`
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
// ignore-test auxiliary file for include-single-expr.rs
|
||||
|
||||
0
|
||||
|
||||
// trailing comment permitted
|
|
@ -0,0 +1,5 @@
|
|||
// ignore-test auxiliary file for include-single-expr.rs
|
||||
|
||||
0
|
||||
10
|
||||
100
|
|
@ -0,0 +1,6 @@
|
|||
// error-pattern include macro expected single expression
|
||||
|
||||
fn main() {
|
||||
include!("include-single-expr-helper.rs");
|
||||
include!("include-single-expr-helper-1.rs");
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
error: include macro expected single expression in source
|
||||
--> $DIR/include-single-expr-helper.rs:4:1
|
||||
|
|
||||
LL | 10
|
||||
| ^^
|
||||
|
|
||||
= note: `#[deny(incomplete_include)]` on by default
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -2,9 +2,7 @@ error[E0401]: can't use generic parameters from outer function
|
|||
--> $DIR/inner-static-type-parameter.rs:6:19
|
||||
|
|
||||
LL | fn foo<T>() {
|
||||
| --- - type parameter from outer function
|
||||
| |
|
||||
| try adding a local generic parameter in this method instead
|
||||
| - type parameter from outer function
|
||||
LL | static a: Bar<T> = Bar::What;
|
||||
| ^ use of generic parameter from outer function
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
unsafe fn foo<A>() {
|
||||
extern "C" {
|
||||
static baz: *const A;
|
||||
//~^ ERROR can't use generic parameters from outer function
|
||||
}
|
||||
|
||||
let bar: *const u64 = core::mem::transmute(&baz);
|
||||
}
|
||||
|
||||
fn main() { }
|
|
@ -0,0 +1,12 @@
|
|||
error[E0401]: can't use generic parameters from outer function
|
||||
--> $DIR/issue-65025-extern-static-parent-generics.rs:3:28
|
||||
|
|
||||
LL | unsafe fn foo<A>() {
|
||||
| - type parameter from outer function
|
||||
LL | extern "C" {
|
||||
LL | static baz: *const A;
|
||||
| ^ use of generic parameter from outer function
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0401`.
|
|
@ -0,0 +1,29 @@
|
|||
#![feature(const_generics)]
|
||||
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
|
||||
|
||||
fn f<T>() {
|
||||
extern "C" {
|
||||
static a: *const T;
|
||||
//~^ ERROR can't use generic parameters from outer function
|
||||
}
|
||||
}
|
||||
|
||||
fn g<T: Default>() {
|
||||
static a: *const T = Default::default();
|
||||
//~^ ERROR can't use generic parameters from outer function
|
||||
}
|
||||
|
||||
fn h<const N: usize>() {
|
||||
extern "C" {
|
||||
static a: [u8; N];
|
||||
//~^ ERROR can't use generic parameters from outer function
|
||||
}
|
||||
}
|
||||
|
||||
fn i<const N: usize>() {
|
||||
static a: [u8; N] = [0; N];
|
||||
//~^ ERROR can't use generic parameters from outer function
|
||||
//~^^ ERROR can't use generic parameters from outer function
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,53 @@
|
|||
error[E0401]: can't use generic parameters from outer function
|
||||
--> $DIR/issue-65035-static-with-parent-generics.rs:6:26
|
||||
|
|
||||
LL | fn f<T>() {
|
||||
| - type parameter from outer function
|
||||
LL | extern "C" {
|
||||
LL | static a: *const T;
|
||||
| ^ use of generic parameter from outer function
|
||||
|
||||
error[E0401]: can't use generic parameters from outer function
|
||||
--> $DIR/issue-65035-static-with-parent-generics.rs:12:22
|
||||
|
|
||||
LL | fn g<T: Default>() {
|
||||
| - type parameter from outer function
|
||||
LL | static a: *const T = Default::default();
|
||||
| ^ use of generic parameter from outer function
|
||||
|
||||
error[E0401]: can't use generic parameters from outer function
|
||||
--> $DIR/issue-65035-static-with-parent-generics.rs:18:24
|
||||
|
|
||||
LL | fn h<const N: usize>() {
|
||||
| - const parameter from outer function
|
||||
LL | extern "C" {
|
||||
LL | static a: [u8; N];
|
||||
| ^ use of generic parameter from outer function
|
||||
|
||||
error[E0401]: can't use generic parameters from outer function
|
||||
--> $DIR/issue-65035-static-with-parent-generics.rs:24:20
|
||||
|
|
||||
LL | fn i<const N: usize>() {
|
||||
| - const parameter from outer function
|
||||
LL | static a: [u8; N] = [0; N];
|
||||
| ^ use of generic parameter from outer function
|
||||
|
||||
error[E0401]: can't use generic parameters from outer function
|
||||
--> $DIR/issue-65035-static-with-parent-generics.rs:24:29
|
||||
|
|
||||
LL | fn i<const N: usize>() {
|
||||
| - const parameter from outer function
|
||||
LL | static a: [u8; N] = [0; N];
|
||||
| ^ use of generic parameter from outer function
|
||||
|
||||
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
|
||||
--> $DIR/issue-65035-static-with-parent-generics.rs:1:12
|
||||
|
|
||||
LL | #![feature(const_generics)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0401`.
|
|
@ -520,7 +520,7 @@ LL | if &let 0 = 0 {}
|
|||
| ^^^^^^^^^^
|
||||
| |
|
||||
| expected bool, found &bool
|
||||
| help: consider dereferencing the borrow: `*&let 0 = 0`
|
||||
| help: consider removing the borrow: `let 0 = 0`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found type `&bool`
|
||||
|
@ -708,7 +708,7 @@ LL | while &let 0 = 0 {}
|
|||
| ^^^^^^^^^^
|
||||
| |
|
||||
| expected bool, found &bool
|
||||
| help: consider dereferencing the borrow: `*&let 0 = 0`
|
||||
| help: consider removing the borrow: `let 0 = 0`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found type `&bool`
|
||||
|
|
|
@ -2,25 +2,25 @@ error[E0599]: no method named `as_str` found for type `&str` in the current scop
|
|||
--> $DIR/remove-as_str.rs:2:7
|
||||
|
|
||||
LL | s.as_str();
|
||||
| ^^^^^^ try removing `as_str`
|
||||
| -^^^^^^-- help: remove this method call
|
||||
|
||||
error[E0599]: no method named `as_str` found for type `&'a str` in the current scope
|
||||
--> $DIR/remove-as_str.rs:7:7
|
||||
|
|
||||
LL | s.as_str();
|
||||
| ^^^^^^ try removing `as_str`
|
||||
| -^^^^^^-- help: remove this method call
|
||||
|
||||
error[E0599]: no method named `as_str` found for type `&mut str` in the current scope
|
||||
--> $DIR/remove-as_str.rs:12:7
|
||||
|
|
||||
LL | s.as_str();
|
||||
| ^^^^^^ try removing `as_str`
|
||||
| -^^^^^^-- help: remove this method call
|
||||
|
||||
error[E0599]: no method named `as_str` found for type `&&str` in the current scope
|
||||
--> $DIR/remove-as_str.rs:17:7
|
||||
|
|
||||
LL | s.as_str();
|
||||
| ^^^^^^ try removing `as_str`
|
||||
| -^^^^^^-- help: remove this method call
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ fn main() {
|
|||
println!("cargo:rerun-if-changed={}", entry.path().to_str().unwrap());
|
||||
let file = fs::read_to_string(entry.path()).unwrap()
|
||||
.replace("syntax::register_diagnostics!", "register_diagnostics!");
|
||||
let contents = format!("(|| {{\n{}\n}})();", file);
|
||||
let contents = format!("(|| {{\n{}\n}})()", file);
|
||||
|
||||
fs::write(&out_dir.join(&format!("error_{}.rs", idx)), &contents).unwrap();
|
||||
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
//! Checks that all error codes have at least one test to prevent having error
|
||||
//! codes that are silently not thrown by the compiler anymore.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::Path;
|
||||
|
||||
// A few of those error codes can't be tested but all the others can and *should* be tested!
|
||||
const WHITELIST: &[&str] = &[
|
||||
"E0183",
|
||||
"E0227",
|
||||
"E0279",
|
||||
"E0280",
|
||||
"E0311",
|
||||
"E0313",
|
||||
"E0314",
|
||||
"E0315",
|
||||
"E0377",
|
||||
"E0456",
|
||||
"E0461",
|
||||
"E0462",
|
||||
"E0464",
|
||||
"E0465",
|
||||
"E0472",
|
||||
"E0473",
|
||||
"E0474",
|
||||
"E0475",
|
||||
"E0476",
|
||||
"E0479",
|
||||
"E0480",
|
||||
"E0481",
|
||||
"E0482",
|
||||
"E0483",
|
||||
"E0484",
|
||||
"E0485",
|
||||
"E0486",
|
||||
"E0487",
|
||||
"E0488",
|
||||
"E0489",
|
||||
"E0514",
|
||||
"E0519",
|
||||
"E0523",
|
||||
"E0526",
|
||||
"E0554",
|
||||
"E0570",
|
||||
"E0629",
|
||||
"E0630",
|
||||
"E0640",
|
||||
"E0717",
|
||||
"E0727",
|
||||
"E0729",
|
||||
];
|
||||
|
||||
fn extract_error_codes(f: &str, error_codes: &mut HashMap<String, bool>) {
|
||||
let mut reached_no_explanation = false;
|
||||
let mut last_error_code = None;
|
||||
|
||||
for line in f.lines() {
|
||||
let s = line.trim();
|
||||
if s.starts_with('E') && s.ends_with(": r##\"") {
|
||||
if let Some(err_code) = s.splitn(2, ':').next() {
|
||||
let err_code = err_code.to_owned();
|
||||
last_error_code = Some(err_code.clone());
|
||||
if !error_codes.contains_key(&err_code) {
|
||||
error_codes.insert(err_code, false);
|
||||
}
|
||||
}
|
||||
} else if s.starts_with("```") && s.contains("compile_fail") && s.contains('E') {
|
||||
if let Some(err_code) = s.splitn(2, 'E').skip(1).next() {
|
||||
if let Some(err_code) = err_code.splitn(2, ',').next() {
|
||||
let nb = error_codes.entry(format!("E{}", err_code)).or_insert(false);
|
||||
*nb = true;
|
||||
}
|
||||
}
|
||||
} else if s == ";" {
|
||||
reached_no_explanation = true;
|
||||
} else if reached_no_explanation && s.starts_with('E') {
|
||||
if let Some(err_code) = s.splitn(2, ',').next() {
|
||||
let err_code = err_code.to_owned();
|
||||
if !error_codes.contains_key(&err_code) { // this check should *never* fail!
|
||||
error_codes.insert(err_code, false);
|
||||
}
|
||||
}
|
||||
} else if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
|
||||
if let Some(last) = last_error_code {
|
||||
error_codes.get_mut(&last).map(|x| *x = true);
|
||||
}
|
||||
last_error_code = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_error_codes_from_tests(f: &str, error_codes: &mut HashMap<String, bool>) {
|
||||
for line in f.lines() {
|
||||
let s = line.trim();
|
||||
if s.starts_with("error[E") || s.starts_with("warning[E") {
|
||||
if let Some(err_code) = s.splitn(2, ']').next() {
|
||||
if let Some(err_code) = err_code.splitn(2, '[').skip(1).next() {
|
||||
let nb = error_codes.entry(err_code.to_owned()).or_insert(false);
|
||||
*nb = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check(path: &Path, bad: &mut bool) {
|
||||
println!("Checking which error codes lack tests...");
|
||||
let mut error_codes: HashMap<String, bool> = HashMap::new();
|
||||
super::walk(path,
|
||||
&mut |path| super::filter_dirs(path),
|
||||
&mut |entry, contents| {
|
||||
let file_name = entry.file_name();
|
||||
if file_name == "error_codes.rs" {
|
||||
extract_error_codes(contents, &mut error_codes);
|
||||
} else if entry.path().extension() == Some(OsStr::new("stderr")) {
|
||||
extract_error_codes_from_tests(contents, &mut error_codes);
|
||||
}
|
||||
});
|
||||
println!("Found {} error codes", error_codes.len());
|
||||
|
||||
let mut errors = Vec::new();
|
||||
for (err_code, nb) in &error_codes {
|
||||
if !*nb && !WHITELIST.contains(&err_code.as_str()) {
|
||||
errors.push(format!("Error code {} needs to have at least one UI test!", err_code));
|
||||
}
|
||||
}
|
||||
errors.sort();
|
||||
for err in &errors {
|
||||
eprintln!("{}", err);
|
||||
}
|
||||
println!("Found {} error codes with no tests", errors.len());
|
||||
if !errors.is_empty() {
|
||||
*bad = true;
|
||||
}
|
||||
println!("Done!");
|
||||
}
|
|
@ -41,6 +41,7 @@ pub mod extdeps;
|
|||
pub mod ui_tests;
|
||||
pub mod unit_tests;
|
||||
pub mod unstable_book;
|
||||
pub mod error_codes_check;
|
||||
|
||||
fn filter_dirs(path: &Path) -> bool {
|
||||
let skip = [
|
||||
|
|
|
@ -35,6 +35,7 @@ fn main() {
|
|||
deps::check_whitelist(&path, &cargo, &mut bad);
|
||||
extdeps::check(&path, &mut bad);
|
||||
ui_tests::check(&path, &mut bad);
|
||||
error_codes_check::check(&path, &mut bad);
|
||||
|
||||
if bad {
|
||||
eprintln!("some tidy checks failed");
|
||||
|
|
Loading…
Reference in New Issue