Auto merge of #97388 - Dylan-DPC:rollup-tfuc4tf, r=Dylan-DPC
Rollup of 5 pull requests Successful merges: - #95953 (Modify MIR building to drop repeat expressions with length zero) - #96913 (RFC3239: Implement `cfg(target)` - Part 2) - #97233 ([RFC 2011] Library code) - #97370 (Minor improvement on else-no-if diagnostic) - #97384 (Fix metadata stats.) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
fe9c64d0af
26 changed files with 680 additions and 115 deletions
|
@ -454,6 +454,15 @@ pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> {
|
||||||
sess.first_attr_value_str_by_name(attrs, sym::crate_name)
|
sess.first_attr_value_str_by_name(attrs, sym::crate_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Condition {
|
||||||
|
pub name: Symbol,
|
||||||
|
pub name_span: Span,
|
||||||
|
pub value: Option<Symbol>,
|
||||||
|
pub value_span: Option<Span>,
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
/// Tests if a cfg-pattern matches the cfg set
|
/// Tests if a cfg-pattern matches the cfg set
|
||||||
pub fn cfg_matches(
|
pub fn cfg_matches(
|
||||||
cfg: &ast::MetaItem,
|
cfg: &ast::MetaItem,
|
||||||
|
@ -462,70 +471,42 @@ pub fn cfg_matches(
|
||||||
features: Option<&Features>,
|
features: Option<&Features>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
eval_condition(cfg, sess, features, &mut |cfg| {
|
eval_condition(cfg, sess, features, &mut |cfg| {
|
||||||
try_gate_cfg(cfg, sess, features);
|
try_gate_cfg(cfg.name, cfg.span, sess, features);
|
||||||
let error = |span, msg| {
|
if let Some(names_valid) = &sess.check_config.names_valid {
|
||||||
sess.span_diagnostic.span_err(span, msg);
|
if !names_valid.contains(&cfg.name) {
|
||||||
true
|
sess.buffer_lint_with_diagnostic(
|
||||||
};
|
UNEXPECTED_CFGS,
|
||||||
if cfg.path.segments.len() != 1 {
|
cfg.span,
|
||||||
return error(cfg.path.span, "`cfg` predicate key must be an identifier");
|
lint_node_id,
|
||||||
}
|
"unexpected `cfg` condition name",
|
||||||
match &cfg.kind {
|
BuiltinLintDiagnostics::UnexpectedCfg((cfg.name, cfg.name_span), None),
|
||||||
MetaItemKind::List(..) => {
|
|
||||||
error(cfg.span, "unexpected parentheses after `cfg` predicate key")
|
|
||||||
}
|
|
||||||
MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
|
|
||||||
handle_errors(
|
|
||||||
sess,
|
|
||||||
lit.span,
|
|
||||||
AttrError::UnsupportedLiteral(
|
|
||||||
"literal in `cfg` predicate value must be a string",
|
|
||||||
lit.kind.is_bytestr(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
true
|
|
||||||
}
|
|
||||||
MetaItemKind::NameValue(..) | MetaItemKind::Word => {
|
|
||||||
let ident = cfg.ident().expect("multi-segment cfg predicate");
|
|
||||||
let name = ident.name;
|
|
||||||
let value = cfg.value_str();
|
|
||||||
if let Some(names_valid) = &sess.check_config.names_valid {
|
|
||||||
if !names_valid.contains(&name) {
|
|
||||||
sess.buffer_lint_with_diagnostic(
|
|
||||||
UNEXPECTED_CFGS,
|
|
||||||
cfg.span,
|
|
||||||
lint_node_id,
|
|
||||||
"unexpected `cfg` condition name",
|
|
||||||
BuiltinLintDiagnostics::UnexpectedCfg((name, ident.span), None),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(value) = value {
|
|
||||||
if let Some(values) = &sess.check_config.values_valid.get(&name) {
|
|
||||||
if !values.contains(&value) {
|
|
||||||
sess.buffer_lint_with_diagnostic(
|
|
||||||
UNEXPECTED_CFGS,
|
|
||||||
cfg.span,
|
|
||||||
lint_node_id,
|
|
||||||
"unexpected `cfg` condition value",
|
|
||||||
BuiltinLintDiagnostics::UnexpectedCfg(
|
|
||||||
(name, ident.span),
|
|
||||||
Some((value, cfg.name_value_literal_span().unwrap())),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sess.config.contains(&(name, value))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(value) = cfg.value {
|
||||||
|
if let Some(values) = &sess.check_config.values_valid.get(&cfg.name) {
|
||||||
|
if !values.contains(&value) {
|
||||||
|
sess.buffer_lint_with_diagnostic(
|
||||||
|
UNEXPECTED_CFGS,
|
||||||
|
cfg.span,
|
||||||
|
lint_node_id,
|
||||||
|
"unexpected `cfg` condition value",
|
||||||
|
BuiltinLintDiagnostics::UnexpectedCfg(
|
||||||
|
(cfg.name, cfg.name_span),
|
||||||
|
cfg.value_span.map(|vs| (value, vs)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sess.config.contains(&(cfg.name, cfg.value))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_gate_cfg(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) {
|
fn try_gate_cfg(name: Symbol, span: Span, sess: &ParseSess, features: Option<&Features>) {
|
||||||
let gate = find_gated_cfg(|sym| cfg.has_name(sym));
|
let gate = find_gated_cfg(|sym| sym == name);
|
||||||
if let (Some(feats), Some(gated_cfg)) = (features, gate) {
|
if let (Some(feats), Some(gated_cfg)) = (features, gate) {
|
||||||
gate_cfg(&gated_cfg, cfg.span, sess, feats);
|
gate_cfg(&gated_cfg, span, sess, feats);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -563,11 +544,11 @@ pub fn eval_condition(
|
||||||
cfg: &ast::MetaItem,
|
cfg: &ast::MetaItem,
|
||||||
sess: &ParseSess,
|
sess: &ParseSess,
|
||||||
features: Option<&Features>,
|
features: Option<&Features>,
|
||||||
eval: &mut impl FnMut(&ast::MetaItem) -> bool,
|
eval: &mut impl FnMut(Condition) -> bool,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match cfg.kind {
|
match cfg.kind {
|
||||||
ast::MetaItemKind::List(ref mis) if cfg.name_or_empty() == sym::version => {
|
ast::MetaItemKind::List(ref mis) if cfg.name_or_empty() == sym::version => {
|
||||||
try_gate_cfg(cfg, sess, features);
|
try_gate_cfg(sym::version, cfg.span, sess, features);
|
||||||
let (min_version, span) = match &mis[..] {
|
let (min_version, span) = match &mis[..] {
|
||||||
[NestedMetaItem::Literal(Lit { kind: LitKind::Str(sym, ..), span, .. })] => {
|
[NestedMetaItem::Literal(Lit { kind: LitKind::Str(sym, ..), span, .. })] => {
|
||||||
(sym, span)
|
(sym, span)
|
||||||
|
@ -649,6 +630,25 @@ pub fn eval_condition(
|
||||||
|
|
||||||
!eval_condition(mis[0].meta_item().unwrap(), sess, features, eval)
|
!eval_condition(mis[0].meta_item().unwrap(), sess, features, eval)
|
||||||
}
|
}
|
||||||
|
sym::target => {
|
||||||
|
if let Some(features) = features && !features.cfg_target_compact {
|
||||||
|
feature_err(
|
||||||
|
sess,
|
||||||
|
sym::cfg_target_compact,
|
||||||
|
cfg.span,
|
||||||
|
&"compact `cfg(target(..))` is experimental and subject to change"
|
||||||
|
).emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
mis.iter().fold(true, |res, mi| {
|
||||||
|
let mut mi = mi.meta_item().unwrap().clone();
|
||||||
|
if let [seg, ..] = &mut mi.path.segments[..] {
|
||||||
|
seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
res & eval_condition(&mi, sess, features, eval)
|
||||||
|
})
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
struct_span_err!(
|
struct_span_err!(
|
||||||
sess.span_diagnostic,
|
sess.span_diagnostic,
|
||||||
|
@ -662,7 +662,32 @@ pub fn eval_condition(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::MetaItemKind::Word | ast::MetaItemKind::NameValue(..) => eval(cfg),
|
ast::MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => {
|
||||||
|
sess.span_diagnostic
|
||||||
|
.span_err(cfg.path.span, "`cfg` predicate key must be an identifier");
|
||||||
|
true
|
||||||
|
}
|
||||||
|
MetaItemKind::NameValue(ref lit) if !lit.kind.is_str() => {
|
||||||
|
handle_errors(
|
||||||
|
sess,
|
||||||
|
lit.span,
|
||||||
|
AttrError::UnsupportedLiteral(
|
||||||
|
"literal in `cfg` predicate value must be a string",
|
||||||
|
lit.kind.is_bytestr(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
ast::MetaItemKind::Word | ast::MetaItemKind::NameValue(..) => {
|
||||||
|
let ident = cfg.ident().expect("multi-segment cfg predicate");
|
||||||
|
eval(Condition {
|
||||||
|
name: ident.name,
|
||||||
|
name_span: ident.span,
|
||||||
|
value: cfg.value_str(),
|
||||||
|
value_span: cfg.name_value_literal_span(),
|
||||||
|
span: cfg.span,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
//! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax`
|
//! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax`
|
||||||
//! to this crate.
|
//! to this crate.
|
||||||
|
|
||||||
|
#![feature(let_chains)]
|
||||||
#![feature(let_else)]
|
#![feature(let_else)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
|
@ -319,6 +319,8 @@ declare_features! (
|
||||||
(active, cfg_sanitize, "1.41.0", Some(39699), None),
|
(active, cfg_sanitize, "1.41.0", Some(39699), None),
|
||||||
/// Allows `cfg(target_abi = "...")`.
|
/// Allows `cfg(target_abi = "...")`.
|
||||||
(active, cfg_target_abi, "1.55.0", Some(80970), None),
|
(active, cfg_target_abi, "1.55.0", Some(80970), None),
|
||||||
|
/// Allows `cfg(target(abi = "..."))`.
|
||||||
|
(active, cfg_target_compact, "1.63.0", Some(96901), None),
|
||||||
/// Allows `cfg(target_has_atomic_load_store = "...")`.
|
/// Allows `cfg(target_has_atomic_load_store = "...")`.
|
||||||
(active, cfg_target_has_atomic, "1.60.0", Some(94039), None),
|
(active, cfg_target_has_atomic, "1.60.0", Some(94039), None),
|
||||||
/// Allows `cfg(target_has_atomic_equal_alignment = "...")`.
|
/// Allows `cfg(target_has_atomic_equal_alignment = "...")`.
|
||||||
|
|
|
@ -536,9 +536,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
|
|
||||||
fn encode_crate_root(&mut self) -> LazyValue<CrateRoot> {
|
fn encode_crate_root(&mut self) -> LazyValue<CrateRoot> {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let mut i = self.position();
|
let mut i = 0;
|
||||||
|
let preamble_bytes = self.position() - i;
|
||||||
|
|
||||||
// Encode the crate deps
|
// Encode the crate deps
|
||||||
|
i = self.position();
|
||||||
let crate_deps = self.encode_crate_deps();
|
let crate_deps = self.encode_crate_deps();
|
||||||
let dylib_dependency_formats = self.encode_dylib_dependency_formats();
|
let dylib_dependency_formats = self.encode_dylib_dependency_formats();
|
||||||
let dep_bytes = self.position() - i;
|
let dep_bytes = self.position() - i;
|
||||||
|
@ -564,7 +566,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
let native_libraries = self.encode_native_libraries();
|
let native_libraries = self.encode_native_libraries();
|
||||||
let native_lib_bytes = self.position() - i;
|
let native_lib_bytes = self.position() - i;
|
||||||
|
|
||||||
|
i = self.position();
|
||||||
let foreign_modules = self.encode_foreign_modules();
|
let foreign_modules = self.encode_foreign_modules();
|
||||||
|
let foreign_modules_bytes = self.position() - i;
|
||||||
|
|
||||||
// Encode DefPathTable
|
// Encode DefPathTable
|
||||||
i = self.position();
|
i = self.position();
|
||||||
|
@ -584,6 +588,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
i = self.position();
|
i = self.position();
|
||||||
let incoherent_impls = self.encode_incoherent_impls();
|
let incoherent_impls = self.encode_incoherent_impls();
|
||||||
let incoherent_impls_bytes = self.position() - i;
|
let incoherent_impls_bytes = self.position() - i;
|
||||||
|
|
||||||
// Encode MIR.
|
// Encode MIR.
|
||||||
i = self.position();
|
i = self.position();
|
||||||
self.encode_mir();
|
self.encode_mir();
|
||||||
|
@ -596,6 +601,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
let item_bytes = self.position() - i;
|
let item_bytes = self.position() - i;
|
||||||
|
|
||||||
// Encode the allocation index
|
// Encode the allocation index
|
||||||
|
i = self.position();
|
||||||
let interpret_alloc_index = {
|
let interpret_alloc_index = {
|
||||||
let mut interpret_alloc_index = Vec::new();
|
let mut interpret_alloc_index = Vec::new();
|
||||||
let mut n = 0;
|
let mut n = 0;
|
||||||
|
@ -618,6 +624,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
self.lazy_array(interpret_alloc_index)
|
self.lazy_array(interpret_alloc_index)
|
||||||
};
|
};
|
||||||
|
let interpret_alloc_index_bytes = self.position() - i;
|
||||||
|
|
||||||
// Encode the proc macro data. This affects 'tables',
|
// Encode the proc macro data. This affects 'tables',
|
||||||
// so we need to do this before we encode the tables
|
// so we need to do this before we encode the tables
|
||||||
|
@ -662,9 +669,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
let source_map = self.encode_source_map();
|
let source_map = self.encode_source_map();
|
||||||
let source_map_bytes = self.position() - i;
|
let source_map_bytes = self.position() - i;
|
||||||
|
|
||||||
|
i = self.position();
|
||||||
let attrs = tcx.hir().krate_attrs();
|
let attrs = tcx.hir().krate_attrs();
|
||||||
let has_default_lib_allocator = tcx.sess.contains_name(&attrs, sym::default_lib_allocator);
|
let has_default_lib_allocator = tcx.sess.contains_name(&attrs, sym::default_lib_allocator);
|
||||||
|
|
||||||
let root = self.lazy(CrateRoot {
|
let root = self.lazy(CrateRoot {
|
||||||
name: tcx.crate_name(LOCAL_CRATE),
|
name: tcx.crate_name(LOCAL_CRATE),
|
||||||
extra_filename: tcx.sess.opts.cg.extra_filename.clone(),
|
extra_filename: tcx.sess.opts.cg.extra_filename.clone(),
|
||||||
|
@ -707,9 +714,34 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
expn_hashes,
|
expn_hashes,
|
||||||
def_path_hash_map,
|
def_path_hash_map,
|
||||||
});
|
});
|
||||||
|
let final_bytes = self.position() - i;
|
||||||
|
|
||||||
let total_bytes = self.position();
|
let total_bytes = self.position();
|
||||||
|
|
||||||
|
let computed_total_bytes = preamble_bytes
|
||||||
|
+ dep_bytes
|
||||||
|
+ lib_feature_bytes
|
||||||
|
+ lang_item_bytes
|
||||||
|
+ diagnostic_item_bytes
|
||||||
|
+ native_lib_bytes
|
||||||
|
+ foreign_modules_bytes
|
||||||
|
+ def_path_table_bytes
|
||||||
|
+ traits_bytes
|
||||||
|
+ impls_bytes
|
||||||
|
+ incoherent_impls_bytes
|
||||||
|
+ mir_bytes
|
||||||
|
+ item_bytes
|
||||||
|
+ interpret_alloc_index_bytes
|
||||||
|
+ proc_macro_data_bytes
|
||||||
|
+ tables_bytes
|
||||||
|
+ debugger_visualizers_bytes
|
||||||
|
+ exported_symbols_bytes
|
||||||
|
+ hygiene_bytes
|
||||||
|
+ def_path_hash_map_bytes
|
||||||
|
+ source_map_bytes
|
||||||
|
+ final_bytes;
|
||||||
|
assert_eq!(total_bytes, computed_total_bytes);
|
||||||
|
|
||||||
if tcx.sess.meta_stats() {
|
if tcx.sess.meta_stats() {
|
||||||
let mut zero_bytes = 0;
|
let mut zero_bytes = 0;
|
||||||
for e in self.opaque.data.iter() {
|
for e in self.opaque.data.iter() {
|
||||||
|
@ -718,27 +750,41 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eprintln!("metadata stats:");
|
let perc = |bytes| (bytes * 100) as f64 / total_bytes as f64;
|
||||||
eprintln!(" dep bytes: {}", dep_bytes);
|
let p = |label, bytes| {
|
||||||
eprintln!(" lib feature bytes: {}", lib_feature_bytes);
|
eprintln!("{:>21}: {:>8} bytes ({:4.1}%)", label, bytes, perc(bytes));
|
||||||
eprintln!(" lang item bytes: {}", lang_item_bytes);
|
};
|
||||||
eprintln!(" diagnostic item bytes: {}", diagnostic_item_bytes);
|
|
||||||
eprintln!(" native bytes: {}", native_lib_bytes);
|
eprintln!("");
|
||||||
eprintln!(" debugger visualizers bytes: {}", debugger_visualizers_bytes);
|
eprintln!(
|
||||||
eprintln!(" source_map bytes: {}", source_map_bytes);
|
"{} metadata bytes, of which {} bytes ({:.1}%) are zero",
|
||||||
eprintln!(" traits bytes: {}", traits_bytes);
|
total_bytes,
|
||||||
eprintln!(" impls bytes: {}", impls_bytes);
|
zero_bytes,
|
||||||
eprintln!(" incoherent_impls bytes: {}", incoherent_impls_bytes);
|
perc(zero_bytes)
|
||||||
eprintln!(" exp. symbols bytes: {}", exported_symbols_bytes);
|
);
|
||||||
eprintln!(" def-path table bytes: {}", def_path_table_bytes);
|
p("preamble", preamble_bytes);
|
||||||
eprintln!(" def-path hashes bytes: {}", def_path_hash_map_bytes);
|
p("dep", dep_bytes);
|
||||||
eprintln!(" proc-macro-data-bytes: {}", proc_macro_data_bytes);
|
p("lib feature", lib_feature_bytes);
|
||||||
eprintln!(" mir bytes: {}", mir_bytes);
|
p("lang item", lang_item_bytes);
|
||||||
eprintln!(" item bytes: {}", item_bytes);
|
p("diagnostic item", diagnostic_item_bytes);
|
||||||
eprintln!(" table bytes: {}", tables_bytes);
|
p("native lib", native_lib_bytes);
|
||||||
eprintln!(" hygiene bytes: {}", hygiene_bytes);
|
p("foreign modules", foreign_modules_bytes);
|
||||||
eprintln!(" zero bytes: {}", zero_bytes);
|
p("def-path table", def_path_table_bytes);
|
||||||
eprintln!(" total bytes: {}", total_bytes);
|
p("traits", traits_bytes);
|
||||||
|
p("impls", impls_bytes);
|
||||||
|
p("incoherent_impls", incoherent_impls_bytes);
|
||||||
|
p("mir", mir_bytes);
|
||||||
|
p("item", item_bytes);
|
||||||
|
p("interpret_alloc_index", interpret_alloc_index_bytes);
|
||||||
|
p("proc-macro-data", proc_macro_data_bytes);
|
||||||
|
p("tables", tables_bytes);
|
||||||
|
p("debugger visualizers", debugger_visualizers_bytes);
|
||||||
|
p("exported symbols", exported_symbols_bytes);
|
||||||
|
p("hygiene", hygiene_bytes);
|
||||||
|
p("def-path hashes", def_path_hash_map_bytes);
|
||||||
|
p("source_map", source_map_bytes);
|
||||||
|
p("final", final_bytes);
|
||||||
|
eprintln!("");
|
||||||
}
|
}
|
||||||
|
|
||||||
root
|
root
|
||||||
|
|
|
@ -52,11 +52,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ExprKind::Repeat { value, count } => {
|
ExprKind::Repeat { value, count } => {
|
||||||
let value_operand = unpack!(
|
if Some(0) == count.try_eval_usize(this.tcx, this.param_env) {
|
||||||
block =
|
this.build_zero_repeat(block, value, scope, source_info)
|
||||||
this.as_operand(block, scope, &this.thir[value], None, NeedsTemporary::No)
|
} else {
|
||||||
);
|
let value_operand = unpack!(
|
||||||
block.and(Rvalue::Repeat(value_operand, count))
|
block = this.as_operand(
|
||||||
|
block,
|
||||||
|
scope,
|
||||||
|
&this.thir[value],
|
||||||
|
None,
|
||||||
|
NeedsTemporary::No
|
||||||
|
)
|
||||||
|
);
|
||||||
|
block.and(Rvalue::Repeat(value_operand, count))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Binary { op, lhs, rhs } => {
|
ExprKind::Binary { op, lhs, rhs } => {
|
||||||
let lhs = unpack!(
|
let lhs = unpack!(
|
||||||
|
@ -516,6 +525,37 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_zero_repeat(
|
||||||
|
&mut self,
|
||||||
|
mut block: BasicBlock,
|
||||||
|
value: ExprId,
|
||||||
|
scope: Option<region::Scope>,
|
||||||
|
outer_source_info: SourceInfo,
|
||||||
|
) -> BlockAnd<Rvalue<'tcx>> {
|
||||||
|
let this = self;
|
||||||
|
let value = &this.thir[value];
|
||||||
|
let elem_ty = value.ty;
|
||||||
|
if let Some(Category::Constant) = Category::of(&value.kind) {
|
||||||
|
// Repeating a const does nothing
|
||||||
|
} else {
|
||||||
|
// For a non-const, we may need to generate an appropriate `Drop`
|
||||||
|
let value_operand =
|
||||||
|
unpack!(block = this.as_operand(block, scope, value, None, NeedsTemporary::No));
|
||||||
|
if let Operand::Move(to_drop) = value_operand {
|
||||||
|
let success = this.cfg.start_new_block();
|
||||||
|
this.cfg.terminate(
|
||||||
|
block,
|
||||||
|
outer_source_info,
|
||||||
|
TerminatorKind::Drop { place: to_drop, target: success, unwind: None },
|
||||||
|
);
|
||||||
|
this.diverge_from(block);
|
||||||
|
block = success;
|
||||||
|
}
|
||||||
|
this.record_operands_moved(&[value_operand]);
|
||||||
|
}
|
||||||
|
block.and(Rvalue::Aggregate(Box::new(AggregateKind::Array(elem_ty)), Vec::new()))
|
||||||
|
}
|
||||||
|
|
||||||
fn limit_capture_mutability(
|
fn limit_capture_mutability(
|
||||||
&mut self,
|
&mut self,
|
||||||
upvar_span: Span,
|
upvar_span: Span,
|
||||||
|
|
|
@ -1033,6 +1033,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
self.cfg.block_data(start).terminator().kind,
|
self.cfg.block_data(start).terminator().kind,
|
||||||
TerminatorKind::Assert { .. }
|
TerminatorKind::Assert { .. }
|
||||||
| TerminatorKind::Call { .. }
|
| TerminatorKind::Call { .. }
|
||||||
|
| TerminatorKind::Drop { .. }
|
||||||
| TerminatorKind::DropAndReplace { .. }
|
| TerminatorKind::DropAndReplace { .. }
|
||||||
| TerminatorKind::FalseUnwind { .. }
|
| TerminatorKind::FalseUnwind { .. }
|
||||||
| TerminatorKind::InlineAsm { .. }
|
| TerminatorKind::InlineAsm { .. }
|
||||||
|
|
|
@ -2291,16 +2291,9 @@ impl<'a> Parser<'a> {
|
||||||
.span_label(else_span, "expected an `if` or a block after this `else`")
|
.span_label(else_span, "expected an `if` or a block after this `else`")
|
||||||
.span_suggestion(
|
.span_suggestion(
|
||||||
cond.span.shrink_to_lo(),
|
cond.span.shrink_to_lo(),
|
||||||
"add an `if` if this is the condition to an chained `if` statement after the `else`",
|
"add an `if` if this is the condition of a chained `else if` statement",
|
||||||
"if ".to_string(),
|
"if ".to_string(),
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
).multipart_suggestion(
|
|
||||||
"... otherwise, place this expression inside of a block if it is not an `if` condition",
|
|
||||||
vec![
|
|
||||||
(cond.span.shrink_to_lo(), "{ ".to_string()),
|
|
||||||
(cond.span.shrink_to_hi(), " }".to_string()),
|
|
||||||
],
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
self.parse_if_after_cond(AttrVec::new(), cond.span.shrink_to_lo(), cond)?
|
self.parse_if_after_cond(AttrVec::new(), cond.span.shrink_to_lo(), cond)?
|
||||||
|
|
|
@ -427,6 +427,7 @@ symbols! {
|
||||||
cfg_panic,
|
cfg_panic,
|
||||||
cfg_sanitize,
|
cfg_sanitize,
|
||||||
cfg_target_abi,
|
cfg_target_abi,
|
||||||
|
cfg_target_compact,
|
||||||
cfg_target_feature,
|
cfg_target_feature,
|
||||||
cfg_target_has_atomic,
|
cfg_target_has_atomic,
|
||||||
cfg_target_has_atomic_equal_alignment,
|
cfg_target_has_atomic_equal_alignment,
|
||||||
|
@ -1375,6 +1376,7 @@ symbols! {
|
||||||
sym,
|
sym,
|
||||||
sync,
|
sync,
|
||||||
t32,
|
t32,
|
||||||
|
target,
|
||||||
target_abi,
|
target_abi,
|
||||||
target_arch,
|
target_arch,
|
||||||
target_endian,
|
target_endian,
|
||||||
|
|
|
@ -89,8 +89,8 @@ impl<'tcx> OnUnimplementedDirective {
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |item| {
|
attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |cfg| {
|
||||||
if let Some(symbol) = item.value_str() && let Err(guar) = parse_value(symbol) {
|
if let Some(value) = cfg.value && let Err(guar) = parse_value(value) {
|
||||||
errored = Some(guar);
|
errored = Some(guar);
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
@ -226,14 +226,12 @@ impl<'tcx> OnUnimplementedDirective {
|
||||||
condition,
|
condition,
|
||||||
&tcx.sess.parse_sess,
|
&tcx.sess.parse_sess,
|
||||||
Some(tcx.features()),
|
Some(tcx.features()),
|
||||||
&mut |c| {
|
&mut |cfg| {
|
||||||
c.ident().map_or(false, |ident| {
|
let value = cfg.value.map(|v| {
|
||||||
let value = c.value_str().map(|s| {
|
OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map)
|
||||||
OnUnimplementedFormatString(s).format(tcx, trait_ref, &options_map)
|
});
|
||||||
});
|
|
||||||
|
|
||||||
options.contains(&(ident.name, value))
|
options.contains(&(cfg.name, value))
|
||||||
})
|
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
debug!("evaluate: skipping {:?} due to condition", command);
|
debug!("evaluate: skipping {:?} due to condition", command);
|
||||||
|
|
109
library/core/src/asserting.rs
Normal file
109
library/core/src/asserting.rs
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
// Contains the machinery necessary to print useful `assert!` messages. Not intended for public
|
||||||
|
// usage, not even nightly use-cases.
|
||||||
|
//
|
||||||
|
// Based on https://github.com/dtolnay/case-studies/tree/master/autoref-specialization. When
|
||||||
|
// 'specialization' is robust enough (5 years? 10 years? Never?), `Capture` can be specialized
|
||||||
|
// to [Printable].
|
||||||
|
|
||||||
|
#![allow(missing_debug_implementations)]
|
||||||
|
#![doc(hidden)]
|
||||||
|
#![unstable(feature = "generic_assert_internals", issue = "44838")]
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
fmt::{Debug, Formatter},
|
||||||
|
marker::PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
|
// ***** TryCapture - Generic *****
|
||||||
|
|
||||||
|
/// Marker used by [Capture]
|
||||||
|
#[unstable(feature = "generic_assert_internals", issue = "44838")]
|
||||||
|
pub struct TryCaptureWithoutDebug;
|
||||||
|
|
||||||
|
/// Catches an arbitrary `E` and modifies `to` accordingly
|
||||||
|
#[unstable(feature = "generic_assert_internals", issue = "44838")]
|
||||||
|
pub trait TryCaptureGeneric<E, M> {
|
||||||
|
/// Similar to [TryCapturePrintable] but generic to any `E`.
|
||||||
|
fn try_capture(&self, to: &mut Capture<E, M>);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E> TryCaptureGeneric<E, TryCaptureWithoutDebug> for &Wrapper<&E> {
|
||||||
|
#[inline]
|
||||||
|
fn try_capture(&self, _: &mut Capture<E, TryCaptureWithoutDebug>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E> Debug for Capture<E, TryCaptureWithoutDebug> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
|
||||||
|
f.write_str("N/A")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ***** TryCapture - Printable *****
|
||||||
|
|
||||||
|
/// Marker used by [Capture]
|
||||||
|
#[unstable(feature = "generic_assert_internals", issue = "44838")]
|
||||||
|
pub struct TryCaptureWithDebug;
|
||||||
|
|
||||||
|
/// Catches an arbitrary `E: Printable` and modifies `to` accordingly
|
||||||
|
#[unstable(feature = "generic_assert_internals", issue = "44838")]
|
||||||
|
pub trait TryCapturePrintable<E, M> {
|
||||||
|
/// Similar as [TryCaptureGeneric] but specialized to any `E: Printable`.
|
||||||
|
fn try_capture(&self, to: &mut Capture<E, M>);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E> TryCapturePrintable<E, TryCaptureWithDebug> for Wrapper<&E>
|
||||||
|
where
|
||||||
|
E: Printable,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn try_capture(&self, to: &mut Capture<E, TryCaptureWithDebug>) {
|
||||||
|
to.elem = Some(*self.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E> Debug for Capture<E, TryCaptureWithDebug>
|
||||||
|
where
|
||||||
|
E: Printable,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
|
||||||
|
match self.elem {
|
||||||
|
None => f.write_str("N/A"),
|
||||||
|
Some(ref value) => Debug::fmt(value, f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ***** Others *****
|
||||||
|
|
||||||
|
/// All possible captured `assert!` elements
|
||||||
|
///
|
||||||
|
/// # Types
|
||||||
|
///
|
||||||
|
/// * `E`: **E**lement that is going to be displayed.
|
||||||
|
/// * `M`: **M**arker used to differentiate [Capture]s in regards to [Debug].
|
||||||
|
#[unstable(feature = "generic_assert_internals", issue = "44838")]
|
||||||
|
pub struct Capture<E, M> {
|
||||||
|
// If None, then `E` does not implements [Printable] or `E` wasn't evaluated (`assert!( ... )`
|
||||||
|
// short-circuited).
|
||||||
|
//
|
||||||
|
// If Some, then `E` implements [Printable] and was evaluated.
|
||||||
|
pub elem: Option<E>,
|
||||||
|
phantom: PhantomData<M>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M, T> Capture<M, T> {
|
||||||
|
#[inline]
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self { elem: None, phantom: PhantomData }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Necessary for the implementations of `TryCapture*`
|
||||||
|
#[unstable(feature = "generic_assert_internals", issue = "44838")]
|
||||||
|
pub struct Wrapper<T>(pub T);
|
||||||
|
|
||||||
|
/// Tells which elements can be copied and displayed
|
||||||
|
#[unstable(feature = "generic_assert_internals", issue = "44838")]
|
||||||
|
pub trait Printable: Copy + Debug {}
|
||||||
|
|
||||||
|
impl<T> Printable for T where T: Copy + Debug {}
|
|
@ -310,6 +310,7 @@ pub mod ops;
|
||||||
pub mod any;
|
pub mod any;
|
||||||
pub mod array;
|
pub mod array;
|
||||||
pub mod ascii;
|
pub mod ascii;
|
||||||
|
pub mod asserting;
|
||||||
#[unstable(feature = "async_iterator", issue = "79024")]
|
#[unstable(feature = "async_iterator", issue = "79024")]
|
||||||
pub mod async_iter;
|
pub mod async_iter;
|
||||||
pub mod cell;
|
pub mod cell;
|
||||||
|
|
37
library/core/tests/asserting.rs
Normal file
37
library/core/tests/asserting.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
use core::asserting::{Capture, TryCaptureGeneric, TryCapturePrintable, Wrapper};
|
||||||
|
|
||||||
|
macro_rules! test {
|
||||||
|
($test_name:ident, $elem:expr, $captured_elem:expr, $output:literal) => {
|
||||||
|
#[test]
|
||||||
|
fn $test_name() {
|
||||||
|
let elem = $elem;
|
||||||
|
let mut capture = Capture::new();
|
||||||
|
assert!(capture.elem == None);
|
||||||
|
(&Wrapper(&elem)).try_capture(&mut capture);
|
||||||
|
assert!(capture.elem == $captured_elem);
|
||||||
|
assert_eq!(format!("{:?}", capture), $output);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
struct NoCopy;
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
struct NoCopyNoDebug;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
|
struct NoDebug;
|
||||||
|
|
||||||
|
test!(
|
||||||
|
capture_with_non_copyable_and_non_debugabble_elem_has_correct_params,
|
||||||
|
NoCopyNoDebug,
|
||||||
|
None,
|
||||||
|
"N/A"
|
||||||
|
);
|
||||||
|
|
||||||
|
test!(capture_with_non_copyable_elem_has_correct_params, NoCopy, None, "N/A");
|
||||||
|
|
||||||
|
test!(capture_with_non_debugabble_elem_has_correct_params, NoDebug, None, "N/A");
|
||||||
|
|
||||||
|
test!(capture_with_copyable_and_debugabble_elem_has_correct_params, 1i32, Some(1i32), "1");
|
|
@ -35,6 +35,7 @@
|
||||||
#![feature(float_minimum_maximum)]
|
#![feature(float_minimum_maximum)]
|
||||||
#![feature(future_join)]
|
#![feature(future_join)]
|
||||||
#![feature(future_poll_fn)]
|
#![feature(future_poll_fn)]
|
||||||
|
#![feature(generic_assert_internals)]
|
||||||
#![feature(array_try_from_fn)]
|
#![feature(array_try_from_fn)]
|
||||||
#![feature(hasher_prefixfree_extras)]
|
#![feature(hasher_prefixfree_extras)]
|
||||||
#![feature(hashmap_internals)]
|
#![feature(hashmap_internals)]
|
||||||
|
@ -104,6 +105,7 @@ mod alloc;
|
||||||
mod any;
|
mod any;
|
||||||
mod array;
|
mod array;
|
||||||
mod ascii;
|
mod ascii;
|
||||||
|
mod asserting;
|
||||||
mod atomic;
|
mod atomic;
|
||||||
mod bool;
|
mod bool;
|
||||||
mod cell;
|
mod cell;
|
||||||
|
|
17
src/test/ui/cfg/cfg-target-compact-errors.rs
Normal file
17
src/test/ui/cfg/cfg-target-compact-errors.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// check-fail
|
||||||
|
|
||||||
|
#![feature(cfg_target_compact)]
|
||||||
|
|
||||||
|
#[cfg(target(o::o))]
|
||||||
|
//~^ ERROR `cfg` predicate key must be an identifier
|
||||||
|
fn one() {}
|
||||||
|
|
||||||
|
#[cfg(target(os = 8))]
|
||||||
|
//~^ ERROR literal in `cfg` predicate value must be a string
|
||||||
|
fn two() {}
|
||||||
|
|
||||||
|
#[cfg(target(os = "linux", pointer(width = "64")))]
|
||||||
|
//~^ ERROR invalid predicate `target_pointer`
|
||||||
|
fn three() {}
|
||||||
|
|
||||||
|
fn main() {}
|
22
src/test/ui/cfg/cfg-target-compact-errors.stderr
Normal file
22
src/test/ui/cfg/cfg-target-compact-errors.stderr
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
error: `cfg` predicate key must be an identifier
|
||||||
|
--> $DIR/cfg-target-compact-errors.rs:5:14
|
||||||
|
|
|
||||||
|
LL | #[cfg(target(o::o))]
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error[E0565]: literal in `cfg` predicate value must be a string
|
||||||
|
--> $DIR/cfg-target-compact-errors.rs:9:19
|
||||||
|
|
|
||||||
|
LL | #[cfg(target(os = 8))]
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error[E0537]: invalid predicate `target_pointer`
|
||||||
|
--> $DIR/cfg-target-compact-errors.rs:13:28
|
||||||
|
|
|
||||||
|
LL | #[cfg(target(os = "linux", pointer(width = "64")))]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0537, E0565.
|
||||||
|
For more information about an error, try `rustc --explain E0537`.
|
10
src/test/ui/cfg/cfg-target-compact.rs
Normal file
10
src/test/ui/cfg/cfg-target-compact.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// run-pass
|
||||||
|
#![feature(cfg_target_compact)]
|
||||||
|
|
||||||
|
#[cfg(target(os = "linux", pointer_width = "64"))]
|
||||||
|
pub fn main() {
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target(os = "linux", pointer_width = "64")))]
|
||||||
|
pub fn main() {
|
||||||
|
}
|
15
src/test/ui/check-cfg/compact-names.rs
Normal file
15
src/test/ui/check-cfg/compact-names.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// This test check that we correctly emit an warning for compact cfg
|
||||||
|
//
|
||||||
|
// check-pass
|
||||||
|
// compile-flags:--check-cfg=names() -Z unstable-options
|
||||||
|
|
||||||
|
#![feature(cfg_target_compact)]
|
||||||
|
|
||||||
|
#[cfg(target(os = "linux", arch = "arm"))]
|
||||||
|
pub fn expected() {}
|
||||||
|
|
||||||
|
#[cfg(target(os = "linux", architecture = "arm"))]
|
||||||
|
//~^ WARNING unexpected `cfg` condition name
|
||||||
|
pub fn unexpected() {}
|
||||||
|
|
||||||
|
fn main() {}
|
10
src/test/ui/check-cfg/compact-names.stderr
Normal file
10
src/test/ui/check-cfg/compact-names.stderr
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
warning: unexpected `cfg` condition name
|
||||||
|
--> $DIR/compact-names.rs:11:28
|
||||||
|
|
|
||||||
|
LL | #[cfg(target(os = "linux", architecture = "arm"))]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(unexpected_cfgs)]` on by default
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
15
src/test/ui/check-cfg/compact-values.rs
Normal file
15
src/test/ui/check-cfg/compact-values.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// This test check that we correctly emit an warning for compact cfg
|
||||||
|
//
|
||||||
|
// check-pass
|
||||||
|
// compile-flags:--check-cfg=values() -Z unstable-options
|
||||||
|
|
||||||
|
#![feature(cfg_target_compact)]
|
||||||
|
|
||||||
|
#[cfg(target(os = "linux", arch = "arm"))]
|
||||||
|
pub fn expected() {}
|
||||||
|
|
||||||
|
#[cfg(target(os = "linux", arch = "X"))]
|
||||||
|
//~^ WARNING unexpected `cfg` condition value
|
||||||
|
pub fn unexpected() {}
|
||||||
|
|
||||||
|
fn main() {}
|
11
src/test/ui/check-cfg/compact-values.stderr
Normal file
11
src/test/ui/check-cfg/compact-values.stderr
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
warning: unexpected `cfg` condition value
|
||||||
|
--> $DIR/compact-values.rs:11:28
|
||||||
|
|
|
||||||
|
LL | #[cfg(target(os = "linux", arch = "X"))]
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(unexpected_cfgs)]` on by default
|
||||||
|
= note: expected values for `target_arch` are: aarch64, arm, avr, bpf, hexagon, m68k, mips, mips64, msp430, nvptx64, powerpc, powerpc64, riscv32, riscv64, s390x, sparc, sparc64, wasm32, wasm64, x86, x86_64
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
15
src/test/ui/drop/repeat-drop-2.rs
Normal file
15
src/test/ui/drop/repeat-drop-2.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
fn borrowck_catch() {
|
||||||
|
let foo = String::new();
|
||||||
|
let _bar = foo;
|
||||||
|
let _baz = [foo; 0]; //~ ERROR use of moved value: `foo` [E0382]
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: [String; 0] = [String::new(); 0];
|
||||||
|
//~^ ERROR destructors cannot be evaluated at compile-time [E0493]
|
||||||
|
|
||||||
|
fn must_be_init() {
|
||||||
|
let x: u8;
|
||||||
|
let _ = [x; 0]; //~ ERROR: use of possibly-uninitialized variable: `x`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
29
src/test/ui/drop/repeat-drop-2.stderr
Normal file
29
src/test/ui/drop/repeat-drop-2.stderr
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
error[E0382]: use of moved value: `foo`
|
||||||
|
--> $DIR/repeat-drop-2.rs:4:17
|
||||||
|
|
|
||||||
|
LL | let foo = String::new();
|
||||||
|
| --- move occurs because `foo` has type `String`, which does not implement the `Copy` trait
|
||||||
|
LL | let _bar = foo;
|
||||||
|
| --- value moved here
|
||||||
|
LL | let _baz = [foo; 0];
|
||||||
|
| ^^^ value used here after move
|
||||||
|
|
||||||
|
error[E0493]: destructors cannot be evaluated at compile-time
|
||||||
|
--> $DIR/repeat-drop-2.rs:7:25
|
||||||
|
|
|
||||||
|
LL | const _: [String; 0] = [String::new(); 0];
|
||||||
|
| -^^^^^^^^^^^^^----
|
||||||
|
| ||
|
||||||
|
| |constants cannot evaluate destructors
|
||||||
|
| value is dropped here
|
||||||
|
|
||||||
|
error[E0381]: use of possibly-uninitialized variable: `x`
|
||||||
|
--> $DIR/repeat-drop-2.rs:12:14
|
||||||
|
|
|
||||||
|
LL | let _ = [x; 0];
|
||||||
|
| ^ use of possibly-uninitialized `x`
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0381, E0382, E0493.
|
||||||
|
For more information about an error, try `rustc --explain E0381`.
|
120
src/test/ui/drop/repeat-drop.rs
Normal file
120
src/test/ui/drop/repeat-drop.rs
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
// run-pass
|
||||||
|
// ignore-wasm32-bare no unwinding panic
|
||||||
|
// ignore-avr no unwinding panic
|
||||||
|
// ignore-nvptx64 no unwinding panic
|
||||||
|
|
||||||
|
static mut CHECK: usize = 0;
|
||||||
|
|
||||||
|
struct DropChecker(usize);
|
||||||
|
|
||||||
|
impl Drop for DropChecker {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
if CHECK != self.0 - 1 {
|
||||||
|
panic!("Found {}, should have found {}", CHECK, self.0 - 1);
|
||||||
|
}
|
||||||
|
CHECK = self.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! check_drops {
|
||||||
|
($l:literal) => {
|
||||||
|
unsafe { assert_eq!(CHECK, $l) }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DropPanic;
|
||||||
|
|
||||||
|
impl Drop for DropPanic {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_zero() {
|
||||||
|
unsafe { CHECK = 0 };
|
||||||
|
let foo = DropChecker(1);
|
||||||
|
let v: [DropChecker; 0] = [foo; 0];
|
||||||
|
check_drops!(1);
|
||||||
|
std::mem::drop(v);
|
||||||
|
check_drops!(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_one() {
|
||||||
|
unsafe { CHECK = 0 };
|
||||||
|
let foo = DropChecker(1);
|
||||||
|
let v: [DropChecker; 1] = [foo; 1];
|
||||||
|
check_drops!(0);
|
||||||
|
std::mem::drop(v);
|
||||||
|
check_drops!(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const DROP_CHECKER: DropChecker = DropChecker(1);
|
||||||
|
|
||||||
|
fn const_zero() {
|
||||||
|
unsafe { CHECK = 0 };
|
||||||
|
let v: [DropChecker; 0] = [DROP_CHECKER; 0];
|
||||||
|
check_drops!(0);
|
||||||
|
std::mem::drop(v);
|
||||||
|
check_drops!(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn const_one() {
|
||||||
|
unsafe { CHECK = 0 };
|
||||||
|
let v: [DropChecker; 1] = [DROP_CHECKER; 1];
|
||||||
|
check_drops!(0);
|
||||||
|
std::mem::drop(v);
|
||||||
|
check_drops!(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn const_generic_zero<const N: usize>() {
|
||||||
|
unsafe { CHECK = 0 };
|
||||||
|
let v: [DropChecker; N] = [DROP_CHECKER; N];
|
||||||
|
check_drops!(0);
|
||||||
|
std::mem::drop(v);
|
||||||
|
check_drops!(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn const_generic_one<const N: usize>() {
|
||||||
|
unsafe { CHECK = 0 };
|
||||||
|
let v: [DropChecker; N] = [DROP_CHECKER; N];
|
||||||
|
check_drops!(0);
|
||||||
|
std::mem::drop(v);
|
||||||
|
check_drops!(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure that things are allowed to promote as expected
|
||||||
|
|
||||||
|
fn allow_promote() {
|
||||||
|
unsafe { CHECK = 0 };
|
||||||
|
let foo = DropChecker(1);
|
||||||
|
let v: &'static [DropChecker; 0] = &[foo; 0];
|
||||||
|
check_drops!(1);
|
||||||
|
std::mem::drop(v);
|
||||||
|
check_drops!(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that unwinding in the drop causes the right things to drop in the right order
|
||||||
|
fn on_unwind() {
|
||||||
|
unsafe { CHECK = 0 };
|
||||||
|
std::panic::catch_unwind(|| {
|
||||||
|
let panic = DropPanic;
|
||||||
|
let _local = DropChecker(2);
|
||||||
|
let _v = (DropChecker(1), [panic; 0]);
|
||||||
|
std::process::abort();
|
||||||
|
})
|
||||||
|
.unwrap_err();
|
||||||
|
check_drops!(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
value_zero();
|
||||||
|
value_one();
|
||||||
|
const_zero();
|
||||||
|
const_one();
|
||||||
|
const_generic_zero::<0>();
|
||||||
|
const_generic_one::<1>();
|
||||||
|
allow_promote();
|
||||||
|
on_unwind();
|
||||||
|
}
|
13
src/test/ui/feature-gates/feature-gate-cfg-target-compact.rs
Normal file
13
src/test/ui/feature-gates/feature-gate-cfg-target-compact.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#[cfg(target(os = "x"))] //~ ERROR compact `cfg(target(..))` is experimental
|
||||||
|
struct Foo(u64, u64);
|
||||||
|
|
||||||
|
#[cfg_attr(target(os = "x"), x)] //~ ERROR compact `cfg(target(..))` is experimental
|
||||||
|
struct Bar(u64, u64);
|
||||||
|
|
||||||
|
#[cfg(not(any(all(target(os = "x")))))] //~ ERROR compact `cfg(target(..))` is experimental
|
||||||
|
fn foo() {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
cfg!(target(os = "x"));
|
||||||
|
//~^ ERROR compact `cfg(target(..))` is experimental and subject to change
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
error[E0658]: compact `cfg(target(..))` is experimental and subject to change
|
||||||
|
--> $DIR/feature-gate-cfg-target-compact.rs:1:7
|
||||||
|
|
|
||||||
|
LL | #[cfg(target(os = "x"))]
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #96901 <https://github.com/rust-lang/rust/issues/96901> for more information
|
||||||
|
= help: add `#![feature(cfg_target_compact)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error[E0658]: compact `cfg(target(..))` is experimental and subject to change
|
||||||
|
--> $DIR/feature-gate-cfg-target-compact.rs:4:12
|
||||||
|
|
|
||||||
|
LL | #[cfg_attr(target(os = "x"), x)]
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #96901 <https://github.com/rust-lang/rust/issues/96901> for more information
|
||||||
|
= help: add `#![feature(cfg_target_compact)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error[E0658]: compact `cfg(target(..))` is experimental and subject to change
|
||||||
|
--> $DIR/feature-gate-cfg-target-compact.rs:7:19
|
||||||
|
|
|
||||||
|
LL | #[cfg(not(any(all(target(os = "x")))))]
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #96901 <https://github.com/rust-lang/rust/issues/96901> for more information
|
||||||
|
= help: add `#![feature(cfg_target_compact)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error[E0658]: compact `cfg(target(..))` is experimental and subject to change
|
||||||
|
--> $DIR/feature-gate-cfg-target-compact.rs:11:10
|
||||||
|
|
|
||||||
|
LL | cfg!(target(os = "x"));
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #96901 <https://github.com/rust-lang/rust/issues/96901> for more information
|
||||||
|
= help: add `#![feature(cfg_target_compact)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
|
@ -6,14 +6,10 @@ LL | } else false {
|
||||||
| |
|
| |
|
||||||
| expected an `if` or a block after this `else`
|
| expected an `if` or a block after this `else`
|
||||||
|
|
|
|
||||||
help: add an `if` if this is the condition to an chained `if` statement after the `else`
|
help: add an `if` if this is the condition of a chained `else if` statement
|
||||||
|
|
|
|
||||||
LL | } else if false {
|
LL | } else if false {
|
||||||
| ++
|
| ++
|
||||||
help: ... otherwise, place this expression inside of a block if it is not an `if` condition
|
|
||||||
|
|
|
||||||
LL | } else { false } {
|
|
||||||
| + +
|
|
||||||
|
|
||||||
error: expected `{`, found `falsy`
|
error: expected `{`, found `falsy`
|
||||||
--> $DIR/else-no-if.rs:10:12
|
--> $DIR/else-no-if.rs:10:12
|
||||||
|
@ -23,14 +19,10 @@ LL | } else falsy() {
|
||||||
| |
|
| |
|
||||||
| expected an `if` or a block after this `else`
|
| expected an `if` or a block after this `else`
|
||||||
|
|
|
|
||||||
help: add an `if` if this is the condition to an chained `if` statement after the `else`
|
help: add an `if` if this is the condition of a chained `else if` statement
|
||||||
|
|
|
|
||||||
LL | } else if falsy() {
|
LL | } else if falsy() {
|
||||||
| ++
|
| ++
|
||||||
help: ... otherwise, place this expression inside of a block if it is not an `if` condition
|
|
||||||
|
|
|
||||||
LL | } else { falsy() } {
|
|
||||||
| + +
|
|
||||||
|
|
||||||
error: expected `{`, found `falsy`
|
error: expected `{`, found `falsy`
|
||||||
--> $DIR/else-no-if.rs:17:12
|
--> $DIR/else-no-if.rs:17:12
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue