1
Fork 0

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:
bors 2022-05-25 11:17:34 +00:00
commit fe9c64d0af
26 changed files with 680 additions and 115 deletions

View file

@ -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)
}
#[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
pub fn cfg_matches(
cfg: &ast::MetaItem,
@ -462,70 +471,42 @@ pub fn cfg_matches(
features: Option<&Features>,
) -> bool {
eval_condition(cfg, sess, features, &mut |cfg| {
try_gate_cfg(cfg, sess, features);
let error = |span, msg| {
sess.span_diagnostic.span_err(span, msg);
true
};
if cfg.path.segments.len() != 1 {
return error(cfg.path.span, "`cfg` predicate key must be an identifier");
}
match &cfg.kind {
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(),
),
try_gate_cfg(cfg.name, cfg.span, sess, features);
if let Some(names_valid) = &sess.check_config.names_valid {
if !names_valid.contains(&cfg.name) {
sess.buffer_lint_with_diagnostic(
UNEXPECTED_CFGS,
cfg.span,
lint_node_id,
"unexpected `cfg` condition name",
BuiltinLintDiagnostics::UnexpectedCfg((cfg.name, cfg.name_span), None),
);
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>) {
let gate = find_gated_cfg(|sym| cfg.has_name(sym));
fn try_gate_cfg(name: Symbol, span: Span, sess: &ParseSess, features: Option<&Features>) {
let gate = find_gated_cfg(|sym| sym == name);
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,
sess: &ParseSess,
features: Option<&Features>,
eval: &mut impl FnMut(&ast::MetaItem) -> bool,
eval: &mut impl FnMut(Condition) -> bool,
) -> bool {
match cfg.kind {
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[..] {
[NestedMetaItem::Literal(Lit { kind: LitKind::Str(sym, ..), span, .. })] => {
(sym, span)
@ -649,6 +630,25 @@ pub fn eval_condition(
!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!(
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,
})
}
}
}

View file

@ -4,6 +4,7 @@
//! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax`
//! to this crate.
#![feature(let_chains)]
#![feature(let_else)]
#[macro_use]

View file

@ -319,6 +319,8 @@ declare_features! (
(active, cfg_sanitize, "1.41.0", Some(39699), None),
/// Allows `cfg(target_abi = "...")`.
(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 = "...")`.
(active, cfg_target_has_atomic, "1.60.0", Some(94039), None),
/// Allows `cfg(target_has_atomic_equal_alignment = "...")`.

View file

@ -536,9 +536,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
fn encode_crate_root(&mut self) -> LazyValue<CrateRoot> {
let tcx = self.tcx;
let mut i = self.position();
let mut i = 0;
let preamble_bytes = self.position() - i;
// Encode the crate deps
i = self.position();
let crate_deps = self.encode_crate_deps();
let dylib_dependency_formats = self.encode_dylib_dependency_formats();
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_lib_bytes = self.position() - i;
i = self.position();
let foreign_modules = self.encode_foreign_modules();
let foreign_modules_bytes = self.position() - i;
// Encode DefPathTable
i = self.position();
@ -584,6 +588,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
i = self.position();
let incoherent_impls = self.encode_incoherent_impls();
let incoherent_impls_bytes = self.position() - i;
// Encode MIR.
i = self.position();
self.encode_mir();
@ -596,6 +601,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let item_bytes = self.position() - i;
// Encode the allocation index
i = self.position();
let interpret_alloc_index = {
let mut interpret_alloc_index = Vec::new();
let mut n = 0;
@ -618,6 +624,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}
self.lazy_array(interpret_alloc_index)
};
let interpret_alloc_index_bytes = self.position() - i;
// Encode the proc macro data. This affects '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_bytes = self.position() - i;
i = self.position();
let attrs = tcx.hir().krate_attrs();
let has_default_lib_allocator = tcx.sess.contains_name(&attrs, sym::default_lib_allocator);
let root = self.lazy(CrateRoot {
name: tcx.crate_name(LOCAL_CRATE),
extra_filename: tcx.sess.opts.cg.extra_filename.clone(),
@ -707,9 +714,34 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
expn_hashes,
def_path_hash_map,
});
let final_bytes = self.position() - i;
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() {
let mut zero_bytes = 0;
for e in self.opaque.data.iter() {
@ -718,27 +750,41 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}
}
eprintln!("metadata stats:");
eprintln!(" dep bytes: {}", dep_bytes);
eprintln!(" lib feature bytes: {}", lib_feature_bytes);
eprintln!(" lang item bytes: {}", lang_item_bytes);
eprintln!(" diagnostic item bytes: {}", diagnostic_item_bytes);
eprintln!(" native bytes: {}", native_lib_bytes);
eprintln!(" debugger visualizers bytes: {}", debugger_visualizers_bytes);
eprintln!(" source_map bytes: {}", source_map_bytes);
eprintln!(" traits bytes: {}", traits_bytes);
eprintln!(" impls bytes: {}", impls_bytes);
eprintln!(" incoherent_impls bytes: {}", incoherent_impls_bytes);
eprintln!(" exp. symbols bytes: {}", exported_symbols_bytes);
eprintln!(" def-path table bytes: {}", def_path_table_bytes);
eprintln!(" def-path hashes bytes: {}", def_path_hash_map_bytes);
eprintln!(" proc-macro-data-bytes: {}", proc_macro_data_bytes);
eprintln!(" mir bytes: {}", mir_bytes);
eprintln!(" item bytes: {}", item_bytes);
eprintln!(" table bytes: {}", tables_bytes);
eprintln!(" hygiene bytes: {}", hygiene_bytes);
eprintln!(" zero bytes: {}", zero_bytes);
eprintln!(" total bytes: {}", total_bytes);
let perc = |bytes| (bytes * 100) as f64 / total_bytes as f64;
let p = |label, bytes| {
eprintln!("{:>21}: {:>8} bytes ({:4.1}%)", label, bytes, perc(bytes));
};
eprintln!("");
eprintln!(
"{} metadata bytes, of which {} bytes ({:.1}%) are zero",
total_bytes,
zero_bytes,
perc(zero_bytes)
);
p("preamble", preamble_bytes);
p("dep", dep_bytes);
p("lib feature", lib_feature_bytes);
p("lang item", lang_item_bytes);
p("diagnostic item", diagnostic_item_bytes);
p("native lib", native_lib_bytes);
p("foreign modules", foreign_modules_bytes);
p("def-path table", def_path_table_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

View file

@ -52,11 +52,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
})
}
ExprKind::Repeat { value, count } => {
let value_operand = unpack!(
block =
this.as_operand(block, scope, &this.thir[value], None, NeedsTemporary::No)
);
block.and(Rvalue::Repeat(value_operand, count))
if Some(0) == count.try_eval_usize(this.tcx, this.param_env) {
this.build_zero_repeat(block, value, scope, source_info)
} else {
let value_operand = unpack!(
block = this.as_operand(
block,
scope,
&this.thir[value],
None,
NeedsTemporary::No
)
);
block.and(Rvalue::Repeat(value_operand, count))
}
}
ExprKind::Binary { op, lhs, rhs } => {
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(
&mut self,
upvar_span: Span,

View file

@ -1033,6 +1033,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.cfg.block_data(start).terminator().kind,
TerminatorKind::Assert { .. }
| TerminatorKind::Call { .. }
| TerminatorKind::Drop { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::InlineAsm { .. }

View file

@ -2291,16 +2291,9 @@ impl<'a> Parser<'a> {
.span_label(else_span, "expected an `if` or a block after this `else`")
.span_suggestion(
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(),
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();
self.parse_if_after_cond(AttrVec::new(), cond.span.shrink_to_lo(), cond)?

View file

@ -427,6 +427,7 @@ symbols! {
cfg_panic,
cfg_sanitize,
cfg_target_abi,
cfg_target_compact,
cfg_target_feature,
cfg_target_has_atomic,
cfg_target_has_atomic_equal_alignment,
@ -1375,6 +1376,7 @@ symbols! {
sym,
sync,
t32,
target,
target_abi,
target_arch,
target_endian,

View file

@ -89,8 +89,8 @@ impl<'tcx> OnUnimplementedDirective {
None,
)
})?;
attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |item| {
if let Some(symbol) = item.value_str() && let Err(guar) = parse_value(symbol) {
attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |cfg| {
if let Some(value) = cfg.value && let Err(guar) = parse_value(value) {
errored = Some(guar);
}
true
@ -226,14 +226,12 @@ impl<'tcx> OnUnimplementedDirective {
condition,
&tcx.sess.parse_sess,
Some(tcx.features()),
&mut |c| {
c.ident().map_or(false, |ident| {
let value = c.value_str().map(|s| {
OnUnimplementedFormatString(s).format(tcx, trait_ref, &options_map)
});
&mut |cfg| {
let value = cfg.value.map(|v| {
OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map)
});
options.contains(&(ident.name, value))
})
options.contains(&(cfg.name, value))
},
) {
debug!("evaluate: skipping {:?} due to condition", command);