Auto merge of #117309 - workingjubilee:rollup-zqb1dun, r=workingjubilee

Rollup of 8 pull requests

Successful merges:

 - #116534 (Remove -Zdep-tasks.)
 - #116739 (Make `E0277` use short paths)
 - #116816 (Create `windows/api.rs` for safer FFI)
 - #116945 (When encountering sealed traits, point types that implement it)
 - #117025 (Cleanup and improve `--check-cfg` implementation)
 - #117256 (Parse rustc version at compile time)
 - #117268 (`rustc_interface` cleanups)
 - #117277 (fix failure to detect a too-big-type after adding padding)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-10-28 09:07:06 +00:00
commit 615d0f2400
43 changed files with 767 additions and 453 deletions

View File

@ -4054,7 +4054,6 @@ dependencies = [
"rustc_hir_analysis",
"rustc_hir_typeck",
"rustc_incremental",
"rustc_index",
"rustc_lint",
"rustc_macros",
"rustc_metadata",

View File

@ -539,6 +539,7 @@ pub trait LayoutCalculator {
// Align the maximum variant size to the largest alignment.
size = size.align_to(align.abi);
// FIXME(oli-obk): deduplicate and harden these checks
if size.bytes() >= dl.obj_size_bound() {
return None;
}
@ -1103,6 +1104,10 @@ fn univariant<
inverse_memory_index.into_iter().map(|it| it.index() as u32).collect()
};
let size = min_size.align_to(align.abi);
// FIXME(oli-obk): deduplicate and harden these checks
if size.bytes() >= dl.obj_size_bound() {
return None;
}
let mut layout_of_single_non_zst_field = None;
let mut abi = Abi::Aggregate { sized };
// Try to make this a Scalar/ScalarPair.

View File

@ -10,10 +10,9 @@ use rustc_session::config::ExpectedValues;
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::parse::{feature_err, ParseSess};
use rustc_session::Session;
use rustc_session::{RustcVersion, Session};
use rustc_span::hygiene::Transparency;
use rustc_span::{symbol::sym, symbol::Symbol, Span};
use std::fmt::{self, Display};
use std::num::NonZeroU32;
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
@ -24,8 +23,6 @@ use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
/// For more, see [this pull request](https://github.com/rust-lang/rust/pull/100591).
pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
pub const CURRENT_RUSTC_VERSION: &str = env!("CFG_RELEASE");
pub fn is_builtin_attr(attr: &Attribute) -> bool {
attr.is_doc_comment() || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name))
}
@ -153,7 +150,7 @@ pub enum StabilityLevel {
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
#[derive(HashStable_Generic)]
pub enum Since {
Version(Version),
Version(RustcVersion),
/// Stabilized in the upcoming version, whatever number that is.
Current,
/// Failed to parse a stabilization version.
@ -382,7 +379,7 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
let since = if let Some(since) = since {
if since.as_str() == VERSION_PLACEHOLDER {
Since::Current
} else if let Some(version) = parse_version(since.as_str(), false) {
} else if let Some(version) = parse_version(since) {
Since::Version(version)
} else {
sess.emit_err(session_diagnostics::InvalidSince { span: attr.span });
@ -567,31 +564,20 @@ fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &F
}
}
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(HashStable_Generic)]
pub struct Version {
pub major: u16,
pub minor: u16,
pub patch: u16,
}
fn parse_version(s: &str, allow_appendix: bool) -> Option<Version> {
let mut components = s.split('-');
/// Parse a rustc version number written inside string literal in an attribute,
/// like appears in `since = "1.0.0"`. Suffixes like "-dev" and "-nightly" are
/// not accepted in this position, unlike when parsing CFG_RELEASE.
fn parse_version(s: Symbol) -> Option<RustcVersion> {
let mut components = s.as_str().split('-');
let d = components.next()?;
if !allow_appendix && components.next().is_some() {
if components.next().is_some() {
return None;
}
let mut digits = d.splitn(3, '.');
let major = digits.next()?.parse().ok()?;
let minor = digits.next()?.parse().ok()?;
let patch = digits.next().unwrap_or("0").parse().ok()?;
Some(Version { major, minor, patch })
}
impl Display for Version {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
}
Some(RustcVersion { major, minor, patch })
}
/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
@ -623,17 +609,16 @@ pub fn eval_condition(
return false;
}
};
let Some(min_version) = parse_version(min_version.as_str(), false) else {
let Some(min_version) = parse_version(*min_version) else {
sess.emit_warning(session_diagnostics::UnknownVersionLiteral { span: *span });
return false;
};
let rustc_version = parse_version(CURRENT_RUSTC_VERSION, true).unwrap();
// See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details
if sess.assume_incomplete_release {
rustc_version > min_version
RustcVersion::CURRENT > min_version
} else {
rustc_version >= min_version
RustcVersion::CURRENT >= min_version
}
}
ast::MetaItemKind::List(mis) => {

View File

@ -27,6 +27,6 @@ pub use StabilityLevel::*;
pub use rustc_ast::attr::*;
pub(crate) use rustc_ast::HashStableContext;
pub(crate) use rustc_session::HashStableContext;
fluent_messages! { "../messages.ftl" }

View File

@ -317,7 +317,7 @@ fn run_compiler(
return Ok(());
}
let cfg = interface::parse_cfgspecs(&early_error_handler, matches.opt_strs("cfg"));
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 mut config = interface::Config {

View File

@ -26,7 +26,6 @@ rustc_middle = { path = "../rustc_middle" }
rustc_ast_lowering = { path = "../rustc_ast_lowering" }
rustc_ast_passes = { path = "../rustc_ast_passes" }
rustc_incremental = { path = "../rustc_incremental" }
rustc_index = { path = "../rustc_index" }
rustc_traits = { path = "../rustc_traits" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }

View File

@ -26,7 +26,7 @@ fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
})
}
/// This is a callback from `rustc_ast` as it cannot access the implicit state
/// This is a callback from `rustc_errors` as it cannot access the implicit state
/// in `rustc_middle` otherwise. It is used when diagnostic messages are
/// emitted and stores them in the current query, if there is one.
fn track_diagnostic(diagnostic: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {

View File

@ -15,8 +15,10 @@ use rustc_middle::{bug, ty};
use rustc_parse::maybe_new_parser_from_source_str;
use rustc_query_impl::QueryCtxt;
use rustc_query_system::query::print_query_stack;
use rustc_session::config::{self, CheckCfg, ExpectedValues, Input, OutFileName, OutputFilenames};
use rustc_session::parse::{CrateConfig, ParseSess};
use rustc_session::config::{
self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName, OutputFilenames,
};
use rustc_session::parse::ParseSess;
use rustc_session::CompilerIO;
use rustc_session::Session;
use rustc_session::{lint, EarlyErrorHandler};
@ -61,14 +63,13 @@ impl Compiler {
}
}
/// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`.
pub fn parse_cfgspecs(
handler: &EarlyErrorHandler,
cfgspecs: Vec<String>,
) -> FxHashSet<(String, Option<String>)> {
/// Converts strings provided as `--cfg [cfgspec]` into a `Cfg`.
pub fn parse_cfg(handler: &EarlyErrorHandler, cfgs: Vec<String>) -> Cfg<String> {
// 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 |_| {
let cfg = cfgspecs
.into_iter()
cfgs.into_iter()
.map(|s| {
let sess = ParseSess::with_silent_emitter(Some(format!(
"this error occurred on the command line: `--cfg={s}`"
@ -97,7 +98,10 @@ pub fn parse_cfgspecs(
}
MetaItemKind::NameValue(..) | MetaItemKind::Word => {
let ident = meta_item.ident().expect("multi-segment cfg key");
return (ident.name, meta_item.value_str());
return (
ident.name.to_string(),
meta_item.value_str().map(|sym| sym.to_string()),
);
}
}
}
@ -118,13 +122,14 @@ pub fn parse_cfgspecs(
error!(r#"expected `key` or `key="value"`"#);
}
})
.collect::<CrateConfig>();
cfg.into_iter().map(|(a, b)| (a.to_string(), b.map(|b| b.to_string()))).collect()
.collect::<Cfg<String>>()
})
}
/// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> CheckCfg {
pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> CheckCfg<String> {
// 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
// are enabled by default.
@ -140,7 +145,7 @@ pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> Check
let filename = FileName::cfg_spec_source_code(&s);
macro_rules! error {
($reason: expr) => {
($reason:expr) => {
handler.early_error(format!(
concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"),
s
@ -148,217 +153,202 @@ pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> Check
};
}
let expected_error =
|| error!("expected `cfg(name, values(\"value1\", \"value2\", ... \"valueN\"))`");
let expected_error = || -> ! {
error!("expected `cfg(name, values(\"value1\", \"value2\", ... \"valueN\"))`")
};
match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) {
Ok(mut parser) => match parser.parse_meta_item() {
Ok(meta_item) if parser.token == token::Eof => {
if let Some(args) = meta_item.meta_item_list() {
if meta_item.has_name(sym::names) {
// defaults are flipped for the old syntax
if old_syntax == None {
check_cfg.exhaustive_names = false;
check_cfg.exhaustive_values = false;
}
old_syntax = Some(true);
let Ok(mut parser) = maybe_new_parser_from_source_str(&sess, filename, s.to_string())
else {
expected_error();
};
check_cfg.exhaustive_names = true;
for arg in args {
if arg.is_word() && arg.ident().is_some() {
let ident = arg.ident().expect("multi-segment cfg key");
check_cfg
.expecteds
.entry(ident.name.to_string())
.or_insert(ExpectedValues::Any);
} else {
error!("`names()` arguments must be simple identifiers");
}
}
} else if meta_item.has_name(sym::values) {
// defaults are flipped for the 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 name.is_word() && name.ident().is_some() {
let ident = name.ident().expect("multi-segment cfg key");
let expected_values = check_cfg
.expecteds
.entry(ident.name.to_string())
.and_modify(|expected_values| match expected_values {
ExpectedValues::Some(_) => {}
ExpectedValues::Any => {
// handle the case where names(...) was done
// before values by changing to a list
*expected_values =
ExpectedValues::Some(FxHashSet::default());
}
})
.or_insert_with(|| {
ExpectedValues::Some(FxHashSet::default())
});
let ExpectedValues::Some(expected_values) = expected_values
else {
bug!("`expected_values` should be a list a values")
};
for val in values {
if let Some(LitKind::Str(s, _)) =
val.lit().map(|lit| &lit.kind)
{
expected_values.insert(Some(s.to_string()));
} else {
error!(
"`values()` arguments must be string literals"
);
}
}
if values.is_empty() {
expected_values.insert(None);
}
} else {
error!(
"`values()` first argument must be a simple identifier"
);
}
} else if args.is_empty() {
check_cfg.exhaustive_values = true;
} else {
expected_error();
}
} else if meta_item.has_name(sym::cfg) {
old_syntax = Some(false);
let mut names = Vec::new();
let mut values: FxHashSet<_> = Default::default();
let mut any_specified = false;
let mut values_specified = false;
let mut values_any_specified = false;
for arg in args {
if arg.is_word() && let Some(ident) = arg.ident() {
if values_specified {
error!("`cfg()` names cannot be after values");
}
names.push(ident);
} else if arg.has_name(sym::any)
&& let Some(args) = arg.meta_item_list()
{
if any_specified {
error!("`any()` cannot be specified multiple times");
}
any_specified = true;
if !args.is_empty() {
error!("`any()` must be empty");
}
} else if arg.has_name(sym::values)
&& let Some(args) = arg.meta_item_list()
{
if names.is_empty() {
error!(
"`values()` cannot be specified before the names"
);
} else if values_specified {
error!(
"`values()` cannot be specified multiple times"
);
}
values_specified = true;
for arg in args {
if let Some(LitKind::Str(s, _)) =
arg.lit().map(|lit| &lit.kind)
{
values.insert(Some(s.to_string()));
} else if arg.has_name(sym::any)
&& let Some(args) = arg.meta_item_list()
{
if values_any_specified {
error!(
"`any()` in `values()` cannot be specified multiple times"
);
}
values_any_specified = true;
if !args.is_empty() {
error!("`any()` must be empty");
}
} else {
error!(
"`values()` arguments must be string literals or `any()`"
);
}
}
} else {
error!(
"`cfg()` arguments must be simple identifiers, `any()` or `values(...)`"
);
}
}
if values.is_empty() && !values_any_specified && !any_specified {
values.insert(None);
} else if !values.is_empty() && values_any_specified {
error!(
"`values()` arguments cannot specify string literals and `any()` at the same time"
);
}
if any_specified {
if !names.is_empty()
|| !values.is_empty()
|| values_any_specified
{
error!("`cfg(any())` can only be provided in isolation");
}
check_cfg.exhaustive_names = false;
} else {
for name in names {
check_cfg
.expecteds
.entry(name.to_string())
.and_modify(|v| match v {
ExpectedValues::Some(v)
if !values_any_specified =>
{
v.extend(values.clone())
}
ExpectedValues::Some(_) => *v = ExpectedValues::Any,
ExpectedValues::Any => {}
})
.or_insert_with(|| {
if values_any_specified {
ExpectedValues::Any
} else {
ExpectedValues::Some(values.clone())
}
});
}
}
} else {
expected_error();
}
} else {
expected_error();
}
}
Ok(..) => expected_error(),
Err(err) => {
err.cancel();
expected_error();
}
},
Err(errs) => {
drop(errs);
let meta_item = match parser.parse_meta_item() {
Ok(meta_item) if parser.token == token::Eof => meta_item,
Ok(..) => expected_error(),
Err(err) => {
err.cancel();
expected_error();
}
};
let Some(args) = meta_item.meta_item_list() else {
expected_error();
};
if meta_item.has_name(sym::names) {
// defaults are flipped for the old syntax
if old_syntax == None {
check_cfg.exhaustive_names = false;
check_cfg.exhaustive_values = false;
}
old_syntax = Some(true);
check_cfg.exhaustive_names = true;
for arg in args {
if arg.is_word() && arg.ident().is_some() {
let ident = arg.ident().expect("multi-segment cfg key");
check_cfg
.expecteds
.entry(ident.name.to_string())
.or_insert(ExpectedValues::Any);
} else {
error!("`names()` arguments must be simple identifiers");
}
}
} else if meta_item.has_name(sym::values) {
// defaults are flipped for the 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 name.is_word() && name.ident().is_some() {
let ident = name.ident().expect("multi-segment cfg key");
let expected_values = check_cfg
.expecteds
.entry(ident.name.to_string())
.and_modify(|expected_values| match expected_values {
ExpectedValues::Some(_) => {}
ExpectedValues::Any => {
// handle the case where names(...) was done
// before values by changing to a list
*expected_values = ExpectedValues::Some(FxHashSet::default());
}
})
.or_insert_with(|| ExpectedValues::Some(FxHashSet::default()));
let ExpectedValues::Some(expected_values) = expected_values else {
bug!("`expected_values` should be a list a values")
};
for val in values {
if let Some(LitKind::Str(s, _)) = val.lit().map(|lit| &lit.kind) {
expected_values.insert(Some(s.to_string()));
} else {
error!("`values()` arguments must be string literals");
}
}
if values.is_empty() {
expected_values.insert(None);
}
} else {
error!("`values()` first argument must be a simple identifier");
}
} else if args.is_empty() {
check_cfg.exhaustive_values = true;
} else {
expected_error();
}
} else if meta_item.has_name(sym::cfg) {
old_syntax = Some(false);
let mut names = Vec::new();
let mut values: FxHashSet<_> = Default::default();
let mut any_specified = false;
let mut values_specified = false;
let mut values_any_specified = false;
for arg in args {
if arg.is_word() && let Some(ident) = arg.ident() {
if values_specified {
error!("`cfg()` names cannot be after values");
}
names.push(ident);
} else if arg.has_name(sym::any)
&& let Some(args) = arg.meta_item_list()
{
if any_specified {
error!("`any()` cannot be specified multiple times");
}
any_specified = true;
if !args.is_empty() {
error!("`any()` must be empty");
}
} else if arg.has_name(sym::values)
&& let Some(args) = arg.meta_item_list()
{
if names.is_empty() {
error!("`values()` cannot be specified before the names");
} else if values_specified {
error!("`values()` cannot be specified multiple times");
}
values_specified = true;
for arg in args {
if let Some(LitKind::Str(s, _)) =
arg.lit().map(|lit| &lit.kind)
{
values.insert(Some(s.to_string()));
} else if arg.has_name(sym::any)
&& let Some(args) = arg.meta_item_list()
{
if values_any_specified {
error!(
"`any()` in `values()` cannot be specified multiple times"
);
}
values_any_specified = true;
if !args.is_empty() {
error!("`any()` must be empty");
}
} else {
error!(
"`values()` arguments must be string literals or `any()`"
);
}
}
} else {
error!(
"`cfg()` arguments must be simple identifiers, `any()` or `values(...)`"
);
}
}
if values.is_empty() && !values_any_specified && !any_specified {
values.insert(None);
} else if !values.is_empty() && values_any_specified {
error!(
"`values()` arguments cannot specify string literals and `any()` at the same time"
);
}
if any_specified {
if names.is_empty()
&& values.is_empty()
&& !values_specified
&& !values_any_specified
{
check_cfg.exhaustive_names = false;
} else {
error!("`cfg(any())` can only be provided in isolation");
}
} else {
for name in names {
check_cfg
.expecteds
.entry(name.to_string())
.and_modify(|v| match v {
ExpectedValues::Some(v) if !values_any_specified => {
v.extend(values.clone())
}
ExpectedValues::Some(_) => *v = ExpectedValues::Any,
ExpectedValues::Any => {}
})
.or_insert_with(|| {
if values_any_specified {
ExpectedValues::Any
} else {
ExpectedValues::Some(values.clone())
}
});
}
}
} else {
expected_error();
}
}
@ -372,8 +362,8 @@ pub struct Config {
pub opts: config::Options,
/// cfg! configuration in addition to the default ones
pub crate_cfg: FxHashSet<(String, Option<String>)>,
pub crate_check_cfg: CheckCfg,
pub crate_cfg: Cfg<String>,
pub crate_check_cfg: CheckCfg<String>,
pub input: Input,
pub output_dir: Option<PathBuf>,

View File

@ -1,17 +1,16 @@
#![allow(rustc::bad_opt_access)]
use crate::interface::parse_cfgspecs;
use rustc_data_structures::fx::FxHashSet;
use crate::interface::parse_cfg;
use rustc_data_structures::profiling::TimePassesFormat;
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, to_crate_config};
use rustc_session::config::{build_configuration, build_session_options};
use rustc_session::config::{
BranchProtection, Externs, OomStrategy, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet,
ProcMacroExecutionStrategy, SymbolManglingVersion, WasiExecModel,
@ -31,26 +30,18 @@ use rustc_span::FileName;
use rustc_span::SourceFileHashAlgorithm;
use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel};
use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel};
use std::collections::{BTreeMap, BTreeSet};
use std::num::NonZeroUsize;
use std::path::{Path, PathBuf};
use std::sync::Arc;
type CfgSpecs = FxHashSet<(String, Option<String>)>;
fn build_session_options_and_crate_config(
fn mk_session(
handler: &mut EarlyErrorHandler,
matches: getopts::Matches,
) -> (Options, CfgSpecs) {
let sessopts = build_session_options(handler, &matches);
let cfg = parse_cfgspecs(handler, matches.opt_strs("cfg"));
(sessopts, cfg)
}
fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Session, CfgSpecs) {
) -> (Session, Cfg<String>) {
let registry = registry::Registry::new(&[]);
let (sessopts, cfg) = build_session_options_and_crate_config(handler, matches);
let sessopts = build_session_options(handler, &matches);
let cfg = parse_cfg(handler, matches.opt_strs("cfg"));
let temps_dir = sessopts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
let io = CompilerIO {
input: Input::Str { name: FileName::Custom(String::new()), input: String::new() },
@ -141,7 +132,7 @@ fn test_switch_implies_cfg_test() {
let matches = optgroups().parse(&["--test".to_string()]).unwrap();
let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
let (sess, cfg) = mk_session(&mut handler, matches);
let cfg = build_configuration(&sess, to_crate_config(cfg));
let cfg = build_configuration(&sess, cfg);
assert!(cfg.contains(&(sym::test, None)));
});
}
@ -153,7 +144,7 @@ fn test_switch_implies_cfg_test_unless_cfg_test() {
let matches = optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]).unwrap();
let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
let (sess, cfg) = mk_session(&mut handler, matches);
let cfg = build_configuration(&sess, to_crate_config(cfg));
let cfg = build_configuration(&sess, cfg);
let mut test_items = cfg.iter().filter(|&&(name, _)| name == sym::test);
assert!(test_items.next().is_some());
assert!(test_items.next().is_none());
@ -684,7 +675,6 @@ fn test_unstable_options_tracking_hash() {
// tidy-alphabetical-start
untracked!(assert_incr_state, Some(String::from("loaded")));
untracked!(deduplicate_diagnostics, false);
untracked!(dep_tasks, true);
untracked!(dont_buffer_diagnostics, true);
untracked!(dump_dep_graph, true);
untracked!(dump_mir, Some(String::from("abc")));
@ -880,6 +870,6 @@ fn test_edition_parsing() {
let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
let matches = optgroups().parse(&["--edition=2018".to_string()]).unwrap();
let (sessopts, _) = build_session_options_and_crate_config(&mut handler, matches);
let sessopts = build_session_options(&mut handler, &matches);
assert!(sessopts.edition == Edition::Edition2018)
}

View File

@ -3,18 +3,17 @@ use info;
use libloading::Library;
use rustc_ast as ast;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::fx::FxHashMap;
#[cfg(parallel_compiler)]
use rustc_data_structures::sync;
use rustc_errors::registry::Registry;
use rustc_parse::validate_attr;
use rustc_session as session;
use rustc_session::config::CheckCfg;
use rustc_session::config::{self, CrateType};
use rustc_session::config::{OutFileName, OutputFilenames, OutputTypes};
use rustc_session::config::{
self, Cfg, CheckCfg, CrateType, OutFileName, OutputFilenames, OutputTypes,
};
use rustc_session::filesearch::sysroot_candidates;
use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer};
use rustc_session::parse::CrateConfig;
use rustc_session::{filesearch, output, Session};
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::edition::Edition;
@ -38,7 +37,7 @@ pub type MakeBackendFn = fn() -> Box<dyn CodegenBackend>;
/// This is performed by checking whether a set of permitted features
/// is available on the target machine, by querying the codegen backend.
pub fn add_configuration(
cfg: &mut CrateConfig,
cfg: &mut Cfg<Symbol>,
sess: &mut Session,
codegen_backend: &dyn CodegenBackend,
) {
@ -60,8 +59,8 @@ pub fn add_configuration(
pub fn create_session(
handler: &EarlyErrorHandler,
sopts: config::Options,
cfg: FxHashSet<(String, Option<String>)>,
check_cfg: CheckCfg,
cfg: Cfg<String>,
check_cfg: CheckCfg<String>,
locale_resources: &'static [&'static str],
file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
io: CompilerIO,
@ -121,12 +120,13 @@ pub fn create_session(
codegen_backend.init(&sess);
let mut cfg = config::build_configuration(&sess, config::to_crate_config(cfg));
let mut cfg = config::build_configuration(&sess, cfg);
add_configuration(&mut cfg, &mut sess, &*codegen_backend);
let mut check_cfg = config::to_crate_check_config(check_cfg);
let mut check_cfg = check_cfg.intern();
check_cfg.fill_well_known(&sess.target);
// These configs use symbols, rather than strings.
sess.parse_sess.config = cfg;
sess.parse_sess.check_config = check_cfg;

View File

@ -0,0 +1,59 @@
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::{parenthesized, parse_macro_input, LitStr, Token};
pub struct Input {
variable: LitStr,
}
mod kw {
syn::custom_keyword!(env);
}
impl Parse for Input {
// Input syntax is `env!("CFG_RELEASE")` to facilitate grepping.
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let paren;
input.parse::<kw::env>()?;
input.parse::<Token![!]>()?;
parenthesized!(paren in input);
let variable: LitStr = paren.parse()?;
Ok(Input { variable })
}
}
pub(crate) fn current_version(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as Input);
TokenStream::from(match RustcVersion::parse_env_var(&input.variable) {
Ok(RustcVersion { major, minor, patch }) => quote!(
Self { major: #major, minor: #minor, patch: #patch }
),
Err(err) => syn::Error::new(Span::call_site(), err).into_compile_error(),
})
}
struct RustcVersion {
major: u16,
minor: u16,
patch: u16,
}
impl RustcVersion {
fn parse_env_var(env_var: &LitStr) -> Result<Self, Box<dyn std::error::Error>> {
let value = proc_macro::tracked_env::var(env_var.value())?;
Self::parse_str(&value)
.ok_or_else(|| format!("failed to parse rustc version: {:?}", value).into())
}
fn parse_str(value: &str) -> Option<Self> {
// Ignore any suffixes such as "-dev" or "-nightly".
let mut components = value.split('-').next().unwrap().splitn(3, '.');
let major = components.next()?.parse().ok()?;
let minor = components.next()?.parse().ok()?;
let patch = components.next().unwrap_or("0").parse().ok()?;
Some(RustcVersion { major, minor, patch })
}
}

View File

@ -15,6 +15,7 @@ use synstructure::decl_derive;
use proc_macro::TokenStream;
mod current_version;
mod diagnostics;
mod hash_stable;
mod lift;
@ -25,6 +26,11 @@ mod symbols;
mod type_foldable;
mod type_visitable;
#[proc_macro]
pub fn current_rustc_version(input: TokenStream) -> TokenStream {
current_version::current_version(input)
}
#[proc_macro]
pub fn rustc_queries(input: TokenStream) -> TokenStream {
query::rustc_queries(input)

View File

@ -16,7 +16,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE};
use rustc_session::lint::{BuiltinLintDiagnostics, Level, Lint, LintBuffer};
use rustc_session::parse::feature_err_issue;
use rustc_session::Session;
use rustc_session::{RustcVersion, Session};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use std::num::NonZeroU32;
@ -129,11 +129,6 @@ pub fn deprecation_in_effect(depr: &Deprecation) -> bool {
let is_since_rustc_version = depr.is_since_rustc_version;
let since = depr.since.as_ref().map(Symbol::as_str);
fn parse_version(ver: &str) -> Vec<u32> {
// We ignore non-integer components of the version (e.g., "nightly").
ver.split(|c| c == '.' || c == '-').flat_map(|s| s.parse()).collect()
}
if !is_since_rustc_version {
// The `since` field doesn't have semantic purpose without `#![staged_api]`.
return true;
@ -144,16 +139,18 @@ pub fn deprecation_in_effect(depr: &Deprecation) -> bool {
return false;
}
if let Some(rustc) = option_env!("CFG_RELEASE") {
let since: Vec<u32> = parse_version(&since);
let rustc: Vec<u32> = parse_version(rustc);
// We simply treat invalid `since` attributes as relating to a previous
// Rust version, thus always displaying the warning.
if since.len() != 3 {
return true;
}
return since <= rustc;
// We ignore non-integer components of the version (e.g., "nightly").
let since: Vec<u16> =
since.split(|c| c == '.' || c == '-').flat_map(|s| s.parse()).collect();
// We simply treat invalid `since` attributes as relating to a previous
// Rust version, thus always displaying the warning.
if since.len() != 3 {
return true;
}
let rustc = RustcVersion::CURRENT;
return since.as_slice() <= &[rustc.major, rustc.minor, rustc.patch];
};
// Assume deprecation is in effect if "since" field is missing

View File

@ -440,8 +440,6 @@ where
);
if let Some(key) = Q::Key::recover(tcx, &dep_node) {
#[cfg(debug_assertions)]
let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered();
force_query(query, QueryCtxt::new(tcx), key, dep_node);
true
} else {

View File

@ -149,7 +149,6 @@ impl<D: Deps> DepGraph<D> {
DepNode { kind: D::DEP_KIND_RED, hash: Fingerprint::ZERO.into() },
EdgesVec::new(),
None,
false,
);
assert_eq!(red_node_index, DepNodeIndex::FOREVER_RED_NODE);
match red_node_prev_index_and_color {
@ -373,8 +372,6 @@ impl<D: Deps> DepGraphData<D> {
let current_fingerprint =
hash_result.map(|f| dcx.with_stable_hashing_context(|mut hcx| f(&mut hcx, &result)));
let print_status = cfg!(debug_assertions) && dcx.sess().opts.unstable_opts.dep_tasks;
// Intern the new `DepNode`.
let (dep_node_index, prev_and_color) = self.current.intern_node(
dcx.profiler(),
@ -382,7 +379,6 @@ impl<D: Deps> DepGraphData<D> {
key,
edges,
current_fingerprint,
print_status,
);
hashing_timer.finish_with_query_invocation_id(dep_node_index.into());
@ -589,8 +585,6 @@ impl<D: Deps> DepGraph<D> {
cx.with_stable_hashing_context(|mut hcx| hash_result(&mut hcx, result))
});
let print_status = cfg!(debug_assertions) && cx.sess().opts.unstable_opts.dep_tasks;
// Intern the new `DepNode` with the dependencies up-to-now.
let (dep_node_index, prev_and_color) = data.current.intern_node(
cx.profiler(),
@ -598,7 +592,6 @@ impl<D: Deps> DepGraph<D> {
node,
edges,
current_fingerprint,
print_status,
);
hashing_timer.finish_with_query_invocation_id(dep_node_index.into());
@ -1219,20 +1212,13 @@ impl<D: Deps> CurrentDepGraph<D> {
key: DepNode,
edges: EdgesVec,
fingerprint: Option<Fingerprint>,
print_status: bool,
) -> (DepNodeIndex, Option<(SerializedDepNodeIndex, DepNodeColor)>) {
let print_status = cfg!(debug_assertions) && print_status;
// Get timer for profiling `DepNode` interning
let _node_intern_timer =
self.node_intern_event_id.map(|eid| profiler.generic_activity_with_event_id(eid));
if let Some(prev_index) = prev_graph.node_to_index_opt(&key) {
let get_dep_node_index = |color, fingerprint| {
if print_status {
eprintln!("[task::{color:}] {key:?}");
}
let get_dep_node_index = |fingerprint| {
let mut prev_index_to_index = self.prev_index_to_index.lock();
let dep_node_index = match prev_index_to_index[prev_index] {
@ -1256,12 +1242,12 @@ impl<D: Deps> CurrentDepGraph<D> {
if fingerprint == prev_graph.fingerprint_by_index(prev_index) {
// This is a green node: it existed in the previous compilation,
// its query was re-executed, and it has the same result as before.
let dep_node_index = get_dep_node_index("green", fingerprint);
let dep_node_index = get_dep_node_index(fingerprint);
(dep_node_index, Some((prev_index, DepNodeColor::Green(dep_node_index))))
} else {
// This is a red node: it existed in the previous compilation, its query
// was re-executed, but it has a different result from before.
let dep_node_index = get_dep_node_index("red", fingerprint);
let dep_node_index = get_dep_node_index(fingerprint);
(dep_node_index, Some((prev_index, DepNodeColor::Red)))
}
} else {
@ -1269,14 +1255,10 @@ impl<D: Deps> CurrentDepGraph<D> {
// session, its query was re-executed, but it doesn't compute a result hash
// (i.e. it represents a `no_hash` query), so we have no way of determining
// whether or not the result was the same as before.
let dep_node_index = get_dep_node_index("unknown", Fingerprint::ZERO);
let dep_node_index = get_dep_node_index(Fingerprint::ZERO);
(dep_node_index, Some((prev_index, DepNodeColor::Red)))
}
} else {
if print_status {
eprintln!("[task::new] {key:?}");
}
let fingerprint = fingerprint.unwrap_or(Fingerprint::ZERO);
// This is a new node: it didn't exist in the previous compilation session.

View File

@ -9,14 +9,13 @@ use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
use crate::{lint, HashStableContext};
use crate::{EarlyErrorHandler, Session};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
use rustc_target::abi::Align;
use rustc_target::spec::LinkSelfContainedComponents;
use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, SplitDebuginfo};
use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS};
use crate::parse::{CrateCheckConfig, CrateConfig};
use rustc_feature::UnstableFeatures;
use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
use rustc_span::source_map::{FileName, FilePathMapping};
@ -1248,8 +1247,8 @@ pub const fn default_lib_output() -> CrateType {
CrateType::Rlib
}
fn default_configuration(sess: &Session) -> CrateConfig {
// NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below.
fn default_configuration(sess: &Session) -> Cfg<Symbol> {
// NOTE: This should be kept in sync with `CheckCfg::<Symbol>::fill_well_known` below.
let end = &sess.target.endian;
let arch = &sess.target.arch;
let wordsz = sess.target.pointer_width.to_string();
@ -1265,7 +1264,7 @@ fn default_configuration(sess: &Session) -> CrateConfig {
sess.emit_fatal(err);
});
let mut ret = CrateConfig::default();
let mut ret = Cfg::default();
ret.reserve(7); // the minimum number of insertions
// Target bindings.
ret.insert((sym::target_os, Some(Symbol::intern(os))));
@ -1358,15 +1357,17 @@ fn default_configuration(sess: &Session) -> CrateConfig {
ret
}
/// Converts the crate `cfg!` configuration from `String` to `Symbol`.
/// `rustc_interface::interface::Config` accepts this in the compiler configuration,
/// but the symbol interner is not yet set up then, so we must convert it later.
pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
}
/// The parsed `--cfg` options that define the compilation environment of the
/// crate, used to drive conditional compilation. `T` is always `String` or
/// `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
/// relating to `--cfg`.
pub type Cfg<T> = FxIndexSet<(T, Option<T>)>;
/// The parsed `--check-cfg` options
pub struct CheckCfg<T = String> {
/// The parsed `--check-cfg` options. The `<T>` structure is similar to `Cfg`.
pub struct CheckCfg<T> {
/// Is well known names activated
pub exhaustive_names: bool,
/// Is well known values activated
@ -1385,8 +1386,8 @@ impl<T> Default for CheckCfg<T> {
}
}
impl<T> CheckCfg<T> {
fn map_data<O: Eq + Hash>(self, f: impl Fn(T) -> O) -> CheckCfg<O> {
impl CheckCfg<String> {
pub fn intern(self) -> CheckCfg<Symbol> {
CheckCfg {
exhaustive_names: self.exhaustive_names,
exhaustive_values: self.exhaustive_values,
@ -1395,10 +1396,10 @@ impl<T> CheckCfg<T> {
.into_iter()
.map(|(name, values)| {
(
f(name),
Symbol::intern(&name),
match values {
ExpectedValues::Some(values) => ExpectedValues::Some(
values.into_iter().map(|b| b.map(|b| f(b))).collect(),
values.into_iter().map(|b| b.map(|b| Symbol::intern(&b))).collect(),
),
ExpectedValues::Any => ExpectedValues::Any,
},
@ -1441,14 +1442,7 @@ impl<'a, T: Eq + Hash + Copy + 'a> Extend<&'a T> for ExpectedValues<T> {
}
}
/// Converts the crate `--check-cfg` options from `String` to `Symbol`.
/// `rustc_interface::interface::Config` accepts this in the compiler configuration,
/// but the symbol interner is not yet set up then, so we must convert it later.
pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
cfg.map_data(|s| Symbol::intern(&s))
}
impl CrateCheckConfig {
impl CheckCfg<Symbol> {
pub fn fill_well_known(&mut self, current_target: &Target) {
if !self.exhaustive_values && !self.exhaustive_names {
return;
@ -1588,7 +1582,13 @@ impl CrateCheckConfig {
}
}
pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
pub fn build_configuration(sess: &Session, user_cfg: Cfg<String>) -> Cfg<Symbol> {
// 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
// some default and generated configuration items.
let default_cfg = default_configuration(sess);

View File

@ -43,6 +43,9 @@ pub mod output;
pub use getopts;
mod version;
pub use version::RustcVersion;
fluent_messages! { "../messages.ftl" }
/// Requirements for a `StableHashingContext` to be used in this crate.

View File

@ -1492,9 +1492,6 @@ options! {
dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
"in dep-info output, omit targets for tracking dependencies of the dep-info files \
themselves (default: no)"),
dep_tasks: bool = (false, parse_bool, [UNTRACKED],
"print tasks that execute and the color their dep node gets (requires debug build) \
(default: no)"),
dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
"emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) \
(default: no)"),

View File

@ -1,7 +1,7 @@
//! Contains `ParseSess` which holds state living beyond what one `Parser` might.
//! It also serves as an input to the parser itself.
use crate::config::CheckCfg;
use crate::config::{Cfg, CheckCfg};
use crate::errors::{
CliFeatureDiagnosticHelp, FeatureDiagnosticForIssue, FeatureDiagnosticHelp, FeatureGateError,
};
@ -9,7 +9,7 @@ use crate::lint::{
builtin::UNSTABLE_SYNTAX_PRE_EXPANSION, BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId,
};
use rustc_ast::node_id::NodeId;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc};
use rustc_errors::{emitter::SilentEmitter, Handler};
use rustc_errors::{
@ -25,11 +25,6 @@ use rustc_span::{Span, Symbol};
use rustc_ast::attr::AttrIdGenerator;
use std::str;
/// The set of keys (and, optionally, values) that define the compilation
/// environment of the crate, used to drive conditional compilation.
pub type CrateConfig = FxIndexSet<(Symbol, Option<Symbol>)>;
pub type CrateCheckConfig = CheckCfg<Symbol>;
/// Collected spans during parsing for places where a certain feature was
/// used and should be feature gated accordingly in `check_crate`.
#[derive(Default)]
@ -193,8 +188,8 @@ pub fn add_feature_diagnostics_for_issue(
pub struct ParseSess {
pub span_diagnostic: Handler,
pub unstable_features: UnstableFeatures,
pub config: CrateConfig,
pub check_config: CrateCheckConfig,
pub config: Cfg<Symbol>,
pub check_config: CheckCfg<Symbol>,
pub edition: Edition,
/// Places where raw identifiers were used. This is used to avoid complaining about idents
/// clashing with keywords in new editions.
@ -237,8 +232,8 @@ impl ParseSess {
Self {
span_diagnostic: handler,
unstable_features: UnstableFeatures::from_environment(None),
config: FxIndexSet::default(),
check_config: CrateCheckConfig::default(),
config: Cfg::default(),
check_config: CheckCfg::default(),
edition: ExpnId::root().expn_data().edition,
raw_identifier_spans: Default::default(),
bad_unicode_identifiers: Lock::new(Default::default()),

View File

@ -0,0 +1,19 @@
use std::fmt::{self, Display};
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(HashStable_Generic)]
pub struct RustcVersion {
pub major: u16,
pub minor: u16,
pub patch: u16,
}
impl RustcVersion {
pub const CURRENT: Self = current_rustc_version!(env!("CFG_RELEASE"));
}
impl Display for RustcVersion {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
}
}

View File

@ -2691,8 +2691,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if let DefKind::Trait = tcx.def_kind(item_def_id)
&& !visible_item
{
// FIXME(estebank): extend this to search for all the types that do
// implement this trait and list them.
err.note(format!(
"`{short_item_name}` is a \"sealed trait\", because to implement \
it you also need to implement `{}`, which is not accessible; \
@ -2700,6 +2698,34 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
types that already implement it",
with_no_trimmed_paths!(tcx.def_path_str(def_id)),
));
let impls_of = tcx.trait_impls_of(def_id);
let impls = impls_of
.non_blanket_impls()
.values()
.flatten()
.chain(impls_of.blanket_impls().iter())
.collect::<Vec<_>>();
if !impls.is_empty() {
let len = impls.len();
let mut types = impls.iter()
.map(|t| with_no_trimmed_paths!(format!(
" {}",
tcx.type_of(*t).instantiate_identity(),
)))
.collect::<Vec<_>>();
let post = if types.len() > 9 {
types.truncate(8);
format!("\nand {} others", len - 8)
} else {
String::new()
};
err.help(format!(
"the following type{} implement{} the trait:\n{}{post}",
pluralize!(len),
if len == 1 { "s" } else { "" },
types.join("\n"),
));
}
}
}
} else {

View File

@ -426,14 +426,18 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
return;
}
let trait_ref = trait_predicate.to_poly_trait_ref();
let (post_message, pre_message, type_def) = self
let (post_message, pre_message, type_def, file_note) = self
.get_parent_trait_ref(obligation.cause.code())
.map(|(t, s)| {
let (t, file) = self.tcx.short_ty_string(t);
(
format!(" in `{t}`"),
format!("within `{t}`, "),
s.map(|s| (format!("within this `{t}`"), s)),
file.map(|file| format!(
"the full trait has been written to '{}'",
file.display(),
))
)
})
.unwrap_or_default();
@ -541,6 +545,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.emit();
return;
}
file_note.map(|note| err.note(note));
if let Some(s) = label {
// If it has a custom `#[rustc_on_unimplemented]`
// error message, let's display it as the label!
@ -1094,7 +1100,7 @@ pub(super) trait InferCtxtPrivExt<'tcx> {
fn get_parent_trait_ref(
&self,
code: &ObligationCauseCode<'tcx>,
) -> Option<(String, Option<Span>)>;
) -> Option<(Ty<'tcx>, Option<Span>)>;
/// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
/// with the same path as `trait_ref`, a help message about
@ -1943,7 +1949,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn get_parent_trait_ref(
&self,
code: &ObligationCauseCode<'tcx>,
) -> Option<(String, Option<Span>)> {
) -> Option<(Ty<'tcx>, Option<Span>)> {
match code {
ObligationCauseCode::BuiltinDerivedObligation(data) => {
let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
@ -1953,7 +1959,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let ty = parent_trait_ref.skip_binder().self_ty();
let span = TyCategory::from_ty(self.tcx, ty)
.map(|(_, def_id)| self.tcx.def_span(def_id));
Some((ty.to_string(), span))
Some((ty, span))
}
}
}

View File

@ -19,6 +19,9 @@ pub(super) fn sanity_check_layout<'tcx>(
if layout.size.bytes() % layout.align.abi.bytes() != 0 {
bug!("size is not a multiple of align, in the following layout:\n{layout:#?}");
}
if layout.size.bytes() >= cx.tcx.data_layout.obj_size_bound() {
bug!("size is too large, in the following layout:\n{layout:#?}");
}
if !cfg!(debug_assertions) {
// Stop here, the rest is kind of expensive.

View File

@ -0,0 +1,157 @@
//! # Safe(r) wrappers around Windows API functions.
//!
//! This module contains fairly thin wrappers around Windows API functions,
//! aimed at centralising safety instead of having unsafe blocks spread
//! throughout higher level code. This makes it much easier to audit FFI safety.
//!
//! Not all functions can be made completely safe without more context but in
//! such cases we should still endeavour to reduce the caller's burden of safety
//! as much as possible.
//!
//! ## Guidelines for wrappers
//!
//! Items here should be named similarly to their raw Windows API name, except
//! that they follow Rust's case conventions. E.g. function names are
//! lower_snake_case. The idea here is that it should be easy for a Windows
//! C/C++ programmer to identify the underlying function that's being wrapped
//! while not looking too out of place in Rust code.
//!
//! Every use of an `unsafe` block must have a related SAFETY comment, even if
//! it's trivially safe (for example, see `get_last_error`). Public unsafe
//! functions must document what the caller has to do to call them safely.
//!
//! Avoid unchecked `as` casts. For integers, either assert that the integer
//! is in range or use `try_into` instead. For pointers, prefer to use
//! `ptr.cast::<Type>()` when possible.
//!
//! This module must only depend on core and not on std types as the eventual
//! hope is to have std depend on sys and not the other way around.
//! However, some amount of glue code may currently be necessary so such code
//! should go in sys/windows/mod.rs rather than here. See `IoResult` as an example.
use core::ffi::c_void;
use core::ptr::addr_of;
use super::c;
/// Helper method for getting the size of `T` as a u32.
/// Errors at compile time if the size would overflow.
///
/// While a type larger than u32::MAX is unlikely, it is possible if only because of a bug.
/// However, one key motivation for this function is to avoid the temptation to
/// use frequent `as` casts. This is risky because they are too powerful.
/// For example, the following will compile today:
///
/// `std::mem::size_of::<u64> as u32`
///
/// Note that `size_of` is never actually called, instead a function pointer is
/// converted to a `u32`. Clippy would warn about this but, alas, it's not run
/// on the standard library.
const fn win32_size_of<T: Sized>() -> u32 {
// Const assert that the size is less than u32::MAX.
// Uses a trait to workaround restriction on using generic types in inner items.
trait Win32SizeOf: Sized {
const WIN32_SIZE_OF: u32 = {
let size = core::mem::size_of::<Self>();
assert!(size <= u32::MAX as usize);
size as u32
};
}
impl<T: Sized> Win32SizeOf for T {}
T::WIN32_SIZE_OF
}
/// The `SetFileInformationByHandle` function takes a generic parameter by
/// making the user specify the type (class), a pointer to the data and its
/// size. This trait allows attaching that information to a Rust type so that
/// [`set_file_information_by_handle`] can be called safely.
///
/// This trait is designed so that it can support variable sized types.
/// However, currently Rust's std only uses fixed sized structures.
///
/// # Safety
///
/// * `as_ptr` must return a pointer to memory that is readable up to `size` bytes.
/// * `CLASS` must accurately reflect the type pointed to by `as_ptr`. E.g.
/// the `FILE_BASIC_INFO` structure has the class `FileBasicInfo`.
pub unsafe trait SetFileInformation {
/// The type of information to set.
const CLASS: i32;
/// A pointer to the file information to set.
fn as_ptr(&self) -> *const c_void;
/// The size of the type pointed to by `as_ptr`.
fn size(&self) -> u32;
}
/// Helper trait for implementing `SetFileInformation` for statically sized types.
unsafe trait SizedSetFileInformation: Sized {
const CLASS: i32;
}
unsafe impl<T: SizedSetFileInformation> SetFileInformation for T {
const CLASS: i32 = T::CLASS;
fn as_ptr(&self) -> *const c_void {
addr_of!(*self).cast::<c_void>()
}
fn size(&self) -> u32 {
win32_size_of::<Self>()
}
}
// SAFETY: FILE_BASIC_INFO, FILE_END_OF_FILE_INFO, FILE_ALLOCATION_INFO,
// FILE_DISPOSITION_INFO, FILE_DISPOSITION_INFO_EX and FILE_IO_PRIORITY_HINT_INFO
// are all plain `repr(C)` structs that only contain primitive types.
// The given information classes correctly match with the struct.
unsafe impl SizedSetFileInformation for c::FILE_BASIC_INFO {
const CLASS: i32 = c::FileBasicInfo;
}
unsafe impl SizedSetFileInformation for c::FILE_END_OF_FILE_INFO {
const CLASS: i32 = c::FileEndOfFileInfo;
}
unsafe impl SizedSetFileInformation for c::FILE_ALLOCATION_INFO {
const CLASS: i32 = c::FileAllocationInfo;
}
unsafe impl SizedSetFileInformation for c::FILE_DISPOSITION_INFO {
const CLASS: i32 = c::FileDispositionInfo;
}
unsafe impl SizedSetFileInformation for c::FILE_DISPOSITION_INFO_EX {
const CLASS: i32 = c::FileDispositionInfoEx;
}
unsafe impl SizedSetFileInformation for c::FILE_IO_PRIORITY_HINT_INFO {
const CLASS: i32 = c::FileIoPriorityHintInfo;
}
#[inline]
pub fn set_file_information_by_handle<T: SetFileInformation>(
handle: c::HANDLE,
info: &T,
) -> Result<(), WinError> {
unsafe fn set_info(
handle: c::HANDLE,
class: i32,
info: *const c_void,
size: u32,
) -> Result<(), WinError> {
let result = c::SetFileInformationByHandle(handle, class, info, size);
(result != 0).then_some(()).ok_or_else(|| get_last_error())
}
// SAFETY: The `SetFileInformation` trait ensures that this is safe.
unsafe { set_info(handle, T::CLASS, info.as_ptr(), info.size()) }
}
/// Gets the error from the last function.
/// This must be called immediately after the function that sets the error to
/// avoid the risk of another function overwriting it.
pub fn get_last_error() -> WinError {
// SAFETY: This just returns a thread-local u32 and has no other effects.
unsafe { WinError { code: c::GetLastError() } }
}
/// An error code as returned by [`get_last_error`].
///
/// This is usually a 16-bit Win32 error code but may be a 32-bit HRESULT or NTSTATUS.
/// Check the documentation of the Windows API function being called for expected errors.
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct WinError {
pub code: u32,
}

View File

@ -2224,6 +2224,7 @@ Windows.Win32.Storage.FileSystem.FILE_ACCESS_RIGHTS
Windows.Win32.Storage.FileSystem.FILE_ADD_FILE
Windows.Win32.Storage.FileSystem.FILE_ADD_SUBDIRECTORY
Windows.Win32.Storage.FileSystem.FILE_ALL_ACCESS
Windows.Win32.Storage.FileSystem.FILE_ALLOCATION_INFO
Windows.Win32.Storage.FileSystem.FILE_APPEND_DATA
Windows.Win32.Storage.FileSystem.FILE_ATTRIBUTE_ARCHIVE
Windows.Win32.Storage.FileSystem.FILE_ATTRIBUTE_COMPRESSED
@ -2284,6 +2285,7 @@ Windows.Win32.Storage.FileSystem.FILE_GENERIC_READ
Windows.Win32.Storage.FileSystem.FILE_GENERIC_WRITE
Windows.Win32.Storage.FileSystem.FILE_ID_BOTH_DIR_INFO
Windows.Win32.Storage.FileSystem.FILE_INFO_BY_HANDLE_CLASS
Windows.Win32.Storage.FileSystem.FILE_IO_PRIORITY_HINT_INFO
Windows.Win32.Storage.FileSystem.FILE_LIST_DIRECTORY
Windows.Win32.Storage.FileSystem.FILE_NAME_NORMALIZED
Windows.Win32.Storage.FileSystem.FILE_NAME_OPENED

View File

@ -3129,6 +3129,16 @@ impl ::core::clone::Clone for FILETIME {
pub type FILE_ACCESS_RIGHTS = u32;
pub const FILE_ADD_FILE: FILE_ACCESS_RIGHTS = 2u32;
pub const FILE_ADD_SUBDIRECTORY: FILE_ACCESS_RIGHTS = 4u32;
#[repr(C)]
pub struct FILE_ALLOCATION_INFO {
pub AllocationSize: i64,
}
impl ::core::marker::Copy for FILE_ALLOCATION_INFO {}
impl ::core::clone::Clone for FILE_ALLOCATION_INFO {
fn clone(&self) -> Self {
*self
}
}
pub const FILE_ALL_ACCESS: FILE_ACCESS_RIGHTS = 2032127u32;
pub const FILE_APPEND_DATA: FILE_ACCESS_RIGHTS = 4u32;
pub const FILE_ATTRIBUTE_ARCHIVE: FILE_FLAGS_AND_ATTRIBUTES = 32u32;
@ -3270,6 +3280,16 @@ impl ::core::clone::Clone for FILE_ID_BOTH_DIR_INFO {
}
}
pub type FILE_INFO_BY_HANDLE_CLASS = i32;
#[repr(C)]
pub struct FILE_IO_PRIORITY_HINT_INFO {
pub PriorityHint: PRIORITY_HINT,
}
impl ::core::marker::Copy for FILE_IO_PRIORITY_HINT_INFO {}
impl ::core::clone::Clone for FILE_IO_PRIORITY_HINT_INFO {
fn clone(&self) -> Self {
*self
}
}
pub const FILE_LIST_DIRECTORY: FILE_ACCESS_RIGHTS = 1u32;
pub const FILE_NAME_NORMALIZED: GETFINALPATHNAMEBYHANDLE_FLAGS = 0u32;
pub const FILE_NAME_OPENED: GETFINALPATHNAMEBYHANDLE_FLAGS = 8u32;
@ -3775,6 +3795,7 @@ pub const PIPE_SERVER_END: NAMED_PIPE_MODE = 1u32;
pub const PIPE_TYPE_BYTE: NAMED_PIPE_MODE = 0u32;
pub const PIPE_TYPE_MESSAGE: NAMED_PIPE_MODE = 4u32;
pub const PIPE_WAIT: NAMED_PIPE_MODE = 0u32;
pub type PRIORITY_HINT = i32;
pub type PROCESSOR_ARCHITECTURE = u16;
pub type PROCESS_CREATION_FLAGS = u32;
#[repr(C)]

View File

@ -19,7 +19,7 @@ use crate::thread;
use core::ffi::c_void;
use super::path::maybe_verbatim;
use super::to_u16s;
use super::{api, to_u16s, IoResult};
pub struct File {
handle: Handle,
@ -123,7 +123,7 @@ impl Iterator for ReadDir {
let mut wfd = mem::zeroed();
loop {
if c::FindNextFileW(self.handle.0, &mut wfd) == 0 {
if c::GetLastError() == c::ERROR_NO_MORE_FILES {
if api::get_last_error().code == c::ERROR_NO_MORE_FILES {
return None;
} else {
return Some(Err(Error::last_os_error()));
@ -318,17 +318,8 @@ impl File {
}
pub fn truncate(&self, size: u64) -> io::Result<()> {
let mut info = c::FILE_END_OF_FILE_INFO { EndOfFile: size as c::LARGE_INTEGER };
let size = mem::size_of_val(&info);
cvt(unsafe {
c::SetFileInformationByHandle(
self.handle.as_raw_handle(),
c::FileEndOfFileInfo,
&mut info as *mut _ as *mut _,
size as c::DWORD,
)
})?;
Ok(())
let info = c::FILE_END_OF_FILE_INFO { EndOfFile: size as i64 };
api::set_file_information_by_handle(self.handle.as_raw_handle(), &info).io_result()
}
#[cfg(not(target_vendor = "uwp"))]
@ -565,23 +556,14 @@ impl File {
}
pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
let mut info = c::FILE_BASIC_INFO {
let info = c::FILE_BASIC_INFO {
CreationTime: 0,
LastAccessTime: 0,
LastWriteTime: 0,
ChangeTime: 0,
FileAttributes: perm.attrs,
};
let size = mem::size_of_val(&info);
cvt(unsafe {
c::SetFileInformationByHandle(
self.handle.as_raw_handle(),
c::FileBasicInfo,
&mut info as *mut _ as *mut _,
size as c::DWORD,
)
})?;
Ok(())
api::set_file_information_by_handle(self.handle.as_raw_handle(), &info).io_result()
}
pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
@ -641,38 +623,20 @@ impl File {
/// If the operation is not supported for this filesystem or OS version
/// then errors will be `ERROR_NOT_SUPPORTED` or `ERROR_INVALID_PARAMETER`.
fn posix_delete(&self) -> io::Result<()> {
let mut info = c::FILE_DISPOSITION_INFO_EX {
let info = c::FILE_DISPOSITION_INFO_EX {
Flags: c::FILE_DISPOSITION_FLAG_DELETE
| c::FILE_DISPOSITION_FLAG_POSIX_SEMANTICS
| c::FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE,
};
let size = mem::size_of_val(&info);
cvt(unsafe {
c::SetFileInformationByHandle(
self.handle.as_raw_handle(),
c::FileDispositionInfoEx,
&mut info as *mut _ as *mut _,
size as c::DWORD,
)
})?;
Ok(())
api::set_file_information_by_handle(self.handle.as_raw_handle(), &info).io_result()
}
/// Delete a file using win32 semantics. The file won't actually be deleted
/// until all file handles are closed. However, marking a file for deletion
/// will prevent anyone from opening a new handle to the file.
fn win32_delete(&self) -> io::Result<()> {
let mut info = c::FILE_DISPOSITION_INFO { DeleteFile: c::TRUE as _ };
let size = mem::size_of_val(&info);
cvt(unsafe {
c::SetFileInformationByHandle(
self.handle.as_raw_handle(),
c::FileDispositionInfo,
&mut info as *mut _ as *mut _,
size as c::DWORD,
)
})?;
Ok(())
let info = c::FILE_DISPOSITION_INFO { DeleteFile: c::TRUE as _ };
api::set_file_information_by_handle(self.handle.as_raw_handle(), &info).io_result()
}
/// Fill the given buffer with as many directory entries as will fit.

View File

@ -44,6 +44,18 @@ cfg_if::cfg_if! {
}
}
mod api;
/// Map a Result<T, WinError> to io::Result<T>.
trait IoResult<T> {
fn io_result(self) -> crate::io::Result<T>;
}
impl<T> IoResult<T> for Result<T, api::WinError> {
fn io_result(self) -> crate::io::Result<T> {
self.map_err(|e| crate::io::Error::from_raw_os_error(e.code as i32))
}
}
// SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {
@ -241,11 +253,11 @@ where
// not an actual error.
c::SetLastError(0);
let k = match f1(buf.as_mut_ptr().cast::<u16>(), n as c::DWORD) {
0 if c::GetLastError() == 0 => 0,
0 if api::get_last_error().code == 0 => 0,
0 => return Err(crate::io::Error::last_os_error()),
n => n,
} as usize;
if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER {
if k == n && api::get_last_error().code == c::ERROR_INSUFFICIENT_BUFFER {
n = n.saturating_mul(2).min(c::DWORD::MAX as usize);
} else if k > n {
n = k;

View File

@ -17,10 +17,10 @@ use crate::ptr;
use crate::slice;
use crate::sys::{c, cvt};
use super::to_u16s;
use super::{api, to_u16s};
pub fn errno() -> i32 {
unsafe { c::GetLastError() as i32 }
api::get_last_error().code as i32
}
/// Gets a detailed string description for the given error number.
@ -336,7 +336,7 @@ fn home_dir_crt() -> Option<PathBuf> {
super::fill_utf16_buf(
|buf, mut sz| {
match c::GetUserProfileDirectoryW(token, buf, &mut sz) {
0 if c::GetLastError() != c::ERROR_INSUFFICIENT_BUFFER => 0,
0 if api::get_last_error().code != c::ERROR_INSUFFICIENT_BUFFER => 0,
0 => sz,
_ => sz - 1, // sz includes the null terminator
}

View File

@ -3,6 +3,8 @@
use crate::sys::c;
use crate::thread;
use super::api;
pub struct Handler;
impl Handler {
@ -10,7 +12,7 @@ impl Handler {
// This API isn't available on XP, so don't panic in that case and just
// pray it works out ok.
if c::SetThreadStackGuarantee(&mut 0x5000) == 0
&& c::GetLastError() as u32 != c::ERROR_CALL_NOT_IMPLEMENTED as u32
&& api::get_last_error().code != c::ERROR_CALL_NOT_IMPLEMENTED
{
panic!("failed to reserve stack space for exception handling");
}

View File

@ -9,6 +9,7 @@ use crate::str;
use crate::sys::c;
use crate::sys::cvt;
use crate::sys::handle::Handle;
use crate::sys::windows::api;
use core::str::utf8_char_width;
#[cfg(test)]
@ -369,7 +370,7 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [MaybeUninit<u16>]) -> io::Result<usiz
// ReadConsoleW returns success with ERROR_OPERATION_ABORTED for Ctrl-C or Ctrl-Break.
// Explicitly check for that case here and try again.
if amount == 0 && unsafe { c::GetLastError() } == c::ERROR_OPERATION_ABORTED {
if amount == 0 && api::get_last_error().code == c::ERROR_OPERATION_ABORTED {
continue;
}
break;

View File

@ -139,7 +139,7 @@ fn do_mumble_frotz() {}
```bash
# This turns on checking for feature values, but not for condition names.
rustc --check-cfg 'configure(feature, values("zapping", "lasers"))' \
rustc --check-cfg 'cfg(feature, values("zapping", "lasers"))' \
--check-cfg 'cfg(any())' \
--cfg 'feature="zapping"' -Z unstable-options
```

View File

@ -255,7 +255,7 @@ pub(crate) fn create_config(
interface::Config {
opts: sessopts,
crate_cfg: interface::parse_cfgspecs(handler, cfgs),
crate_cfg: interface::parse_cfg(handler, cfgs),
crate_check_cfg: interface::parse_check_cfg(handler, check_cfgs),
input,
output_file: None,

View File

@ -92,7 +92,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
cfgs.push("doctest".to_owned());
let config = interface::Config {
opts: sessopts,
crate_cfg: interface::parse_cfgspecs(&early_error_handler, cfgs),
crate_cfg: interface::parse_cfg(&early_error_handler, cfgs),
crate_check_cfg: interface::parse_check_cfg(
&early_error_handler,
options.check_cfgs.clone(),

View File

@ -48,13 +48,14 @@ use std::str;
use std::string::ToString;
use askama::Template;
use rustc_attr::{ConstStability, Deprecation, Since, StabilityLevel, CURRENT_RUSTC_VERSION};
use rustc_attr::{ConstStability, Deprecation, Since, StabilityLevel};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_hir::Mutability;
use rustc_middle::middle::stability;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::RustcVersion;
use rustc_span::{
symbol::{sym, Symbol},
BytePos, FileName, RealFileName,
@ -979,7 +980,7 @@ fn render_stability_since_raw_with_extra(
fn since_to_string(since: &Since) -> Option<String> {
match since {
Since::Version(since) => Some(since.to_string()),
Since::Current => Some(CURRENT_RUSTC_VERSION.to_owned()),
Since::Current => Some(RustcVersion::CURRENT.to_string()),
Since::Err => None,
}
}

View File

@ -5,7 +5,7 @@
use crate::msrvs::Msrv;
use hir::LangItem;
use rustc_attr::{Since, CURRENT_RUSTC_VERSION};
use rustc_attr::Since;
use rustc_const_eval::transform::check_consts::ConstCx;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
@ -372,23 +372,16 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool {
// as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262.
let const_stab_rust_version = match since {
Since::Version(version) => RustcVersion::new(
u32::from(version.major),
u32::from(version.minor),
u32::from(version.patch),
),
Since::Current => {
// HACK(nilstrieb): CURRENT_RUSTC_VERSION can return versions like 1.66.0-dev.
// `rustc-semver` doesn't accept the `-dev` version number so we have to strip it off.
let short_version = CURRENT_RUSTC_VERSION.split('-').next().unwrap();
RustcVersion::parse(short_version).unwrap_or_else(|err| {
panic!("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted: `{CURRENT_RUSTC_VERSION}`, {err:?}")
})
},
Since::Version(version) => version,
Since::Current => rustc_session::RustcVersion::CURRENT,
Since::Err => return false,
};
msrv.meets(const_stab_rust_version)
msrv.meets(RustcVersion::new(
u32::from(const_stab_rust_version.major),
u32::from(const_stab_rust_version.minor),
u32::from(const_stab_rust_version.patch),
))
} else {
// Unstable const fn with the feature enabled.
msrv.current().is_none()

View File

@ -0,0 +1,2 @@
error: invalid `--check-cfg` argument: `cfg(any(),values())` (`values()` cannot be specified before the names)

View File

@ -6,7 +6,7 @@
// revisions: multiple_values_any not_empty_any not_empty_values_any
// revisions: values_any_missing_values values_any_before_ident ident_in_values_1
// revisions: ident_in_values_2 unknown_meta_item_1 unknown_meta_item_2 unknown_meta_item_3
// revisions: mixed_values_any mixed_any giberich
// revisions: mixed_values_any mixed_any any_values giberich unterminated
//
// compile-flags: -Z unstable-options
// [anything_else]compile-flags: --check-cfg=anything_else(...)
@ -29,6 +29,8 @@
// [unknown_meta_item_3]compile-flags: --check-cfg=cfg(foo,values(test()))
// [mixed_values_any]compile-flags: --check-cfg=cfg(foo,values("bar",any()))
// [mixed_any]compile-flags: --check-cfg=cfg(any(),values(any()))
// [any_values]compile-flags: --check-cfg=cfg(any(),values())
// [giberich]compile-flags: --check-cfg=cfg(...)
// [unterminated]compile-flags: --check-cfg=cfg(
fn main() {}

View File

@ -0,0 +1,2 @@
error: invalid `--check-cfg` argument: `cfg(` (expected `cfg(name, values("value1", "value2", ... "valueN"))`)

View File

@ -0,0 +1,18 @@
// build-fail
// compile-flags: --target i686-unknown-linux-gnu --crate-type lib
// needs-llvm-components: x86
#![feature(no_core, lang_items)]
#![allow(internal_features)]
#![no_std]
#![no_core]
// 0x7fffffff is fine, but after rounding up it becomes too big
#[repr(C, align(2))]
pub struct Example([u8; 0x7fffffff]);
pub fn lib(_x: Example) {} //~ERROR: too big for the current architecture
#[lang = "sized"]
pub trait Sized {}
#[lang = "copy"]
pub trait Copy: Sized {}

View File

@ -0,0 +1,8 @@
error: values of the type `Example` are too big for the current architecture
--> $DIR/too-big-with-padding.rs:13:1
|
LL | pub fn lib(_x: Example) {}
| ^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error

View File

@ -13,7 +13,43 @@ pub mod a {
}
}
struct S;
impl a::Sealed for S {} //~ ERROR the trait bound `S: Hidden` is not satisfied
pub mod c {
pub trait Sealed: self::d::Hidden {
fn foo() {}
}
struct X;
impl Sealed for X {}
impl self::d::Hidden for X {}
struct Y;
impl Sealed for Y {}
impl self::d::Hidden for Y {}
mod d {
pub trait Hidden {}
}
}
pub mod e {
pub trait Sealed: self::f::Hidden {
fn foo() {}
}
struct X;
impl self::f::Hidden for X {}
struct Y;
impl self::f::Hidden for Y {}
impl<T: self::f::Hidden> Sealed for T {}
mod f {
pub trait Hidden {}
}
}
struct S;
impl a::Sealed for S {} //~ ERROR the trait bound
impl c::Sealed for S {} //~ ERROR the trait bound
impl e::Sealed for S {} //~ ERROR the trait bound
fn main() {}

View File

@ -1,16 +1,50 @@
error[E0277]: the trait bound `S: Hidden` is not satisfied
--> $DIR/sealed-trait-local.rs:17:20
error[E0277]: the trait bound `S: b::Hidden` is not satisfied
--> $DIR/sealed-trait-local.rs:52:20
|
LL | impl a::Sealed for S {}
| ^ the trait `Hidden` is not implemented for `S`
| ^ the trait `b::Hidden` is not implemented for `S`
|
note: required by a bound in `Sealed`
note: required by a bound in `a::Sealed`
--> $DIR/sealed-trait-local.rs:3:23
|
LL | pub trait Sealed: self::b::Hidden {
| ^^^^^^^^^^^^^^^ required by this bound in `Sealed`
= note: `Sealed` is a "sealed trait", because to implement it you also need to implement `a::b::Hidden`, which is not accessible; this is usually done to force you to use one of the provided types that already implement it
= help: the following type implements the trait:
a::X
error: aborting due to previous error
error[E0277]: the trait bound `S: d::Hidden` is not satisfied
--> $DIR/sealed-trait-local.rs:53:20
|
LL | impl c::Sealed for S {}
| ^ the trait `d::Hidden` is not implemented for `S`
|
note: required by a bound in `c::Sealed`
--> $DIR/sealed-trait-local.rs:17:23
|
LL | pub trait Sealed: self::d::Hidden {
| ^^^^^^^^^^^^^^^ required by this bound in `Sealed`
= note: `Sealed` is a "sealed trait", because to implement it you also need to implement `c::d::Hidden`, which is not accessible; this is usually done to force you to use one of the provided types that already implement it
= help: the following types implement the trait:
c::X
c::Y
error[E0277]: the trait bound `S: f::Hidden` is not satisfied
--> $DIR/sealed-trait-local.rs:54:20
|
LL | impl e::Sealed for S {}
| ^ the trait `f::Hidden` is not implemented for `S`
|
note: required by a bound in `e::Sealed`
--> $DIR/sealed-trait-local.rs:35:23
|
LL | pub trait Sealed: self::f::Hidden {
| ^^^^^^^^^^^^^^^ required by this bound in `Sealed`
= note: `Sealed` is a "sealed trait", because to implement it you also need to implement `e::f::Hidden`, which is not accessible; this is usually done to force you to use one of the provided types that already implement it
= help: the following types implement the trait:
e::X
e::Y
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.