diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index fd27be2132614..064f05ef1f3ef 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -545,14 +545,6 @@ pub struct Block { pub rules: BlockCheckMode, pub span: Span, pub tokens: Option, - /// The following *isn't* a parse error, but will cause multiple errors in following stages. - /// ```compile_fail - /// let x = { - /// foo: var - /// }; - /// ``` - /// #34255 - pub could_be_bare_literal: bool, } /// A match pattern. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 474d38fceefd9..274fe312f7fad 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1222,7 +1222,7 @@ fn walk_mt(vis: &mut T, MutTy { ty, mutbl: _ }: &mut MutTy) { } pub fn walk_block(vis: &mut T, block: &mut P) { - let Block { id, stmts, rules: _, span, tokens, could_be_bare_literal: _ } = block.deref_mut(); + let Block { id, stmts, rules: _, span, tokens } = block.deref_mut(); vis.visit_id(id); stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt)); visit_lazy_tts(vis, tokens); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index dcf1d00910a6d..2716601ca4f9d 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1067,7 +1067,7 @@ pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef) } pub fn walk_block<'a, V: Visitor<'a>>(visitor: &mut V, block: &'a Block) -> V::Result { - let Block { stmts, id: _, rules: _, span: _, tokens: _, could_be_bare_literal: _ } = block; + let Block { stmts, id: _, rules: _, span: _, tokens: _ } = block; walk_list!(visitor, visit_stmt, stmts); V::Result::output() } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c9f27d38dfc1e..ced9064fd9f41 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -623,7 +623,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Don't hash unless necessary, because it's expensive. let (opt_hash_including_bodies, attrs_hash) = - self.tcx.hash_owner_nodes(node, &bodies, &attrs); + self.tcx.hash_owner_nodes(node, &bodies, &attrs, define_opaque); let num_nodes = self.item_local_id_counter.as_usize(); let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes); let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies }; diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 5cd653c794566..be11711757e4b 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -395,7 +395,6 @@ mod llvm_enzyme { tokens: None, rules: unsf, span, - could_be_bare_literal: false, }; let unsf_expr = ecx.expr_block(P(unsf_block)); let blackbox_call_expr = ecx.expr_path(ecx.path(span, blackbox_path)); diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index c112589b1319d..50e7b989ed8ab 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -110,7 +110,6 @@ fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P { rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated), span, tokens: None, - could_be_bare_literal: false, })) } diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 2c9b5f40d0dfe..89a750bb39f0c 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -286,7 +286,6 @@ impl<'a> ExtCtxt<'a> { rules: BlockCheckMode::Default, span, tokens: None, - could_be_bare_literal: false, }) } diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index 20f66fae5c01e..9adbcabcf4506 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -118,12 +118,23 @@ metadata_incompatible_rustc = metadata_incompatible_target_modifiers = mixing `{$flag_name_prefixed}` will cause an ABI mismatch in crate `{$local_crate}` - .note = `{$flag_name_prefixed}={$flag_local_value}` in this crate is incompatible with `{$flag_name_prefixed}={$flag_extern_value}` in dependency `{$extern_crate}` + .note = `{$flag_name_prefixed}={$local_value}` in this crate is incompatible with `{$flag_name_prefixed}={$extern_value}` in dependency `{$extern_crate}` .help = the `{$flag_name_prefixed}` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely - metadata_incompatible_target_modifiers_help_allow = if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch={$flag_name}` to silence this error -metadata_incompatible_target_modifiers_help_fix = set `{$flag_name_prefixed}={$flag_extern_value}` in this crate or `{$flag_name_prefixed}={$flag_local_value}` in `{$extern_crate}` +metadata_incompatible_target_modifiers_help_fix = set `{$flag_name_prefixed}={$extern_value}` in this crate or `{$flag_name_prefixed}={$local_value}` in `{$extern_crate}` + +metadata_incompatible_target_modifiers_help_fix_l_missed = set `{$flag_name_prefixed}={$extern_value}` in this crate or unset `{$flag_name_prefixed}` in `{$extern_crate}` +metadata_incompatible_target_modifiers_help_fix_r_missed = unset `{$flag_name_prefixed}` in this crate or set `{$flag_name_prefixed}={$local_value}` in `{$extern_crate}` + +metadata_incompatible_target_modifiers_l_missed = + mixing `{$flag_name_prefixed}` will cause an ABI mismatch in crate `{$local_crate}` + .note = unset `{$flag_name_prefixed}` in this crate is incompatible with `{$flag_name_prefixed}={$extern_value}` in dependency `{$extern_crate}` + .help = the `{$flag_name_prefixed}` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely +metadata_incompatible_target_modifiers_r_missed = + mixing `{$flag_name_prefixed}` will cause an ABI mismatch in crate `{$local_crate}` + .note = `{$flag_name_prefixed}={$local_value}` in this crate is incompatible with unset `{$flag_name_prefixed}` in dependency `{$extern_crate}` + .help = the `{$flag_name_prefixed}` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely metadata_incompatible_wasm_link = `wasm_import_module` is incompatible with other arguments in `#[link]` attributes diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 12503ffd1a67f..b7f13e0afdcde 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -358,30 +358,58 @@ impl CStore { ) { let span = krate.spans.inner_span.shrink_to_lo(); let allowed_flag_mismatches = &tcx.sess.opts.cg.unsafe_allow_abi_mismatch; - let name = tcx.crate_name(LOCAL_CRATE); + let local_crate = tcx.crate_name(LOCAL_CRATE); let tmod_extender = |tmod: &TargetModifier| (tmod.extend(), tmod.clone()); let report_diff = |prefix: &String, opt_name: &String, - flag_local_value: &String, - flag_extern_value: &String| { + flag_local_value: Option<&String>, + flag_extern_value: Option<&String>| { if allowed_flag_mismatches.contains(&opt_name) { return; } - tcx.dcx().emit_err(errors::IncompatibleTargetModifiers { - span, - extern_crate: data.name(), - local_crate: name, - flag_name: opt_name.clone(), - flag_name_prefixed: format!("-{}{}", prefix, opt_name), - flag_local_value: flag_local_value.to_string(), - flag_extern_value: flag_extern_value.to_string(), - }); + let extern_crate = data.name(); + let flag_name = opt_name.clone(); + let flag_name_prefixed = format!("-{}{}", prefix, opt_name); + + match (flag_local_value, flag_extern_value) { + (Some(local_value), Some(extern_value)) => { + tcx.dcx().emit_err(errors::IncompatibleTargetModifiers { + span, + extern_crate, + local_crate, + flag_name, + flag_name_prefixed, + local_value: local_value.to_string(), + extern_value: extern_value.to_string(), + }) + } + (None, Some(extern_value)) => { + tcx.dcx().emit_err(errors::IncompatibleTargetModifiersLMissed { + span, + extern_crate, + local_crate, + flag_name, + flag_name_prefixed, + extern_value: extern_value.to_string(), + }) + } + (Some(local_value), None) => { + tcx.dcx().emit_err(errors::IncompatibleTargetModifiersRMissed { + span, + extern_crate, + local_crate, + flag_name, + flag_name_prefixed, + local_value: local_value.to_string(), + }) + } + (None, None) => panic!("Incorrect target modifiers report_diff(None, None)"), + }; }; let mut it1 = mods.iter().map(tmod_extender); let mut it2 = dep_mods.iter().map(tmod_extender); let mut left_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None; let mut right_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None; - let no_val = "*".to_string(); loop { left_name_val = left_name_val.or_else(|| it1.next()); right_name_val = right_name_val.or_else(|| it2.next()); @@ -389,26 +417,31 @@ impl CStore { (Some(l), Some(r)) => match l.1.opt.cmp(&r.1.opt) { cmp::Ordering::Equal => { if l.0.tech_value != r.0.tech_value { - report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &r.1.value_name); + report_diff( + &l.0.prefix, + &l.0.name, + Some(&l.1.value_name), + Some(&r.1.value_name), + ); } left_name_val = None; right_name_val = None; } cmp::Ordering::Greater => { - report_diff(&r.0.prefix, &r.0.name, &no_val, &r.1.value_name); + report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name)); right_name_val = None; } cmp::Ordering::Less => { - report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &no_val); + report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None); left_name_val = None; } }, (Some(l), None) => { - report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &no_val); + report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None); left_name_val = None; } (None, Some(r)) => { - report_diff(&r.0.prefix, &r.0.name, &no_val, &r.1.value_name); + report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name)); right_name_val = None; } (None, None) => break, diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 2ad6389c0b4ac..0c54628598c48 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -759,8 +759,40 @@ pub struct IncompatibleTargetModifiers { pub local_crate: Symbol, pub flag_name: String, pub flag_name_prefixed: String, - pub flag_local_value: String, - pub flag_extern_value: String, + pub local_value: String, + pub extern_value: String, +} + +#[derive(Diagnostic)] +#[diag(metadata_incompatible_target_modifiers_l_missed)] +#[help] +#[note] +#[help(metadata_incompatible_target_modifiers_help_fix_l_missed)] +#[help(metadata_incompatible_target_modifiers_help_allow)] +pub struct IncompatibleTargetModifiersLMissed { + #[primary_span] + pub span: Span, + pub extern_crate: Symbol, + pub local_crate: Symbol, + pub flag_name: String, + pub flag_name_prefixed: String, + pub extern_value: String, +} + +#[derive(Diagnostic)] +#[diag(metadata_incompatible_target_modifiers_r_missed)] +#[help] +#[note] +#[help(metadata_incompatible_target_modifiers_help_fix_r_missed)] +#[help(metadata_incompatible_target_modifiers_help_allow)] +pub struct IncompatibleTargetModifiersRMissed { + #[primary_span] + pub span: Span, + pub extern_crate: Symbol, + pub local_crate: Symbol, + pub flag_name: String, + pub flag_name_prefixed: String, + pub local_value: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 68b9a4f56b96d..347bc5ea31289 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -14,7 +14,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::*; use rustc_macros::{Decodable, Encodable, HashStable}; -use rustc_span::{ErrorGuaranteed, ExpnId}; +use rustc_span::{ErrorGuaranteed, ExpnId, Span}; use crate::query::Providers; use crate::ty::{EarlyBinder, ImplSubject, TyCtxt}; @@ -157,6 +157,7 @@ impl<'tcx> TyCtxt<'tcx> { node: OwnerNode<'_>, bodies: &SortedMap>, attrs: &SortedMap, + define_opaque: Option<&[(Span, LocalDefId)]>, ) -> (Option, Option) { if self.needs_crate_hash() { self.with_stable_hashing_context(|mut hcx| { @@ -168,6 +169,10 @@ impl<'tcx> TyCtxt<'tcx> { let mut stable_hasher = StableHasher::new(); attrs.hash_stable(&mut hcx, &mut stable_hasher); + + // Hash the defined opaque types, which are not present in the attrs. + define_opaque.hash_stable(&mut hcx, &mut stable_hasher); + let h2 = stable_hasher.finish(); (Some(h1), Some(h2)) }) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f54dd2b0040ae..834d1f2a4a8de 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1288,7 +1288,8 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> { let bodies = Default::default(); let attrs = hir::AttributeMap::EMPTY; - let (opt_hash_including_bodies, _) = self.tcx.hash_owner_nodes(node, &bodies, &attrs.map); + let (opt_hash_including_bodies, _) = + self.tcx.hash_owner_nodes(node, &bodies, &attrs.map, attrs.define_opaque); let node = node.into(); self.opt_hir_owner_nodes(Some(self.tcx.arena.alloc(hir::OwnerNodes { opt_hash_including_bodies, diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index f2ce0c46dd33d..29d400a957b47 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -115,7 +115,6 @@ impl<'tcx> MatchPairTree<'tcx> { place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty)); } - // Place can be none if the pattern refers to a non-captured place in a closure. let place = place_builder.try_to_place(cx); let mut subpairs = Vec::new(); let test_case = match pattern.kind { @@ -321,7 +320,7 @@ impl<'tcx> MatchPairTree<'tcx> { if let Some(test_case) = test_case { // This pattern is refutable, so push a new match-pair node. match_pairs.push(MatchPairTree { - place: place.expect("refutable patterns should always have a place to inspect"), + place, test_case, subpairs, pattern_ty: pattern.ty, diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 710538ef4b867..3acf2a6a2a61a 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -13,13 +13,13 @@ use std::sync::Arc; use rustc_abi::VariantIdx; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_hir::{BindingMode, ByRef}; +use rustc_hir::{BindingMode, ByRef, LetStmt, LocalSource, Node}; use rustc_middle::bug; use rustc_middle::middle::region; use rustc_middle::mir::{self, *}; use rustc_middle::thir::{self, *}; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty}; -use rustc_span::{BytePos, Pos, Span, Symbol}; +use rustc_span::{BytePos, Pos, Span, Symbol, sym}; use tracing::{debug, instrument}; use crate::builder::ForGuard::{self, OutsideGuard, RefWithinGuard}; @@ -1279,7 +1279,13 @@ impl<'tcx> TestCase<'tcx> { #[derive(Debug, Clone)] pub(crate) struct MatchPairTree<'tcx> { /// This place... - place: Place<'tcx>, + /// + /// --- + /// This can be `None` if it referred to a non-captured place in a closure. + /// + /// Invariant: Can only be `None` when `test_case` is `Or`. + /// Therefore this must be `Some(_)` after or-pattern expansion. + place: Option>, /// ... must pass this test... test_case: TestCase<'tcx>, @@ -2099,9 +2105,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Extract the match-pair from the highest priority candidate let match_pair = &candidates[0].match_pairs[0]; let test = self.pick_test_for_match_pair(match_pair); + // Unwrap is ok after simplification. + let match_place = match_pair.place.unwrap(); debug!(?test, ?match_pair); - (match_pair.place, test) + (match_place, test) } /// Given a test, we partition the input candidates into several buckets. @@ -2796,13 +2804,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { )))), }; let for_arm_body = self.local_decls.push(local); - self.var_debug_info.push(VarDebugInfo { - name, - source_info: debug_source_info, - value: VarDebugInfoContents::Place(for_arm_body.into()), - composite: None, - argument_index: None, - }); + if self.should_emit_debug_info_for_binding(name, var_id) { + self.var_debug_info.push(VarDebugInfo { + name, + source_info: debug_source_info, + value: VarDebugInfoContents::Place(for_arm_body.into()), + composite: None, + argument_index: None, + }); + } let locals = if has_guard.0 { let ref_for_guard = self.local_decls.push(LocalDecl::<'tcx> { // This variable isn't mutated but has a name, so has to be @@ -2815,13 +2825,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { BindingForm::RefForGuard, ))), }); - self.var_debug_info.push(VarDebugInfo { - name, - source_info: debug_source_info, - value: VarDebugInfoContents::Place(ref_for_guard.into()), - composite: None, - argument_index: None, - }); + if self.should_emit_debug_info_for_binding(name, var_id) { + self.var_debug_info.push(VarDebugInfo { + name, + source_info: debug_source_info, + value: VarDebugInfoContents::Place(ref_for_guard.into()), + composite: None, + argument_index: None, + }); + } LocalsForNode::ForGuard { ref_for_guard, for_arm_body } } else { LocalsForNode::One(for_arm_body) @@ -2829,4 +2841,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug!(?locals); self.var_indices.insert(var_id, locals); } + + /// Some bindings are introduced when producing HIR from the AST and don't + /// actually exist in the source. Skip producing debug info for those when + /// we can recognize them. + fn should_emit_debug_info_for_binding(&self, name: Symbol, var_id: LocalVarId) -> bool { + // For now we only recognize the output of desugaring assigns. + if name != sym::lhs { + return true; + } + + let tcx = self.tcx; + for (_, node) in tcx.hir_parent_iter(var_id.0) { + // FIXME(khuey) at what point is it safe to bail on the iterator? + // Can we stop at the first non-Pat node? + if matches!(node, Node::LetStmt(&LetStmt { source: LocalSource::AssignDesugar(_), .. })) + { + return false; + } + } + + true + } } diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 7ef9e48326f63..d1f9d4c34fe1e 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -470,8 +470,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // than one, but it'd be very unusual to have two sides that // both require tests; you'd expect one side to be simplified // away.) - let (match_pair_index, match_pair) = - candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == test_place)?; + let (match_pair_index, match_pair) = candidate + .match_pairs + .iter() + .enumerate() + .find(|&(_, mp)| mp.place == Some(test_place))?; // If true, the match pair is completely entailed by its corresponding test // branch, so it can be removed. If false, the match pair is _compatible_ @@ -514,7 +517,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidate .match_pairs .iter() - .any(|mp| mp.place == test_place && is_covering_range(&mp.test_case)) + .any(|mp| mp.place == Some(test_place) && is_covering_range(&mp.test_case)) }; if sorted_candidates .get(&TestBranch::Failure) diff --git a/compiler/rustc_mir_build/src/builder/matches/util.rs b/compiler/rustc_mir_build/src/builder/matches/util.rs index ed3b652e4ef5d..589e350a03fc3 100644 --- a/compiler/rustc_mir_build/src/builder/matches/util.rs +++ b/compiler/rustc_mir_build/src/builder/matches/util.rs @@ -173,10 +173,14 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { // } // ``` // Hence we fake borrow using a deep borrow. - self.fake_borrow(match_pair.place, FakeBorrowKind::Deep); + if let Some(place) = match_pair.place { + self.fake_borrow(place, FakeBorrowKind::Deep); + } } else { // Insert a Shallow borrow of any place that is switched on. - self.fake_borrow(match_pair.place, FakeBorrowKind::Shallow); + if let Some(place) = match_pair.place { + self.fake_borrow(place, FakeBorrowKind::Shallow); + } for subpair in &match_pair.subpairs { self.visit_match_pair(subpair); diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 6d4308cda1a60..3253222b8f23f 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -757,10 +757,6 @@ parse_struct_literal_body_without_path = struct literal body without path .suggestion = you might have forgotten to add the struct literal inside the block -parse_struct_literal_needing_parens = - invalid struct literal - .suggestion = you might need to surround the struct literal with parentheses - parse_struct_literal_not_allowed_here = struct literals are not allowed here .suggestion = surround the struct literal with parentheses diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index e090d9cf7600e..f813c3380fcbd 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1272,24 +1272,6 @@ pub(crate) struct StructLiteralBodyWithoutPathSugg { pub after: Span, } -#[derive(Diagnostic)] -#[diag(parse_struct_literal_needing_parens)] -pub(crate) struct StructLiteralNeedingParens { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub sugg: StructLiteralNeedingParensSugg, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")] -pub(crate) struct StructLiteralNeedingParensSugg { - #[suggestion_part(code = "(")] - pub before: Span, - #[suggestion_part(code = ")")] - pub after: Span, -} - #[derive(Diagnostic)] #[diag(parse_unmatched_angle_brackets)] pub(crate) struct UnmatchedAngleBrackets { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index c1cca1186af49..ef044fe9d6385 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -40,9 +40,8 @@ use crate::errors::{ HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, - StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg, - SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator, - UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, + StructLiteralBodyWithoutPathSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, + TernaryOperator, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType, }; use crate::parser::attr::InnerAttrPolicy; @@ -949,7 +948,6 @@ impl<'a> Parser<'a> { lo: Span, s: BlockCheckMode, maybe_struct_name: token::Token, - can_be_struct_literal: bool, ) -> Option>> { if self.token.is_ident() && self.look_ahead(1, |t| t == &token::Colon) { // We might be having a struct literal where people forgot to include the path: @@ -975,47 +973,23 @@ impl<'a> Parser<'a> { // fn foo() -> Foo { Path { // field: value, // } } - let guar = err.delay_as_bug(); + err.cancel(); self.restore_snapshot(snapshot); - let mut tail = self.mk_block( + let guar = self.dcx().emit_err(StructLiteralBodyWithoutPath { + span: expr.span, + sugg: StructLiteralBodyWithoutPathSugg { + before: expr.span.shrink_to_lo(), + after: expr.span.shrink_to_hi(), + }, + }); + Ok(self.mk_block( thin_vec![self.mk_stmt_err(expr.span, guar)], s, lo.to(self.prev_token.span), - ); - tail.could_be_bare_literal = true; - if maybe_struct_name.is_ident() && can_be_struct_literal { - // Account for `if Example { a: one(), }.is_pos() {}`. - // expand `before` so that we take care of module path such as: - // `foo::Bar { ... } ` - // we expect to suggest `(foo::Bar { ... })` instead of `foo::(Bar { ... })` - let sm = self.psess.source_map(); - let before = maybe_struct_name.span.shrink_to_lo(); - if let Ok(extend_before) = sm.span_extend_prev_while(before, |t| { - t.is_alphanumeric() || t == ':' || t == '_' - }) { - Err(self.dcx().create_err(StructLiteralNeedingParens { - span: maybe_struct_name.span.to(expr.span), - sugg: StructLiteralNeedingParensSugg { - before: extend_before.shrink_to_lo(), - after: expr.span.shrink_to_hi(), - }, - })) - } else { - return None; - } - } else { - self.dcx().emit_err(StructLiteralBodyWithoutPath { - span: expr.span, - sugg: StructLiteralBodyWithoutPathSugg { - before: expr.span.shrink_to_lo(), - after: expr.span.shrink_to_hi(), - }, - }); - Ok(tail) - } + )) } (Err(err), Ok(tail)) => { - // We have a block tail that contains a somehow valid type ascription expr. + // We have a block tail that contains a somehow valid expr. err.cancel(); Ok(tail) } @@ -1025,10 +999,7 @@ impl<'a> Parser<'a> { self.consume_block(exp!(OpenBrace), exp!(CloseBrace), ConsumeClosingDelim::Yes); Err(err) } - (Ok(_), Ok(mut tail)) => { - tail.could_be_bare_literal = true; - Ok(tail) - } + (Ok(_), Ok(tail)) => Ok(tail), }); } None diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index c48f91643e88a..92e83577f1b13 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2296,7 +2296,7 @@ impl<'a> Parser<'a> { }); } - let (attrs, blk) = self.parse_block_common(lo, blk_mode, true, None)?; + let (attrs, blk) = self.parse_block_common(lo, blk_mode, None)?; Ok(self.mk_expr_with_attrs(blk.span, ExprKind::Block(blk, opt_label), attrs)) } @@ -3474,19 +3474,9 @@ impl<'a> Parser<'a> { } fn is_certainly_not_a_block(&self) -> bool { + // `{ ident, ` and `{ ident: ` cannot start a block. self.look_ahead(1, |t| t.is_ident()) - && ( - // `{ ident, ` cannot start a block. - self.look_ahead(2, |t| t == &token::Comma) - || self.look_ahead(2, |t| t == &token::Colon) - && ( - // `{ ident: token, ` cannot start a block. - self.look_ahead(4, |t| t == &token::Comma) - // `{ ident: ` cannot start a block unless it's a type ascription - // `ident: Type`. - || self.look_ahead(3, |t| !t.can_begin_type()) - ) - ) + && self.look_ahead(2, |t| t == &token::Comma || t == &token::Colon) } fn maybe_parse_struct_expr( diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index c32a79f690911..aad1857837554 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2538,7 +2538,7 @@ impl<'a> Parser<'a> { *sig_hi = self.prev_token.span; (AttrVec::new(), None) } else if self.check(exp!(OpenBrace)) || self.token.is_whole_block() { - self.parse_block_common(self.token.span, BlockCheckMode::Default, false, None) + self.parse_block_common(self.token.span, BlockCheckMode::Default, None) .map(|(attrs, body)| (attrs, Some(body)))? } else if self.token == token::Eq { // Recover `fn foo() = $expr;`. diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 0fe247078d51f..97cd4d2117f87 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -668,7 +668,7 @@ impl<'a> Parser<'a> { &mut self, loop_header: Option, ) -> PResult<'a, (AttrVec, P)> { - self.parse_block_common(self.token.span, BlockCheckMode::Default, true, loop_header) + self.parse_block_common(self.token.span, BlockCheckMode::Default, loop_header) } /// Parses a block. Inner attributes are allowed, block labels are not. @@ -679,7 +679,6 @@ impl<'a> Parser<'a> { &mut self, lo: Span, blk_mode: BlockCheckMode, - can_be_struct_literal: bool, loop_header: Option, ) -> PResult<'a, (AttrVec, P)> { maybe_whole!(self, NtBlock, |block| (AttrVec::new(), block)); @@ -691,12 +690,7 @@ impl<'a> Parser<'a> { } let attrs = self.parse_inner_attributes()?; - let tail = match self.maybe_suggest_struct_literal( - lo, - blk_mode, - maybe_ident, - can_be_struct_literal, - ) { + let tail = match self.maybe_suggest_struct_literal(lo, blk_mode, maybe_ident) { Some(tail) => tail?, None => self.parse_block_tail(lo, blk_mode, AttemptLocalParseRecovery::Yes)?, }; @@ -1043,14 +1037,7 @@ impl<'a> Parser<'a> { rules: BlockCheckMode, span: Span, ) -> P { - P(Block { - stmts, - id: DUMMY_NODE_ID, - rules, - span, - tokens: None, - could_be_bare_literal: false, - }) + P(Block { stmts, id: DUMMY_NODE_ID, rules, span, tokens: None }) } pub(super) fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 11d07407aa18d..6bc644e9e1177 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -675,11 +675,6 @@ struct DiagMetadata<'ast> { /// they are used (in a `break` or `continue` statement) unused_labels: FxIndexMap, - /// Only used for better errors on `let x = { foo: bar };`. - /// In the case of a parse error with `let x = { foo: bar, };`, this isn't needed, it's only - /// needed for cases where this parses as a correct type ascription. - current_block_could_be_bare_struct_literal: Option, - /// Only used for better errors on `let : ;`. current_let_binding: Option<(Span, Option, Option)>, @@ -4661,13 +4656,6 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.ribs[ValueNS].push(Rib::new(RibKind::Normal)); } - let prev = self.diag_metadata.current_block_could_be_bare_struct_literal.take(); - if let (true, [Stmt { kind: StmtKind::Expr(expr), .. }]) = - (block.could_be_bare_literal, &block.stmts[..]) - && let ExprKind::Type(..) = expr.kind - { - self.diag_metadata.current_block_could_be_bare_struct_literal = Some(block.span); - } // Descend into the block. for stmt in &block.stmts { if let StmtKind::Item(ref item) = stmt.kind @@ -4681,7 +4669,6 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.visit_stmt(stmt); } - self.diag_metadata.current_block_could_be_bare_struct_literal = prev; // Move back up. self.parent_scope.module = orig_module; diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 75232e0de0052..cf8db2267f41e 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -450,7 +450,6 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { err.span_suggestion_verbose(sugg.0, sugg.1, &sugg.2, Applicability::MaybeIncorrect); } - self.suggest_bare_struct_literal(&mut err); self.suggest_changing_type_to_const_param(&mut err, res, source, span); self.explain_functions_in_pattern(&mut err, res, source); @@ -1279,19 +1278,6 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } - fn suggest_bare_struct_literal(&mut self, err: &mut Diag<'_>) { - if let Some(span) = self.diag_metadata.current_block_could_be_bare_struct_literal { - err.multipart_suggestion( - "you might have meant to write a `struct` literal", - vec![ - (span.shrink_to_lo(), "{ SomeStruct ".to_string()), - (span.shrink_to_hi(), "}".to_string()), - ], - Applicability::HasPlaceholders, - ); - } - } - fn explain_functions_in_pattern( &mut self, err: &mut Diag<'_>, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 03475058ce82e..4cc666b3e37d2 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -94,45 +94,49 @@ fn tmod_push_impl( tmod_vals: &BTreeMap, tmods: &mut Vec, ) { - tmods.push(TargetModifier { opt, value_name: tmod_vals.get(&opt).cloned().unwrap_or_default() }) + if let Some(v) = tmod_vals.get(&opt) { + tmods.push(TargetModifier { opt, value_name: v.clone() }) + } } macro_rules! tmod_push { - ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $mods:expr, $tmod_vals:expr) => { - tmod_push_impl( - OptionsTargetModifiers::$struct_name($tmod_enum_name::$opt_name), - $tmod_vals, - $mods, - ); + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr) => { + if *$opt_expr != $init { + tmod_push_impl( + OptionsTargetModifiers::$struct_name($tmod_enum_name::$opt_name), + $tmod_vals, + $mods, + ); + } }; } macro_rules! gather_tmods { - ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr, [SUBSTRUCT], [TARGET_MODIFIER]) => { compile_error!("SUBSTRUCT can't be target modifier"); }; - ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr, [UNTRACKED], [TARGET_MODIFIER]) => { - tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals) + tmod_push!($struct_name, $tmod_enum_name, $opt_name, $opt_expr, $init, $mods, $tmod_vals) }; - ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr, [TRACKED], [TARGET_MODIFIER]) => { - tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals) + tmod_push!($struct_name, $tmod_enum_name, $opt_name, $opt_expr, $init, $mods, $tmod_vals) }; - ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr, [TRACKED_NO_CRATE_HASH], [TARGET_MODIFIER]) => { - tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals) + tmod_push!($struct_name, $tmod_enum_name, $opt_name, $opt_expr, $init, $mods, $tmod_vals) }; - ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr, [SUBSTRUCT], []) => { $opt_expr.gather_target_modifiers($mods, $tmod_vals); }; - ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr, [UNTRACKED], []) => {{}}; - ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr, [TRACKED], []) => {{}}; - ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr, [TRACKED_NO_CRATE_HASH], []) => {{}}; } @@ -474,7 +478,8 @@ macro_rules! tmod_enum { $($pout)* Self::$opt => { let mut parsed : $t = Default::default(); - parse::$parse(&mut parsed, Some($puser_value)); + let val = if $puser_value.is_empty() { None } else { Some($puser_value) }; + parse::$parse(&mut parsed, val); ExtendedTargetModifierInfo { prefix: $prefix.to_string(), name: stringify!($opt).to_string().replace('_', "-"), @@ -569,7 +574,7 @@ macro_rules! options { _tmod_vals: &BTreeMap, ) { $({ - gather_tmods!($struct_name, $tmod_enum_name, $opt, &self.$opt, _mods, _tmod_vals, + gather_tmods!($struct_name, $tmod_enum_name, $opt, &self.$opt, $init, _mods, _tmod_vals, [$dep_tracking_marker], [$($tmod),*]); })* } @@ -681,10 +686,9 @@ fn build_options( ), } } - if let Some(tmod) = *tmod - && let Some(value) = value - { - target_modifiers.insert(tmod, value.to_string()); + if let Some(tmod) = *tmod { + let v = value.map_or(String::new(), ToOwned::to_owned); + target_modifiers.insert(tmod, v); } } None => early_dcx.early_fatal(format!("unknown {outputname} option: `{key}`")), diff --git a/library/std/src/sys/net/connection/xous/tcpstream.rs b/library/std/src/sys/net/connection/xous/tcpstream.rs index 283b1fe9a33b9..e8aea8b706a58 100644 --- a/library/std/src/sys/net/connection/xous/tcpstream.rs +++ b/library/std/src/sys/net/connection/xous/tcpstream.rs @@ -324,7 +324,7 @@ impl TcpStream { } Ok(SocketAddr::V6(SocketAddrV6::new(new_addr.into(), self.local_port, 0, 0))) } - _ => Err(io::const_error!(io::ErrorKind::InvalidInput, "tnternal error")), + _ => Err(io::const_error!(io::ErrorKind::InvalidInput, "internal error")), } } diff --git a/src/build_helper/src/metrics.rs b/src/build_helper/src/metrics.rs index b6daac32a4412..fdff9cd18cea7 100644 --- a/src/build_helper/src/metrics.rs +++ b/src/build_helper/src/metrics.rs @@ -109,6 +109,8 @@ pub struct BuildStep { pub r#type: String, pub children: Vec, pub duration: Duration, + // Full name of the step, including all parent names + pub full_name: String, } impl BuildStep { @@ -116,7 +118,7 @@ impl BuildStep { /// The most important thing is that the build step aggregates the /// durations of all children, so that it can be easily accessed. pub fn from_invocation(invocation: &JsonInvocation) -> Self { - fn parse(node: &JsonNode) -> Option { + fn parse(node: &JsonNode, parent_name: &str) -> Option { match node { JsonNode::RustbuildStep { type_: kind, @@ -124,11 +126,14 @@ impl BuildStep { duration_excluding_children_sec, .. } => { - let children: Vec<_> = children.into_iter().filter_map(parse).collect(); + let full_name = format!("{parent_name}-{kind}"); + let children: Vec<_> = + children.into_iter().filter_map(|s| parse(s, &full_name)).collect(); let children_duration = children.iter().map(|c| c.duration).sum::(); Some(BuildStep { r#type: kind.to_string(), children, + full_name, duration: children_duration + Duration::from_secs_f64(*duration_excluding_children_sec), }) @@ -138,8 +143,13 @@ impl BuildStep { } let duration = Duration::from_secs_f64(invocation.duration_including_children_sec); - let children: Vec<_> = invocation.children.iter().filter_map(parse).collect(); - Self { r#type: "total".to_string(), children, duration } + + // The root "total" step is kind of a virtual step that encompasses all other steps, + // but it is not a real parent of the other steps. + // We thus start the parent name hierarchy here and use an empty string + // as the parent name of the top-level steps. + let children: Vec<_> = invocation.children.iter().filter_map(|s| parse(s, "")).collect(); + Self { r#type: "total".to_string(), children, duration, full_name: "total".to_string() } } pub fn find_all_by_type(&self, r#type: &str) -> Vec<&Self> { @@ -156,33 +166,38 @@ impl BuildStep { child.find_by_type(r#type, result); } } -} -/// Writes build steps into a nice indented table. -pub fn format_build_steps(root: &BuildStep) -> String { - use std::fmt::Write; - - let mut substeps: Vec<(u32, &BuildStep)> = Vec::new(); + /// Returns a Vec with all substeps, ordered by their hierarchical order. + /// The first element of the tuple is the depth of a given step. + pub fn linearize_steps(&self) -> Vec<(u32, &BuildStep)> { + let mut substeps: Vec<(u32, &BuildStep)> = Vec::new(); - fn visit<'a>(step: &'a BuildStep, level: u32, substeps: &mut Vec<(u32, &'a BuildStep)>) { - substeps.push((level, step)); - for child in &step.children { - visit(child, level + 1, substeps); + fn visit<'a>(step: &'a BuildStep, level: u32, substeps: &mut Vec<(u32, &'a BuildStep)>) { + substeps.push((level, step)); + for child in &step.children { + visit(child, level + 1, substeps); + } } + + visit(self, 0, &mut substeps); + substeps } +} - visit(root, 0, &mut substeps); +/// Writes build steps into a nice indented table. +pub fn format_build_steps(root: &BuildStep) -> String { + use std::fmt::Write; let mut output = String::new(); - for (level, step) in substeps { - let label = format!( - "{}{}", - ".".repeat(level as usize), - // Bootstrap steps can be generic and thus contain angle brackets (<...>). - // However, Markdown interprets these as HTML, so we need to escap ethem. - step.r#type.replace('<', "<").replace('>', ">") - ); + for (level, step) in root.linearize_steps() { + let label = format!("{}{}", ".".repeat(level as usize), escape_step_name(step)); writeln!(output, "{label:.<65}{:>8.2}s", step.duration.as_secs_f64()).unwrap(); } output } + +/// Bootstrap steps can be generic and thus contain angle brackets (<...>). +/// However, Markdown interprets these as HTML, so we need to escap ethem. +pub fn escape_step_name(step: &BuildStep) -> String { + step.r#type.replace('<', "<").replace('>', ">") +} diff --git a/src/ci/citool/Cargo.lock b/src/ci/citool/Cargo.lock index c061ec6ebdcee..800eaae076650 100644 --- a/src/ci/citool/Cargo.lock +++ b/src/ci/citool/Cargo.lock @@ -107,6 +107,7 @@ dependencies = [ "build_helper", "clap", "csv", + "diff", "glob-match", "insta", "serde", @@ -241,6 +242,12 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "displaydoc" version = "0.2.5" diff --git a/src/ci/citool/Cargo.toml b/src/ci/citool/Cargo.toml index dde09224afe84..f18436a126359 100644 --- a/src/ci/citool/Cargo.toml +++ b/src/ci/citool/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" anyhow = "1" clap = { version = "4.5", features = ["derive"] } csv = "1" +diff = "0.1" glob-match = "0.2" serde = { version = "1", features = ["derive"] } serde_yaml = "0.9" diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs index 98e9be0f35af3..2b001f28b0eb4 100644 --- a/src/ci/citool/src/analysis.rs +++ b/src/ci/citool/src/analysis.rs @@ -1,33 +1,134 @@ use std::collections::{BTreeMap, HashMap, HashSet}; +use std::fmt::Debug; use build_helper::metrics::{ - BuildStep, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, format_build_steps, + BuildStep, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, escape_step_name, + format_build_steps, }; use crate::metrics; use crate::metrics::{JobMetrics, JobName, get_test_suites}; use crate::utils::{output_details, pluralize}; -pub fn output_bootstrap_stats(metrics: &JsonRoot) { +/// Outputs durations of individual bootstrap steps from the gathered bootstrap invocations, +/// and also a table with summarized information about executed tests. +pub fn output_bootstrap_stats(metrics: &JsonRoot, parent_metrics: Option<&JsonRoot>) { if !metrics.invocations.is_empty() { println!("# Bootstrap steps"); - record_bootstrap_step_durations(&metrics); + record_bootstrap_step_durations(&metrics, parent_metrics); record_test_suites(&metrics); } } -fn record_bootstrap_step_durations(metrics: &JsonRoot) { +fn record_bootstrap_step_durations(metrics: &JsonRoot, parent_metrics: Option<&JsonRoot>) { + let parent_steps: HashMap = parent_metrics + .map(|metrics| { + metrics + .invocations + .iter() + .map(|invocation| { + (invocation.cmdline.clone(), BuildStep::from_invocation(invocation)) + }) + .collect() + }) + .unwrap_or_default(); + for invocation in &metrics.invocations { let step = BuildStep::from_invocation(invocation); let table = format_build_steps(&step); eprintln!("Step `{}`\n{table}\n", invocation.cmdline); - output_details(&invocation.cmdline, || { + output_details(&format!("{} (steps)", invocation.cmdline), || { println!("
{table}
"); }); + + // If there was a parent bootstrap invocation with the same cmdline, diff it + if let Some(parent_step) = parent_steps.get(&invocation.cmdline) { + let table = format_build_step_diffs(&step, parent_step); + + let duration_before = parent_step.duration.as_secs(); + let duration_after = step.duration.as_secs(); + output_details( + &format!("{} (diff) ({duration_before}s -> {duration_after}s)", invocation.cmdline), + || { + println!("{table}"); + }, + ); + } } eprintln!("Recorded {} bootstrap invocation(s)", metrics.invocations.len()); } +/// Creates a table that displays a diff between the durations of steps between +/// two bootstrap invocations. +/// It also shows steps that were missing before/after. +fn format_build_step_diffs(current: &BuildStep, parent: &BuildStep) -> String { + use std::fmt::Write; + + // Helper struct that compares steps by their full name + struct StepByName<'a>((u32, &'a BuildStep)); + + impl<'a> PartialEq for StepByName<'a> { + fn eq(&self, other: &Self) -> bool { + self.0.1.full_name.eq(&other.0.1.full_name) + } + } + + fn get_steps(step: &BuildStep) -> Vec { + step.linearize_steps().into_iter().map(|v| StepByName(v)).collect() + } + + let steps_before = get_steps(parent); + let steps_after = get_steps(current); + + let mut table = "| Step | Before | After | Change |\n".to_string(); + writeln!(table, "|:-----|-------:|------:|-------:|").unwrap(); + + // Try to match removed, added and same steps using a classic diff algorithm + for result in diff::slice(&steps_before, &steps_after) { + let (step, before, after, change) = match result { + // The step was found both before and after + diff::Result::Both(before, after) => { + let duration_before = before.0.1.duration; + let duration_after = after.0.1.duration; + let pct_change = duration_after.as_secs_f64() / duration_before.as_secs_f64(); + let pct_change = pct_change * 100.0; + // Normalize around 100, to get + for regression and - for improvements + let pct_change = pct_change - 100.0; + ( + before, + format!("{:.2}s", duration_before.as_secs_f64()), + format!("{:.2}s", duration_after.as_secs_f64()), + format!("{pct_change:.1}%"), + ) + } + // The step was only found in the parent, so it was likely removed + diff::Result::Left(removed) => ( + removed, + format!("{:.2}s", removed.0.1.duration.as_secs_f64()), + "".to_string(), + "(removed)".to_string(), + ), + // The step was only found in the current commit, so it was likely added + diff::Result::Right(added) => ( + added, + "".to_string(), + format!("{:.2}s", added.0.1.duration.as_secs_f64()), + "(added)".to_string(), + ), + }; + + let prefix = ".".repeat(step.0.0 as usize); + writeln!( + table, + "| {prefix}{} | {before} | {after} | {change} |", + escape_step_name(step.0.1), + ) + .unwrap(); + } + + table +} + fn record_test_suites(metrics: &JsonRoot) { let suites = metrics::get_test_suites(&metrics); @@ -82,8 +183,7 @@ fn render_table(suites: BTreeMap) -> String { table } -/// Computes a post merge CI analysis report of test differences -/// between the `parent` and `current` commits. +/// Outputs a report of test differences between the `parent` and `current` commits. pub fn output_test_diffs(job_metrics: HashMap) { let aggregated_test_diffs = aggregate_test_diffs(&job_metrics); report_test_diffs(aggregated_test_diffs); diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index 5a84ecb5e47e5..5f5c50dc43a0e 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -144,31 +144,35 @@ fn postprocess_metrics( job_name: Option, ) -> anyhow::Result<()> { let metrics = load_metrics(&metrics_path)?; - output_bootstrap_stats(&metrics); - let (Some(parent), Some(job_name)) = (parent, job_name) else { - return Ok(()); - }; - - // This command is executed also on PR builds, which might not have parent metrics - // available, because some PR jobs don't run on auto builds, and PR jobs do not upload metrics - // due to missing permissions. - // To avoid having to detect if this is a PR job, and to avoid having failed steps in PR jobs, - // we simply print an error if the parent metrics were not found, but otherwise exit - // successfully. - match download_job_metrics(&job_name, &parent).context("cannot download parent metrics") { - Ok(parent_metrics) => { - let job_metrics = HashMap::from([( - job_name, - JobMetrics { parent: Some(parent_metrics), current: metrics }, - )]); - output_test_diffs(job_metrics); - } - Err(error) => { - eprintln!("Metrics for job `{job_name}` and commit `{parent}` not found: {error:?}"); + if let (Some(parent), Some(job_name)) = (parent, job_name) { + // This command is executed also on PR builds, which might not have parent metrics + // available, because some PR jobs don't run on auto builds, and PR jobs do not upload metrics + // due to missing permissions. + // To avoid having to detect if this is a PR job, and to avoid having failed steps in PR jobs, + // we simply print an error if the parent metrics were not found, but otherwise exit + // successfully. + match download_job_metrics(&job_name, &parent).context("cannot download parent metrics") { + Ok(parent_metrics) => { + output_bootstrap_stats(&metrics, Some(&parent_metrics)); + + let job_metrics = HashMap::from([( + job_name, + JobMetrics { parent: Some(parent_metrics), current: metrics }, + )]); + output_test_diffs(job_metrics); + return Ok(()); + } + Err(error) => { + eprintln!( + "Metrics for job `{job_name}` and commit `{parent}` not found: {error:?}" + ); + } } } + output_bootstrap_stats(&metrics, None); + Ok(()) } diff --git a/src/tools/rustfmt/src/closures.rs b/src/tools/rustfmt/src/closures.rs index a37b47e3bc955..61e148cdf1884 100644 --- a/src/tools/rustfmt/src/closures.rs +++ b/src/tools/rustfmt/src/closures.rs @@ -176,7 +176,6 @@ fn rewrite_closure_with_block( .first() .map(|attr| attr.span.to(body.span)) .unwrap_or(body.span), - could_be_bare_literal: false, }; let block = crate::expr::rewrite_block_with_visitor( context, diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs index 664c90b991a9b..e239ff47c043e 100644 --- a/src/tools/rustfmt/src/macros.rs +++ b/src/tools/rustfmt/src/macros.rs @@ -423,7 +423,6 @@ fn rewrite_empty_macro_def_body( rules: ast::BlockCheckMode::Default, span, tokens: None, - could_be_bare_literal: false, }; block.rewrite_result(context, shape) } diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 4a929a376d782..a33e03d5861ed 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -3189,7 +3189,6 @@ ui/parser/issues/issue-108495-dec.rs ui/parser/issues/issue-110014.rs ui/parser/issues/issue-111148.rs ui/parser/issues/issue-111416.rs -ui/parser/issues/issue-111692.rs ui/parser/issues/issue-112188.rs ui/parser/issues/issue-112458.rs ui/parser/issues/issue-113110-non-item-at-module-root.rs diff --git a/tests/codegen/assign-desugar-debuginfo.rs b/tests/codegen/assign-desugar-debuginfo.rs new file mode 100644 index 0000000000000..77ee8758b3b3b --- /dev/null +++ b/tests/codegen/assign-desugar-debuginfo.rs @@ -0,0 +1,18 @@ +//@ compile-flags: -g -Zmir-opt-level=0 + +#![crate_type = "lib"] + +#[inline(never)] +fn swizzle(a: u32, b: u32, c: u32) -> (u32, (u32, u32)) { + (b, (c, a)) +} + +pub fn work() { + let mut a = 1; + let mut b = 2; + let mut c = 3; + (a, (b, c)) = swizzle(a, b, c); + println!("{a} {b} {c}"); +} + +// CHECK-NOT: !DILocalVariable(name: "lhs", diff --git a/tests/incremental/define-opaques.rs b/tests/incremental/define-opaques.rs new file mode 100644 index 0000000000000..d6eae23834122 --- /dev/null +++ b/tests/incremental/define-opaques.rs @@ -0,0 +1,19 @@ +//@ revisions: rpass1 cfail2 + +#![feature(type_alias_impl_trait)] + +pub type Foo = impl Sized; + +#[cfg_attr(rpass1, define_opaque())] +#[cfg_attr(cfail2, define_opaque(Foo))] +fn a() { + //[cfail2]~^ ERROR item does not constrain `Foo::{opaque#0}` + let _: Foo = b(); +} + +#[define_opaque(Foo)] +fn b() -> Foo { + () +} + +fn main() {} diff --git a/tests/ui-fulldeps/pprust-expr-roundtrip.rs b/tests/ui-fulldeps/pprust-expr-roundtrip.rs index 37e328a315f1e..4a866560e798a 100644 --- a/tests/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/tests/ui-fulldeps/pprust-expr-roundtrip.rs @@ -114,7 +114,6 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P)) { rules: BlockCheckMode::Default, span: DUMMY_SP, tokens: None, - could_be_bare_literal: false, }); iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None))); } diff --git a/tests/ui/closures/upvar-or-pattern-issue-138958.rs b/tests/ui/closures/upvar-or-pattern-issue-138958.rs new file mode 100644 index 0000000000000..fe9ebc0a7e69c --- /dev/null +++ b/tests/ui/closures/upvar-or-pattern-issue-138958.rs @@ -0,0 +1,11 @@ +//@ edition:2024 +//@ check-pass + +pub fn f(x: (u32, u32)) { + let _ = || { + let ((0, a) | (a, _)) = x; + a + }; +} + +fn main() {} diff --git a/tests/ui/parser/issues/issue-111692.rs b/tests/ui/parser/issues/issue-111692.rs deleted file mode 100644 index 56096f706a8a7..0000000000000 --- a/tests/ui/parser/issues/issue-111692.rs +++ /dev/null @@ -1,32 +0,0 @@ -mod module { - #[derive(Eq, PartialEq)] - pub struct Type { - pub x: u8, - pub y: u8, - } - - pub const C: u8 = 32u8; -} - -fn test(x: module::Type) { - if x == module::Type { x: module::C, y: 1 } { //~ ERROR invalid struct literal - } -} - -fn test2(x: module::Type) { - if x ==module::Type { x: module::C, y: 1 } { //~ ERROR invalid struct literal - } -} - - -fn test3(x: module::Type) { - if x == Type { x: module::C, y: 1 } { //~ ERROR invalid struct literal - } -} - -fn test4(x: module::Type) { - if x == demo_module::Type { x: module::C, y: 1 } { //~ ERROR invalid struct literal - } -} - -fn main() { } diff --git a/tests/ui/parser/issues/issue-111692.stderr b/tests/ui/parser/issues/issue-111692.stderr deleted file mode 100644 index 068b0483b0fd3..0000000000000 --- a/tests/ui/parser/issues/issue-111692.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error: invalid struct literal - --> $DIR/issue-111692.rs:12:21 - | -LL | if x == module::Type { x: module::C, y: 1 } { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: you might need to surround the struct literal with parentheses - | -LL | if x == (module::Type { x: module::C, y: 1 }) { - | + + - -error: invalid struct literal - --> $DIR/issue-111692.rs:17:20 - | -LL | if x ==module::Type { x: module::C, y: 1 } { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: you might need to surround the struct literal with parentheses - | -LL | if x ==(module::Type { x: module::C, y: 1 }) { - | + + - -error: invalid struct literal - --> $DIR/issue-111692.rs:23:13 - | -LL | if x == Type { x: module::C, y: 1 } { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: you might need to surround the struct literal with parentheses - | -LL | if x == (Type { x: module::C, y: 1 }) { - | + + - -error: invalid struct literal - --> $DIR/issue-111692.rs:28:26 - | -LL | if x == demo_module::Type { x: module::C, y: 1 } { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: you might need to surround the struct literal with parentheses - | -LL | if x == (demo_module::Type { x: module::C, y: 1 }) { - | + + - -error: aborting due to 4 previous errors - diff --git a/tests/ui/parser/method-call-on-struct-literal-in-if-condition.rs b/tests/ui/parser/method-call-on-struct-literal-in-if-condition.rs deleted file mode 100644 index 8be7c9ee8ac3a..0000000000000 --- a/tests/ui/parser/method-call-on-struct-literal-in-if-condition.rs +++ /dev/null @@ -1,13 +0,0 @@ -pub struct Example { a: i32 } - -impl Example { - fn is_pos(&self) -> bool { self.a > 0 } -} - -fn one() -> i32 { 1 } - -fn main() { - if Example { a: one(), }.is_pos() { //~ ERROR invalid struct literal - println!("Positive!"); - } -} diff --git a/tests/ui/parser/method-call-on-struct-literal-in-if-condition.stderr b/tests/ui/parser/method-call-on-struct-literal-in-if-condition.stderr deleted file mode 100644 index f7822ba11246b..0000000000000 --- a/tests/ui/parser/method-call-on-struct-literal-in-if-condition.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error: invalid struct literal - --> $DIR/method-call-on-struct-literal-in-if-condition.rs:10:8 - | -LL | if Example { a: one(), }.is_pos() { - | ^^^^^^^^^^^^^^^^^^^^^ - | -help: you might need to surround the struct literal with parentheses - | -LL | if (Example { a: one(), }).is_pos() { - | + + - -error: aborting due to 1 previous error - diff --git a/tests/ui/parser/struct-literal-in-for.rs b/tests/ui/parser/struct-literal-in-for.rs deleted file mode 100644 index 3227ae37bfd05..0000000000000 --- a/tests/ui/parser/struct-literal-in-for.rs +++ /dev/null @@ -1,17 +0,0 @@ -struct Foo { - x: isize, -} - -impl Foo { - fn hi(&self) -> bool { - true - } -} - -fn main() { - for x in Foo { //~ ERROR struct literals are not allowed here - x: 3 //~^ ERROR `bool` is not an iterator - }.hi() { - println!("yo"); - } -} diff --git a/tests/ui/parser/struct-literal-in-for.stderr b/tests/ui/parser/struct-literal-in-for.stderr deleted file mode 100644 index 1c91eba68e399..0000000000000 --- a/tests/ui/parser/struct-literal-in-for.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error: struct literals are not allowed here - --> $DIR/struct-literal-in-for.rs:12:14 - | -LL | for x in Foo { - | ______________^ -LL | | x: 3 -LL | | }.hi() { - | |_____^ - | -help: surround the struct literal with parentheses - | -LL ~ for x in (Foo { -LL | x: 3 -LL ~ }).hi() { - | - -error[E0277]: `bool` is not an iterator - --> $DIR/struct-literal-in-for.rs:12:14 - | -LL | for x in Foo { - | ______________^ -LL | | x: 3 -LL | | }.hi() { - | |__________^ `bool` is not an iterator - | - = help: the trait `Iterator` is not implemented for `bool` - = note: required for `bool` to implement `IntoIterator` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/parser/struct-literal-in-if.rs b/tests/ui/parser/struct-literal-in-if.rs deleted file mode 100644 index c4a253c3da25a..0000000000000 --- a/tests/ui/parser/struct-literal-in-if.rs +++ /dev/null @@ -1,22 +0,0 @@ -struct Foo { - x: isize, -} - -impl Foo { - fn hi(&self) -> bool { - true - } -} - -fn main() { - if Foo { //~ ERROR struct literals are not allowed here - x: 3 - }.hi() { - println!("yo"); - } - if let true = Foo { //~ ERROR struct literals are not allowed here - x: 3 - }.hi() { - println!("yo"); - } -} diff --git a/tests/ui/parser/struct-literal-in-if.stderr b/tests/ui/parser/struct-literal-in-if.stderr deleted file mode 100644 index 8b72469fcf582..0000000000000 --- a/tests/ui/parser/struct-literal-in-if.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error: struct literals are not allowed here - --> $DIR/struct-literal-in-if.rs:12:8 - | -LL | if Foo { - | ________^ -LL | | x: 3 -LL | | }.hi() { - | |_____^ - | -help: surround the struct literal with parentheses - | -LL ~ if (Foo { -LL | x: 3 -LL ~ }).hi() { - | - -error: struct literals are not allowed here - --> $DIR/struct-literal-in-if.rs:17:19 - | -LL | if let true = Foo { - | ___________________^ -LL | | x: 3 -LL | | }.hi() { - | |_____^ - | -help: surround the struct literal with parentheses - | -LL ~ if let true = (Foo { -LL | x: 3 -LL ~ }).hi() { - | - -error: aborting due to 2 previous errors - diff --git a/tests/ui/parser/struct-literal-in-match-discriminant.rs b/tests/ui/parser/struct-literal-in-match-discriminant.rs deleted file mode 100644 index ce132df5a888b..0000000000000 --- a/tests/ui/parser/struct-literal-in-match-discriminant.rs +++ /dev/null @@ -1,13 +0,0 @@ -struct Foo { - x: isize, -} - -fn main() { - match Foo { //~ ERROR struct literals are not allowed here - x: 3 - } { - Foo { - x: x - } => {} - } -} diff --git a/tests/ui/parser/struct-literal-in-match-discriminant.stderr b/tests/ui/parser/struct-literal-in-match-discriminant.stderr deleted file mode 100644 index 5177f5f126e0b..0000000000000 --- a/tests/ui/parser/struct-literal-in-match-discriminant.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: struct literals are not allowed here - --> $DIR/struct-literal-in-match-discriminant.rs:6:11 - | -LL | match Foo { - | ___________^ -LL | | x: 3 -LL | | } { - | |_____^ - | -help: surround the struct literal with parentheses - | -LL ~ match (Foo { -LL | x: 3 -LL ~ }) { - | - -error: aborting due to 1 previous error - diff --git a/tests/ui/parser/struct-literal-in-while.rs b/tests/ui/parser/struct-literal-in-while.rs deleted file mode 100644 index 86931f7888dd8..0000000000000 --- a/tests/ui/parser/struct-literal-in-while.rs +++ /dev/null @@ -1,22 +0,0 @@ -struct Foo { - x: isize, -} - -impl Foo { - fn hi(&self) -> bool { - true - } -} - -fn main() { - while Foo { //~ ERROR struct literals are not allowed here - x: 3 - }.hi() { - println!("yo"); - } - while let true = Foo { //~ ERROR struct literals are not allowed here - x: 3 - }.hi() { - println!("yo"); - } -} diff --git a/tests/ui/parser/struct-literal-in-while.stderr b/tests/ui/parser/struct-literal-in-while.stderr deleted file mode 100644 index 13d003608a1b0..0000000000000 --- a/tests/ui/parser/struct-literal-in-while.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error: struct literals are not allowed here - --> $DIR/struct-literal-in-while.rs:12:11 - | -LL | while Foo { - | ___________^ -LL | | x: 3 -LL | | }.hi() { - | |_____^ - | -help: surround the struct literal with parentheses - | -LL ~ while (Foo { -LL | x: 3 -LL ~ }).hi() { - | - -error: struct literals are not allowed here - --> $DIR/struct-literal-in-while.rs:17:22 - | -LL | while let true = Foo { - | ______________________^ -LL | | x: 3 -LL | | }.hi() { - | |_____^ - | -help: surround the struct literal with parentheses - | -LL ~ while let true = (Foo { -LL | x: 3 -LL ~ }).hi() { - | - -error: aborting due to 2 previous errors - diff --git a/tests/ui/parser/struct-literal-restrictions-in-lamda.rs b/tests/ui/parser/struct-literal-restrictions-in-lamda.rs deleted file mode 100644 index e185153dcf62a..0000000000000 --- a/tests/ui/parser/struct-literal-restrictions-in-lamda.rs +++ /dev/null @@ -1,17 +0,0 @@ -struct Foo { - x: isize, -} - -impl Foo { - fn hi(&self) -> bool { - true - } -} - -fn main() { - while || Foo { //~ ERROR struct literals are not allowed here - x: 3 //~^ ERROR mismatched types - }.hi() { - println!("yo"); - } -} diff --git a/tests/ui/parser/struct-literal-restrictions-in-lamda.stderr b/tests/ui/parser/struct-literal-restrictions-in-lamda.stderr deleted file mode 100644 index c715486e2da9c..0000000000000 --- a/tests/ui/parser/struct-literal-restrictions-in-lamda.stderr +++ /dev/null @@ -1,37 +0,0 @@ -error: struct literals are not allowed here - --> $DIR/struct-literal-restrictions-in-lamda.rs:12:14 - | -LL | while || Foo { - | ______________^ -LL | | x: 3 -LL | | }.hi() { - | |_____^ - | -help: surround the struct literal with parentheses - | -LL ~ while || (Foo { -LL | x: 3 -LL ~ }).hi() { - | - -error[E0308]: mismatched types - --> $DIR/struct-literal-restrictions-in-lamda.rs:12:11 - | -LL | while || Foo { - | ___________^ -LL | | x: 3 -LL | | }.hi() { - | |__________^ expected `bool`, found closure - | - = note: expected type `bool` - found closure `{closure@$DIR/struct-literal-restrictions-in-lamda.rs:12:11: 12:13}` -help: use parentheses to call this closure - | -LL ~ while (|| Foo { -LL | x: 3 -LL ~ }.hi())() { - | - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/parser/struct-literal-variant-in-if.rs b/tests/ui/parser/struct-literal-variant-in-if.rs deleted file mode 100644 index 4ef8effaf1f5f..0000000000000 --- a/tests/ui/parser/struct-literal-variant-in-if.rs +++ /dev/null @@ -1,25 +0,0 @@ -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -enum E { - V { field: bool }, - I { field1: bool, field2: usize }, - J { field: isize }, - K { field: &'static str}, -} -fn test_E(x: E) { - let field = true; - if x == E::V { field } {} - //~^ ERROR expected value, found struct variant `E::V` - //~| ERROR mismatched types - if x == E::I { field1: true, field2: 42 } {} - //~^ ERROR struct literals are not allowed here - if x == E::V { field: false } {} - //~^ ERROR struct literals are not allowed here - if x == E::J { field: -42 } {} - //~^ ERROR struct literals are not allowed here - if x == E::K { field: "" } {} - //~^ ERROR struct literals are not allowed here - let y: usize = (); - //~^ ERROR mismatched types -} - -fn main() {} diff --git a/tests/ui/parser/struct-literal-variant-in-if.stderr b/tests/ui/parser/struct-literal-variant-in-if.stderr deleted file mode 100644 index 15f059f145bbb..0000000000000 --- a/tests/ui/parser/struct-literal-variant-in-if.stderr +++ /dev/null @@ -1,76 +0,0 @@ -error: struct literals are not allowed here - --> $DIR/struct-literal-variant-in-if.rs:13:13 - | -LL | if x == E::I { field1: true, field2: 42 } {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: surround the struct literal with parentheses - | -LL | if x == (E::I { field1: true, field2: 42 }) {} - | + + - -error: struct literals are not allowed here - --> $DIR/struct-literal-variant-in-if.rs:15:13 - | -LL | if x == E::V { field: false } {} - | ^^^^^^^^^^^^^^^^^^^^^ - | -help: surround the struct literal with parentheses - | -LL | if x == (E::V { field: false }) {} - | + + - -error: struct literals are not allowed here - --> $DIR/struct-literal-variant-in-if.rs:17:13 - | -LL | if x == E::J { field: -42 } {} - | ^^^^^^^^^^^^^^^^^^^ - | -help: surround the struct literal with parentheses - | -LL | if x == (E::J { field: -42 }) {} - | + + - -error: struct literals are not allowed here - --> $DIR/struct-literal-variant-in-if.rs:19:13 - | -LL | if x == E::K { field: "" } {} - | ^^^^^^^^^^^^^^^^^^ - | -help: surround the struct literal with parentheses - | -LL | if x == (E::K { field: "" }) {} - | + + - -error[E0533]: expected value, found struct variant `E::V` - --> $DIR/struct-literal-variant-in-if.rs:10:13 - | -LL | if x == E::V { field } {} - | ^^^^ not a value - | -help: you might have meant to create a new value of the struct - | -LL | if x == (E::V { field }) {} - | + + - -error[E0308]: mismatched types - --> $DIR/struct-literal-variant-in-if.rs:10:20 - | -LL | if x == E::V { field } {} - | ---------------^^^^^-- - | | | - | | expected `()`, found `bool` - | expected this to be `()` - -error[E0308]: mismatched types - --> $DIR/struct-literal-variant-in-if.rs:21:20 - | -LL | let y: usize = (); - | ----- ^^ expected `usize`, found `()` - | | - | expected due to this - -error: aborting due to 7 previous errors - -Some errors have detailed explanations: E0308, E0533. -For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/parser/struct-literals-in-invalid-places.rs b/tests/ui/parser/struct-literals-in-invalid-places.rs new file mode 100644 index 0000000000000..eed51b9458318 --- /dev/null +++ b/tests/ui/parser/struct-literals-in-invalid-places.rs @@ -0,0 +1,92 @@ +fn main() { + if Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here + println!("yo"); + } + if let true = Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here + println!("yo"); + } + + for x in Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here + //~^ ERROR `bool` is not an iterator + println!("yo"); + } + + while Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here + println!("yo"); + } + while let true = Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here + println!("yo"); + } + + match Foo { x: 3 } { //~ ERROR struct literals are not allowed here + Foo { x: x } => {} + } + + let _ = |x: E| { + let field = true; + if x == E::V { field } {} + //~^ ERROR expected value, found struct variant `E::V` + //~| ERROR mismatched types + if x == E::I { field1: true, field2: 42 } {} + //~^ ERROR struct literals are not allowed here + if x == E::V { field: false } {} + //~^ ERROR struct literals are not allowed here + if x == E::J { field: -42 } {} + //~^ ERROR struct literals are not allowed here + if x == E::K { field: "" } {} + //~^ ERROR struct literals are not allowed here + let y: usize = (); + //~^ ERROR mismatched types + }; + + // Regression test for . + while || Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here + //~^ ERROR mismatched types + println!("yo"); + } + + // This uses `one()` over `1` as token `one` may begin a type and thus back when type ascription + // `$expr : $ty` still existed, `{ x: one` could've been the start of a block expr which used to + // make the compiler take a different execution path. Now it no longer makes a difference tho. + + // Regression test for . + if Foo { x: one(), }.hi() { //~ ERROR struct literals are not allowed here + println!("Positive!"); + } + + const FOO: Foo = Foo { x: 1 }; + // Below, test that we correctly parenthesize the struct literals. + + // Regression test for . + if FOO == self::Foo { x: one() } {} //~ ERROR struct literals are not allowed here + + if FOO == Foo::<> { x: one() } {} //~ ERROR struct literals are not allowed here + + fn env>() { + if FOO == ::Out { x: one() } {} //~ ERROR struct literals are not allowed here + //~^ ERROR usage of qualified paths in this context is experimental + } +} + +#[derive(PartialEq, Eq)] +struct Foo { + x: isize, +} + +impl Foo { + fn hi(&self) -> bool { + true + } +} + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +enum E { + V { field: bool }, + I { field1: bool, field2: usize }, + J { field: isize }, + K { field: &'static str}, +} + +fn one() -> isize { 1 } + +trait Trait { type Out; } diff --git a/tests/ui/parser/struct-literals-in-invalid-places.stderr b/tests/ui/parser/struct-literals-in-invalid-places.stderr new file mode 100644 index 0000000000000..39dc2d2efb75b --- /dev/null +++ b/tests/ui/parser/struct-literals-in-invalid-places.stderr @@ -0,0 +1,234 @@ +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:2:8 + | +LL | if Foo { x: 3 }.hi() { + | ^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | if (Foo { x: 3 }).hi() { + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:5:19 + | +LL | if let true = Foo { x: 3 }.hi() { + | ^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | if let true = (Foo { x: 3 }).hi() { + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:9:14 + | +LL | for x in Foo { x: 3 }.hi() { + | ^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | for x in (Foo { x: 3 }).hi() { + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:14:11 + | +LL | while Foo { x: 3 }.hi() { + | ^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | while (Foo { x: 3 }).hi() { + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:17:22 + | +LL | while let true = Foo { x: 3 }.hi() { + | ^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | while let true = (Foo { x: 3 }).hi() { + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:21:11 + | +LL | match Foo { x: 3 } { + | ^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | match (Foo { x: 3 }) { + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:30:17 + | +LL | if x == E::I { field1: true, field2: 42 } {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | if x == (E::I { field1: true, field2: 42 }) {} + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:32:17 + | +LL | if x == E::V { field: false } {} + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | if x == (E::V { field: false }) {} + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:34:17 + | +LL | if x == E::J { field: -42 } {} + | ^^^^^^^^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | if x == (E::J { field: -42 }) {} + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:36:17 + | +LL | if x == E::K { field: "" } {} + | ^^^^^^^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | if x == (E::K { field: "" }) {} + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:43:14 + | +LL | while || Foo { x: 3 }.hi() { + | ^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | while || (Foo { x: 3 }).hi() { + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:53:8 + | +LL | if Foo { x: one(), }.hi() { + | ^^^^^^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | if (Foo { x: one(), }).hi() { + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:61:15 + | +LL | if FOO == self::Foo { x: one() } {} + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | if FOO == (self::Foo { x: one() }) {} + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:63:15 + | +LL | if FOO == Foo::<> { x: one() } {} + | ^^^^^^^^^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | if FOO == (Foo::<> { x: one() }) {} + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:66:19 + | +LL | if FOO == ::Out { x: one() } {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | if FOO == (::Out { x: one() }) {} + | + + + +error[E0658]: usage of qualified paths in this context is experimental + --> $DIR/struct-literals-in-invalid-places.rs:66:19 + | +LL | if FOO == ::Out { x: one() } {} + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #86935 for more information + = help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0277]: `bool` is not an iterator + --> $DIR/struct-literals-in-invalid-places.rs:9:14 + | +LL | for x in Foo { x: 3 }.hi() { + | ^^^^^^^^^^^^^^^^^ `bool` is not an iterator + | + = help: the trait `Iterator` is not implemented for `bool` + = note: required for `bool` to implement `IntoIterator` + +error[E0533]: expected value, found struct variant `E::V` + --> $DIR/struct-literals-in-invalid-places.rs:27:17 + | +LL | if x == E::V { field } {} + | ^^^^ not a value + | +help: you might have meant to create a new value of the struct + | +LL | if x == (E::V { field }) {} + | + + + +error[E0308]: mismatched types + --> $DIR/struct-literals-in-invalid-places.rs:27:24 + | +LL | if x == E::V { field } {} + | ---------------^^^^^-- + | | | + | | expected `()`, found `bool` + | expected this to be `()` + | +help: you might have meant to return this value + | +LL | if x == E::V { return field; } {} + | ++++++ + + +error[E0308]: mismatched types + --> $DIR/struct-literals-in-invalid-places.rs:38:24 + | +LL | let y: usize = (); + | ----- ^^ expected `usize`, found `()` + | | + | expected due to this + +error[E0308]: mismatched types + --> $DIR/struct-literals-in-invalid-places.rs:43:11 + | +LL | while || Foo { x: 3 }.hi() { + | ^^^^^^^^^^^^^^^^^^^^ expected `bool`, found closure + | + = note: expected type `bool` + found closure `{closure@$DIR/struct-literals-in-invalid-places.rs:43:11: 43:13}` +help: use parentheses to call this closure + | +LL | while (|| Foo { x: 3 }.hi())() { + | + +++ + +error: aborting due to 21 previous errors + +Some errors have detailed explanations: E0277, E0308, E0533, E0658. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/parser/type-ascription-in-pattern.rs b/tests/ui/parser/type-ascription-in-pattern.rs index fec168afba1dd..18d7061d69c8d 100644 --- a/tests/ui/parser/type-ascription-in-pattern.rs +++ b/tests/ui/parser/type-ascription-in-pattern.rs @@ -1,11 +1,10 @@ fn foo(x: bool) -> i32 { - match x { + match x { //~ ERROR struct literals are not allowed here x: i32 => x, //~ ERROR expected - //~^ ERROR mismatched types - true => 42., - false => 0.333, + true => 42., //~ ERROR expected identifier + false => 0.333, //~ ERROR expected identifier } -} +} //~ ERROR expected one of fn main() { match foo(true) { diff --git a/tests/ui/parser/type-ascription-in-pattern.stderr b/tests/ui/parser/type-ascription-in-pattern.stderr index 0919075499368..135879f208b2b 100644 --- a/tests/ui/parser/type-ascription-in-pattern.stderr +++ b/tests/ui/parser/type-ascription-in-pattern.stderr @@ -1,18 +1,64 @@ -error: expected one of `@` or `|`, found `:` - --> $DIR/type-ascription-in-pattern.rs:3:10 +error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, `}`, or an operator, found `=>` + --> $DIR/type-ascription-in-pattern.rs:3:16 | +LL | match x { + | - while parsing this struct LL | x: i32 => x, - | ^ --- specifying the type of a pattern isn't supported - | | - | expected one of `@` or `|` + | -^^ expected one of 8 possible tokens + | | + | help: try adding a comma: `,` + +error: expected identifier, found keyword `true` + --> $DIR/type-ascription-in-pattern.rs:4:9 | -help: maybe write a path separator here +LL | match x { + | - while parsing this struct +LL | x: i32 => x, +LL | true => 42., + | ^^^^ expected identifier, found keyword + +error: expected identifier, found keyword `false` + --> $DIR/type-ascription-in-pattern.rs:5:9 | -LL | x::i32 => x, - | ~~ +LL | match x { + | - while parsing this struct +... +LL | false => 0.333, + | ^^^^^ expected identifier, found keyword + +error: struct literals are not allowed here + --> $DIR/type-ascription-in-pattern.rs:2:11 + | +LL | match x { + | ___________^ +LL | | x: i32 => x, +LL | | true => 42., +LL | | false => 0.333, +LL | | } + | |_____^ + | +help: surround the struct literal with parentheses + | +LL ~ match (x { +LL | x: i32 => x, +LL | true => 42., +LL | false => 0.333, +LL ~ }) + | + +error: expected one of `.`, `?`, `{`, or an operator, found `}` + --> $DIR/type-ascription-in-pattern.rs:7:1 + | +LL | match x { + | ----- while parsing this `match` expression +... +LL | } + | - expected one of `.`, `?`, `{`, or an operator +LL | } + | ^ unexpected token error: expected one of `...`, `..=`, `..`, or `|`, found `:` - --> $DIR/type-ascription-in-pattern.rs:12:11 + --> $DIR/type-ascription-in-pattern.rs:11:11 | LL | 42: i32 => (), | ^ --- specifying the type of a pattern isn't supported @@ -20,7 +66,7 @@ LL | 42: i32 => (), | expected one of `...`, `..=`, `..`, or `|` error: expected `|`, found `:` - --> $DIR/type-ascription-in-pattern.rs:13:10 + --> $DIR/type-ascription-in-pattern.rs:12:10 | LL | _: f64 => (), | ^ --- specifying the type of a pattern isn't supported @@ -28,7 +74,7 @@ LL | _: f64 => (), | expected `|` error: expected one of `@` or `|`, found `:` - --> $DIR/type-ascription-in-pattern.rs:14:10 + --> $DIR/type-ascription-in-pattern.rs:13:10 | LL | x: i32 => (), | ^ --- specifying the type of a pattern isn't supported @@ -40,15 +86,5 @@ help: maybe write a path separator here LL | x::i32 => (), | ~~ -error[E0308]: mismatched types - --> $DIR/type-ascription-in-pattern.rs:3:19 - | -LL | fn foo(x: bool) -> i32 { - | --- expected `i32` because of return type -LL | match x { -LL | x: i32 => x, - | ^ expected `i32`, found `bool` - -error: aborting due to 5 previous errors +error: aborting due to 8 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/target_modifiers/auxiliary/enabled_reg_struct_return.rs b/tests/ui/target_modifiers/auxiliary/enabled_reg_struct_return.rs new file mode 100644 index 0000000000000..4bda4ba24c548 --- /dev/null +++ b/tests/ui/target_modifiers/auxiliary/enabled_reg_struct_return.rs @@ -0,0 +1,7 @@ +//@ no-prefer-dynamic +//@ compile-flags: --target i686-unknown-linux-gnu -Zreg-struct-return=true +//@ needs-llvm-components: x86 + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] diff --git a/tests/ui/target_modifiers/defaults_check.error.stderr b/tests/ui/target_modifiers/defaults_check.error.stderr index 4833fe906775c..936fbbc94d6d6 100644 --- a/tests/ui/target_modifiers/defaults_check.error.stderr +++ b/tests/ui/target_modifiers/defaults_check.error.stderr @@ -5,8 +5,8 @@ LL | #![feature(no_core)] | ^ | = help: the `-Zreg-struct-return` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely - = note: `-Zreg-struct-return=true` in this crate is incompatible with `-Zreg-struct-return=` in dependency `default_reg_struct_return` - = help: set `-Zreg-struct-return=` in this crate or `-Zreg-struct-return=true` in `default_reg_struct_return` + = note: `-Zreg-struct-return=true` in this crate is incompatible with unset `-Zreg-struct-return` in dependency `default_reg_struct_return` + = help: unset `-Zreg-struct-return` in this crate or set `-Zreg-struct-return=true` in `default_reg_struct_return` = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=reg-struct-return` to silence this error error: aborting due to 1 previous error diff --git a/tests/ui/target_modifiers/no_value_bool.error.stderr b/tests/ui/target_modifiers/no_value_bool.error.stderr new file mode 100644 index 0000000000000..0484960dc62d6 --- /dev/null +++ b/tests/ui/target_modifiers/no_value_bool.error.stderr @@ -0,0 +1,13 @@ +error: mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `no_value_bool` + --> $DIR/no_value_bool.rs:16:1 + | +LL | #![feature(no_core)] + | ^ + | + = help: the `-Zreg-struct-return` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely + = note: unset `-Zreg-struct-return` in this crate is incompatible with `-Zreg-struct-return=true` in dependency `enabled_reg_struct_return` + = help: set `-Zreg-struct-return=true` in this crate or unset `-Zreg-struct-return` in `enabled_reg_struct_return` + = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=reg-struct-return` to silence this error + +error: aborting due to 1 previous error + diff --git a/tests/ui/target_modifiers/no_value_bool.error_explicit.stderr b/tests/ui/target_modifiers/no_value_bool.error_explicit.stderr new file mode 100644 index 0000000000000..0484960dc62d6 --- /dev/null +++ b/tests/ui/target_modifiers/no_value_bool.error_explicit.stderr @@ -0,0 +1,13 @@ +error: mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `no_value_bool` + --> $DIR/no_value_bool.rs:16:1 + | +LL | #![feature(no_core)] + | ^ + | + = help: the `-Zreg-struct-return` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely + = note: unset `-Zreg-struct-return` in this crate is incompatible with `-Zreg-struct-return=true` in dependency `enabled_reg_struct_return` + = help: set `-Zreg-struct-return=true` in this crate or unset `-Zreg-struct-return` in `enabled_reg_struct_return` + = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=reg-struct-return` to silence this error + +error: aborting due to 1 previous error + diff --git a/tests/ui/target_modifiers/no_value_bool.rs b/tests/ui/target_modifiers/no_value_bool.rs new file mode 100644 index 0000000000000..ceba40afa8968 --- /dev/null +++ b/tests/ui/target_modifiers/no_value_bool.rs @@ -0,0 +1,22 @@ +// Tests that bool target modifier value (true) in dependency crate is ok linked +// with the -Zflag specified without value (-Zflag=true is consistent with -Zflag) + +//@ aux-build:enabled_reg_struct_return.rs +//@ compile-flags: --target i686-unknown-linux-gnu -Cpanic=abort +//@ needs-llvm-components: x86 + +//@ revisions: ok ok_explicit error error_explicit +//@[ok] compile-flags: -Zreg-struct-return +//@[ok_explicit] compile-flags: -Zreg-struct-return=true +//@[error] compile-flags: +//@[error_explicit] compile-flags: -Zreg-struct-return=false +//@[ok] check-pass +//@[ok_explicit] check-pass + +#![feature(no_core)] +//[error]~^ ERROR mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `no_value_bool` +//[error_explicit]~^^ ERROR mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `no_value_bool` +#![crate_type = "rlib"] +#![no_core] + +extern crate enabled_reg_struct_return;