mirror of
https://github.com/rust-lang/rust
synced 2024-10-02 14:54:35 +00:00
Rollup merge of #117376 - nnethercote:rustc_interface-more, r=oli-obk
More `rustc_interface` cleanups In particular, following up #117268 with more improvement to `--cfg`/`--check-cfg` handling. r? ``@oli-obk``
This commit is contained in:
commit
d96bdbe218
|
@ -317,13 +317,11 @@ fn run_compiler(
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let cfg = interface::parse_cfg(&early_error_handler, matches.opt_strs("cfg"));
|
|
||||||
let check_cfg = interface::parse_check_cfg(&early_error_handler, matches.opt_strs("check-cfg"));
|
|
||||||
let (odir, ofile) = make_output(&matches);
|
let (odir, ofile) = make_output(&matches);
|
||||||
let mut config = interface::Config {
|
let mut config = interface::Config {
|
||||||
opts: sopts,
|
opts: sopts,
|
||||||
crate_cfg: cfg,
|
crate_cfg: matches.opt_strs("cfg"),
|
||||||
crate_check_cfg: check_cfg,
|
crate_check_cfg: matches.opt_strs("check-cfg"),
|
||||||
input: Input::File(PathBuf::new()),
|
input: Input::File(PathBuf::new()),
|
||||||
output_file: ofile,
|
output_file: ofile,
|
||||||
output_dir: odir,
|
output_dir: odir,
|
||||||
|
|
|
@ -33,9 +33,7 @@ fn track_diagnostic(diagnostic: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnost
|
||||||
tls::with_context_opt(|icx| {
|
tls::with_context_opt(|icx| {
|
||||||
if let Some(icx) = icx {
|
if let Some(icx) = icx {
|
||||||
if let Some(diagnostics) = icx.diagnostics {
|
if let Some(diagnostics) = icx.diagnostics {
|
||||||
let mut diagnostics = diagnostics.lock();
|
diagnostics.lock().extend(Some(diagnostic.clone()));
|
||||||
diagnostics.extend(Some(diagnostic.clone()));
|
|
||||||
std::mem::drop(diagnostics);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Diagnostics are tracked, we can ignore the dependency.
|
// Diagnostics are tracked, we can ignore the dependency.
|
||||||
|
|
|
@ -64,11 +64,7 @@ pub fn build_output_filenames(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts strings provided as `--cfg [cfgspec]` into a `Cfg`.
|
/// Converts strings provided as `--cfg [cfgspec]` into a `Cfg`.
|
||||||
pub fn parse_cfg(handler: &EarlyErrorHandler, cfgs: Vec<String>) -> Cfg<String> {
|
pub(crate) fn parse_cfg(handler: &EarlyErrorHandler, cfgs: Vec<String>) -> Cfg {
|
||||||
// This creates a short-lived `SessionGlobals`, containing an interner. The
|
|
||||||
// parsed values are converted from symbols to strings before exiting
|
|
||||||
// because the symbols are meaningless once the interner is gone.
|
|
||||||
rustc_span::create_default_session_if_not_set_then(move |_| {
|
|
||||||
cfgs.into_iter()
|
cfgs.into_iter()
|
||||||
.map(|s| {
|
.map(|s| {
|
||||||
let sess = ParseSess::with_silent_emitter(Some(format!(
|
let sess = ParseSess::with_silent_emitter(Some(format!(
|
||||||
|
@ -98,10 +94,7 @@ macro_rules! error {
|
||||||
}
|
}
|
||||||
MetaItemKind::NameValue(..) | MetaItemKind::Word => {
|
MetaItemKind::NameValue(..) | MetaItemKind::Word => {
|
||||||
let ident = meta_item.ident().expect("multi-segment cfg key");
|
let ident = meta_item.ident().expect("multi-segment cfg key");
|
||||||
return (
|
return (ident.name, meta_item.value_str());
|
||||||
ident.name.to_string(),
|
|
||||||
meta_item.value_str().map(|sym| sym.to_string()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,15 +115,11 @@ macro_rules! error {
|
||||||
error!(r#"expected `key` or `key="value"`"#);
|
error!(r#"expected `key` or `key="value"`"#);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Cfg<String>>()
|
.collect::<Cfg>()
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
|
/// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
|
||||||
pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> CheckCfg<String> {
|
pub(crate) fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> CheckCfg {
|
||||||
// The comment about `SessionGlobals` and symbols in `parse_cfg` above
|
|
||||||
// applies here too.
|
|
||||||
rustc_span::create_default_session_if_not_set_then(move |_| {
|
|
||||||
// If any --check-cfg is passed then exhaustive_values and exhaustive_names
|
// If any --check-cfg is passed then exhaustive_values and exhaustive_names
|
||||||
// are enabled by default.
|
// are enabled by default.
|
||||||
let exhaustive_names = !specs.is_empty();
|
let exhaustive_names = !specs.is_empty();
|
||||||
|
@ -175,40 +164,34 @@ macro_rules! error {
|
||||||
expected_error();
|
expected_error();
|
||||||
};
|
};
|
||||||
|
|
||||||
if meta_item.has_name(sym::names) {
|
let mut set_old_syntax = || {
|
||||||
// defaults are flipped for the old syntax
|
// defaults are flipped for the old syntax
|
||||||
if old_syntax == None {
|
if old_syntax == None {
|
||||||
check_cfg.exhaustive_names = false;
|
check_cfg.exhaustive_names = false;
|
||||||
check_cfg.exhaustive_values = false;
|
check_cfg.exhaustive_values = false;
|
||||||
}
|
}
|
||||||
old_syntax = Some(true);
|
old_syntax = Some(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
if meta_item.has_name(sym::names) {
|
||||||
|
set_old_syntax();
|
||||||
|
|
||||||
check_cfg.exhaustive_names = true;
|
check_cfg.exhaustive_names = true;
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if arg.is_word() && arg.ident().is_some() {
|
if arg.is_word() && let Some(ident) = arg.ident() {
|
||||||
let ident = arg.ident().expect("multi-segment cfg key");
|
check_cfg.expecteds.entry(ident.name).or_insert(ExpectedValues::Any);
|
||||||
check_cfg
|
|
||||||
.expecteds
|
|
||||||
.entry(ident.name.to_string())
|
|
||||||
.or_insert(ExpectedValues::Any);
|
|
||||||
} else {
|
} else {
|
||||||
error!("`names()` arguments must be simple identifiers");
|
error!("`names()` arguments must be simple identifiers");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if meta_item.has_name(sym::values) {
|
} else if meta_item.has_name(sym::values) {
|
||||||
// defaults are flipped for the old syntax
|
set_old_syntax();
|
||||||
if old_syntax == None {
|
|
||||||
check_cfg.exhaustive_names = false;
|
|
||||||
check_cfg.exhaustive_values = false;
|
|
||||||
}
|
|
||||||
old_syntax = Some(true);
|
|
||||||
|
|
||||||
if let Some((name, values)) = args.split_first() {
|
if let Some((name, values)) = args.split_first() {
|
||||||
if name.is_word() && name.ident().is_some() {
|
if name.is_word() && let Some(ident) = name.ident() {
|
||||||
let ident = name.ident().expect("multi-segment cfg key");
|
|
||||||
let expected_values = check_cfg
|
let expected_values = check_cfg
|
||||||
.expecteds
|
.expecteds
|
||||||
.entry(ident.name.to_string())
|
.entry(ident.name)
|
||||||
.and_modify(|expected_values| match expected_values {
|
.and_modify(|expected_values| match expected_values {
|
||||||
ExpectedValues::Some(_) => {}
|
ExpectedValues::Some(_) => {}
|
||||||
ExpectedValues::Any => {
|
ExpectedValues::Any => {
|
||||||
|
@ -225,7 +208,7 @@ macro_rules! error {
|
||||||
|
|
||||||
for val in values {
|
for val in values {
|
||||||
if let Some(LitKind::Str(s, _)) = val.lit().map(|lit| &lit.kind) {
|
if let Some(LitKind::Str(s, _)) = val.lit().map(|lit| &lit.kind) {
|
||||||
expected_values.insert(Some(s.to_string()));
|
expected_values.insert(Some(*s));
|
||||||
} else {
|
} else {
|
||||||
error!("`values()` arguments must be string literals");
|
error!("`values()` arguments must be string literals");
|
||||||
}
|
}
|
||||||
|
@ -258,9 +241,7 @@ macro_rules! error {
|
||||||
error!("`cfg()` names cannot be after values");
|
error!("`cfg()` names cannot be after values");
|
||||||
}
|
}
|
||||||
names.push(ident);
|
names.push(ident);
|
||||||
} else if arg.has_name(sym::any)
|
} else if arg.has_name(sym::any) && let Some(args) = arg.meta_item_list() {
|
||||||
&& let Some(args) = arg.meta_item_list()
|
|
||||||
{
|
|
||||||
if any_specified {
|
if any_specified {
|
||||||
error!("`any()` cannot be specified multiple times");
|
error!("`any()` cannot be specified multiple times");
|
||||||
}
|
}
|
||||||
|
@ -268,9 +249,7 @@ macro_rules! error {
|
||||||
if !args.is_empty() {
|
if !args.is_empty() {
|
||||||
error!("`any()` must be empty");
|
error!("`any()` must be empty");
|
||||||
}
|
}
|
||||||
} else if arg.has_name(sym::values)
|
} else if arg.has_name(sym::values) && let Some(args) = arg.meta_item_list() {
|
||||||
&& let Some(args) = arg.meta_item_list()
|
|
||||||
{
|
|
||||||
if names.is_empty() {
|
if names.is_empty() {
|
||||||
error!("`values()` cannot be specified before the names");
|
error!("`values()` cannot be specified before the names");
|
||||||
} else if values_specified {
|
} else if values_specified {
|
||||||
|
@ -279,26 +258,18 @@ macro_rules! error {
|
||||||
values_specified = true;
|
values_specified = true;
|
||||||
|
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if let Some(LitKind::Str(s, _)) =
|
if let Some(LitKind::Str(s, _)) = arg.lit().map(|lit| &lit.kind) {
|
||||||
arg.lit().map(|lit| &lit.kind)
|
values.insert(Some(*s));
|
||||||
{
|
} else if arg.has_name(sym::any) && let Some(args) = arg.meta_item_list() {
|
||||||
values.insert(Some(s.to_string()));
|
|
||||||
} else if arg.has_name(sym::any)
|
|
||||||
&& let Some(args) = arg.meta_item_list()
|
|
||||||
{
|
|
||||||
if values_any_specified {
|
if values_any_specified {
|
||||||
error!(
|
error!("`any()` in `values()` cannot be specified multiple times");
|
||||||
"`any()` in `values()` cannot be specified multiple times"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
values_any_specified = true;
|
values_any_specified = true;
|
||||||
if !args.is_empty() {
|
if !args.is_empty() {
|
||||||
error!("`any()` must be empty");
|
error!("`any()` must be empty");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error!(
|
error!("`values()` arguments must be string literals or `any()`");
|
||||||
"`values()` arguments must be string literals or `any()`"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -330,7 +301,7 @@ macro_rules! error {
|
||||||
for name in names {
|
for name in names {
|
||||||
check_cfg
|
check_cfg
|
||||||
.expecteds
|
.expecteds
|
||||||
.entry(name.to_string())
|
.entry(name.name)
|
||||||
.and_modify(|v| match v {
|
.and_modify(|v| match v {
|
||||||
ExpectedValues::Some(v) if !values_any_specified => {
|
ExpectedValues::Some(v) if !values_any_specified => {
|
||||||
v.extend(values.clone())
|
v.extend(values.clone())
|
||||||
|
@ -353,7 +324,6 @@ macro_rules! error {
|
||||||
}
|
}
|
||||||
|
|
||||||
check_cfg
|
check_cfg
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The compiler configuration
|
/// The compiler configuration
|
||||||
|
@ -361,9 +331,9 @@ pub struct Config {
|
||||||
/// Command line options
|
/// Command line options
|
||||||
pub opts: config::Options,
|
pub opts: config::Options,
|
||||||
|
|
||||||
/// cfg! configuration in addition to the default ones
|
/// Unparsed cfg! configuration in addition to the default ones.
|
||||||
pub crate_cfg: Cfg<String>,
|
pub crate_cfg: Vec<String>,
|
||||||
pub crate_check_cfg: CheckCfg<String>,
|
pub crate_check_cfg: Vec<String>,
|
||||||
|
|
||||||
pub input: Input,
|
pub input: Input,
|
||||||
pub output_dir: Option<PathBuf>,
|
pub output_dir: Option<PathBuf>,
|
||||||
|
@ -436,8 +406,8 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
|
||||||
let (mut sess, codegen_backend) = util::create_session(
|
let (mut sess, codegen_backend) = util::create_session(
|
||||||
&handler,
|
&handler,
|
||||||
config.opts,
|
config.opts,
|
||||||
config.crate_cfg,
|
parse_cfg(&handler, config.crate_cfg),
|
||||||
config.crate_check_cfg,
|
parse_check_cfg(&handler, config.crate_check_cfg),
|
||||||
config.locale_resources,
|
config.locale_resources,
|
||||||
config.file_loader,
|
config.file_loader,
|
||||||
CompilerIO {
|
CompilerIO {
|
||||||
|
|
|
@ -392,34 +392,16 @@ fn generated_output_paths(
|
||||||
out_filenames
|
out_filenames
|
||||||
}
|
}
|
||||||
|
|
||||||
// Runs `f` on every output file path and returns the first non-None result, or None if `f`
|
|
||||||
// returns None for every file path.
|
|
||||||
fn check_output<F, T>(output_paths: &[PathBuf], f: F) -> Option<T>
|
|
||||||
where
|
|
||||||
F: Fn(&PathBuf) -> Option<T>,
|
|
||||||
{
|
|
||||||
for output_path in output_paths {
|
|
||||||
if let Some(result) = f(output_path) {
|
|
||||||
return Some(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_contains_path(output_paths: &[PathBuf], input_path: &Path) -> bool {
|
fn output_contains_path(output_paths: &[PathBuf], input_path: &Path) -> bool {
|
||||||
let input_path = try_canonicalize(input_path).ok();
|
let input_path = try_canonicalize(input_path).ok();
|
||||||
if input_path.is_none() {
|
if input_path.is_none() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let check = |output_path: &PathBuf| {
|
output_paths.iter().any(|output_path| try_canonicalize(output_path).ok() == input_path)
|
||||||
if try_canonicalize(output_path).ok() == input_path { Some(()) } else { None }
|
|
||||||
};
|
|
||||||
check_output(output_paths, check).is_some()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option<PathBuf> {
|
fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option<&PathBuf> {
|
||||||
let check = |output_path: &PathBuf| output_path.is_dir().then(|| output_path.clone());
|
output_paths.iter().find(|output_path| output_path.is_dir())
|
||||||
check_output(output_paths, check)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn escape_dep_filename(filename: &str) -> String {
|
fn escape_dep_filename(filename: &str) -> String {
|
||||||
|
@ -602,9 +584,7 @@ fn output_filenames(tcx: TyCtxt<'_>, (): ()) -> Arc<OutputFilenames> {
|
||||||
let (_, krate) = &*tcx.resolver_for_lowering(()).borrow();
|
let (_, krate) = &*tcx.resolver_for_lowering(()).borrow();
|
||||||
let crate_name = tcx.crate_name(LOCAL_CRATE);
|
let crate_name = tcx.crate_name(LOCAL_CRATE);
|
||||||
|
|
||||||
// FIXME: rustdoc passes &[] instead of &krate.attrs here
|
|
||||||
let outputs = util::build_output_filenames(&krate.attrs, sess);
|
let outputs = util::build_output_filenames(&krate.attrs, sess);
|
||||||
|
|
||||||
let output_paths =
|
let output_paths =
|
||||||
generated_output_paths(tcx, &outputs, sess.io.output_file.is_some(), crate_name);
|
generated_output_paths(tcx, &outputs, sess.io.output_file.is_some(), crate_name);
|
||||||
|
|
||||||
|
@ -882,16 +862,18 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
|
||||||
|
|
||||||
let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, tr));
|
let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, tr));
|
||||||
|
|
||||||
// A slightly edited version of the code in `rustc_trait_selection::traits::vtable::vtable_entries`,
|
// A slightly edited version of the code in
|
||||||
// that works without self type and just counts number of entries.
|
// `rustc_trait_selection::traits::vtable::vtable_entries`, that works without self
|
||||||
|
// type and just counts number of entries.
|
||||||
//
|
//
|
||||||
// Note that this is technically wrong, for traits which have associated types in supertraits:
|
// Note that this is technically wrong, for traits which have associated types in
|
||||||
|
// supertraits:
|
||||||
//
|
//
|
||||||
// trait A: AsRef<Self::T> + AsRef<()> { type T; }
|
// trait A: AsRef<Self::T> + AsRef<()> { type T; }
|
||||||
//
|
//
|
||||||
// Without self type we can't normalize `Self::T`, so we can't know if `AsRef<Self::T>` and
|
// Without self type we can't normalize `Self::T`, so we can't know if `AsRef<Self::T>`
|
||||||
// `AsRef<()>` are the same trait, thus we assume that those are different, and potentially
|
// and `AsRef<()>` are the same trait, thus we assume that those are different, and
|
||||||
// over-estimate how many vtable entries there are.
|
// potentially over-estimate how many vtable entries there are.
|
||||||
//
|
//
|
||||||
// Similarly this is wrong for traits that have methods with possibly-impossible bounds.
|
// Similarly this is wrong for traits that have methods with possibly-impossible bounds.
|
||||||
// For example:
|
// For example:
|
||||||
|
@ -918,10 +900,10 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
|
||||||
let own_existential_entries =
|
let own_existential_entries =
|
||||||
tcx.own_existential_vtable_entries(trait_ref.def_id());
|
tcx.own_existential_vtable_entries(trait_ref.def_id());
|
||||||
|
|
||||||
// The original code here ignores the method if its predicates are impossible.
|
// The original code here ignores the method if its predicates are
|
||||||
// We can't really do that as, for example, all not trivial bounds on generic
|
// impossible. We can't really do that as, for example, all not trivial
|
||||||
// parameters are impossible (since we don't know the parameters...),
|
// bounds on generic parameters are impossible (since we don't know the
|
||||||
// see the comment above.
|
// parameters...), see the comment above.
|
||||||
entries_ignoring_upcasting += own_existential_entries.len();
|
entries_ignoring_upcasting += own_existential_entries.len();
|
||||||
|
|
||||||
if emit_vptr {
|
if emit_vptr {
|
||||||
|
|
|
@ -2,32 +2,21 @@
|
||||||
use crate::interface::parse_cfg;
|
use crate::interface::parse_cfg;
|
||||||
use rustc_data_structures::profiling::TimePassesFormat;
|
use rustc_data_structures::profiling::TimePassesFormat;
|
||||||
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
|
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
|
||||||
use rustc_session::config::rustc_optgroups;
|
|
||||||
use rustc_session::config::Cfg;
|
|
||||||
use rustc_session::config::DebugInfo;
|
|
||||||
use rustc_session::config::Input;
|
|
||||||
use rustc_session::config::InstrumentXRay;
|
|
||||||
use rustc_session::config::LinkSelfContained;
|
|
||||||
use rustc_session::config::Polonius;
|
|
||||||
use rustc_session::config::TraitSolver;
|
|
||||||
use rustc_session::config::{build_configuration, build_session_options};
|
|
||||||
use rustc_session::config::{
|
use rustc_session::config::{
|
||||||
BranchProtection, Externs, OomStrategy, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet,
|
build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg,
|
||||||
ProcMacroExecutionStrategy, SymbolManglingVersion, WasiExecModel,
|
DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs, Input,
|
||||||
|
InstrumentCoverage, InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli,
|
||||||
|
MirSpanview, OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet,
|
||||||
|
Passes, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion,
|
||||||
|
TraitSolver, WasiExecModel,
|
||||||
};
|
};
|
||||||
use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
|
|
||||||
use rustc_session::config::{DumpMonoStatsFormat, MirSpanview};
|
|
||||||
use rustc_session::config::{ErrorOutputType, ExternLocation, LocationDetail, Options, Strip};
|
|
||||||
use rustc_session::config::{InstrumentCoverage, Passes};
|
|
||||||
use rustc_session::lint::Level;
|
use rustc_session::lint::Level;
|
||||||
use rustc_session::search_paths::SearchPath;
|
use rustc_session::search_paths::SearchPath;
|
||||||
use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
|
use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
|
||||||
use rustc_session::{build_session, getopts, Session};
|
use rustc_session::{build_session, getopts, CompilerIO, EarlyErrorHandler, Session};
|
||||||
use rustc_session::{CompilerIO, EarlyErrorHandler};
|
|
||||||
use rustc_span::edition::{Edition, DEFAULT_EDITION};
|
use rustc_span::edition::{Edition, DEFAULT_EDITION};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::FileName;
|
use rustc_span::{FileName, SourceFileHashAlgorithm};
|
||||||
use rustc_span::SourceFileHashAlgorithm;
|
|
||||||
use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel};
|
use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel};
|
||||||
use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel};
|
use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel};
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
|
@ -35,10 +24,7 @@
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
fn mk_session(
|
fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Session, Cfg) {
|
||||||
handler: &mut EarlyErrorHandler,
|
|
||||||
matches: getopts::Matches,
|
|
||||||
) -> (Session, Cfg<String>) {
|
|
||||||
let registry = registry::Registry::new(&[]);
|
let registry = registry::Registry::new(&[]);
|
||||||
let sessopts = build_session_options(handler, &matches);
|
let sessopts = build_session_options(handler, &matches);
|
||||||
let cfg = parse_cfg(handler, matches.opt_strs("cfg"));
|
let cfg = parse_cfg(handler, matches.opt_strs("cfg"));
|
||||||
|
|
|
@ -36,11 +36,7 @@
|
||||||
///
|
///
|
||||||
/// This is performed by checking whether a set of permitted features
|
/// This is performed by checking whether a set of permitted features
|
||||||
/// is available on the target machine, by querying the codegen backend.
|
/// is available on the target machine, by querying the codegen backend.
|
||||||
pub fn add_configuration(
|
pub fn add_configuration(cfg: &mut Cfg, sess: &mut Session, codegen_backend: &dyn CodegenBackend) {
|
||||||
cfg: &mut Cfg<Symbol>,
|
|
||||||
sess: &mut Session,
|
|
||||||
codegen_backend: &dyn CodegenBackend,
|
|
||||||
) {
|
|
||||||
let tf = sym::target_feature;
|
let tf = sym::target_feature;
|
||||||
|
|
||||||
let unstable_target_features = codegen_backend.target_features(sess, true);
|
let unstable_target_features = codegen_backend.target_features(sess, true);
|
||||||
|
@ -59,8 +55,8 @@ pub fn add_configuration(
|
||||||
pub fn create_session(
|
pub fn create_session(
|
||||||
handler: &EarlyErrorHandler,
|
handler: &EarlyErrorHandler,
|
||||||
sopts: config::Options,
|
sopts: config::Options,
|
||||||
cfg: Cfg<String>,
|
cfg: Cfg,
|
||||||
check_cfg: CheckCfg<String>,
|
mut check_cfg: CheckCfg,
|
||||||
locale_resources: &'static [&'static str],
|
locale_resources: &'static [&'static str],
|
||||||
file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
|
file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
|
||||||
io: CompilerIO,
|
io: CompilerIO,
|
||||||
|
@ -123,7 +119,6 @@ pub fn create_session(
|
||||||
let mut cfg = config::build_configuration(&sess, cfg);
|
let mut cfg = config::build_configuration(&sess, cfg);
|
||||||
add_configuration(&mut cfg, &mut sess, &*codegen_backend);
|
add_configuration(&mut cfg, &mut sess, &*codegen_backend);
|
||||||
|
|
||||||
let mut check_cfg = check_cfg.intern();
|
|
||||||
check_cfg.fill_well_known(&sess.target);
|
check_cfg.fill_well_known(&sess.target);
|
||||||
|
|
||||||
// These configs use symbols, rather than strings.
|
// These configs use symbols, rather than strings.
|
||||||
|
@ -487,21 +482,6 @@ fn categorize_crate_type(s: Symbol) -> Option<CrateType> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<CrateType> {
|
pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<CrateType> {
|
||||||
// Unconditionally collect crate types from attributes to make them used
|
|
||||||
let attr_types: Vec<CrateType> = attrs
|
|
||||||
.iter()
|
|
||||||
.filter_map(|a| {
|
|
||||||
if a.has_name(sym::crate_type) {
|
|
||||||
match a.value_str() {
|
|
||||||
Some(s) => categorize_crate_type(s),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// If we're generating a test executable, then ignore all other output
|
// If we're generating a test executable, then ignore all other output
|
||||||
// styles at all other locations
|
// styles at all other locations
|
||||||
if session.opts.test {
|
if session.opts.test {
|
||||||
|
@ -515,6 +495,13 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<C
|
||||||
#[allow(rustc::bad_opt_access)]
|
#[allow(rustc::bad_opt_access)]
|
||||||
let mut base = session.opts.crate_types.clone();
|
let mut base = session.opts.crate_types.clone();
|
||||||
if base.is_empty() {
|
if base.is_empty() {
|
||||||
|
let attr_types = attrs.iter().filter_map(|a| {
|
||||||
|
if a.has_name(sym::crate_type) && let Some(s) = a.value_str() {
|
||||||
|
categorize_crate_type(s)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
base.extend(attr_types);
|
base.extend(attr_types);
|
||||||
if base.is_empty() {
|
if base.is_empty() {
|
||||||
base.push(output::default_output_for_target(session));
|
base.push(output::default_output_for_target(session));
|
||||||
|
|
|
@ -1247,8 +1247,8 @@ pub const fn default_lib_output() -> CrateType {
|
||||||
CrateType::Rlib
|
CrateType::Rlib
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_configuration(sess: &Session) -> Cfg<Symbol> {
|
fn default_configuration(sess: &Session) -> Cfg {
|
||||||
// NOTE: This should be kept in sync with `CheckCfg::<Symbol>::fill_well_known` below.
|
// NOTE: This should be kept in sync with `CheckCfg::fill_well_known` below.
|
||||||
let end = &sess.target.endian;
|
let end = &sess.target.endian;
|
||||||
let arch = &sess.target.arch;
|
let arch = &sess.target.arch;
|
||||||
let wordsz = sess.target.pointer_width.to_string();
|
let wordsz = sess.target.pointer_width.to_string();
|
||||||
|
@ -1358,56 +1358,21 @@ fn default_configuration(sess: &Session) -> Cfg<Symbol> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The parsed `--cfg` options that define the compilation environment of the
|
/// The parsed `--cfg` options that define the compilation environment of the
|
||||||
/// crate, used to drive conditional compilation. `T` is always `String` or
|
/// crate, used to drive conditional compilation.
|
||||||
/// `Symbol`. Strings are used temporarily very early on. Once the the main
|
|
||||||
/// symbol interner is running, they are converted to symbols.
|
|
||||||
///
|
///
|
||||||
/// An `FxIndexSet` is used to ensure deterministic ordering of error messages
|
/// An `FxIndexSet` is used to ensure deterministic ordering of error messages
|
||||||
/// relating to `--cfg`.
|
/// relating to `--cfg`.
|
||||||
pub type Cfg<T> = FxIndexSet<(T, Option<T>)>;
|
pub type Cfg = FxIndexSet<(Symbol, Option<Symbol>)>;
|
||||||
|
|
||||||
/// The parsed `--check-cfg` options. The `<T>` structure is similar to `Cfg`.
|
/// The parsed `--check-cfg` options.
|
||||||
pub struct CheckCfg<T> {
|
#[derive(Default)]
|
||||||
|
pub struct CheckCfg {
|
||||||
/// Is well known names activated
|
/// Is well known names activated
|
||||||
pub exhaustive_names: bool,
|
pub exhaustive_names: bool,
|
||||||
/// Is well known values activated
|
/// Is well known values activated
|
||||||
pub exhaustive_values: bool,
|
pub exhaustive_values: bool,
|
||||||
/// All the expected values for a config name
|
/// All the expected values for a config name
|
||||||
pub expecteds: FxHashMap<T, ExpectedValues<T>>,
|
pub expecteds: FxHashMap<Symbol, ExpectedValues<Symbol>>,
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Default for CheckCfg<T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
CheckCfg {
|
|
||||||
exhaustive_names: false,
|
|
||||||
exhaustive_values: false,
|
|
||||||
expecteds: FxHashMap::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CheckCfg<String> {
|
|
||||||
pub fn intern(self) -> CheckCfg<Symbol> {
|
|
||||||
CheckCfg {
|
|
||||||
exhaustive_names: self.exhaustive_names,
|
|
||||||
exhaustive_values: self.exhaustive_values,
|
|
||||||
expecteds: self
|
|
||||||
.expecteds
|
|
||||||
.into_iter()
|
|
||||||
.map(|(name, values)| {
|
|
||||||
(
|
|
||||||
Symbol::intern(&name),
|
|
||||||
match values {
|
|
||||||
ExpectedValues::Some(values) => ExpectedValues::Some(
|
|
||||||
values.into_iter().map(|b| b.map(|b| Symbol::intern(&b))).collect(),
|
|
||||||
),
|
|
||||||
ExpectedValues::Any => ExpectedValues::Any,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ExpectedValues<T> {
|
pub enum ExpectedValues<T> {
|
||||||
|
@ -1442,7 +1407,7 @@ fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CheckCfg<Symbol> {
|
impl CheckCfg {
|
||||||
pub fn fill_well_known(&mut self, current_target: &Target) {
|
pub fn fill_well_known(&mut self, current_target: &Target) {
|
||||||
if !self.exhaustive_values && !self.exhaustive_names {
|
if !self.exhaustive_values && !self.exhaustive_names {
|
||||||
return;
|
return;
|
||||||
|
@ -1582,13 +1547,7 @@ pub fn fill_well_known(&mut self, current_target: &Target) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_configuration(sess: &Session, user_cfg: Cfg<String>) -> Cfg<Symbol> {
|
pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg {
|
||||||
// We can now intern these strings.
|
|
||||||
let mut user_cfg: Cfg<Symbol> = user_cfg
|
|
||||||
.into_iter()
|
|
||||||
.map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b))))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Combine the configuration requested by the session (command line) with
|
// Combine the configuration requested by the session (command line) with
|
||||||
// some default and generated configuration items.
|
// some default and generated configuration items.
|
||||||
let default_cfg = default_configuration(sess);
|
let default_cfg = default_configuration(sess);
|
||||||
|
|
|
@ -188,8 +188,8 @@ pub fn add_feature_diagnostics_for_issue(
|
||||||
pub struct ParseSess {
|
pub struct ParseSess {
|
||||||
pub span_diagnostic: Handler,
|
pub span_diagnostic: Handler,
|
||||||
pub unstable_features: UnstableFeatures,
|
pub unstable_features: UnstableFeatures,
|
||||||
pub config: Cfg<Symbol>,
|
pub config: Cfg,
|
||||||
pub check_config: CheckCfg<Symbol>,
|
pub check_config: CheckCfg,
|
||||||
pub edition: Edition,
|
pub edition: Edition,
|
||||||
/// Places where raw identifiers were used. This is used to avoid complaining about idents
|
/// Places where raw identifiers were used. This is used to avoid complaining about idents
|
||||||
/// clashing with keywords in new editions.
|
/// clashing with keywords in new editions.
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
|
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
|
||||||
use rustc_session::config::{self, CrateType, ErrorOutputType, ResolveDocLinks};
|
use rustc_session::config::{self, CrateType, ErrorOutputType, ResolveDocLinks};
|
||||||
|
use rustc_session::lint;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_session::{lint, EarlyErrorHandler};
|
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::{source_map, Span};
|
use rustc_span::{source_map, Span};
|
||||||
|
|
||||||
|
@ -175,7 +175,6 @@ pub(crate) fn new_handler(
|
||||||
|
|
||||||
/// Parse, resolve, and typecheck the given crate.
|
/// Parse, resolve, and typecheck the given crate.
|
||||||
pub(crate) fn create_config(
|
pub(crate) fn create_config(
|
||||||
handler: &EarlyErrorHandler,
|
|
||||||
RustdocOptions {
|
RustdocOptions {
|
||||||
input,
|
input,
|
||||||
crate_name,
|
crate_name,
|
||||||
|
@ -255,8 +254,8 @@ pub(crate) fn create_config(
|
||||||
|
|
||||||
interface::Config {
|
interface::Config {
|
||||||
opts: sessopts,
|
opts: sessopts,
|
||||||
crate_cfg: interface::parse_cfg(handler, cfgs),
|
crate_cfg: cfgs,
|
||||||
crate_check_cfg: interface::parse_check_cfg(handler, check_cfgs),
|
crate_check_cfg: check_cfgs,
|
||||||
input,
|
input,
|
||||||
output_file: None,
|
output_file: None,
|
||||||
output_dir: None,
|
output_dir: None,
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
use rustc_resolve::rustdoc::span_of_fragments;
|
use rustc_resolve::rustdoc::span_of_fragments;
|
||||||
use rustc_session::config::{self, CrateType, ErrorOutputType};
|
use rustc_session::config::{self, CrateType, ErrorOutputType};
|
||||||
use rustc_session::parse::ParseSess;
|
use rustc_session::parse::ParseSess;
|
||||||
use rustc_session::{lint, EarlyErrorHandler, Session};
|
use rustc_session::{lint, Session};
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::source_map::SourceMap;
|
use rustc_span::source_map::SourceMap;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
|
@ -85,18 +85,13 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
|
||||||
..config::Options::default()
|
..config::Options::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let early_error_handler = EarlyErrorHandler::new(ErrorOutputType::default());
|
|
||||||
|
|
||||||
let mut cfgs = options.cfgs.clone();
|
let mut cfgs = options.cfgs.clone();
|
||||||
cfgs.push("doc".to_owned());
|
cfgs.push("doc".to_owned());
|
||||||
cfgs.push("doctest".to_owned());
|
cfgs.push("doctest".to_owned());
|
||||||
let config = interface::Config {
|
let config = interface::Config {
|
||||||
opts: sessopts,
|
opts: sessopts,
|
||||||
crate_cfg: interface::parse_cfg(&early_error_handler, cfgs),
|
crate_cfg: cfgs,
|
||||||
crate_check_cfg: interface::parse_check_cfg(
|
crate_check_cfg: options.check_cfgs.clone(),
|
||||||
&early_error_handler,
|
|
||||||
options.check_cfgs.clone(),
|
|
||||||
),
|
|
||||||
input,
|
input,
|
||||||
output_file: None,
|
output_file: None,
|
||||||
output_dir: None,
|
output_dir: None,
|
||||||
|
|
|
@ -757,8 +757,7 @@ fn main_args(
|
||||||
(false, true) => {
|
(false, true) => {
|
||||||
let input = options.input.clone();
|
let input = options.input.clone();
|
||||||
let edition = options.edition;
|
let edition = options.edition;
|
||||||
let config =
|
let config = core::create_config(options, &render_options, using_internal_features);
|
||||||
core::create_config(handler, options, &render_options, using_internal_features);
|
|
||||||
|
|
||||||
// `markdown::render` can invoke `doctest::make_test`, which
|
// `markdown::render` can invoke `doctest::make_test`, which
|
||||||
// requires session globals and a thread pool, so we use
|
// requires session globals and a thread pool, so we use
|
||||||
|
@ -791,7 +790,7 @@ fn main_args(
|
||||||
let scrape_examples_options = options.scrape_examples_options.clone();
|
let scrape_examples_options = options.scrape_examples_options.clone();
|
||||||
let bin_crate = options.bin_crate;
|
let bin_crate = options.bin_crate;
|
||||||
|
|
||||||
let config = core::create_config(handler, options, &render_options, using_internal_features);
|
let config = core::create_config(options, &render_options, using_internal_features);
|
||||||
|
|
||||||
interface::run_compiler(config, |compiler| {
|
interface::run_compiler(config, |compiler| {
|
||||||
let sess = compiler.session();
|
let sess = compiler.session();
|
||||||
|
|
Loading…
Reference in a new issue