diff options
Diffstat (limited to 'src/librustc_session/session.rs')
| -rw-r--r-- | src/librustc_session/session.rs | 330 |
1 files changed, 229 insertions, 101 deletions
diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index 2fb7977dce9..48e36fdb3d4 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -1,41 +1,32 @@ +use crate::cgu_reuse_tracker::CguReuseTracker; use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo}; - -use crate::cgu_reuse_tracker::CguReuseTracker; -use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; - -use crate::config::{self, OutputType, PrintRequest, Sanitizer, SwitchWithOptPath}; +use crate::config::{self, CrateType, OutputType, PrintRequest, Sanitizer, SwitchWithOptPath}; use crate::filesearch; use crate::lint; +use crate::parse::ParseSess; use crate::search_paths::{PathKind, SearchPath}; -use rustc_data_structures::profiling::duration_to_secs_str; -use rustc_errors::ErrorReported; -use rustc_data_structures::base_n; -use rustc_data_structures::impl_stable_hash_via_hash; +pub use rustc_ast::crate_disambiguator::CrateDisambiguator; +use rustc_data_structures::flock; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::jobserver::{self, Client}; +use rustc_data_structures::profiling::{duration_to_secs_str, SelfProfiler, SelfProfilerRef}; use rustc_data_structures::sync::{ self, AtomicU64, AtomicUsize, Lock, Lrc, Once, OneThread, Ordering, Ordering::SeqCst, }; - -use crate::parse::ParseSess; use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitterWriter; -use rustc_errors::emitter::HumanReadableErrorType; -use rustc_errors::emitter::{Emitter, EmitterWriter}; +use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType}; use rustc_errors::json::JsonEmitter; -use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use rustc_errors::registry::Registry; +use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId, ErrorReported}; use rustc_span::edition::Edition; -use rustc_span::source_map; -use rustc_span::{MultiSpan, Span}; - -use rustc_data_structures::flock; -use rustc_data_structures::jobserver::{self, Client}; -use rustc_data_structures::profiling::{SelfProfiler, SelfProfilerRef}; -use rustc_target::spec::{PanicStrategy, RelroLevel, Target, TargetTriple}; +use rustc_span::source_map::{self, FileLoader, MultiSpan, RealFileLoader, SourceMap, Span}; +use rustc_span::{SourceFileHashAlgorithm, Symbol}; +use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, Target, TargetTriple, TlsModel}; use std::cell::{self, RefCell}; use std::env; -use std::fmt; use std::io::Write; use std::num::NonZeroU32; use std::path::PathBuf; @@ -49,6 +40,18 @@ pub struct OptimizationFuel { out_of_fuel: bool, } +/// The behavior of the CTFE engine when an error occurs with regards to backtraces. +#[derive(Clone, Copy)] +pub enum CtfeBacktrace { + /// Do nothing special, return the error as usual without a backtrace. + Disabled, + /// Capture a backtrace at the point the error is created and return it in the error + /// (to be printed later if/when the error ever actually gets shown to the user). + Capture, + /// Capture a backtrace at the point the error is created and immediately print it out. + Immediate, +} + /// Represents the data associated with a compilation /// session for a single crate. pub struct Session { @@ -71,7 +74,7 @@ pub struct Session { /// (sub)diagnostics that have been set once, but should not be set again, /// in order to avoid redundantly verbose output (Issue #24690, #44953). pub one_time_diagnostics: Lock<FxHashSet<(DiagnosticMessageId, Option<Span>, String)>>, - pub crate_types: Once<Vec<config::CrateType>>, + pub crate_types: Once<Vec<CrateType>>, /// The `crate_disambiguator` is constructed out of all the `-C metadata` /// arguments passed to the compiler. Its value together with the crate-name /// forms a unique global identifier for the crate. It is used to allow @@ -88,10 +91,8 @@ pub struct Session { /// The maximum length of types during monomorphization. pub type_length_limit: Once<usize>, - /// Map from imported macro spans (which consist of - /// the localized span for the macro body) to the - /// macro name and definition span in the source crate. - pub imported_macro_spans: OneThread<RefCell<FxHashMap<Span, (String, Span)>>>, + /// The maximum blocks a const expression can evaluate. + pub const_eval_limit: Once<usize>, incr_comp_session: OneThread<RefCell<IncrCompSession>>, /// Used for incremental compilation tests. Will only be populated if @@ -136,6 +137,26 @@ pub struct Session { /// Path for libraries that will take preference over libraries shipped by Rust. /// Used by windows-gnu targets to priortize system mingw-w64 libraries. pub system_library_path: OneThread<RefCell<Option<Option<PathBuf>>>>, + + /// Tracks the current behavior of the CTFE engine when an error occurs. + /// Options range from returning the error without a backtrace to returning an error + /// and immediately printing the backtrace to stderr. + pub ctfe_backtrace: Lock<CtfeBacktrace>, + + /// This tracks where `-Zunleash-the-miri-inside-of-you` was used to get around a + /// const check, optionally with the relevant feature gate. We use this to + /// warn about unleashing, but with a single diagnostic instead of dozens that + /// drown everything else in noise. + miri_unleashed_features: Lock<Vec<(Span, Option<Symbol>)>>, + + /// Base directory containing the `src/` for the Rust standard library, and + /// potentially `rustc` as well, if we can can find it. Right now it's always + /// `$sysroot/lib/rustlib/src/rust` (i.e. the `rustup` `rust-src` component). + /// + /// This directory is what the virtual `/rustc/$hash` is translated back to, + /// if Rust was built with path remapping to `/rustc/$hash` enabled + /// (the `rust.remap-debuginfo` option in `config.toml`). + pub real_rust_source_base_dir: Option<PathBuf>, } pub struct PerfStats { @@ -146,7 +167,7 @@ pub struct PerfStats { /// Total number of values canonicalized queries constructed. pub queries_canonicalized: AtomicUsize, /// Number of times this query is invoked. - pub normalize_ty_after_erasing_regions: AtomicUsize, + pub normalize_generic_arg_after_erasing_regions: AtomicUsize, /// Number of times this query is invoked. pub normalize_projection_ty: AtomicUsize, } @@ -175,6 +196,44 @@ impl From<&'static lint::Lint> for DiagnosticMessageId { } impl Session { + pub fn miri_unleashed_feature(&self, span: Span, feature_gate: Option<Symbol>) { + self.miri_unleashed_features.lock().push((span, feature_gate)); + } + + fn check_miri_unleashed_features(&self) { + let unleashed_features = self.miri_unleashed_features.lock(); + if !unleashed_features.is_empty() { + let mut must_err = false; + // Create a diagnostic pointing at where things got unleashed. + let mut diag = self.struct_warn("skipping const checks"); + for &(span, feature_gate) in unleashed_features.iter() { + // FIXME: `span_label` doesn't do anything, so we use "help" as a hack. + if let Some(feature_gate) = feature_gate { + diag.span_help(span, &format!("skipping check for `{}` feature", feature_gate)); + // The unleash flag must *not* be used to just "hack around" feature gates. + must_err = true; + } else { + diag.span_help(span, "skipping check that does not even have a feature gate"); + } + } + diag.emit(); + // If we should err, make sure we did. + if must_err && !self.has_errors() { + // We have skipped a feature gate, and not run into other errors... reject. + self.err( + "`-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature \ + gates, except when testing error paths in the CTFE engine", + ); + } + } + } + + /// Invoked all the way at the end to finish off diagnostics printing. + pub fn finish_diagnostics(&self, registry: &Registry) { + self.check_miri_unleashed_features(); + self.diagnostic().print_error_count(registry); + } + pub fn local_crate_disambiguator(&self) -> CrateDisambiguator { *self.crate_disambiguator.get() } @@ -526,9 +585,6 @@ impl Session { self.opts.debugging_opts.fewer_names || !more_names } - pub fn no_landing_pads(&self) -> bool { - self.opts.debugging_opts.no_landing_pads || self.panic_strategy() == PanicStrategy::Abort - } pub fn unstable_options(&self) -> bool { self.opts.debugging_opts.unstable_options } @@ -540,25 +596,42 @@ impl Session { .unwrap_or(self.opts.debug_assertions) } - pub fn crt_static(&self) -> bool { + /// Check whether this compile session and crate type use static crt. + pub fn crt_static(&self, crate_type: Option<CrateType>) -> bool { // If the target does not opt in to crt-static support, use its default. if self.target.target.options.crt_static_respected { - self.crt_static_feature() + self.crt_static_feature(crate_type) } else { self.target.target.options.crt_static_default } } - pub fn crt_static_feature(&self) -> bool { + /// Check whether this compile session and crate type use `crt-static` feature. + pub fn crt_static_feature(&self, crate_type: Option<CrateType>) -> bool { let requested_features = self.opts.cg.target_feature.split(','); let found_negative = requested_features.clone().any(|r| r == "-crt-static"); let found_positive = requested_features.clone().any(|r| r == "+crt-static"); - // If the target we're compiling for requests a static crt by default, - // then see if the `-crt-static` feature was passed to disable that. - // Otherwise if we don't have a static crt by default then see if the - // `+crt-static` feature was passed. - if self.target.target.options.crt_static_default { !found_negative } else { found_positive } + if found_positive || found_negative { + found_positive + } else if crate_type == Some(CrateType::ProcMacro) + || crate_type == None && self.opts.crate_types.contains(&CrateType::ProcMacro) + { + // FIXME: When crate_type is not available, + // we use compiler options to determine the crate_type. + // We can't check `#![crate_type = "proc-macro"]` here. + false + } else { + self.target.target.options.crt_static_default + } + } + + pub fn relocation_model(&self) -> RelocModel { + self.opts.cg.relocation_model.unwrap_or(self.target.target.options.relocation_model) + } + + pub fn tls_model(&self) -> TlsModel { + self.opts.debugging_opts.tls_model.unwrap_or(self.target.target.options.tls_model) } pub fn must_not_eliminate_frame_pointers(&self) -> bool { @@ -573,6 +646,33 @@ impl Session { } } + pub fn must_emit_unwind_tables(&self) -> bool { + // This is used to control the emission of the `uwtable` attribute on + // LLVM functions. + // + // At the very least, unwind tables are needed when compiling with + // `-C panic=unwind`. + // + // On some targets (including windows), however, exceptions include + // other events such as illegal instructions, segfaults, etc. This means + // that on Windows we end up still needing unwind tables even if the `-C + // panic=abort` flag is passed. + // + // You can also find more info on why Windows needs unwind tables in: + // https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 + // + // If a target requires unwind tables, then they must be emitted. + // Otherwise, we can defer to the `-C force-unwind-tables=<yes/no>` + // value, if it is provided, or disable them, if not. + if self.panic_strategy() == PanicStrategy::Unwind { + true + } else if self.target.target.options.requires_uwtable { + true + } else { + self.opts.cg.force_unwind_tables.unwrap_or(false) + } + } + /// Returns the symbol name for the registrar function, /// given the crate `Svh` and the function `DefIndex`. pub fn generate_plugin_registrar_symbol(&self, disambiguator: CrateDisambiguator) -> String { @@ -694,8 +794,8 @@ impl Session { self.perf_stats.queries_canonicalized.load(Ordering::Relaxed) ); println!( - "normalize_ty_after_erasing_regions: {}", - self.perf_stats.normalize_ty_after_erasing_regions.load(Ordering::Relaxed) + "normalize_generic_arg_after_erasing_regions: {}", + self.perf_stats.normalize_generic_arg_after_erasing_regions.load(Ordering::Relaxed) ); println!( "normalize_projection_ty: {}", @@ -745,6 +845,13 @@ impl Session { return n as usize; } + // If incremental compilation is turned on, we default to a high number + // codegen units in order to reduce the "collateral damage" small + // changes cause. + if self.opts.incremental.is_some() { + return 256; + } + // Why is 16 codegen units the default all the time? // // The main reason for enabling multiple codegen units by default is to @@ -841,16 +948,15 @@ pub fn build_session( local_crate_source_file: Option<PathBuf>, registry: rustc_errors::registry::Registry, ) -> Session { - let file_path_mapping = sopts.file_path_mapping(); - build_session_with_source_map( sopts, local_crate_source_file, registry, - Lrc::new(source_map::SourceMap::new(file_path_mapping)), DiagnosticOutput::Default, Default::default(), + None, ) + .0 } fn default_emitter( @@ -870,7 +976,7 @@ fn default_emitter( short, macro_backtrace, ); - Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing())) + Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing)) } else { let emitter = match dst { None => EmitterWriter::stderr( @@ -891,7 +997,7 @@ fn default_emitter( macro_backtrace, ), }; - Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing())) + Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing)) } } (config::ErrorOutputType::Json { pretty, json_rendered }, None) => Box::new( @@ -902,7 +1008,7 @@ fn default_emitter( json_rendered, macro_backtrace, ) - .ui_testing(sopts.debugging_opts.ui_testing()), + .ui_testing(sopts.debugging_opts.ui_testing), ), (config::ErrorOutputType::Json { pretty, json_rendered }, Some(dst)) => Box::new( JsonEmitter::new( @@ -913,7 +1019,7 @@ fn default_emitter( json_rendered, macro_backtrace, ) - .ui_testing(sopts.debugging_opts.ui_testing()), + .ui_testing(sopts.debugging_opts.ui_testing), ), } } @@ -927,10 +1033,10 @@ pub fn build_session_with_source_map( sopts: config::Options, local_crate_source_file: Option<PathBuf>, registry: rustc_errors::registry::Registry, - source_map: Lrc<source_map::SourceMap>, diagnostics_output: DiagnosticOutput, - lint_caps: FxHashMap<lint::LintId, lint::Level>, -) -> Session { + driver_lint_caps: FxHashMap<lint::LintId, lint::Level>, + file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>, +) -> (Session, Lrc<SourceMap>) { // FIXME: This is not general enough to make the warning lint completely override // normal diagnostic warnings, since the warning lint can also be denied and changed // later via the source code. @@ -948,23 +1054,33 @@ pub fn build_session_with_source_map( DiagnosticOutput::Default => None, DiagnosticOutput::Raw(write) => Some(write), }; + + let target_cfg = config::build_target_config(&sopts, sopts.error_format); + let host_triple = TargetTriple::from_triple(config::host_triple()); + let host = Target::search(&host_triple).unwrap_or_else(|e| { + early_error(sopts.error_format, &format!("Error loading host specification: {}", e)) + }); + + let loader = file_loader.unwrap_or(Box::new(RealFileLoader)); + let hash_kind = sopts.debugging_opts.src_hash_algorithm.unwrap_or_else(|| { + if target_cfg.target.options.is_like_msvc { + SourceFileHashAlgorithm::Sha1 + } else { + SourceFileHashAlgorithm::Md5 + } + }); + let source_map = Lrc::new(SourceMap::with_file_loader_and_hash_kind( + loader, + sopts.file_path_mapping(), + hash_kind, + )); let emitter = default_emitter(&sopts, registry, &source_map, write_dest); - let diagnostic_handler = rustc_errors::Handler::with_emitter_and_flags( + let span_diagnostic = rustc_errors::Handler::with_emitter_and_flags( emitter, sopts.debugging_opts.diagnostic_handler_flags(can_emit_warnings), ); - build_session_(sopts, local_crate_source_file, diagnostic_handler, source_map, lint_caps) -} - -fn build_session_( - sopts: config::Options, - local_crate_source_file: Option<PathBuf>, - span_diagnostic: rustc_errors::Handler, - source_map: Lrc<source_map::SourceMap>, - driver_lint_caps: FxHashMap<lint::LintId, lint::Level>, -) -> Session { let self_profiler = if let SwitchWithOptPath::Enabled(ref d) = sopts.debugging_opts.self_profile { let directory = @@ -986,13 +1102,7 @@ fn build_session_( None }; - let host_triple = TargetTriple::from_triple(config::host_triple()); - let host = Target::search(&host_triple).unwrap_or_else(|e| { - span_diagnostic.fatal(&format!("Error loading host specification: {}", e)).raise() - }); - let target_cfg = config::build_target_config(&sopts, &span_diagnostic); - - let parse_sess = ParseSess::with_span_handler(span_diagnostic, source_map); + let parse_sess = ParseSess::with_span_handler(span_diagnostic, source_map.clone()); let sysroot = match &sopts.maybe_sysroot { Some(sysroot) => sysroot.clone(), None => filesearch::get_or_default_sysroot(), @@ -1037,6 +1147,32 @@ fn build_session_( sopts.debugging_opts.time_passes, ); + let ctfe_backtrace = Lock::new(match env::var("RUSTC_CTFE_BACKTRACE") { + Ok(ref val) if val == "immediate" => CtfeBacktrace::Immediate, + Ok(ref val) if val != "0" => CtfeBacktrace::Capture, + _ => CtfeBacktrace::Disabled, + }); + + // Try to find a directory containing the Rust `src`, for more details see + // the doc comment on the `real_rust_source_base_dir` field. + let real_rust_source_base_dir = { + // This is the location used by the `rust-src` `rustup` component. + let mut candidate = sysroot.join("lib/rustlib/src/rust"); + if let Ok(metadata) = candidate.symlink_metadata() { + // Replace the symlink rustbuild creates, with its destination. + // We could try to use `fs::canonicalize` instead, but that might + // produce unnecessarily verbose path. + if metadata.file_type().is_symlink() { + if let Ok(symlink_dest) = std::fs::read_link(&candidate) { + candidate = symlink_dest; + } + } + } + + // Only use this directory if it has a file we can expect to always find. + if candidate.join("src/libstd/lib.rs").is_file() { Some(candidate) } else { None } + }; + let sess = Session { target: target_cfg, host, @@ -1053,7 +1189,7 @@ fn build_session_( features: Once::new(), recursion_limit: Once::new(), type_length_limit: Once::new(), - imported_macro_spans: OneThread::new(RefCell::new(FxHashMap::default())), + const_eval_limit: Once::new(), incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)), cgu_reuse_tracker, prof, @@ -1061,7 +1197,7 @@ fn build_session_( symbol_hash_time: Lock::new(Duration::from_secs(0)), decode_def_path_tables_time: Lock::new(Duration::from_secs(0)), queries_canonicalized: AtomicUsize::new(0), - normalize_ty_after_erasing_regions: AtomicUsize::new(0), + normalize_generic_arg_after_erasing_regions: AtomicUsize::new(0), normalize_projection_ty: AtomicUsize::new(0), }, code_stats: Default::default(), @@ -1074,11 +1210,14 @@ fn build_session_( trait_methods_not_found: Lock::new(Default::default()), confused_type_with_std_module: Lock::new(Default::default()), system_library_path: OneThread::new(RefCell::new(Default::default())), + ctfe_backtrace, + miri_unleashed_features: Lock::new(Default::default()), + real_rust_source_base_dir, }; validate_commandline_args_with_session_available(&sess); - sess + (sess, source_map) } // If it is useful to have a Session available already for validating a @@ -1112,6 +1251,23 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } } + // Unwind tables cannot be disabled if the target requires them. + if let Some(include_uwtables) = sess.opts.cg.force_unwind_tables { + if sess.panic_strategy() == PanicStrategy::Unwind && !include_uwtables { + sess.err( + "panic=unwind requires unwind tables, they cannot be disabled \ + with `-C force-unwind-tables=no`.", + ); + } + + if sess.target.target.options.requires_uwtable && !include_uwtables { + sess.err( + "target requires unwind tables, they cannot be disabled with \ + `-C force-unwind-tables=no`.", + ); + } + } + // PGO does not work reliably with panic=unwind on Windows. Let's make it // an error to combine the two for now. It always runs into an assertions // if LLVM is built with assertions, but without assertions it sometimes @@ -1162,34 +1318,6 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } } -/// Hash value constructed out of all the `-C metadata` arguments passed to the -/// compiler. Together with the crate-name forms a unique global identifier for -/// the crate. -#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy, RustcEncodable, RustcDecodable)] -pub struct CrateDisambiguator(Fingerprint); - -impl CrateDisambiguator { - pub fn to_fingerprint(self) -> Fingerprint { - self.0 - } -} - -impl fmt::Display for CrateDisambiguator { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - let (a, b) = self.0.as_value(); - let as_u128 = a as u128 | ((b as u128) << 64); - f.write_str(&base_n::encode(as_u128, base_n::CASE_INSENSITIVE)) - } -} - -impl From<Fingerprint> for CrateDisambiguator { - fn from(fingerprint: Fingerprint) -> CrateDisambiguator { - CrateDisambiguator(fingerprint) - } -} - -impl_stable_hash_via_hash!(CrateDisambiguator); - /// Holds data on the current incremental compilation session, if there is one. #[derive(Debug)] pub enum IncrCompSession { |
