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:
bors 2019-10-08 21:32:07 +00:00
commit b5bd31ec6d
49 changed files with 579 additions and 1050 deletions

View File

@ -1,40 +1,3 @@
# The Rust Code of Conduct # The Rust Code of Conduct
A version of this document [can be found online](https://www.rust-lang.org/conduct.html). The Code of Conduct for this repository [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

View File

@ -9,7 +9,6 @@ use std::hash::Hash;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
use std::mem; use std::mem;
use crate::ty::{self, TyCtxt}; use crate::ty::{self, TyCtxt};
use crate::util::common::{ProfileQueriesMsg, profq_msg};
use parking_lot::{Mutex, Condvar}; use parking_lot::{Mutex, Condvar};
use crate::ich::{StableHashingContext, StableHashingContextProvider, Fingerprint}; use crate::ich::{StableHashingContext, StableHashingContextProvider, Fingerprint};
@ -256,10 +255,6 @@ impl DepGraph {
// - we can get an idea of the runtime cost. // - we can get an idea of the runtime cost.
let mut hcx = cx.get_stable_hashing_context(); 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 { let result = if no_tcx {
task(cx, arg) task(cx, arg)
} else { } 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 current_fingerprint = hash_result(&mut hcx, &result);
let dep_node_index = finish_task_and_alloc_depnode( let dep_node_index = finish_task_and_alloc_depnode(

View File

@ -466,7 +466,6 @@ fn main() {
``` ```
"##, "##,
E0139: r##" E0139: r##"
#### Note: this error code is no longer emitted by the compiler. #### 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##" 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 ```compile_fail,E0496
struct Foo<'a> { struct Foo<'a> {
@ -1594,8 +1595,11 @@ fn main() {
"##, "##,
E0497: r##" E0497: r##"
A stability attribute was used outside of the standard library. Erroneous code #### Note: this error code is no longer emitted by the compiler.
example:
A stability attribute was used outside of the standard library.
Erroneous code example:
```compile_fail ```compile_fail
#[stable] // error: stability attributes may not be used outside of the #[stable] // error: stability attributes may not be used outside of the
@ -2125,7 +2129,7 @@ rejected in your own crates.
// E0272, // on_unimplemented #0 // E0272, // on_unimplemented #0
// E0273, // on_unimplemented #1 // E0273, // on_unimplemented #1
// E0274, // on_unimplemented #2 // E0274, // on_unimplemented #2
E0278, // requirement is not satisfied // E0278, // requirement is not satisfied
E0279, // requirement is not satisfied E0279, // requirement is not satisfied
E0280, // requirement is not satisfied E0280, // requirement is not satisfied
// E0285, // overflow evaluation builtin bounds // 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 E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax
E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders
E0697, // closures cannot be static 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 E0708, // `async` non-`move` closures with parameters are not currently
// supported // 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 E0710, // an unknown tool name found in scoped lint
E0711, // a feature has been declared with conflicting stability attributes E0711, // a feature has been declared with conflicting stability attributes
// E0702, // replaced with a generic attribute input check // E0702, // replaced with a generic attribute input check

View File

@ -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 { impl fmt::Debug for Expr {

View File

@ -368,6 +368,12 @@ pub mod parser {
Allow, Allow,
"possible meta-variable misuse at macro definition" "possible meta-variable misuse at macro definition"
} }
declare_lint! {
pub INCOMPLETE_INCLUDE,
Deny,
"trailing content in included file"
}
} }
declare_lint! { declare_lint! {

View File

@ -28,6 +28,7 @@ use crate::hir::intravisit;
use crate::hir; use crate::hir;
use crate::lint::builtin::BuiltinLintDiagnostics; use crate::lint::builtin::BuiltinLintDiagnostics;
use crate::lint::builtin::parser::{ILL_FORMED_ATTRIBUTE_INPUT, META_VARIABLE_MISUSE}; 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::session::{Session, DiagnosticMessageId};
use crate::ty::TyCtxt; use crate::ty::TyCtxt;
use crate::ty::query::Providers; use crate::ty::query::Providers;
@ -83,6 +84,7 @@ impl Lint {
match lint_id { match lint_id {
BufferedEarlyLintId::IllFormedAttributeInput => ILL_FORMED_ATTRIBUTE_INPUT, BufferedEarlyLintId::IllFormedAttributeInput => ILL_FORMED_ATTRIBUTE_INPUT,
BufferedEarlyLintId::MetaVariableMisuse => META_VARIABLE_MISUSE, BufferedEarlyLintId::MetaVariableMisuse => META_VARIABLE_MISUSE,
BufferedEarlyLintId::IncompleteInclude => INCOMPLETE_INCLUDE,
} }
} }

View File

@ -1316,10 +1316,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"), "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
query_dep_graph: bool = (false, parse_bool, [UNTRACKED], query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
"enable queries of the dependency graph for regression testing"), "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], no_analysis: bool = (false, parse_bool, [UNTRACKED],
"parse and expand the source, but run no analysis"), "parse and expand the source, but run no analysis"),
extra_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED], extra_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED],

View File

@ -11,7 +11,6 @@ use crate::session::config::{OutputType, PrintRequest, SwitchWithOptPath};
use crate::session::search_paths::{PathKind, SearchPath}; use crate::session::search_paths::{PathKind, SearchPath};
use crate::util::nodemap::{FxHashMap, FxHashSet}; use crate::util::nodemap::{FxHashMap, FxHashSet};
use crate::util::common::{duration_to_secs_str, ErrorReported}; use crate::util::common::{duration_to_secs_str, ErrorReported};
use crate::util::common::ProfileQueriesMsg;
use rustc_data_structures::base_n; use rustc_data_structures::base_n;
use rustc_data_structures::sync::{ use rustc_data_structures::sync::{
@ -46,7 +45,7 @@ use std::fmt;
use std::io::Write; use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
use std::time::Duration; use std::time::Duration;
use std::sync::{Arc, mpsc}; use std::sync::Arc;
mod code_stats; mod code_stats;
pub mod config; pub mod config;
@ -125,9 +124,6 @@ pub struct Session {
/// `-Zquery-dep-graph` is specified. /// `-Zquery-dep-graph` is specified.
pub cgu_reuse_tracker: CguReuseTracker, 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`. /// Used by `-Z self-profile`.
pub prof: SelfProfilerRef, pub prof: SelfProfilerRef,
@ -509,13 +505,6 @@ impl Session {
pub fn time_extended(&self) -> bool { pub fn time_extended(&self) -> bool {
self.opts.debugging_opts.time_passes 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 { pub fn instrument_mcount(&self) -> bool {
self.opts.debugging_opts.instrument_mcount self.opts.debugging_opts.instrument_mcount
} }
@ -1234,7 +1223,6 @@ fn build_session_(
incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)), incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)),
cgu_reuse_tracker, cgu_reuse_tracker,
prof: SelfProfilerRef::new(self_profiler), prof: SelfProfilerRef::new(self_profiler),
profile_channel: Lock::new(None),
perf_stats: PerfStats { perf_stats: PerfStats {
symbol_hash_time: Lock::new(Duration::from_secs(0)), symbol_hash_time: Lock::new(Duration::from_secs(0)),
decode_def_path_tables_time: Lock::new(Duration::from_secs(0)), decode_def_path_tables_time: Lock::new(Duration::from_secs(0)),

View File

@ -1075,7 +1075,7 @@ where
let desc = &format!("encode_query_results for {}", let desc = &format!("encode_query_results for {}",
::std::any::type_name::<Q>()); ::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(); let shards = Q::query_cache(tcx).lock_shards();
assert!(shards.iter().all(|shard| shard.active.is_empty())); assert!(shards.iter().all(|shard| shard.active.is_empty()));
for (key, entry) in shards.iter().flat_map(|shard| shard.results.iter()) { for (key, entry) in shards.iter().flat_map(|shard| shard.results.iter()) {

View File

@ -9,8 +9,6 @@ use crate::ty::query::Query;
use crate::ty::query::config::{QueryConfig, QueryDescription}; use crate::ty::query::config::{QueryConfig, QueryDescription};
use crate::ty::query::job::{QueryJob, QueryResult, QueryInfo}; use crate::ty::query::job::{QueryJob, QueryResult, QueryInfo};
use crate::util::common::{profq_msg, ProfileQueriesMsg, QueryMsg};
use errors::DiagnosticBuilder; use errors::DiagnosticBuilder;
use errors::Level; use errors::Level;
use errors::Diagnostic; 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. /// A type representing the responsibility to execute the job in the `job` field.
/// This will poison the relevant query if dropped. /// This will poison the relevant query if dropped.
pub(super) struct JobOwner<'a, 'tcx, Q: QueryDescription<'tcx>> { pub(super) struct JobOwner<'a, 'tcx, Q: QueryDescription<'tcx>> {
@ -111,7 +82,6 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
loop { loop {
let mut lock = cache.get_shard_by_value(key).lock(); let mut lock = cache.get_shard_by_value(key).lock();
if let Some(value) = lock.results.get(key) { if let Some(value) = lock.results.get(key) {
profq_msg!(tcx, ProfileQueriesMsg::CacheHit);
tcx.prof.query_cache_hit(Q::NAME); tcx.prof.query_cache_hit(Q::NAME);
let result = (value.value.clone(), value.index); let result = (value.value.clone(), value.index);
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -358,13 +328,6 @@ impl<'tcx> TyCtxt<'tcx> {
key, key,
span); 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) { let job = match JobOwner::try_get(self, span, &key) {
TryGetJob::NotYetStarted(job) => job, TryGetJob::NotYetStarted(job) => job,
TryGetJob::Cycle(result) => return result, TryGetJob::Cycle(result) => return result,
@ -383,7 +346,6 @@ impl<'tcx> TyCtxt<'tcx> {
if Q::ANON { if Q::ANON {
profq_msg!(self, ProfileQueriesMsg::ProviderBegin);
let prof_timer = self.prof.query_provider(Q::NAME); let prof_timer = self.prof.query_provider(Q::NAME);
let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
@ -395,7 +357,6 @@ impl<'tcx> TyCtxt<'tcx> {
}); });
drop(prof_timer); drop(prof_timer);
profq_msg!(self, ProfileQueriesMsg::ProviderEnd);
self.dep_graph.read_index(dep_node_index); self.dep_graph.read_index(dep_node_index);
@ -468,7 +429,6 @@ impl<'tcx> TyCtxt<'tcx> {
}; };
let result = if let Some(result) = result { let result = if let Some(result) = result {
profq_msg!(self, ProfileQueriesMsg::CacheHit);
result result
} else { } else {
// We could not load a result from the on-disk cache, so // We could not load a result from the on-disk cache, so
@ -542,7 +502,6 @@ impl<'tcx> TyCtxt<'tcx> {
- dep-node: {:?}", - dep-node: {:?}",
key, dep_node); key, dep_node);
profq_msg!(self, ProfileQueriesMsg::ProviderBegin);
let prof_timer = self.prof.query_provider(Q::NAME); let prof_timer = self.prof.query_provider(Q::NAME);
let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
@ -564,7 +523,6 @@ impl<'tcx> TyCtxt<'tcx> {
}); });
drop(prof_timer); drop(prof_timer);
profq_msg!(self, ProfileQueriesMsg::ProviderEnd);
if unlikely!(!diagnostics.is_empty()) { if unlikely!(!diagnostics.is_empty()) {
if dep_node.kind != crate::dep_graph::DepKind::Null { 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); let _ = self.get_query::<Q>(DUMMY_SP, key);
} else { } else {
profq_msg!(self, ProfileQueriesMsg::CacheHit);
self.prof.query_cache_hit(Q::NAME); self.prof.query_cache_hit(Q::NAME);
} }
} }
#[allow(dead_code)] #[allow(dead_code)]
fn force_query<Q: QueryDescription<'tcx>>(self, key: Q::Key, span: Span, dep_node: DepNode) { 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. // We may be concurrently trying both execute and force a query.
// Ensure that only one of them runs the query. // Ensure that only one of them runs the query.
let job = match JobOwner::try_get(self, span, &key) { let job = match JobOwner::try_get(self, span, &key) {

View File

@ -6,11 +6,8 @@ use std::cell::Cell;
use std::fmt::Debug; use std::fmt::Debug;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use std::sync::mpsc::{Sender};
use syntax_pos::{SpanData};
use syntax::symbol::{Symbol, sym}; use syntax::symbol::{Symbol, sym};
use rustc_macros::HashStable; use rustc_macros::HashStable;
use crate::dep_graph::{DepNode};
use crate::session::Session; use crate::session::Session;
#[cfg(test)] #[cfg(test)]
@ -26,17 +23,6 @@ pub struct ErrorReported;
thread_local!(static TIME_DEPTH: Cell<usize> = Cell::new(0)); 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)] #[allow(nonstandard_style)]
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct QueryMsg { pub struct QueryMsg {
@ -44,53 +30,6 @@ pub struct QueryMsg {
pub msg: Option<String>, 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 /// Read the current depth of `time()` calls. This is used to
/// encourage indentation across threads. /// encourage indentation across threads.
pub fn time_depth() -> usize { 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 pub fn time<T, F>(sess: &Session, what: &str, f: F) -> T where
F: FnOnce() -> T, 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, F: FnOnce() -> T,
{ {
if !do_it { return f(); } 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 r
}); });
if let Some(sess) = sess {
if cfg!(debug_assertions) {
profq_msg(sess, ProfileQueriesMsg::TimeBegin(what.to_string()))
}
}
let start = Instant::now(); let start = Instant::now();
let rv = f(); let rv = f();
let dur = start.elapsed(); 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); print_time_passes_entry(true, what, dur);

View File

@ -116,7 +116,7 @@ fn prepare_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
info!("adding bytecode {}", name); info!("adding bytecode {}", name);
let bc_encoded = data.data(); 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) { match DecodedBytecode::new(bc_encoded) {
Ok(b) => Ok((b.bytecode(), b.identifier().to_string())), Ok(b) => Ok((b.bytecode(), b.identifier().to_string())),
Err(e) => Err(diag_handler.fatal(&e)), Err(e) => Err(diag_handler.fatal(&e)),
@ -295,7 +295,7 @@ fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
for (bc_decoded, name) in serialized_modules { for (bc_decoded, name) in serialized_modules {
let _timer = cgcx.prof.generic_activity("LLVM_fat_lto_link_module"); let _timer = cgcx.prof.generic_activity("LLVM_fat_lto_link_module");
info!("linking {:?}", name); 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(); let data = bc_decoded.data();
linker.add(&data).map_err(|()| { linker.add(&data).map_err(|()| {
let msg = format!("failed to load bc of {:?}", name); 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()); 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::LLVMRunPassManager(pm, module.module_llvm.llmod()));
llvm::LLVMDisposePassManager(pm); llvm::LLVMDisposePassManager(pm);

View File

@ -427,7 +427,6 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext<LlvmCodegenBackend>,
{ {
let _timer = cgcx.prof.generic_activity("LLVM_module_optimize_function_passes"); let _timer = cgcx.prof.generic_activity("LLVM_module_optimize_function_passes");
time_ext(config.time_passes, time_ext(config.time_passes,
None,
&format!("llvm function passes [{}]", module_name.unwrap()), &format!("llvm function passes [{}]", module_name.unwrap()),
|| { || {
llvm::LLVMRustRunFunctionPassManager(fpm, llmod) 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"); let _timer = cgcx.prof.generic_activity("LLVM_module_optimize_module_passes");
time_ext(config.time_passes, time_ext(config.time_passes,
None,
&format!("llvm module passes [{}]", module_name.unwrap()), &format!("llvm module passes [{}]", module_name.unwrap()),
|| { || {
llvm::LLVMRunPassManager(mpm, llmod) llvm::LLVMRunPassManager(mpm, llmod)
@ -538,7 +536,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<LlvmCodegenBackend>,
embed_bitcode(cgcx, llcx, llmod, None); 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> { || -> Result<(), FatalError> {
if config.emit_ir { if config.emit_ir {
let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_ir"); let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_ir");

View File

@ -1535,7 +1535,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
let name = cratepath.file_name().unwrap().to_str().unwrap(); let name = cratepath.file_name().unwrap().to_str().unwrap();
let name = &name[3..name.len() - 5]; // chop off lib/.rlib 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)); let mut archive = <B as ArchiveBuilder>::new(sess, &dst, Some(cratepath));
archive.update_symbols(); archive.update_symbols();

View File

@ -160,7 +160,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
} }
MaybeAsync::Async(std::thread::spawn(move || { 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) { match load_data(report_incremental_info, &path) {
LoadResult::DataOutOfDate => LoadResult::DataOutOfDate, LoadResult::DataOutOfDate => LoadResult::DataOutOfDate,
LoadResult::Error { message } => LoadResult::Error { message }, LoadResult::Error { message } => LoadResult::Error { message },

View File

@ -1,6 +1,5 @@
use crate::queries::Queries; use crate::queries::Queries;
use crate::util; use crate::util;
use crate::profile;
pub use crate::passes::BoxedResolver; pub use crate::passes::BoxedResolver;
use rustc::lint; use rustc::lint;
@ -115,17 +114,7 @@ where
compiler.sess.diagnostic().print_error_count(&util::diagnostics_registry()); compiler.sess.diagnostic().print_error_count(&util::diagnostics_registry());
}); });
if compiler.sess.profile_queries() { f(&compiler)
profile::begin(&compiler.sess);
}
let r = f(&compiler);
if compiler.sess.profile_queries() {
profile::dump(&compiler.sess, "profile_queries".to_string())
}
r
} }
pub fn run_compiler<F, R>(mut config: Config, f: F) -> R pub fn run_compiler<F, R>(mut config: Config, f: F) -> R

View File

@ -16,6 +16,5 @@ mod passes;
mod queries; mod queries;
pub mod util; pub mod util;
mod proc_macro_decls; mod proc_macro_decls;
mod profile;
pub use interface::{run_compiler, Config}; pub use interface::{run_compiler, Config};

View File

@ -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!()
},
}
}
}
}
}

View File

@ -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();
}

View File

@ -1,4 +1,4 @@
syntax::register_diagnostics! { syntax::register_diagnostics! {
; ;
E0721, // `await` keyword // E0721, // `await` keyword
} }

View File

@ -953,7 +953,7 @@ https://doc.rust-lang.org/std/cell/
"##, "##,
E0388: r##" E0388: r##"
E0388 was removed and is no longer issued. #### Note: this error code is no longer emitted by the compiler.
"##, "##,
E0389: r##" E0389: r##"

View File

@ -1,12 +1,15 @@
syntax::register_diagnostics! { syntax::register_diagnostics! {
/*
E0014: r##" 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 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 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 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! 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 const FOO2: i32 = { 0 }; // but brackets are useless here
``` ```
"##, "##,
*/
E0130: r##" E0130: r##"
You declared a pattern as an argument in a foreign function declaration. You declared a pattern as an argument in a foreign function declaration.
Erroneous code example: Erroneous code example:
```compile_fail ```compile_fail
@ -57,6 +60,20 @@ extern {
E0136: r##" E0136: r##"
A binary can only have one entry point, and by default that entry point is the 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. function `main()`. If there are multiple such functions, please rename one.
Erroneous code example:
```compile_fail,E0136
fn main() {
// ...
}
// ...
fn main() { // error!
// ...
}
```
"##, "##,
E0137: r##" E0137: r##"

View File

@ -1,8 +1,9 @@
syntax::register_diagnostics! { syntax::register_diagnostics! {
E0445: r##" E0445: r##"
A private trait was used on a public type parameter bound. Erroneous code A private trait was used on a public type parameter bound.
examples:
Erroneous code examples:
```compile_fail,E0445 ```compile_fail,E0445
#![deny(private_in_public)] #![deny(private_in_public)]
@ -32,7 +33,9 @@ pub fn foo<T: Foo> (t: T) {} // ok!
"##, "##,
E0446: r##" 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 ```compile_fail,E0446
#![deny(private_in_public)] #![deny(private_in_public)]
@ -65,7 +68,9 @@ mod Foo {
E0447: r##" E0447: r##"
#### Note: this error code is no longer emitted by the compiler. #### 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() { fn foo() {
@ -79,7 +84,11 @@ is invalid.
"##, "##,
E0448: r##" 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 ```compile_fail
pub enum Foo { pub enum Foo {
@ -106,7 +115,9 @@ pub enum Foo {
"##, "##,
E0451: r##" 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 ```compile_fail,E0451
mod Bar { mod Bar {

View File

@ -20,7 +20,7 @@ use syntax_pos::{BytePos, Span, MultiSpan};
use crate::resolve_imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver}; use crate::resolve_imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver};
use crate::{path_names_to_string, KNOWN_TOOLS}; 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}; use crate::{PathResult, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Segment};
type Res = def::Res<ast::NodeId>; type Res = def::Res<ast::NodeId>;
@ -102,7 +102,7 @@ impl<'a> Resolver<'a> {
&self, span: Span, resolution_error: ResolutionError<'_> &self, span: Span, resolution_error: ResolutionError<'_>
) -> DiagnosticBuilder<'_> { ) -> DiagnosticBuilder<'_> {
match resolution_error { match resolution_error {
ResolutionError::GenericParamsFromOuterFunction(outer_res) => { ResolutionError::GenericParamsFromOuterFunction(outer_res, has_generic_params) => {
let mut err = struct_span_err!(self.session, let mut err = struct_span_err!(self.session,
span, span,
E0401, E0401,
@ -148,22 +148,24 @@ impl<'a> Resolver<'a> {
} }
} }
// Try to retrieve the span of the function signature and generate a new message if has_generic_params == HasGenericParams::Yes {
// with a local type or const parameter. // Try to retrieve the span of the function signature and generate a new
let sugg_msg = &format!("try using a local generic parameter instead"); // message with a local type or const parameter.
if let Some((sugg_span, new_snippet)) = cm.generate_local_type_param_snippet(span) { let sugg_msg = &format!("try using a local generic parameter instead");
// Suggest the modification to the user if let Some((sugg_span, snippet)) = cm.generate_local_type_param_snippet(span) {
err.span_suggestion( // Suggest the modification to the user
sugg_span, err.span_suggestion(
sugg_msg, sugg_span,
new_snippet, sugg_msg,
Applicability::MachineApplicable, snippet,
); Applicability::MachineApplicable,
} else if let Some(sp) = cm.generate_fn_name_span(span) { );
err.span_label(sp, } else if let Some(sp) = cm.generate_fn_name_span(span) {
format!("try adding a local generic parameter in this method instead")); err.span_label(sp,
} else { format!("try adding a local generic parameter in this method instead"));
err.help(&format!("try using a local generic parameter instead")); } else {
err.help(&format!("try using a local generic parameter instead"));
}
} }
err err

View File

@ -5,7 +5,6 @@
//! If you wonder why there's no `early.rs`, that's because it's split into three files - //! 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`. //! `build_reduced_graph.rs`, `macros.rs` and `resolve_imports.rs`.
use GenericParameters::*;
use RibKind::*; use RibKind::*;
use crate::{path_names_to_string, BindingError, CrateLint, LexicalScopeBinding}; use crate::{path_names_to_string, BindingError, CrateLint, LexicalScopeBinding};
@ -46,16 +45,6 @@ struct BindingInfo {
binding_mode: BindingMode, 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)] #[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum PatternSource { enum PatternSource {
Match, Match,
@ -85,6 +74,10 @@ enum PatBoundCtx {
Or, 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, /// The rib kind restricts certain accesses,
/// e.g. to a `Res::Local` of an outer item. /// e.g. to a `Res::Local` of an outer item.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
@ -103,7 +96,7 @@ crate enum RibKind<'a> {
FnItemRibKind, FnItemRibKind,
/// We passed through an item scope. Disallow upvars. /// We passed through an item scope. Disallow upvars.
ItemRibKind, ItemRibKind(HasGenericParams),
/// We're in a constant item. Can't refer to dynamic stuff. /// We're in a constant item. Can't refer to dynamic stuff.
ConstantItemRibKind, ConstantItemRibKind,
@ -134,7 +127,7 @@ impl RibKind<'_> {
| ModuleRibKind(_) | ModuleRibKind(_)
| MacroDefinition(_) => false, | MacroDefinition(_) => false,
AssocItemRibKind AssocItemRibKind
| ItemRibKind | ItemRibKind(_)
| ForwardTyParamBanRibKind | ForwardTyParamBanRibKind
| TyParamAsConstParamTy => true, | TyParamAsConstParamTy => true,
} }
@ -406,17 +399,21 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
visit::walk_poly_trait_ref(self, tref, m); visit::walk_poly_trait_ref(self, tref, m);
} }
fn visit_foreign_item(&mut self, foreign_item: &'tcx ForeignItem) { 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) => { 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::Static(..) => {
ForeignItemKind::Ty => NoGenericParams, self.with_item_rib(HasGenericParams::No, |this| {
ForeignItemKind::Macro(..) => NoGenericParams, visit::walk_foreign_item(this, foreign_item);
}; });
self.with_generic_param_rib(generic_params, |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) { fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, declaration: &'tcx FnDecl, _: Span, _: NodeId) {
debug!("(resolving function) entering function"); debug!("(resolving function) entering function");
@ -660,7 +657,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
fn resolve_adt(&mut self, item: &Item, generics: &Generics) { fn resolve_adt(&mut self, item: &Item, generics: &Generics) {
debug!("resolve_adt"); debug!("resolve_adt");
self.with_current_self_item(item, |this| { 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); let item_def_id = this.r.definitions.local_def_id(item.id);
this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| { this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| {
visit::walk_item(this, item); visit::walk_item(this, item);
@ -719,10 +716,8 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
ItemKind::TyAlias(_, ref generics) | ItemKind::TyAlias(_, ref generics) |
ItemKind::OpaqueTy(_, ref generics) | ItemKind::OpaqueTy(_, ref generics) |
ItemKind::Fn(_, _, ref generics, _) => { ItemKind::Fn(_, _, ref generics, _) => {
self.with_generic_param_rib( self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes),
HasGenericParams(generics, ItemRibKind), |this| visit::walk_item(this, item));
|this| visit::walk_item(this, item)
);
} }
ItemKind::Enum(_, ref generics) | ItemKind::Enum(_, ref generics) |
@ -740,7 +735,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
ItemKind::Trait(.., ref generics, ref bounds, ref trait_items) => { ItemKind::Trait(.., ref generics, ref bounds, ref trait_items) => {
// Create a new rib for the trait-wide type parameters. // 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); 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.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
this.visit_generics(generics); this.visit_generics(generics);
@ -748,35 +743,32 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
for trait_item in trait_items { for trait_item in trait_items {
this.with_trait_items(trait_items, |this| { this.with_trait_items(trait_items, |this| {
let generic_params = HasGenericParams( this.with_generic_param_rib(&trait_item.generics, AssocItemRibKind,
&trait_item.generics, |this| {
AssocItemRibKind, match trait_item.kind {
); TraitItemKind::Const(ref ty, ref default) => {
this.with_generic_param_rib(generic_params, |this| { this.visit_ty(ty);
match trait_item.kind {
TraitItemKind::Const(ref ty, ref default) => {
this.visit_ty(ty);
// Only impose the restrictions of // Only impose the restrictions of
// ConstRibKind for an actual constant // ConstRibKind for an actual constant
// expression in a provided default. // expression in a provided default.
if let Some(ref expr) = *default{ if let Some(ref expr) = *default{
this.with_constant_rib(|this| { this.with_constant_rib(|this| {
this.visit_expr(expr); this.visit_expr(expr);
}); });
}
} }
} TraitItemKind::Method(_, _) => {
TraitItemKind::Method(_, _) => { visit::walk_trait_item(this, trait_item)
visit::walk_trait_item(this, trait_item) }
} TraitItemKind::Type(..) => {
TraitItemKind::Type(..) => { visit::walk_trait_item(this, trait_item)
visit::walk_trait_item(this, trait_item) }
} TraitItemKind::Macro(_) => {
TraitItemKind::Macro(_) => { panic!("unexpanded macro in resolve!")
panic!("unexpanded macro in resolve!") }
} };
}; });
});
}); });
} }
}); });
@ -785,7 +777,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
ItemKind::TraitAlias(ref generics, ref bounds) => { ItemKind::TraitAlias(ref generics, ref bounds) => {
// Create a new rib for the trait-wide type parameters. // 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); 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.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
this.visit_generics(generics); this.visit_generics(generics);
@ -803,7 +795,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
ItemKind::Static(ref ty, _, ref expr) | ItemKind::Static(ref ty, _, ref expr) |
ItemKind::Const(ref ty, ref expr) => { ItemKind::Const(ref ty, ref expr) => {
debug!("resolve_item ItemKind::Const"); debug!("resolve_item ItemKind::Const");
self.with_item_rib(|this| { self.with_item_rib(HasGenericParams::No, |this| {
this.visit_ty(ty); this.visit_ty(ty);
this.with_constant_rib(|this| { this.with_constant_rib(|this| {
this.visit_expr(expr); 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) where F: FnOnce(&mut Self)
{ {
debug!("with_generic_param_rib"); debug!("with_generic_param_rib");
match generic_params { let mut function_type_rib = Rib::new(kind);
HasGenericParams(generics, rib_kind) => { let mut function_value_rib = Rib::new(kind);
let mut function_type_rib = Rib::new(rib_kind); let mut seen_bindings = FxHashMap::default();
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);
if seen_bindings.contains_key(&ident) { // We also can't shadow bindings from the parent item
let span = seen_bindings.get(&ident).unwrap(); if let AssocItemRibKind = kind {
let err = ResolutionError::NameAlreadyUsedInParameterList( let mut add_bindings_for_ns = |ns| {
ident.name, let parent_rib = self.ribs[ns].iter()
*span, .rfind(|r| if let ItemRibKind(_) = r.kind { true } else { false })
); .expect("associated item outside of an item");
self.r.report_error(param.ident.span, err); seen_bindings.extend(
} parent_rib.bindings.iter().map(|(ident, _)| (*ident, ident.span)),
seen_bindings.entry(ident).or_insert(param.ident.span); );
};
add_bindings_for_ns(ValueNS);
add_bindings_for_ns(TypeNS);
}
// Plain insert (no renaming). for param in &generics.params {
let res = Res::Def( if let GenericParamKind::Lifetime { .. } = param.kind {
DefKind::TyParam, continue;
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);
} }
NoGenericParams => { let def_kind = match param.kind {
// Nothing to do. 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); f(self);
if let HasGenericParams(..) = generic_params { self.ribs[TypeNS].pop();
self.ribs[TypeNS].pop(); self.ribs[ValueNS].pop();
self.ribs[ValueNS].pop();
}
} }
fn with_label_rib(&mut self, kind: RibKind<'a>, f: impl FnOnce(&mut Self)) { 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(); self.label_ribs.pop();
} }
fn with_item_rib(&mut self, f: impl FnOnce(&mut Self)) { fn with_item_rib(&mut self, has_generic_params: HasGenericParams, f: impl FnOnce(&mut Self)) {
self.with_rib(ValueNS, ItemRibKind, |this| this.with_rib(TypeNS, ItemRibKind, f)) 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)) { fn with_constant_rib(&mut self, f: impl FnOnce(&mut Self)) {
@ -1023,7 +1000,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
impl_items: &[ImplItem]) { impl_items: &[ImplItem]) {
debug!("resolve_implementation"); debug!("resolve_implementation");
// If applicable, create a rib for the type parameters. // 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. // Dummy self type for better errors if `Self` is used in the trait path.
this.with_self_rib(Res::SelfTy(None, None), |this| { this.with_self_rib(Res::SelfTy(None, None), |this| {
// Resolve the trait reference, if necessary. // Resolve the trait reference, if necessary.
@ -1044,9 +1021,9 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)"); debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
for impl_item in impl_items { for impl_item in impl_items {
// We also need a new scope for the impl item type parameters. // We also need a new scope for the impl item type parameters.
let generic_params = HasGenericParams(&impl_item.generics, this.with_generic_param_rib(&impl_item.generics,
AssocItemRibKind); AssocItemRibKind,
this.with_generic_param_rib(generic_params, |this| { |this| {
use crate::ResolutionError::*; use crate::ResolutionError::*;
match impl_item.kind { match impl_item.kind {
ImplItemKind::Const(..) => { ImplItemKind::Const(..) => {

View File

@ -61,7 +61,7 @@ use rustc_data_structures::fx::FxIndexMap;
use diagnostics::{Suggestion, ImportSuggestion}; use diagnostics::{Suggestion, ImportSuggestion};
use diagnostics::{find_span_of_binding_until_next_binding, extend_span_to_previous_binding}; 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 resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver};
use macros::{LegacyBinding, LegacyScope}; use macros::{LegacyBinding, LegacyScope};
@ -178,7 +178,7 @@ impl Ord for BindingError {
enum ResolutionError<'a> { enum ResolutionError<'a> {
/// Error E0401: can't use type or const parameters from outer function. /// 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 /// Error E0403: the name is already used for a type or const parameter in this generic
/// parameter list. /// parameter list.
NameAlreadyUsedInParameterList(Name, Span), NameAlreadyUsedInParameterList(Name, Span),
@ -2156,7 +2156,7 @@ impl<'a> Resolver<'a> {
ForwardTyParamBanRibKind | TyParamAsConstParamTy => { ForwardTyParamBanRibKind | TyParamAsConstParamTy => {
// Nothing to do. Continue. // Nothing to do. Continue.
} }
ItemRibKind | FnItemRibKind | AssocItemRibKind => { ItemRibKind(_) | FnItemRibKind | AssocItemRibKind => {
// This was an attempt to access an upvar inside a // This was an attempt to access an upvar inside a
// named function item. This is not allowed, so we // named function item. This is not allowed, so we
// report an error. // report an error.
@ -2184,22 +2184,23 @@ impl<'a> Resolver<'a> {
} }
Res::Def(DefKind::TyParam, _) | Res::SelfTy(..) => { Res::Def(DefKind::TyParam, _) | Res::SelfTy(..) => {
for rib in ribs { for rib in ribs {
match rib.kind { let has_generic_params = match rib.kind {
NormalRibKind | AssocItemRibKind | NormalRibKind | AssocItemRibKind |
ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind | ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind |
ConstantItemRibKind | TyParamAsConstParamTy => { ConstantItemRibKind | TyParamAsConstParamTy => {
// Nothing to do. Continue. // Nothing to do. Continue.
continue;
} }
ItemRibKind | FnItemRibKind => { // This was an attempt to use a type parameter outside its scope.
// This was an attempt to use a type parameter outside its scope. ItemRibKind(has_generic_params) => has_generic_params,
if record_used { FnItemRibKind => HasGenericParams::Yes,
self.report_error( };
span, ResolutionError::GenericParamsFromOuterFunction(res)
); if record_used {
} self.report_error(span, ResolutionError::GenericParamsFromOuterFunction(
return Res::Err; res, has_generic_params));
}
} }
return Res::Err;
} }
} }
Res::Def(DefKind::ConstParam, _) => { Res::Def(DefKind::ConstParam, _) => {
@ -2211,15 +2212,18 @@ impl<'a> Resolver<'a> {
ribs.next(); ribs.next();
} }
for rib in ribs { for rib in ribs {
if let ItemRibKind | FnItemRibKind = rib.kind { let has_generic_params = match rib.kind {
// This was an attempt to use a const parameter outside its scope. ItemRibKind(has_generic_params) => has_generic_params,
if record_used { FnItemRibKind => HasGenericParams::Yes,
self.report_error( _ => continue,
span, ResolutionError::GenericParamsFromOuterFunction(res) };
);
} // This was an attempt to use a const parameter outside its scope.
return Res::Err; if record_used {
self.report_error(span, ResolutionError::GenericParamsFromOuterFunction(
res, has_generic_params));
} }
return Res::Err;
} }
} }
_ => {} _ => {}

View File

@ -115,6 +115,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Err(e) => e Err(e) => e
}; };
let expr = expr.peel_drop_temps();
let cause = self.misc(expr.span); let cause = self.misc(expr.span);
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty); let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e); 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; 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) { match (&expr.kind, &expected.kind, &checked_ty.kind) {
(_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (&exp.kind, &check.kind) { (_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (&exp.kind, &check.kind) {
(&ty::Str, &ty::Array(arr, _)) | (&ty::Str, &ty::Array(arr, _)) |

View File

@ -87,12 +87,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) { 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); 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); extend_err(&mut err);
// Error possibly reported in `check_assign` so avoid emitting error again. // Error possibly reported in `check_assign` so avoid emitting error again.
err.emit_unless(self.is_assign_to_bool(expr, expected_ty)); err.emit_unless(self.is_assign_to_bool(expr, expected_ty));

View File

@ -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() { 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 if let SelfSource::MethodCall(expr) = source {
// of just "as_str". let call_expr = self.tcx.hir().expect_expr(
err.span_label( self.tcx.hir().get_parent_node(expr.hir_id),
span, );
"try removing `as_str`" 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 { } else if let Some(lev_candidate) = lev_candidate {
let def_kind = lev_candidate.def_kind(); let def_kind = lev_candidate.def_kind();
err.span_suggestion( err.span_suggestion(

View File

@ -4216,20 +4216,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn suggest_mismatched_types_on_tail( pub fn suggest_mismatched_types_on_tail(
&self, &self,
err: &mut DiagnosticBuilder<'tcx>, err: &mut DiagnosticBuilder<'tcx>,
expression: &'tcx hir::Expr, expr: &'tcx hir::Expr,
expected: Ty<'tcx>, expected: Ty<'tcx>,
found: Ty<'tcx>, found: Ty<'tcx>,
cause_span: Span, cause_span: Span,
blk_id: hir::HirId, blk_id: hir::HirId,
) -> bool { ) -> 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; let mut pointing_at_return_type = false;
if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) { if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
pointing_at_return_type = self.suggest_missing_return_type( pointing_at_return_type = self.suggest_missing_return_type(
err, &fn_decl, expected, found, can_suggest); err, &fn_decl, expected, found, can_suggest);
} }
self.suggest_ref_or_into(err, expression, expected, found); self.suggest_ref_or_into(err, expr, expected, found);
self.suggest_boxing_when_appropriate(err, expression, expected, found); self.suggest_boxing_when_appropriate(err, expr, expected, found);
pointing_at_return_type pointing_at_return_type
} }

View File

@ -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`). differs from the behavior for `&T`, which is always `Copy`).
"##, "##,
/*
E0205: r##" 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 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 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 the mentioned variant. Note that this may not be possible, as in the example of
```compile_fail,E0205 ```compile_fail,E0204
enum Foo { enum Foo {
Bar(Vec<u32>), Bar(Vec<u32>),
Baz, Baz,
@ -1892,7 +1893,7 @@ This fails because `Vec<T>` does not implement `Copy` for any `T`.
Here's another example that will fail: Here's another example that will fail:
```compile_fail,E0205 ```compile_fail,E0204
#[derive(Copy)] #[derive(Copy)]
enum Foo<'a> { enum Foo<'a> {
Bar(&'a mut bool), 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 This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this
differs from the behavior for `&T`, which is always `Copy`). differs from the behavior for `&T`, which is always `Copy`).
"##, "##,
*/
E0206: r##" E0206: r##"
You can only implement `Copy` for a struct or enum. Both of the following 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 [RFC 1023]: https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md
"##, "##,
/*
E0211: r##" 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 You used a function or type which doesn't fit the requirements for where it was
used. Erroneous code examples: 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: have this definition:
```compile_fail ```compile_fail
@ -2206,7 +2207,6 @@ impl Foo {
} }
``` ```
"##, "##,
*/
E0220: r##" E0220: r##"
You used an associated type which isn't defined in the trait. 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 [`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##" 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 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 type parameter or `Self`. This is not supported yet. An example causing this
error is shown below: error is shown below:
@ -2765,12 +2760,15 @@ trait Foo {
struct MyStruct; struct MyStruct;
impl Foo for MyStruct {
const BAR: f64 = 0f64;
}
fn get_bar_good() -> f64 { fn get_bar_good() -> f64 {
<MyStruct as Foo>::BAR <MyStruct as Foo>::BAR
} }
``` ```
"##, "##,
*/
E0366: r##" E0366: r##"
An attempt was made to implement `Drop` on a concrete specialization of a 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 // between structures with the same definition
// E0558, // replaced with a generic attribute input check // E0558, // replaced with a generic attribute input check
// E0563, // cannot determine a type for this `impl Trait` removed in 6383de15 // 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 `{}` // but `{}` was found in the type `{}`
E0587, // type has conflicting packed and align representation hints E0587, // type has conflicting packed and align representation hints
E0588, // packed type cannot transitively contain a `[repr(align)]` type 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 E0634, // type has conflicting packed representaton hints
E0640, // infer outlives requirements E0640, // infer outlives requirements
E0641, // cannot cast to/from a pointer with an unknown kind 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 E0719, // duplicate values for associated type binding
E0722, // Malformed `#[optimize]` attribute E0722, // Malformed `#[optimize]` attribute
E0724, // `#[ffi_returns_twice]` is only allowed in foreign functions E0724, // `#[ffi_returns_twice]` is only allowed in foreign functions

View File

@ -11,6 +11,7 @@ use syntax_pos::MultiSpan;
pub enum BufferedEarlyLintId { pub enum BufferedEarlyLintId {
IllFormedAttributeInput, IllFormedAttributeInput,
MetaVariableMisuse, MetaVariableMisuse,
IncompleteInclude,
} }
/// Stores buffered lint info which can later be passed to `librustc`. /// Stores buffered lint info which can later be passed to `librustc`.

View File

@ -5,6 +5,7 @@ use syntax::print::pprust;
use syntax::ptr::P; use syntax::ptr::P;
use syntax::symbol::Symbol; use syntax::symbol::Symbol;
use syntax::tokenstream::TokenStream; use syntax::tokenstream::TokenStream;
use syntax::early_buffered_lints::BufferedEarlyLintId;
use smallvec::SmallVec; use smallvec::SmallVec;
use syntax_pos::{self, Pos, Span}; 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> { impl<'a> base::MacResult for ExpandResult<'a> {
fn make_expr(mut self: Box<ExpandResult<'a>>) -> Option<P<ast::Expr>> { 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]>> { fn make_items(mut self: Box<ExpandResult<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> {

View File

@ -29,7 +29,7 @@ LL | if &true {}
| ^^^^^ | ^^^^^
| | | |
| expected bool, found &bool | expected bool, found &bool
| help: consider dereferencing the borrow: `*&true` | help: consider removing the borrow: `true`
| |
= note: expected type `bool` = note: expected type `bool`
found type `&bool` found type `&bool`
@ -41,7 +41,7 @@ LL | if &mut true {}
| ^^^^^^^^^ | ^^^^^^^^^
| | | |
| expected bool, found &mut bool | expected bool, found &mut bool
| help: consider dereferencing the borrow: `*&mut true` | help: consider removing the borrow: `true`
| |
= note: expected type `bool` = note: expected type `bool`
found type `&mut bool` found type `&mut bool`
@ -77,7 +77,7 @@ LL | while &true {}
| ^^^^^ | ^^^^^
| | | |
| expected bool, found &bool | expected bool, found &bool
| help: consider dereferencing the borrow: `*&true` | help: consider removing the borrow: `true`
| |
= note: expected type `bool` = note: expected type `bool`
found type `&bool` found type `&bool`
@ -89,7 +89,7 @@ LL | while &mut true {}
| ^^^^^^^^^ | ^^^^^^^^^
| | | |
| expected bool, found &mut bool | expected bool, found &mut bool
| help: consider dereferencing the borrow: `*&mut true` | help: consider removing the borrow: `true`
| |
= note: expected type `bool` = note: expected type `bool`
found type `&mut bool` found type `&mut bool`

View File

@ -0,0 +1,5 @@
// ignore-test auxiliary file for include-single-expr.rs
0
// trailing comment permitted

View File

@ -0,0 +1,5 @@
// ignore-test auxiliary file for include-single-expr.rs
0
10
100

View File

@ -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");
}

View File

@ -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

View File

@ -2,9 +2,7 @@ error[E0401]: can't use generic parameters from outer function
--> $DIR/inner-static-type-parameter.rs:6:19 --> $DIR/inner-static-type-parameter.rs:6:19
| |
LL | fn foo<T>() { LL | fn foo<T>() {
| --- - type parameter from outer function | - type parameter from outer function
| |
| try adding a local generic parameter in this method instead
LL | static a: Bar<T> = Bar::What; LL | static a: Bar<T> = Bar::What;
| ^ use of generic parameter from outer function | ^ use of generic parameter from outer function

View File

@ -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() { }

View File

@ -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`.

View File

@ -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() {}

View File

@ -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`.

View File

@ -520,7 +520,7 @@ LL | if &let 0 = 0 {}
| ^^^^^^^^^^ | ^^^^^^^^^^
| | | |
| expected bool, found &bool | expected bool, found &bool
| help: consider dereferencing the borrow: `*&let 0 = 0` | help: consider removing the borrow: `let 0 = 0`
| |
= note: expected type `bool` = note: expected type `bool`
found type `&bool` found type `&bool`
@ -708,7 +708,7 @@ LL | while &let 0 = 0 {}
| ^^^^^^^^^^ | ^^^^^^^^^^
| | | |
| expected bool, found &bool | expected bool, found &bool
| help: consider dereferencing the borrow: `*&let 0 = 0` | help: consider removing the borrow: `let 0 = 0`
| |
= note: expected type `bool` = note: expected type `bool`
found type `&bool` found type `&bool`

View File

@ -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 --> $DIR/remove-as_str.rs:2:7
| |
LL | s.as_str(); 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 error[E0599]: no method named `as_str` found for type `&'a str` in the current scope
--> $DIR/remove-as_str.rs:7:7 --> $DIR/remove-as_str.rs:7:7
| |
LL | s.as_str(); 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 error[E0599]: no method named `as_str` found for type `&mut str` in the current scope
--> $DIR/remove-as_str.rs:12:7 --> $DIR/remove-as_str.rs:12:7
| |
LL | s.as_str(); 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 error[E0599]: no method named `as_str` found for type `&&str` in the current scope
--> $DIR/remove-as_str.rs:17:7 --> $DIR/remove-as_str.rs:17:7
| |
LL | s.as_str(); LL | s.as_str();
| ^^^^^^ try removing `as_str` | -^^^^^^-- help: remove this method call
error: aborting due to 4 previous errors error: aborting due to 4 previous errors

View File

@ -15,7 +15,7 @@ fn main() {
println!("cargo:rerun-if-changed={}", entry.path().to_str().unwrap()); println!("cargo:rerun-if-changed={}", entry.path().to_str().unwrap());
let file = fs::read_to_string(entry.path()).unwrap() let file = fs::read_to_string(entry.path()).unwrap()
.replace("syntax::register_diagnostics!", "register_diagnostics!"); .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(); fs::write(&out_dir.join(&format!("error_{}.rs", idx)), &contents).unwrap();

View File

@ -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!");
}

View File

@ -41,6 +41,7 @@ pub mod extdeps;
pub mod ui_tests; pub mod ui_tests;
pub mod unit_tests; pub mod unit_tests;
pub mod unstable_book; pub mod unstable_book;
pub mod error_codes_check;
fn filter_dirs(path: &Path) -> bool { fn filter_dirs(path: &Path) -> bool {
let skip = [ let skip = [

View File

@ -35,6 +35,7 @@ fn main() {
deps::check_whitelist(&path, &cargo, &mut bad); deps::check_whitelist(&path, &cargo, &mut bad);
extdeps::check(&path, &mut bad); extdeps::check(&path, &mut bad);
ui_tests::check(&path, &mut bad); ui_tests::check(&path, &mut bad);
error_codes_check::check(&path, &mut bad);
if bad { if bad {
eprintln!("some tidy checks failed"); eprintln!("some tidy checks failed");