diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ebbed11d04b8d..b93166b80a570 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -309,7 +309,7 @@ jobs: NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 DIST_REQUIRE_ALL_TOOLS: 1 - os: macos-latest + os: macos-12-xl - name: dist-apple-various env: SCRIPT: "./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim" @@ -320,7 +320,7 @@ jobs: NO_LLVM_ASSERTIONS: 1 NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 - os: macos-latest + os: macos-12-xl - name: dist-x86_64-apple-alt env: SCRIPT: "./x.py dist bootstrap --include-default-paths" @@ -331,7 +331,7 @@ jobs: NO_LLVM_ASSERTIONS: 1 NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 - os: macos-latest + os: macos-12-xl - name: x86_64-apple-1 env: SCRIPT: "./x.py --stage 2 test --exclude src/test/ui --exclude src/test/rustdoc --exclude src/test/run-make-fulldeps" @@ -342,7 +342,7 @@ jobs: NO_LLVM_ASSERTIONS: 1 NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 - os: macos-latest + os: macos-12-xl - name: x86_64-apple-2 env: SCRIPT: "./x.py --stage 2 test src/test/ui src/test/rustdoc src/test/run-make-fulldeps" @@ -353,7 +353,7 @@ jobs: NO_LLVM_ASSERTIONS: 1 NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 - os: macos-latest + os: macos-12-xl - name: dist-aarch64-apple env: SCRIPT: "./x.py dist bootstrap --include-default-paths --stage 2" @@ -368,7 +368,7 @@ jobs: NO_OVERFLOW_CHECKS: 1 DIST_REQUIRE_ALL_TOOLS: 1 JEMALLOC_SYS_WITH_LG_PAGE: 14 - os: macos-latest + os: macos-12-xl - name: x86_64-msvc-1 env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler" diff --git a/Cargo.lock b/Cargo.lock index 32dc32a9c0740..dae79e5bc260c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -92,6 +92,15 @@ version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" +[[package]] +name = "ar_archive_writer" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276881980556fdadeb88aa1ffc667e4d2e8fe72531dfabcb7a82bb3c9ea9ba31" +dependencies = [ + "object", +] + [[package]] name = "array_tool" version = "1.0.3" @@ -906,9 +915,9 @@ version = "0.0.0" [[package]] name = "cpufeatures" -version = "0.2.1" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" dependencies = [ "libc", ] @@ -1085,12 +1094,6 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" -[[package]] -name = "difference" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" - [[package]] name = "digest" version = "0.10.2" @@ -1162,6 +1165,12 @@ dependencies = [ "syn", ] +[[package]] +name = "dissimilar" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c97b9233581d84b8e1e689cdd3a47b6f69770084fc246e86a7f78b0d9c1d4a5" + [[package]] name = "dlmalloc" version = "0.2.3" @@ -1283,11 +1292,11 @@ dependencies = [ [[package]] name = "expect-test" -version = "1.0.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceb96f3eaa0d4e8769c52dacfd4eb60183b817ed2f176171b3c691d5022b0f2e" +checksum = "1d4661aca38d826eb7c72fe128e4238220616de4c0cc00db7bfc38e2e1364dd3" dependencies = [ - "difference", + "dissimilar", "once_cell", ] @@ -3495,6 +3504,7 @@ dependencies = [ name = "rustc_codegen_ssa" version = "0.0.0" dependencies = [ + "ar_archive_writer", "bitflags", "cc", "itertools", diff --git a/LICENSES/LLVM-exception.txt b/LICENSES/LLVM-exception.txt new file mode 100644 index 0000000000000..fa4b725a0ee50 --- /dev/null +++ b/LICENSES/LLVM-exception.txt @@ -0,0 +1,15 @@ +---- LLVM Exceptions to the Apache 2.0 License ---- + + As an exception, if, as a result of your compiling your source code, portions + of this Software are embedded into an Object form of such source code, you + may redistribute such embedded portions in such Object form without complying + with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + + In addition, if you combine or link compiled forms of this Software with + software that is licensed under the GPLv2 ("Combined Software") and if a + court of competent jurisdiction determines that the patent provision (Section + 3), the indemnity provision (Section 9) or other Section of the License + conflicts with the conditions of the GPLv2, you may retroactively and + prospectively choose to deem waived or otherwise exclude such Section(s) of + the License, but only in their entirety and only with respect to the Combined + Software. diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 11e7b80f85efd..9c2cf58efed4a 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -354,7 +354,7 @@ pub trait LayoutCalculator { if !always_sized { StructKind::MaybeUnsized } else { StructKind::AlwaysSized } }; - let mut st = self.univariant(dl, &variants[v], &repr, kind)?; + let mut st = self.univariant(dl, &variants[v], repr, kind)?; st.variants = Variants::Single { index: v }; if is_unsafe_cell { @@ -457,7 +457,7 @@ pub trait LayoutCalculator { let mut variant_layouts = variants .iter_enumerated() .map(|(j, v)| { - let mut st = self.univariant(dl, v, &repr, StructKind::AlwaysSized)?; + let mut st = self.univariant(dl, v, repr, StructKind::AlwaysSized)?; st.variants = Variants::Single { index: j }; align = align.max(st.align); @@ -647,8 +647,8 @@ pub trait LayoutCalculator { .map(|(i, field_layouts)| { let mut st = self.univariant( dl, - &field_layouts, - &repr, + field_layouts, + repr, StructKind::Prefixed(min_ity.size(), prefix_align), )?; st.variants = Variants::Single { index: i }; @@ -755,7 +755,7 @@ pub trait LayoutCalculator { // Try to use a ScalarPair for all tagged enums. let mut common_prim = None; let mut common_prim_initialized_in_all_variants = true; - for (field_layouts, layout_variant) in iter::zip(&*variants, &layout_variants) { + for (field_layouts, layout_variant) in iter::zip(variants, &layout_variants) { let FieldsShape::Arbitrary { ref offsets, .. } = layout_variant.fields else { panic!(); }; diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index f2f8e1386a5c7..4d80f904ac461 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1179,7 +1179,7 @@ impl Expr { pub fn peel_parens(&self) -> &Expr { let mut expr = self; while let ExprKind::Paren(inner) = &expr.kind { - expr = &inner; + expr = inner; } expr } @@ -1312,8 +1312,10 @@ pub struct Closure { pub movability: Movability, pub fn_decl: P, pub body: P, - /// The span of the argument block `|...|`. + /// The span of the declaration block: 'move |...| -> ...' pub fn_decl_span: Span, + /// The span of the argument block `|...|` + pub fn_arg_span: Span, } /// Limit types of a range (inclusive or exclusive) @@ -2027,7 +2029,7 @@ impl Ty { pub fn peel_refs(&self) -> &Self { let mut final_ty = self; while let TyKind::Rptr(_, MutTy { ty, .. }) = &final_ty.kind { - final_ty = &ty; + final_ty = ty; } final_ty } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 963e5a608a492..a45ee6067bbae 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -736,8 +736,7 @@ pub fn visit_token(t: &mut Token, vis: &mut T) { return; // Avoid visiting the span for the second time. } token::Interpolated(nt) => { - let mut nt = Lrc::make_mut(nt); - visit_nonterminal(&mut nt, vis); + visit_nonterminal(Lrc::make_mut(nt), vis); } _ => {} } @@ -1368,6 +1367,7 @@ pub fn noop_visit_expr( fn_decl, body, fn_decl_span, + fn_arg_span: _, }) => { vis.visit_closure_binder(binder); vis.visit_asyncness(asyncness); diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 58c6d397ea270..482c302950f01 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -64,7 +64,7 @@ impl TokenTree { match (self, other) { (TokenTree::Token(token, _), TokenTree::Token(token2, _)) => token.kind == token2.kind, (TokenTree::Delimited(_, delim, tts), TokenTree::Delimited(_, delim2, tts2)) => { - delim == delim2 && tts.eq_unspanned(&tts2) + delim == delim2 && tts.eq_unspanned(tts2) } _ => false, } @@ -402,7 +402,7 @@ impl TokenStream { let mut t1 = self.trees(); let mut t2 = other.trees(); for (t1, t2) in iter::zip(&mut t1, &mut t2) { - if !t1.eq_unspanned(&t2) { + if !t1.eq_unspanned(t2) { return false; } } @@ -475,7 +475,7 @@ impl TokenStream { token::Interpolated(nt) => TokenTree::Delimited( DelimSpan::from_single(token.span), Delimiter::Invisible, - TokenStream::from_nonterminal_ast(&nt).flattened(), + TokenStream::from_nonterminal_ast(nt).flattened(), ), _ => TokenTree::Token(token.clone(), spacing), } @@ -511,7 +511,7 @@ impl TokenStream { fn try_glue_to_last(vec: &mut Vec, tt: &TokenTree) -> bool { if let Some(TokenTree::Token(last_tok, Spacing::Joint)) = vec.last() && let TokenTree::Token(tok, spacing) = tt - && let Some(glued_tok) = last_tok.glue(&tok) + && let Some(glued_tok) = last_tok.glue(tok) { // ...then overwrite the last token tree in `vec` with the // glued token, and skip the first token tree from `stream`. diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index fbb4cf43a954c..cdc244c12181d 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -21,6 +21,7 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool { | ast::ExprKind::Loop(..) | ast::ExprKind::ForLoop(..) | ast::ExprKind::TryBlock(..) + | ast::ExprKind::ConstBlock(..) ) } diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs index c96474ccb428a..35454c3a67092 100644 --- a/compiler/rustc_ast/src/util/comments.rs +++ b/compiler/rustc_ast/src/util/comments.rs @@ -110,7 +110,7 @@ pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol { } else { &mut lines }; - if let Some(horizontal) = get_horizontal_trim(&lines, kind) { + if let Some(horizontal) = get_horizontal_trim(lines, kind) { changes = true; // remove a "[ \t]*\*" block from each line, if possible for line in lines.iter_mut() { @@ -147,7 +147,7 @@ fn all_whitespace(s: &str, col: CharPos) -> Option { fn trim_whitespace_prefix(s: &str, col: CharPos) -> &str { let len = s.len(); - match all_whitespace(&s, col) { + match all_whitespace(s, col) { Some(col) => { if col < len { &s[col..] diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 1d6e7914f3a5c..f6f186b51073b 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -52,14 +52,14 @@ impl LitKind { // new symbol because the string in the LitKind is different to the // string in the token. let s = symbol.as_str(); - let symbol = if s.contains(&['\\', '\r']) { + let symbol = if s.contains(['\\', '\r']) { let mut buf = String::with_capacity(s.len()); let mut error = Ok(()); // Force-inlining here is aggressive but the closure is // called on every char in the string, so it can be // hot in programs with many long strings. unescape_literal( - &s, + s, Mode::Str, &mut #[inline(always)] |_, unescaped_char| match unescaped_char { @@ -85,7 +85,7 @@ impl LitKind { if s.contains('\r') { let mut buf = String::with_capacity(s.len()); let mut error = Ok(()); - unescape_literal(&s, Mode::RawStr, &mut |_, unescaped_char| { + unescape_literal(s, Mode::RawStr, &mut |_, unescaped_char| { match unescaped_char { Ok(c) => buf.push(c), Err(err) => { @@ -106,7 +106,7 @@ impl LitKind { let s = symbol.as_str(); let mut buf = Vec::with_capacity(s.len()); let mut error = Ok(()); - unescape_literal(&s, Mode::ByteStr, &mut |_, c| match c { + unescape_literal(s, Mode::ByteStr, &mut |_, c| match c { Ok(c) => buf.push(byte_from_char(c)), Err(err) => { if err.is_fatal() { @@ -122,7 +122,7 @@ impl LitKind { let bytes = if s.contains('\r') { let mut buf = Vec::with_capacity(s.len()); let mut error = Ok(()); - unescape_literal(&s, Mode::RawByteStr, &mut |_, c| match c { + unescape_literal(s, Mode::RawByteStr, &mut |_, c| match c { Ok(c) => buf.push(byte_from_char(c)), Err(err) => { if err.is_fatal() { diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index f65f1f069cba2..819f1884a0692 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -384,7 +384,7 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool { | ast::ExprKind::AssignOp(_, lhs, rhs) | ast::ExprKind::Binary(_, lhs, rhs) => { // X { y: 1 } + X { y: 2 } - contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs) + contains_exterior_struct_lit(lhs) || contains_exterior_struct_lit(rhs) } ast::ExprKind::Await(x) | ast::ExprKind::Unary(_, x) @@ -393,12 +393,12 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool { | ast::ExprKind::Field(x, _) | ast::ExprKind::Index(x, _) => { // &X { y: 1 }, X { y: 1 }.y - contains_exterior_struct_lit(&x) + contains_exterior_struct_lit(x) } ast::ExprKind::MethodCall(box ast::MethodCall { receiver, .. }) => { // X { y: 1 }.bar(...) - contains_exterior_struct_lit(&receiver) + contains_exterior_struct_lit(receiver) } _ => false, diff --git a/compiler/rustc_ast/src/util/unicode.rs b/compiler/rustc_ast/src/util/unicode.rs index f009f7b300ce0..0eae791b25e1c 100644 --- a/compiler/rustc_ast/src/util/unicode.rs +++ b/compiler/rustc_ast/src/util/unicode.rs @@ -17,7 +17,7 @@ pub fn contains_text_flow_control_chars(s: &str) -> bool { // U+2069 - E2 81 A9 let mut bytes = s.as_bytes(); loop { - match core::slice::memchr::memchr(0xE2, &bytes) { + match core::slice::memchr::memchr(0xE2, bytes) { Some(idx) => { // bytes are valid UTF-8 -> E2 must be followed by two bytes let ch = &bytes[idx..idx + 3]; diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index fe27d7fa8de17..991eb489f6ba3 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -840,6 +840,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { fn_decl, body, fn_decl_span: _, + fn_arg_span: _, }) => { visitor.visit_fn(FnKind::Closure(binder, fn_decl, body), expression.span, expression.id) } diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 2a0338adc9ca4..dfef6ec70fcf7 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -222,7 +222,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Wrap the expression in an AnonConst. let parent_def_id = self.current_hir_id_owner; let node_id = self.next_node_id(); - self.create_def(parent_def_id.def_id, node_id, DefPathData::AnonConst); + self.create_def( + parent_def_id.def_id, + node_id, + DefPathData::AnonConst, + *op_sp, + ); let anon_const = AnonConst { id: node_id, value: P(expr) }; hir::InlineAsmOperand::SymFn { anon_const: self.lower_anon_const(&anon_const), diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 82912a733d552..4260805f1dd1f 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -176,6 +176,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl, body, fn_decl_span, + fn_arg_span, }) => { if let Async::Yes { closure_id, .. } = asyncness { self.lower_expr_async_closure( @@ -186,6 +187,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl, body, *fn_decl_span, + *fn_arg_span, ) } else { self.lower_expr_closure( @@ -196,6 +198,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl, body, *fn_decl_span, + *fn_arg_span, ) } } @@ -365,7 +368,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let node_id = self.next_node_id(); // Add a definition for the in-band const def. - self.create_def(parent_def_id.def_id, node_id, DefPathData::AnonConst); + self.create_def(parent_def_id.def_id, node_id, DefPathData::AnonConst, f.span); let anon_const = AnonConst { id: node_id, value: arg }; generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const))); @@ -642,6 +645,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl, body, fn_decl_span: self.lower_span(span), + fn_arg_span: None, movability: Some(hir::Movability::Static), }); @@ -898,6 +902,7 @@ impl<'hir> LoweringContext<'_, 'hir> { decl: &FnDecl, body: &Expr, fn_decl_span: Span, + fn_arg_span: Span, ) -> hir::ExprKind<'hir> { let (binder_clause, generic_params) = self.lower_closure_binder(binder); @@ -928,6 +933,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl, body: body_id, fn_decl_span: self.lower_span(fn_decl_span), + fn_arg_span: Some(self.lower_span(fn_arg_span)), movability: generator_option, }); @@ -984,6 +990,7 @@ impl<'hir> LoweringContext<'_, 'hir> { decl: &FnDecl, body: &Expr, fn_decl_span: Span, + fn_arg_span: Span, ) -> hir::ExprKind<'hir> { if let &ClosureBinder::For { span, .. } = binder { self.tcx.sess.emit_err(NotSupportedForLifetimeBinderAsyncClosure { span }); @@ -1038,6 +1045,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl, body, fn_decl_span: self.lower_span(fn_decl_span), + fn_arg_span: Some(self.lower_span(fn_arg_span)), movability: None, }); hir::ExprKind::Closure(c) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1d27970627854..0258f8fd2d9ab 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -487,6 +487,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { parent: LocalDefId, node_id: ast::NodeId, data: DefPathData, + span: Span, ) -> LocalDefId { debug_assert_ne!(node_id, ast::DUMMY_NODE_ID); assert!( @@ -497,7 +498,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.tcx.hir().def_key(self.local_def_id(node_id)), ); - let def_id = self.tcx.create_def(parent, data).def_id(); + let def_id = self.tcx.at(span).create_def(parent, data).def_id(); debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id); self.resolver.node_id_to_def_id.insert(node_id, def_id); @@ -823,6 +824,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.current_hir_id_owner.def_id, param, DefPathData::LifetimeNs(kw::UnderscoreLifetime), + ident.span, ); debug!(?_def_id); @@ -1151,15 +1153,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let parent_def_id = self.current_hir_id_owner; let node_id = self.next_node_id(); + let span = self.lower_span(ty.span); // Add a definition for the in-band const def. let def_id = self.create_def( parent_def_id.def_id, node_id, DefPathData::AnonConst, + span, ); - let span = self.lower_span(ty.span); let path_expr = Expr { id: ty.id, kind: ExprKind::Path(qself.clone(), path.clone()), @@ -1353,12 +1356,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { itctx, ), ImplTraitContext::Universal => { + let span = t.span; self.create_def( self.current_hir_id_owner.def_id, *def_node_id, DefPathData::ImplTrait, + span, ); - let span = t.span; let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span); let (param, bounds, path) = self.lower_generic_and_bounds(*def_node_id, span, ident, bounds); @@ -1455,6 +1459,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.current_hir_id_owner.def_id, opaque_ty_node_id, DefPathData::ImplTrait, + opaque_ty_span, ); debug!(?opaque_ty_def_id); @@ -1608,6 +1613,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { parent_def_id, node_id, DefPathData::LifetimeNs(lifetime.ident.name), + lifetime.ident.span, ); remapping.insert(old_def_id, new_def_id); @@ -1624,6 +1630,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { parent_def_id, node_id, DefPathData::LifetimeNs(kw::UnderscoreLifetime), + lifetime.ident.span, ); remapping.insert(old_def_id, new_def_id); @@ -1806,7 +1813,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let fn_def_id = self.local_def_id(fn_node_id); let opaque_ty_def_id = - self.create_def(fn_def_id, opaque_ty_node_id, DefPathData::ImplTrait); + self.create_def(fn_def_id, opaque_ty_node_id, DefPathData::ImplTrait, opaque_ty_span); // When we create the opaque type for this async fn, it is going to have // to capture all the lifetimes involved in the signature (including in the @@ -1866,6 +1873,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { opaque_ty_def_id, inner_node_id, DefPathData::LifetimeNs(ident.name), + ident.span, ); new_remapping.insert(outer_def_id, inner_def_id); diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index ebe55a4b77183..d3d8431c163c7 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -519,7 +519,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere ast::MetaItemKind::List(items) => { self.print_path(&item.path, false, 0); self.popen(); - self.commasep(Consistent, &items, |s, i| s.print_meta_list_item(i)); + self.commasep(Consistent, items, |s, i| s.print_meta_list_item(i)); self.pclose(); } } @@ -536,7 +536,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) { match tt { TokenTree::Token(token, _) => { - let token_str = self.token_to_string_ext(&token, convert_dollar_crate); + let token_str = self.token_to_string_ext(token, convert_dollar_crate); self.word(token_str); if let token::DocComment(..) = token.kind { self.hardbreak() @@ -998,7 +998,7 @@ impl<'a> State<'a> { ast::AssocConstraintKind::Bound { bounds } => { if !bounds.is_empty() { self.word_nbsp(":"); - self.print_type_bounds(&bounds); + self.print_type_bounds(bounds); } } } @@ -1035,7 +1035,7 @@ impl<'a> State<'a> { } ast::TyKind::Tup(elts) => { self.popen(); - self.commasep(Inconsistent, &elts, |s, ty| s.print_type(ty)); + self.commasep(Inconsistent, elts, |s, ty| s.print_type(ty)); if elts.len() == 1 { self.word(","); } @@ -1254,7 +1254,7 @@ impl<'a> State<'a> { self.popen(); self.commasep(Consistent, &args, |s, arg| match arg { - AsmArg::Template(template) => s.print_string(&template, ast::StrStyle::Cooked), + AsmArg::Template(template) => s.print_string(template, ast::StrStyle::Cooked), AsmArg::Operand(op) => { let print_reg_or_class = |s: &mut Self, r: &InlineAsmRegOrRegClass| match r { InlineAsmRegOrRegClass::Reg(r) => s.print_symbol(*r, ast::StrStyle::Cooked), @@ -1424,11 +1424,11 @@ impl<'a> State<'a> { self.print_path(path, true, 0); } self.popen(); - self.commasep(Inconsistent, &elts, |s, p| s.print_pat(p)); + self.commasep(Inconsistent, elts, |s, p| s.print_pat(p)); self.pclose(); } PatKind::Or(pats) => { - self.strsep("|", true, Inconsistent, &pats, |s, p| s.print_pat(p)); + self.strsep("|", true, Inconsistent, pats, |s, p| s.print_pat(p)); } PatKind::Path(None, path) => { self.print_path(path, true, 0); @@ -1450,7 +1450,7 @@ impl<'a> State<'a> { } self.commasep_cmnt( Consistent, - &fields, + fields, |s, f| { s.cbox(INDENT_UNIT); if !f.is_shorthand { @@ -1475,7 +1475,7 @@ impl<'a> State<'a> { } PatKind::Tuple(elts) => { self.popen(); - self.commasep(Inconsistent, &elts, |s, p| s.print_pat(p)); + self.commasep(Inconsistent, elts, |s, p| s.print_pat(p)); if elts.len() == 1 { self.word(","); } @@ -1498,7 +1498,7 @@ impl<'a> State<'a> { self.print_pat(inner); } } - PatKind::Lit(e) => self.print_expr(&**e), + PatKind::Lit(e) => self.print_expr(e), PatKind::Range(begin, end, Spanned { node: end_kind, .. }) => { if let Some(e) = begin { self.print_expr(e); @@ -1514,7 +1514,7 @@ impl<'a> State<'a> { } PatKind::Slice(elts) => { self.word("["); - self.commasep(Inconsistent, &elts, |s, p| s.print_pat(p)); + self.commasep(Inconsistent, elts, |s, p| s.print_pat(p)); self.word("]"); } PatKind::Rest => self.word(".."), @@ -1600,7 +1600,7 @@ impl<'a> State<'a> { self.word("<"); - self.commasep(Inconsistent, &generic_params, |s, param| { + self.commasep(Inconsistent, generic_params, |s, param| { s.print_outer_attributes_inline(¶m.attrs); match ¶m.kind { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 81483ac30d1de..4ed16e337d297 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -305,10 +305,10 @@ impl<'a> State<'a> { self.print_expr_tup(exprs); } ast::ExprKind::Call(func, args) => { - self.print_expr_call(func, &args); + self.print_expr_call(func, args); } ast::ExprKind::MethodCall(box ast::MethodCall { seg, receiver, args, .. }) => { - self.print_expr_method_call(seg, &receiver, &args); + self.print_expr_method_call(seg, receiver, args); } ast::ExprKind::Binary(op, lhs, rhs) => { self.print_expr_binary(*op, lhs, rhs); @@ -402,6 +402,7 @@ impl<'a> State<'a> { fn_decl, body, fn_decl_span: _, + fn_arg_span: _, }) => { self.print_closure_binder(binder); self.print_movability(*movability); @@ -605,7 +606,7 @@ impl<'a> State<'a> { match binder { ast::ClosureBinder::NotPresent => {} ast::ClosureBinder::For { generic_params, .. } => { - self.print_formal_generic_params(&generic_params) + self.print_formal_generic_params(generic_params) } } } diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 4a12e1b1b92e0..e379e64706237 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -73,7 +73,7 @@ pub(crate) fn replace_regions_in_mir<'tcx>( // Replace all remaining regions with fresh inference variables. renumber::renumber_mir(infcx, body, promoted); - dump_mir(infcx.tcx, None, "renumber", &0, body, |_, _| Ok(())); + dump_mir(infcx.tcx, false, "renumber", &0, body, |_, _| Ok(())); universal_regions } @@ -331,7 +331,7 @@ pub(super) fn dump_mir_results<'tcx>( return; } - dump_mir(infcx.tcx, None, "nll", &0, body, |pass_where, out| { + dump_mir(infcx.tcx, false, "nll", &0, body, |pass_where, out| { match pass_where { // Before the CFG, dump out the values for each region variable. PassWhere::BeforeCFG => { @@ -358,15 +358,13 @@ pub(super) fn dump_mir_results<'tcx>( // Also dump the inference graph constraints as a graphviz file. let _: io::Result<()> = try { - let mut file = - create_dump_file(infcx.tcx, "regioncx.all.dot", None, "nll", &0, body.source)?; + let mut file = create_dump_file(infcx.tcx, "regioncx.all.dot", false, "nll", &0, body)?; regioncx.dump_graphviz_raw_constraints(&mut file)?; }; // Also dump the inference graph constraints as a graphviz file. let _: io::Result<()> = try { - let mut file = - create_dump_file(infcx.tcx, "regioncx.scc.dot", None, "nll", &0, body.source)?; + let mut file = create_dump_file(infcx.tcx, "regioncx.scc.dot", false, "nll", &0, body)?; regioncx.dump_graphviz_scc_constraints(&mut file)?; }; } diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index 3fa9d56cd01a3..3b406036c356e 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -19,11 +19,6 @@ version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142" -[[package]] -name = "ar" -version = "0.8.0" -source = "git+https://github.com/bjorn3/rust-ar.git?branch=do_not_remove_cg_clif_ranlib#de9ab0e56bf3a208381d342aa5b60f9ff2891648" - [[package]] name = "arrayvec" version = "0.7.2" @@ -324,7 +319,6 @@ dependencies = [ name = "rustc_codegen_cranelift" version = "0.1.0" dependencies = [ - "ar", "cranelift-codegen", "cranelift-frontend", "cranelift-jit", diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index 09cf5b4a1edd8..0fdd5de118ccb 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -18,7 +18,6 @@ target-lexicon = "0.12.0" gimli = { version = "0.26.0", default-features = false, features = ["write"]} object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } -ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" } indexmap = "1.9.1" libloading = { version = "0.7.3", optional = true } once_cell = "1.10.0" diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index f2e3bf16e6184..5a29bc18def54 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -1,35 +1,15 @@ -//! Creation of ar archives like for the lib and staticlib crate type - -use std::collections::BTreeMap; -use std::fs::File; -use std::io::{self, Read, Seek}; use std::path::{Path, PathBuf}; -use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; +use rustc_codegen_ssa::back::archive::{ + get_native_object_symbols, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, +}; use rustc_session::Session; -use object::read::archive::ArchiveFile; -use object::{Object, ObjectSymbol, ReadCache}; - -#[derive(Debug)] -enum ArchiveEntry { - FromArchive { archive_index: usize, file_range: (u64, u64) }, - File(PathBuf), -} - pub(crate) struct ArArchiveBuilderBuilder; impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box + 'a> { - Box::new(ArArchiveBuilder { - sess, - use_gnu_style_archive: sess.target.archive_format == "gnu", - // FIXME fix builtin ranlib on macOS - no_builtin_ranlib: sess.target.is_like_osx, - - src_archives: vec![], - entries: vec![], - }) + Box::new(ArArchiveBuilder::new(sess, get_native_object_symbols)) } fn create_dll_import_lib( @@ -40,200 +20,6 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { _tmpdir: &Path, _is_direct_dependency: bool, ) -> PathBuf { - bug!("creating dll imports is not supported"); - } -} - -pub(crate) struct ArArchiveBuilder<'a> { - sess: &'a Session, - use_gnu_style_archive: bool, - no_builtin_ranlib: bool, - - src_archives: Vec, - // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at - // the end of an archive for linkers to not get confused. - entries: Vec<(Vec, ArchiveEntry)>, -} - -impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { - fn add_file(&mut self, file: &Path) { - self.entries.push(( - file.file_name().unwrap().to_str().unwrap().to_string().into_bytes(), - ArchiveEntry::File(file.to_owned()), - )); - } - - fn add_archive( - &mut self, - archive_path: &Path, - mut skip: Box bool + 'static>, - ) -> std::io::Result<()> { - let read_cache = ReadCache::new(std::fs::File::open(&archive_path)?); - let archive = ArchiveFile::parse(&read_cache).unwrap(); - let archive_index = self.src_archives.len(); - - for entry in archive.members() { - let entry = entry.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; - let file_name = String::from_utf8(entry.name().to_vec()) - .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; - if !skip(&file_name) { - self.entries.push(( - file_name.into_bytes(), - ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() }, - )); - } - } - - self.src_archives.push(read_cache.into_inner()); - Ok(()) - } - - fn build(mut self: Box, output: &Path) -> bool { - enum BuilderKind { - Bsd(ar::Builder), - Gnu(ar::GnuBuilder), - } - - let sess = self.sess; - - let mut symbol_table = BTreeMap::new(); - - let mut entries = Vec::new(); - - for (mut entry_name, entry) in self.entries { - // FIXME only read the symbol table of the object files to avoid having to keep all - // object files in memory at once, or read them twice. - let data = match entry { - ArchiveEntry::FromArchive { archive_index, file_range } => { - // FIXME read symbols from symtab - let src_read_cache = &mut self.src_archives[archive_index]; - - src_read_cache.seek(io::SeekFrom::Start(file_range.0)).unwrap(); - let mut data = std::vec::from_elem(0, usize::try_from(file_range.1).unwrap()); - src_read_cache.read_exact(&mut data).unwrap(); - - data - } - ArchiveEntry::File(file) => std::fs::read(file).unwrap_or_else(|err| { - sess.fatal(&format!( - "error while reading object file during archive building: {}", - err - )); - }), - }; - - if !self.no_builtin_ranlib { - if symbol_table.contains_key(&entry_name) { - // The ar crate can't handle creating a symbol table in case of multiple archive - // members with the same name. Work around this by prepending a number until we - // get a unique name. - for i in 1.. { - let new_name = format!("{}_", i) - .into_bytes() - .into_iter() - .chain(entry_name.iter().copied()) - .collect::>(); - if !symbol_table.contains_key(&new_name) { - entry_name = new_name; - break; - } - } - } - - match object::File::parse(&*data) { - Ok(object) => { - symbol_table.insert( - entry_name.to_vec(), - object - .symbols() - .filter_map(|symbol| { - if symbol.is_undefined() || symbol.is_local() { - None - } else { - symbol.name().map(|name| name.as_bytes().to_vec()).ok() - } - }) - .collect::>(), - ); - } - Err(err) => { - let err = err.to_string(); - if err == "Unknown file magic" { - // Not an object file; skip it. - } else if object::read::archive::ArchiveFile::parse(&*data).is_ok() { - // Nested archive file; skip it. - } else { - sess.fatal(&format!( - "error parsing `{}` during archive creation: {}", - String::from_utf8_lossy(&entry_name), - err - )); - } - } - } - } - - entries.push((entry_name, data)); - } - - let mut builder = if self.use_gnu_style_archive { - BuilderKind::Gnu( - ar::GnuBuilder::new( - File::create(output).unwrap_or_else(|err| { - sess.fatal(&format!( - "error opening destination during archive building: {}", - err - )); - }), - entries.iter().map(|(name, _)| name.clone()).collect(), - ar::GnuSymbolTableFormat::Size32, - symbol_table, - ) - .unwrap(), - ) - } else { - BuilderKind::Bsd( - ar::Builder::new( - File::create(output).unwrap_or_else(|err| { - sess.fatal(&format!( - "error opening destination during archive building: {}", - err - )); - }), - symbol_table, - ) - .unwrap(), - ) - }; - - let any_members = !entries.is_empty(); - - // Add all files - for (entry_name, data) in entries.into_iter() { - let header = ar::Header::new(entry_name, data.len() as u64); - match builder { - BuilderKind::Bsd(ref mut builder) => builder.append(&header, &mut &*data).unwrap(), - BuilderKind::Gnu(ref mut builder) => builder.append(&header, &mut &*data).unwrap(), - } - } - - // Finalize archive - std::mem::drop(builder); - - if self.no_builtin_ranlib { - let ranlib = crate::toolchain::get_toolchain_binary(self.sess, "ranlib"); - - // Run ranlib to be able to link the archive - let status = std::process::Command::new(ranlib) - .arg(output) - .status() - .expect("Couldn't run ranlib"); - - if !status.success() { - self.sess.fatal(&format!("Ranlib exited with code {:?}", status.code())); - } - } - - any_members + unimplemented!("creating dll imports is not yet supported"); } } diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock index 6df2102470fe6..1cb219e12e04d 100644 --- a/compiler/rustc_codegen_gcc/Cargo.lock +++ b/compiler/rustc_codegen_gcc/Cargo.lock @@ -11,12 +11,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "ar" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "450575f58f7bee32816abbff470cbc47797397c2a81e0eaced4b98436daf52e1" - [[package]] name = "bitflags" version = "1.3.2" @@ -212,10 +206,8 @@ dependencies = [ name = "rustc_codegen_gcc" version = "0.1.0" dependencies = [ - "ar", "gccjit", "lang_tester", - "target-lexicon", "tempfile", ] @@ -228,12 +220,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "target-lexicon" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d" - [[package]] name = "tempfile" version = "3.2.0" diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml index 211d19a8dc890..1f3da2f799b78 100644 --- a/compiler/rustc_codegen_gcc/Cargo.toml +++ b/compiler/rustc_codegen_gcc/Cargo.toml @@ -27,10 +27,6 @@ gccjit = { git = "https://github.com/antoyo/gccjit.rs" } # Local copy. #gccjit = { path = "../gccjit.rs" } -target-lexicon = "0.10.0" - -ar = "0.8.0" - [dev-dependencies] lang_tester = "0.3.9" tempfile = "3.1.0" diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs index f18ae7ea5e9b0..11fa074f5ac79 100644 --- a/compiler/rustc_codegen_gcc/src/archive.rs +++ b/compiler/rustc_codegen_gcc/src/archive.rs @@ -1,44 +1,17 @@ -use std::fs::File; use std::path::{Path, PathBuf}; -use crate::errors::RanlibFailure; - -use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; +use rustc_codegen_ssa::back::archive::{ + get_native_object_symbols, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, +}; use rustc_session::Session; use rustc_session::cstore::DllImport; -struct ArchiveConfig<'a> { - sess: &'a Session, - use_native_ar: bool, - use_gnu_style_archive: bool, -} - -#[derive(Debug)] -enum ArchiveEntry { - FromArchive { - archive_index: usize, - entry_index: usize, - }, - File(PathBuf), -} - -pub struct ArArchiveBuilderBuilder; +pub(crate) struct ArArchiveBuilderBuilder; impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box + 'a> { - let config = ArchiveConfig { - sess, - use_native_ar: false, - // FIXME test for linux and System V derivatives instead - use_gnu_style_archive: sess.target.options.archive_format == "gnu", - }; - - Box::new(ArArchiveBuilder { - config, - src_archives: vec![], - entries: vec![], - }) + Box::new(ArArchiveBuilder::new(sess, get_native_object_symbols)) } fn create_dll_import_lib( @@ -49,144 +22,6 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { _tmpdir: &Path, _is_direct_dependency: bool, ) -> PathBuf { - unimplemented!(); - } -} - -pub struct ArArchiveBuilder<'a> { - config: ArchiveConfig<'a>, - src_archives: Vec<(PathBuf, ar::Archive)>, - // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at - // the end of an archive for linkers to not get confused. - entries: Vec<(String, ArchiveEntry)>, -} - -impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { - fn add_file(&mut self, file: &Path) { - self.entries.push(( - file.file_name().unwrap().to_str().unwrap().to_string(), - ArchiveEntry::File(file.to_owned()), - )); - } - - fn add_archive( - &mut self, - archive_path: &Path, - mut skip: Box bool + 'static>, - ) -> std::io::Result<()> { - let mut archive = ar::Archive::new(std::fs::File::open(&archive_path)?); - let archive_index = self.src_archives.len(); - - let mut i = 0; - while let Some(entry) = archive.next_entry() { - let entry = entry?; - let file_name = String::from_utf8(entry.header().identifier().to_vec()) - .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?; - if !skip(&file_name) { - self.entries - .push((file_name, ArchiveEntry::FromArchive { archive_index, entry_index: i })); - } - i += 1; - } - - self.src_archives.push((archive_path.to_owned(), archive)); - Ok(()) - } - - fn build(mut self: Box, output: &Path) -> bool { - use std::process::Command; - - fn add_file_using_ar(archive: &Path, file: &Path) { - Command::new("ar") - .arg("r") // add or replace file - .arg("-c") // silence created file message - .arg(archive) - .arg(&file) - .status() - .unwrap(); - } - - enum BuilderKind<'a> { - Bsd(ar::Builder), - Gnu(ar::GnuBuilder), - NativeAr(&'a Path), - } - - let mut builder = if self.config.use_native_ar { - BuilderKind::NativeAr(output) - } else if self.config.use_gnu_style_archive { - BuilderKind::Gnu(ar::GnuBuilder::new( - File::create(output).unwrap(), - self.entries - .iter() - .map(|(name, _)| name.as_bytes().to_vec()) - .collect(), - )) - } else { - BuilderKind::Bsd(ar::Builder::new(File::create(output).unwrap())) - }; - - let any_members = !self.entries.is_empty(); - - // Add all files - for (entry_name, entry) in self.entries.into_iter() { - match entry { - ArchiveEntry::FromArchive { - archive_index, - entry_index, - } => { - let (ref src_archive_path, ref mut src_archive) = - self.src_archives[archive_index]; - let entry = src_archive.jump_to_entry(entry_index).unwrap(); - let header = entry.header().clone(); - - match builder { - BuilderKind::Bsd(ref mut builder) => { - builder.append(&header, entry).unwrap() - } - BuilderKind::Gnu(ref mut builder) => { - builder.append(&header, entry).unwrap() - } - BuilderKind::NativeAr(archive_file) => { - Command::new("ar") - .arg("x") - .arg(src_archive_path) - .arg(&entry_name) - .status() - .unwrap(); - add_file_using_ar(archive_file, Path::new(&entry_name)); - std::fs::remove_file(entry_name).unwrap(); - } - } - } - ArchiveEntry::File(file) => - match builder { - BuilderKind::Bsd(ref mut builder) => { - builder - .append_file(entry_name.as_bytes(), &mut File::open(file).expect("file for bsd builder")) - .unwrap() - }, - BuilderKind::Gnu(ref mut builder) => { - builder - .append_file(entry_name.as_bytes(), &mut File::open(&file).expect(&format!("file {:?} for gnu builder", file))) - .unwrap() - }, - BuilderKind::NativeAr(archive_file) => add_file_using_ar(archive_file, &file), - }, - } - } - - // Finalize archive - std::mem::drop(builder); - - // Run ranlib to be able to link the archive - let status = - std::process::Command::new("ranlib").arg(output).status().expect("Couldn't run ranlib"); - - if !status.success() { - self.config.sess.emit_fatal(RanlibFailure::new(status.code())); - } - - any_members + unimplemented!("creating dll imports is not yet supported"); } } diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs index 15ad90f9043c0..89fed7be13156 100644 --- a/compiler/rustc_codegen_gcc/src/errors.rs +++ b/compiler/rustc_codegen_gcc/src/errors.rs @@ -16,18 +16,6 @@ impl IntoDiagnosticArg for ExitCode { } } -#[derive(Diagnostic)] -#[diag(codegen_gcc_ranlib_failure)] -pub(crate) struct RanlibFailure { - exit_code: ExitCode, -} - -impl RanlibFailure { - pub fn new(exit_code: Option) -> Self { - RanlibFailure { exit_code: ExitCode(exit_code) } - } -} - #[derive(Diagnostic)] #[diag(codegen_gcc_invalid_monomorphization_basic_integer, code = "E0511")] pub(crate) struct InvalidMonomorphizationBasicInteger<'a> { @@ -227,7 +215,7 @@ pub(crate) struct InvalidMonomorphizationUnsupportedOperation<'a> { #[diag(codegen_gcc_linkage_const_or_mut_type)] pub(crate) struct LinkageConstOrMutType { #[primary_span] - pub span: Span + pub span: Span, } #[derive(Diagnostic)] @@ -238,5 +226,5 @@ pub(crate) struct LTONotSupported; #[diag(codegen_gcc_unwinding_inline_asm)] pub(crate) struct UnwindingInlineAsm { #[primary_span] - pub span: Span + pub span: Span, } diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 0ad39c24025fd..93d6234dc8845 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -11,7 +11,7 @@ bitflags = "1.0" cstr = "0.2" libc = "0.2" measureme = "10.0.0" -object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "archive", "coff", "elf", "macho", "pe"] } +object = { version = "0.29.0", default-features = false, features = ["std", "read"] } tracing = "0.1" rustc_middle = { path = "../rustc_middle" } rustc-demangle = "0.1.21" diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index a8b47633519aa..f3bdacf608555 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -258,13 +258,12 @@ pub fn from_fn_attrs<'ll, 'tcx>( OptimizeAttr::Speed => {} } - let inline = if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { - InlineAttr::Never - } else if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) { - InlineAttr::Hint - } else { - codegen_fn_attrs.inline - }; + let inline = + if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) { + InlineAttr::Hint + } else { + codegen_fn_attrs.inline + }; to_add.extend(inline_attr(cx, inline)); // The `uwtable` attribute according to LLVM is: diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 5c68abeb08baf..0aee1a1439b9b 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -1,31 +1,30 @@ //! A helper class for dealing with static archives use std::env; -use std::ffi::{CStr, CString, OsString}; -use std::fs; -use std::io::{self, Write}; +use std::ffi::{c_char, c_void, CStr, CString, OsString}; +use std::io; use std::mem; use std::path::{Path, PathBuf}; use std::ptr; use std::str; -use object::read::macho::FatArch; - use crate::common; use crate::errors::{ - ArchiveBuildFailure, DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, - ErrorWritingDEFFile, UnknownArchiveKind, + DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile, }; use crate::llvm::archive_ro::{ArchiveRO, Child}; use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport}; -use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; -use rustc_data_structures::memmap::Mmap; +use rustc_codegen_ssa::back::archive::{ + get_native_object_symbols, try_extract_macho_fat_archive, ArArchiveBuilder, + ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, UnknownArchiveKind, +}; + use rustc_session::cstore::DllImport; use rustc_session::Session; /// Helper for adding many files to an archive. #[must_use = "must call build() to finish building the archive"] -pub struct LlvmArchiveBuilder<'a> { +pub(crate) struct LlvmArchiveBuilder<'a> { sess: &'a Session, additions: Vec, } @@ -61,57 +60,6 @@ fn llvm_machine_type(cpu: &str) -> LLVMMachineType { } } -fn try_filter_fat_archs( - archs: object::read::Result<&[impl FatArch]>, - target_arch: object::Architecture, - archive_path: &Path, - archive_map_data: &[u8], -) -> io::Result> { - let archs = archs.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; - - let desired = match archs.iter().filter(|a| a.architecture() == target_arch).next() { - Some(a) => a, - None => return Ok(None), - }; - - let (mut new_f, extracted_path) = tempfile::Builder::new() - .suffix(archive_path.file_name().unwrap()) - .tempfile()? - .keep() - .unwrap(); - - new_f.write_all( - desired.data(archive_map_data).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?, - )?; - - Ok(Some(extracted_path)) -} - -fn try_extract_macho_fat_archive( - sess: &Session, - archive_path: &Path, -) -> io::Result> { - let archive_map = unsafe { Mmap::map(fs::File::open(&archive_path)?)? }; - let target_arch = match sess.target.arch.as_ref() { - "aarch64" => object::Architecture::Aarch64, - "x86_64" => object::Architecture::X86_64, - _ => return Ok(None), - }; - - match object::macho::FatHeader::parse(&*archive_map) { - Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC => { - let archs = object::macho::FatHeader::parse_arch32(&*archive_map); - try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map) - } - Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC_64 => { - let archs = object::macho::FatHeader::parse_arch64(&*archive_map); - try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map) - } - // Not a FatHeader at all, just return None. - _ => Ok(None), - } -} - impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { fn add_archive( &mut self, @@ -160,7 +108,11 @@ pub struct LlvmArchiveBuilderBuilder; impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box + 'a> { - Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() }) + if sess.target.arch == "wasm32" || sess.target.arch == "wasm64" { + Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() }) + } else { + Box::new(ArArchiveBuilder::new(sess, get_llvm_object_symbols)) + } } fn create_dll_import_lib( @@ -309,6 +261,61 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { } } +// The object crate doesn't know how to get symbols for LLVM bitcode and COFF bigobj files. +// As such we need to use LLVM for them. +#[deny(unsafe_op_in_unsafe_fn)] +fn get_llvm_object_symbols( + buf: &[u8], + f: &mut dyn FnMut(&[u8]) -> io::Result<()>, +) -> io::Result { + let is_bitcode = unsafe { llvm::LLVMRustIsBitcode(buf.as_ptr(), buf.len()) }; + + // COFF bigobj file, msvc LTO file or import library. See + // https://github.com/llvm/llvm-project/blob/453f27bc9/llvm/lib/BinaryFormat/Magic.cpp#L38-L51 + let is_unsupported_windows_obj_file = buf.get(0..4) == Some(b"\0\0\xFF\xFF"); + + if is_bitcode || is_unsupported_windows_obj_file { + let mut state = Box::new(f); + + let err = unsafe { + llvm::LLVMRustGetSymbols( + buf.as_ptr(), + buf.len(), + &mut *state as *mut &mut _ as *mut c_void, + callback, + error_callback, + ) + }; + + if err.is_null() { + return Ok(true); + } else { + return Err(unsafe { *Box::from_raw(err as *mut io::Error) }); + } + + unsafe extern "C" fn callback( + state: *mut c_void, + symbol_name: *const c_char, + ) -> *mut c_void { + let f = unsafe { &mut *(state as *mut &mut dyn FnMut(&[u8]) -> io::Result<()>) }; + match f(unsafe { CStr::from_ptr(symbol_name) }.to_bytes()) { + Ok(()) => std::ptr::null_mut(), + Err(err) => Box::into_raw(Box::new(err)) as *mut c_void, + } + } + + unsafe extern "C" fn error_callback(error: *const c_char) -> *mut c_void { + let error = unsafe { CStr::from_ptr(error) }; + Box::into_raw(Box::new(io::Error::new( + io::ErrorKind::Other, + format!("LLVM error: {}", error.to_string_lossy()), + ))) as *mut c_void + } + } else { + get_native_object_symbols(buf, f) + } +} + impl<'a> LlvmArchiveBuilder<'a> { fn build_with_llvm(&mut self, output: &Path) -> io::Result { let kind = &*self.sess.target.archive_format; diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 0fafc214f2f5e..fddfbb23c67d5 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -72,12 +72,6 @@ pub(crate) struct LinkageConstOrMutType { #[diag(codegen_llvm_sanitizer_memtag_requires_mte)] pub(crate) struct SanitizerMemtagRequiresMte; -#[derive(Diagnostic)] -#[diag(codegen_llvm_archive_build_failure)] -pub(crate) struct ArchiveBuildFailure { - pub error: std::io::Error, -} - #[derive(Diagnostic)] #[diag(codegen_llvm_error_writing_def_file)] pub(crate) struct ErrorWritingDEFFile { @@ -97,12 +91,6 @@ pub(crate) struct DlltoolFailImportLibrary<'a> { pub stderr: Cow<'a, str>, } -#[derive(Diagnostic)] -#[diag(codegen_llvm_unknown_archive_kind)] -pub(crate) struct UnknownArchiveKind<'a> { - pub kind: &'a str, -} - #[derive(Diagnostic)] #[diag(codegen_llvm_dynamic_linking_with_lto)] #[note] diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index c14e1656291e8..8a9392255b861 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -983,6 +983,9 @@ pub type SelfProfileBeforePassCallback = unsafe extern "C" fn(*mut c_void, *const c_char, *const c_char); pub type SelfProfileAfterPassCallback = unsafe extern "C" fn(*mut c_void); +pub type GetSymbolsCallback = unsafe extern "C" fn(*mut c_void, *const c_char) -> *mut c_void; +pub type GetSymbolsErrorCallback = unsafe extern "C" fn(*const c_char) -> *mut c_void; + extern "C" { pub fn LLVMRustInstallFatalErrorHandler(); pub fn LLVMRustDisableSystemDialogsOnCrash(); @@ -2474,4 +2477,14 @@ extern "C" { pub fn LLVMRustGetMangledName(V: &Value, out: &RustString); pub fn LLVMRustGetElementTypeArgIndex(CallSite: &Value) -> i32; + + pub fn LLVMRustIsBitcode(ptr: *const u8, len: usize) -> bool; + + pub fn LLVMRustGetSymbols( + buf_ptr: *const u8, + buf_len: usize, + state: *mut c_void, + callback: GetSymbolsCallback, + error_callback: GetSymbolsErrorCallback, + ) -> *mut c_void; } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index c9f5dd0f2c68b..2fa602520dcb0 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -494,6 +494,11 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec= (14, 0, 0) && sess.target.arch == "aarch64" { + features.push("+v8a".into()); + } + if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) { sess.emit_err(TargetFeatureDisableOrEnable { features: f, diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index d868e3d56ba6b..345174fb595ab 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" test = false [dependencies] +ar_archive_writer = "0.1.1" bitflags = "1.2.1" cc = "1.0.69" itertools = "0.10.1" diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 2b1b06d1644c9..58558fb8c4ba2 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -6,14 +6,19 @@ use rustc_span::symbol::Symbol; use super::metadata::search_for_section; +pub use ar_archive_writer::get_native_object_symbols; +use ar_archive_writer::{write_archive_to_stream, ArchiveKind, NewArchiveMember}; use object::read::archive::ArchiveFile; +use object::read::macho::FatArch; +use tempfile::Builder as TempFileBuilder; use std::error::Error; use std::fs::File; -use std::io; +use std::io::{self, Write}; use std::path::{Path, PathBuf}; -use crate::errors::ExtractBundledLibsError; +// Re-exporting for rustc_codegen_llvm::back::archive +pub use crate::errors::{ArchiveBuildFailure, ExtractBundledLibsError, UnknownArchiveKind}; pub trait ArchiveBuilderBuilder { fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box + 'a>; @@ -80,3 +85,225 @@ pub trait ArchiveBuilder<'a> { fn build(self: Box, output: &Path) -> bool; } + +#[must_use = "must call build() to finish building the archive"] +pub struct ArArchiveBuilder<'a> { + sess: &'a Session, + get_object_symbols: + fn(buf: &[u8], f: &mut dyn FnMut(&[u8]) -> io::Result<()>) -> io::Result, + + src_archives: Vec<(PathBuf, Mmap)>, + // Don't use an `HashMap` here, as the order is important. `lib.rmeta` needs + // to be at the end of an archive in some cases for linkers to not get confused. + entries: Vec<(Vec, ArchiveEntry)>, +} + +#[derive(Debug)] +enum ArchiveEntry { + FromArchive { archive_index: usize, file_range: (u64, u64) }, + File(PathBuf), +} + +impl<'a> ArArchiveBuilder<'a> { + pub fn new( + sess: &'a Session, + get_object_symbols: fn( + buf: &[u8], + f: &mut dyn FnMut(&[u8]) -> io::Result<()>, + ) -> io::Result, + ) -> ArArchiveBuilder<'a> { + ArArchiveBuilder { sess, get_object_symbols, src_archives: vec![], entries: vec![] } + } +} + +fn try_filter_fat_archs( + archs: object::read::Result<&[impl FatArch]>, + target_arch: object::Architecture, + archive_path: &Path, + archive_map_data: &[u8], +) -> io::Result> { + let archs = archs.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; + + let desired = match archs.iter().filter(|a| a.architecture() == target_arch).next() { + Some(a) => a, + None => return Ok(None), + }; + + let (mut new_f, extracted_path) = tempfile::Builder::new() + .suffix(archive_path.file_name().unwrap()) + .tempfile()? + .keep() + .unwrap(); + + new_f.write_all( + desired.data(archive_map_data).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?, + )?; + + Ok(Some(extracted_path)) +} + +pub fn try_extract_macho_fat_archive( + sess: &Session, + archive_path: &Path, +) -> io::Result> { + let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? }; + let target_arch = match sess.target.arch.as_ref() { + "aarch64" => object::Architecture::Aarch64, + "x86_64" => object::Architecture::X86_64, + _ => return Ok(None), + }; + + match object::macho::FatHeader::parse(&*archive_map) { + Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC => { + let archs = object::macho::FatHeader::parse_arch32(&*archive_map); + try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map) + } + Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC_64 => { + let archs = object::macho::FatHeader::parse_arch64(&*archive_map); + try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map) + } + // Not a FatHeader at all, just return None. + _ => Ok(None), + } +} + +impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { + fn add_archive( + &mut self, + archive_path: &Path, + mut skip: Box bool + 'static>, + ) -> io::Result<()> { + let mut archive_path = archive_path.to_path_buf(); + if self.sess.target.llvm_target.contains("-apple-macosx") { + if let Some(new_archive_path) = + try_extract_macho_fat_archive(&self.sess, &archive_path)? + { + archive_path = new_archive_path + } + } + + if self.src_archives.iter().any(|archive| archive.0 == archive_path) { + return Ok(()); + } + + let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? }; + let archive = ArchiveFile::parse(&*archive_map) + .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; + let archive_index = self.src_archives.len(); + + for entry in archive.members() { + let entry = entry.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; + let file_name = String::from_utf8(entry.name().to_vec()) + .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; + if !skip(&file_name) { + self.entries.push(( + file_name.into_bytes(), + ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() }, + )); + } + } + + self.src_archives.push((archive_path.to_owned(), archive_map)); + Ok(()) + } + + /// Adds an arbitrary file to this archive + fn add_file(&mut self, file: &Path) { + self.entries.push(( + file.file_name().unwrap().to_str().unwrap().to_string().into_bytes(), + ArchiveEntry::File(file.to_owned()), + )); + } + + /// Combine the provided files, rlibs, and native libraries into a single + /// `Archive`. + fn build(self: Box, output: &Path) -> bool { + let sess = self.sess; + match self.build_inner(output) { + Ok(any_members) => any_members, + Err(e) => sess.emit_fatal(ArchiveBuildFailure { error: e }), + } + } +} + +impl<'a> ArArchiveBuilder<'a> { + fn build_inner(self, output: &Path) -> io::Result { + let archive_kind = match &*self.sess.target.archive_format { + "gnu" => ArchiveKind::Gnu, + "bsd" => ArchiveKind::Bsd, + "darwin" => ArchiveKind::Darwin, + "coff" => ArchiveKind::Coff, + kind => { + self.sess.emit_fatal(UnknownArchiveKind { kind }); + } + }; + + let mut entries = Vec::new(); + + for (entry_name, entry) in self.entries { + let data = + match entry { + ArchiveEntry::FromArchive { archive_index, file_range } => { + let src_archive = &self.src_archives[archive_index]; + + let data = &src_archive.1 + [file_range.0 as usize..file_range.0 as usize + file_range.1 as usize]; + + Box::new(data) as Box> + } + ArchiveEntry::File(file) => unsafe { + Box::new( + Mmap::map(File::open(file).map_err(|err| { + io_error_context("failed to open object file", err) + })?) + .map_err(|err| io_error_context("failed to map object file", err))?, + ) as Box> + }, + }; + + entries.push(NewArchiveMember { + buf: data, + get_symbols: self.get_object_symbols, + member_name: String::from_utf8(entry_name).unwrap(), + mtime: 0, + uid: 0, + gid: 0, + perms: 0o644, + }) + } + + // Write to a temporary file first before atomically renaming to the final name. + // This prevents programs (including rustc) from attempting to read a partial archive. + // It also enables writing an archive with the same filename as a dependency on Windows as + // required by a test. + let mut archive_tmpfile = TempFileBuilder::new() + .suffix(".temp-archive") + .tempfile_in(output.parent().unwrap_or_else(|| Path::new(""))) + .map_err(|err| io_error_context("couldn't create a temp file", err))?; + + write_archive_to_stream( + archive_tmpfile.as_file_mut(), + &entries, + true, + archive_kind, + true, + false, + )?; + + let any_entries = !entries.is_empty(); + drop(entries); + // Drop src_archives to unmap all input archives, which is necessary if we want to write the + // output archive to the same location as an input archive on Windows. + drop(self.src_archives); + + archive_tmpfile + .persist(output) + .map_err(|err| io_error_context("failed to rename archive file", err.error))?; + + Ok(any_entries) + } +} + +fn io_error_context(context: &str, err: io::Error) -> io::Error { + io::Error::new(io::ErrorKind::Other, format!("{context}: {err}")) +} diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index ade50af0aee8d..e3b6fbf1bc7f0 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -534,3 +534,17 @@ pub struct ReadFileError { #[derive(Diagnostic)] #[diag(codegen_ssa_unsupported_link_self_contained)] pub struct UnsupportedLinkSelfContained; + +#[derive(Diagnostic)] +#[diag(codegen_ssa_archive_build_failure)] +// Public for rustc_codegen_llvm::back::archive +pub struct ArchiveBuildFailure { + pub error: std::io::Error, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_unknown_archive_kind)] +// Public for rustc_codegen_llvm::back::archive +pub struct UnknownArchiveKind<'a> { + pub kind: &'a str, +} diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 908555385891d..fbe30154a7c8d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -309,14 +309,14 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { // In the algorithm above, we can change // cast(relative_tag) + niche_variants.start() // into - // cast(tag) + (niche_variants.start() - niche_start) + // cast(tag + (niche_variants.start() - niche_start)) // if either the casted type is no larger than the original // type, or if the niche values are contiguous (in either the // signed or unsigned sense). - let can_incr_after_cast = cast_smaller || niches_ule || niches_sle; + let can_incr = cast_smaller || niches_ule || niches_sle; let data_for_boundary_niche = || -> Option<(IntPredicate, u128)> { - if !can_incr_after_cast { + if !can_incr { None } else if niche_start == low_unsigned { Some((IntPredicate::IntULE, niche_end)) @@ -353,24 +353,33 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { // The algorithm is now this: // is_niche = tag <= niche_end // discr = if is_niche { - // cast(tag) + (niche_variants.start() - niche_start) + // cast(tag + (niche_variants.start() - niche_start)) // } else { // untagged_variant // } // (the first line may instead be tag >= niche_start, // and may be a signed or unsigned comparison) + // The arithmetic must be done before the cast, so we can + // have the correct wrapping behavior. See issue #104519 for + // the consequences of getting this wrong. let is_niche = bx.icmp(predicate, tag, bx.cx().const_uint_big(tag_llty, constant)); + let delta = (niche_variants.start().as_u32() as u128).wrapping_sub(niche_start); + let incr_tag = if delta == 0 { + tag + } else { + bx.add(tag, bx.cx().const_uint_big(tag_llty, delta)) + }; + let cast_tag = if cast_smaller { - bx.intcast(tag, cast_to, false) + bx.intcast(incr_tag, cast_to, false) } else if niches_ule { - bx.zext(tag, cast_to) + bx.zext(incr_tag, cast_to) } else { - bx.sext(tag, cast_to) + bx.sext(incr_tag, cast_to) }; - let delta = (niche_variants.start().as_u32() as u128).wrapping_sub(niche_start); - (is_niche, cast_tag, delta) + (is_niche, cast_tag, 0) } else { // The special cases don't apply, so we'll have to go with // the general algorithm. diff --git a/compiler/rustc_data_structures/src/intern.rs b/compiler/rustc_data_structures/src/intern.rs index 11cbff8ea6a84..76a1288e6d351 100644 --- a/compiler/rustc_data_structures/src/intern.rs +++ b/compiler/rustc_data_structures/src/intern.rs @@ -72,7 +72,7 @@ impl<'a, T: PartialOrd> PartialOrd for Interned<'a, T> { if ptr::eq(self.0, other.0) { Some(Ordering::Equal) } else { - let res = self.0.partial_cmp(&other.0); + let res = self.0.partial_cmp(other.0); debug_assert_ne!(res, Some(Ordering::Equal)); res } @@ -86,7 +86,7 @@ impl<'a, T: Ord> Ord for Interned<'a, T> { if ptr::eq(self.0, other.0) { Ordering::Equal } else { - let res = self.0.cmp(&other.0); + let res = self.0.cmp(other.0); debug_assert_ne!(res, Ordering::Equal); res } diff --git a/compiler/rustc_data_structures/src/memmap.rs b/compiler/rustc_data_structures/src/memmap.rs index 917416df6b867..3d44e17f31d1f 100644 --- a/compiler/rustc_data_structures/src/memmap.rs +++ b/compiler/rustc_data_structures/src/memmap.rs @@ -36,6 +36,12 @@ impl Deref for Mmap { #[inline] fn deref(&self) -> &[u8] { + &self.0 + } +} + +impl AsRef<[u8]> for Mmap { + fn as_ref(&self) -> &[u8] { &*self.0 } } @@ -96,13 +102,13 @@ impl Deref for MmapMut { #[inline] fn deref(&self) -> &[u8] { - &*self.0 + &self.0 } } impl DerefMut for MmapMut { #[inline] fn deref_mut(&mut self) -> &mut [u8] { - &mut *self.0 + &mut self.0 } } diff --git a/compiler/rustc_data_structures/src/owning_ref/mod.rs b/compiler/rustc_data_structures/src/owning_ref/mod.rs index ed5e566184f12..980a540ccba7a 100644 --- a/compiler/rustc_data_structures/src/owning_ref/mod.rs +++ b/compiler/rustc_data_structures/src/owning_ref/mod.rs @@ -899,25 +899,25 @@ unsafe impl StableAddress for OwningRef {} impl AsRef for OwningRef { fn as_ref(&self) -> &T { - &*self + self } } impl AsRef for OwningRefMut { fn as_ref(&self) -> &T { - &*self + self } } impl AsMut for OwningRefMut { fn as_mut(&mut self) -> &mut T { - &mut *self + self } } impl Borrow for OwningRef { fn borrow(&self) -> &T { - &*self + self } } @@ -1021,7 +1021,7 @@ where T: PartialEq, { fn eq(&self, other: &Self) -> bool { - (&*self as &T).eq(&*other as &T) + self.deref().eq(other.deref()) } } @@ -1032,7 +1032,7 @@ where T: PartialOrd, { fn partial_cmp(&self, other: &Self) -> Option { - (&*self as &T).partial_cmp(&*other as &T) + self.deref().partial_cmp(other.deref()) } } @@ -1041,7 +1041,7 @@ where T: Ord, { fn cmp(&self, other: &Self) -> Ordering { - (&*self as &T).cmp(&*other as &T) + self.deref().cmp(other.deref()) } } @@ -1050,7 +1050,7 @@ where T: Hash, { fn hash(&self, state: &mut H) { - (&*self as &T).hash(state); + self.deref().hash(state); } } @@ -1059,7 +1059,7 @@ where T: PartialEq, { fn eq(&self, other: &Self) -> bool { - (&*self as &T).eq(&*other as &T) + self.deref().eq(other.deref()) } } @@ -1070,7 +1070,7 @@ where T: PartialOrd, { fn partial_cmp(&self, other: &Self) -> Option { - (&*self as &T).partial_cmp(&*other as &T) + self.deref().partial_cmp(other.deref()) } } @@ -1079,7 +1079,7 @@ where T: Ord, { fn cmp(&self, other: &Self) -> Ordering { - (&*self as &T).cmp(&*other as &T) + self.deref().cmp(other.deref()) } } @@ -1088,7 +1088,7 @@ where T: Hash, { fn hash(&self, state: &mut H) { - (&*self as &T).hash(state); + self.deref().hash(state); } } diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index ba1960805d84b..aa7a01eed15c9 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -192,7 +192,7 @@ impl SelfProfilerRef { F: for<'a> FnOnce(&'a SelfProfiler) -> TimingGuard<'a>, { let profiler = profiler_ref.profiler.as_ref().unwrap(); - f(&**profiler) + f(profiler) } if self.event_filter_mask.contains(event_filter) { @@ -466,7 +466,7 @@ impl SelfProfilerRef { pub fn with_profiler(&self, f: impl FnOnce(&SelfProfiler)) { if let Some(profiler) = &self.profiler { - f(&profiler) + f(profiler) } } @@ -733,7 +733,7 @@ impl Drop for VerboseTimingGuard<'_> { if let Some((start_time, start_rss, ref message)) = self.start_and_message { let end_rss = get_resident_set_size(); let dur = start_time.elapsed(); - print_time_passes_entry(&message, dur, start_rss, end_rss); + print_time_passes_entry(message, dur, start_rss, end_rss); } } } diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index e2c33e7e06268..cd392a7b678b6 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -366,7 +366,7 @@ impl HashStable for [u8] { impl, CTX> HashStable for Vec { #[inline] fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - (&self[..]).hash_stable(ctx, hasher); + self[..].hash_stable(ctx, hasher); } } @@ -405,7 +405,7 @@ where { #[inline] fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - (&self[..]).hash_stable(ctx, hasher); + self[..].hash_stable(ctx, hasher); } } @@ -440,7 +440,7 @@ impl HashStable for str { impl HashStable for String { #[inline] fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - (&self[..]).hash_stable(hcx, hasher); + self[..].hash_stable(hcx, hasher); } } diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index c550f246e094a..e4f47b22ac358 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -201,7 +201,7 @@ cfg_if! { #[inline(always)] fn deref(&self) -> &T { - &*self.0 + &self.0 } } diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 380fbd732d505..22f87514dd8fa 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -245,10 +245,8 @@ fn run_compiler( interface::run_compiler(config, |compiler| { let sopts = &compiler.session().opts; if sopts.describe_lints { - let mut lint_store = rustc_lint::new_lint_store( - sopts.unstable_opts.no_interleave_lints, - compiler.session().enable_internal_lints(), - ); + let mut lint_store = + rustc_lint::new_lint_store(compiler.session().enable_internal_lints()); let registered_lints = if let Some(register_lints) = compiler.register_lints() { register_lints(compiler.session(), &mut lint_store); diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl index 178e1a67ccecf..a1b7afeb7099d 100644 --- a/compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl +++ b/compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl @@ -1,6 +1,3 @@ -codegen_gcc_ranlib_failure = - Ranlib exited with code {$exit_code} - codegen_gcc_linkage_const_or_mut_type = must have type `*const T` or `*mut T` due to `#[linkage]` attribute diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl index 68a205df6c7ad..e273476b60bb6 100644 --- a/compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl +++ b/compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl @@ -29,9 +29,6 @@ codegen_llvm_linkage_const_or_mut_type = codegen_llvm_sanitizer_memtag_requires_mte = `-Zsanitizer=memtag` requires `-Ctarget-feature=+mte` -codegen_llvm_archive_build_failure = - failed to build archive: {$error} - codegen_llvm_error_writing_def_file = Error writing .DEF file: {$error} @@ -41,9 +38,6 @@ codegen_llvm_error_calling_dlltool = codegen_llvm_dlltool_fail_import_library = Dlltool could not create import library: {$stdout}\n{$stderr} -codegen_llvm_unknown_archive_kind = - Don't know how to build archive of type: {$kind} - codegen_llvm_target_feature_disable_or_enable = the target features {$features} must all be either enabled or disabled together diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl index 70ce559526c36..4d1f9c1c901fc 100644 --- a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl +++ b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl @@ -186,3 +186,9 @@ codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {erro codegen_ssa_read_file = failed to read file: {message} codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target + +codegen_ssa_archive_build_failure = + failed to build archive: {$error} + +codegen_ssa_unknown_archive_kind = + Don't know how to build archive of type: {$kind} diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index c450c276366e1..d8879bf70ed39 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -39,7 +39,7 @@ impl Translate for AnnotateSnippetEmitterWriter { } fn fallback_fluent_bundle(&self) -> &FluentBundle { - &**self.fallback_bundle + &self.fallback_bundle } } @@ -49,7 +49,7 @@ impl Emitter for AnnotateSnippetEmitterWriter { let fluent_args = to_fluent_args(diag.args()); let mut children = diag.children.clone(); - let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args); + let (mut primary_span, suggestions) = self.primary_span_formatted(diag, &fluent_args); self.fix_multispans_in_extern_macros_and_render_macro_backtrace( &mut primary_span, @@ -65,7 +65,7 @@ impl Emitter for AnnotateSnippetEmitterWriter { &diag.code, &primary_span, &children, - &suggestions, + suggestions, ); } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 7d5e4723a6d88..06bb5edc090f4 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -292,7 +292,7 @@ impl Diagnostic { let lint_index = expectation_id.get_lint_index(); expectation_id.set_lint_index(None); let mut stable_id = unstable_to_stable - .get(&expectation_id) + .get(expectation_id) .expect("each unstable `LintExpectationId` must have a matching stable id") .normalize(); diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 1fabe15ff83ba..db595df8ec18c 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -283,7 +283,7 @@ pub trait Emitter: Translate { if self .source_map() .map(|sm| is_case_difference( - &**sm, + sm, substitution, sugg.substitutions[0].parts[0].span, )) @@ -525,7 +525,7 @@ impl Translate for EmitterWriter { } fn fallback_fluent_bundle(&self) -> &FluentBundle { - &**self.fallback_bundle + &self.fallback_bundle } } @@ -538,7 +538,7 @@ impl Emitter for EmitterWriter { let fluent_args = to_fluent_args(diag.args()); let mut children = diag.children.clone(); - let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args); + let (mut primary_span, suggestions) = self.primary_span_formatted(diag, &fluent_args); debug!("emit_diagnostic: suggestions={:?}", suggestions); self.fix_multispans_in_extern_macros_and_render_macro_backtrace( @@ -555,7 +555,7 @@ impl Emitter for EmitterWriter { &diag.code, &primary_span, &children, - &suggestions, + suggestions, self.track_diagnostics.then_some(&diag.emitted_at), ); } @@ -801,7 +801,7 @@ impl EmitterWriter { } let source_string = match file.get_line(line.line_index - 1) { - Some(s) => normalize_whitespace(&*s), + Some(s) => normalize_whitespace(&s), None => return Vec::new(), }; @@ -1148,7 +1148,7 @@ impl EmitterWriter { (pos + 2, annotation.start_col.saturating_sub(left)) }; if let Some(ref label) = annotation.label { - buffer.puts(line_offset + pos, code_offset + col, &label, style); + buffer.puts(line_offset + pos, code_offset + col, label, style); } } @@ -1358,7 +1358,7 @@ impl EmitterWriter { // only render error codes, not lint codes if let Some(DiagnosticId::Error(ref code)) = *code { buffer.append(0, "[", Style::Level(*level)); - buffer.append(0, &code, Style::Level(*level)); + buffer.append(0, code, Style::Level(*level)); buffer.append(0, "]", Style::Level(*level)); label_width += 2 + code.len(); } @@ -1683,7 +1683,7 @@ impl EmitterWriter { }; // Render the replacements for each suggestion - let suggestions = suggestion.splice_lines(&**sm); + let suggestions = suggestion.splice_lines(sm); debug!("emit_suggestion_default: suggestions={:?}", suggestions); if suggestions.is_empty() { @@ -1784,7 +1784,7 @@ impl EmitterWriter { buffer.puts( row_num - 1 + line - line_start, max_line_num_len + 3, - &normalize_whitespace(&*file_lines.file.get_line(line - 1).unwrap()), + &normalize_whitespace(&file_lines.file.get_line(line - 1).unwrap()), Style::Removal, ); } @@ -1926,7 +1926,7 @@ impl EmitterWriter { buffer.putc( row_num, (padding as isize + p) as usize, - if part.is_addition(&sm) { '+' } else { '~' }, + if part.is_addition(sm) { '+' } else { '~' }, Style::Addition, ); } @@ -1973,7 +1973,7 @@ impl EmitterWriter { buffer.puts(row_num, max_line_num_len + 3, &msg, Style::NoStyle); } else if notice_capitalization { let msg = "notice the capitalization difference"; - buffer.puts(row_num, max_line_num_len + 3, &msg, Style::NoStyle); + buffer.puts(row_num, max_line_num_len + 3, msg, Style::NoStyle); } emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?; Ok(()) @@ -2028,7 +2028,7 @@ impl EmitterWriter { for child in children { let span = child.render_span.as_ref().unwrap_or(&child.span); if let Err(err) = self.emit_message_default( - &span, + span, &child.message, args, &None, @@ -2113,7 +2113,7 @@ impl EmitterWriter { *row_num - 1, max_line_num_len + 3, &normalize_whitespace( - &*file_lines.file.get_line(file_lines.lines[line_pos].line_index).unwrap(), + &file_lines.file.get_line(file_lines.lines[line_pos].line_index).unwrap(), ), Style::NoStyle, ); diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index c4498eafa4eab..a37073d8fa32a 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -136,7 +136,7 @@ impl Translate for JsonEmitter { } fn fallback_fluent_bundle(&self) -> &FluentBundle { - &**self.fallback_bundle + &self.fallback_bundle } } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 2be36a6eeb4a2..eb0506c459afa 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -470,6 +470,7 @@ pub enum StashKey { /// Maybe there was a typo where a comma was forgotten before /// FRU syntax MaybeFruTypo, + CallAssocMethod, } fn default_track_diagnostic(_: &Diagnostic) {} @@ -1328,7 +1329,7 @@ impl HandlerInner { diagnostic.children.drain_filter(already_emitted_sub).for_each(|_| {}); - self.emitter.emit_diagnostic(&diagnostic); + self.emitter.emit_diagnostic(diagnostic); if diagnostic.is_error() { self.deduplicated_err_count += 1; } else if let Warning(_) = diagnostic.level { diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs index a452fac074787..afd660ff1bf1f 100644 --- a/compiler/rustc_errors/src/translation.rs +++ b/compiler/rustc_errors/src/translation.rs @@ -59,13 +59,13 @@ pub trait Translate { trace!(?message, ?args); let (identifier, attr) = match message { DiagnosticMessage::Str(msg) | DiagnosticMessage::Eager(msg) => { - return Cow::Borrowed(&msg); + return Cow::Borrowed(msg); } DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr), }; let translate_with_bundle = |bundle: &'a FluentBundle| -> Option<(Cow<'_, str>, Vec<_>)> { - let message = bundle.get_message(&identifier)?; + let message = bundle.get_message(identifier)?; let value = match attr { Some(attr) => message.get_attribute(attr)?.value(), None => message.value()?, @@ -73,7 +73,7 @@ pub trait Translate { debug!(?message, ?value); let mut errs = vec![]; - let translated = bundle.format_pattern(value, Some(&args), &mut errs); + let translated = bundle.format_pattern(value, Some(args), &mut errs); debug!(?translated, ?errs); Some((translated, errs)) }; diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index c978297295d40..4812bdd9dd8b9 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -539,6 +539,9 @@ impl<'a> ExtCtxt<'a> { fn_decl, body, fn_decl_span: span, + // FIXME(SarthakSingh31): This points to the start of the declaration block and + // not the span of the argument block. + fn_arg_span: span, })), ) } diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs index 63998bb6b00cf..a7dfce3b9b8fc 100644 --- a/compiler/rustc_fs_util/src/lib.rs +++ b/compiler/rustc_fs_util/src/lib.rs @@ -65,7 +65,7 @@ pub enum LinkOrCopy { pub fn link_or_copy, Q: AsRef>(p: P, q: Q) -> io::Result { let p = p.as_ref(); let q = q.as_ref(); - match fs::remove_file(&q) { + match fs::remove_file(q) { Ok(()) => (), Err(err) if err.kind() == io::ErrorKind::NotFound => (), Err(err) => return Err(err), diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index 401d3f6689c99..1f8268cc17c53 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -410,7 +410,7 @@ impl<'a> Id<'a> { } pub fn as_slice(&'a self) -> &'a str { - &*self.name + &self.name } } @@ -515,7 +515,7 @@ impl<'a> LabelText<'a> { pub fn to_dot_string(&self) -> String { match *self { LabelStr(ref s) => format!("\"{}\"", s.escape_default()), - EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(&s)), + EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(s)), HtmlStr(ref s) => format!("<{}>", s), } } @@ -529,7 +529,7 @@ impl<'a> LabelText<'a> { EscStr(s) => s, LabelStr(s) => { if s.contains('\\') { - (&*s).escape_default().to_string().into() + s.escape_default().to_string().into() } else { s } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 118eafe2910f0..636e6e1b48d0e 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -943,7 +943,10 @@ pub struct Closure<'hir> { pub bound_generic_params: &'hir [GenericParam<'hir>], pub fn_decl: &'hir FnDecl<'hir>, pub body: BodyId, + /// The span of the declaration block: 'move |...| -> ...' pub fn_decl_span: Span, + /// The span of the argument block `|...|` + pub fn_arg_span: Option, pub movability: Option, } @@ -2434,7 +2437,7 @@ impl<'hir> Ty<'hir> { pub fn peel_refs(&self) -> &Self { let mut final_ty = self; while let TyKind::Rptr(_, MutTy { ty, .. }) = &final_ty.kind { - final_ty = &ty; + final_ty = ty; } final_ty } diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs index 33f02a115ef38..93613ef27d404 100644 --- a/compiler/rustc_hir/src/hir_id.rs +++ b/compiler/rustc_hir/src/hir_id.rs @@ -116,7 +116,7 @@ impl Ord for HirId { impl PartialOrd for HirId { fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(&other)) + Some(self.cmp(other)) } } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index cbb530424ca5d..938ace2c785bb 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -448,7 +448,7 @@ pub trait Visitor<'v>: Sized { pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) { visitor.visit_id(param.hir_id); - visitor.visit_pat(¶m.pat); + visitor.visit_pat(param.pat); } pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { @@ -470,7 +470,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { } ItemKind::Fn(ref sig, ref generics, body_id) => visitor.visit_fn( FnKind::ItemFn(item.ident, generics, sig.header), - &sig.decl, + sig.decl, body_id, item.span, item.hir_id(), @@ -544,7 +544,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body<'v>) { walk_list!(visitor, visit_param, body.params); - visitor.visit_expr(&body.value); + visitor.visit_expr(body.value); } pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) { @@ -580,7 +580,7 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local<'v>) { // dominates the local's definition. walk_list!(visitor, visit_expr, &local.init); visitor.visit_id(local.hir_id); - visitor.visit_pat(&local.pat); + visitor.visit_pat(local.pat); if let Some(els) = local.els { visitor.visit_block(els); } @@ -606,7 +606,7 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) { pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) { visitor.visit_id(arm.hir_id); - visitor.visit_pat(&arm.pat); + visitor.visit_pat(arm.pat); if let Some(ref g) = arm.guard { match g { Guard::If(ref e) => visitor.visit_expr(e), @@ -615,7 +615,7 @@ pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) { } } } - visitor.visit_expr(&arm.body); + visitor.visit_expr(arm.body); } pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) { @@ -660,7 +660,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) { pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<'v>) { visitor.visit_id(field.hir_id); visitor.visit_ident(field.ident); - visitor.visit_pat(&field.pat) + visitor.visit_pat(field.pat) } pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) { @@ -740,6 +740,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) body, capture_clause: _, fn_decl_span: _, + fn_arg_span: _, movability: _, }) => { walk_list!(visitor, visit_generic_param, bound_generic_params); @@ -799,7 +800,7 @@ pub fn walk_let_expr<'v, V: Visitor<'v>>(visitor: &mut V, let_expr: &'v Let<'v>) pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField<'v>) { visitor.visit_id(field.hir_id); visitor.visit_ident(field.ident); - visitor.visit_expr(&field.expr) + visitor.visit_expr(field.expr) } pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) { @@ -807,10 +808,10 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) { match typ.kind { TyKind::Slice(ref ty) => visitor.visit_ty(ty), - TyKind::Ptr(ref mutable_type) => visitor.visit_ty(&mutable_type.ty), + TyKind::Ptr(ref mutable_type) => visitor.visit_ty(mutable_type.ty), TyKind::Rptr(ref lifetime, ref mutable_type) => { visitor.visit_lifetime(lifetime); - visitor.visit_ty(&mutable_type.ty) + visitor.visit_ty(mutable_type.ty) } TyKind::Never => {} TyKind::Tup(tuple_element_types) => { @@ -818,7 +819,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) { } TyKind::BareFn(ref function_declaration) => { walk_list!(visitor, visit_generic_param, function_declaration.generic_params); - visitor.visit_fn_decl(&function_declaration.decl); + visitor.visit_fn_decl(function_declaration.decl); } TyKind::Path(ref qpath) => { visitor.visit_qpath(qpath, typ.hir_id, typ.span); @@ -951,8 +952,8 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai let TraitItem { ident, generics, ref defaultness, ref kind, span, owner_id: _ } = *trait_item; let hir_id = trait_item.hir_id(); visitor.visit_ident(ident); - visitor.visit_generics(&generics); - visitor.visit_defaultness(&defaultness); + visitor.visit_generics(generics); + visitor.visit_defaultness(defaultness); match *kind { TraitItemKind::Const(ref ty, default) => { visitor.visit_id(hir_id); @@ -961,13 +962,13 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai } TraitItemKind::Fn(ref sig, TraitFn::Required(param_names)) => { visitor.visit_id(hir_id); - visitor.visit_fn_decl(&sig.decl); + visitor.visit_fn_decl(sig.decl); for ¶m_name in param_names { visitor.visit_ident(param_name); } } TraitItemKind::Fn(ref sig, TraitFn::Provided(body_id)) => { - visitor.visit_fn(FnKind::Method(ident, sig), &sig.decl, body_id, span, hir_id); + visitor.visit_fn(FnKind::Method(ident, sig), sig.decl, body_id, span, hir_id); } TraitItemKind::Type(bounds, ref default) => { visitor.visit_id(hir_id); @@ -1009,7 +1010,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt ImplItemKind::Fn(ref sig, body_id) => { visitor.visit_fn( FnKind::Method(impl_item.ident, sig), - &sig.decl, + sig.decl, body_id, impl_item.span, impl_item.hir_id(), @@ -1042,7 +1043,7 @@ pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &' pub fn walk_trait_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_ref: &'v TraitRef<'v>) { visitor.visit_id(trait_ref.hir_ref_id); - visitor.visit_path(&trait_ref.path, trait_ref.hir_ref_id) + visitor.visit_path(trait_ref.path, trait_ref.hir_ref_id) } pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericBound<'v>) { @@ -1074,7 +1075,7 @@ pub fn walk_struct_def<'v, V: Visitor<'v>>( pub fn walk_field_def<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v FieldDef<'v>) { visitor.visit_id(field.hir_id); visitor.visit_ident(field.ident); - visitor.visit_ty(&field.ty); + visitor.visit_ty(field.ty); } pub fn walk_enum_def<'v, V: Visitor<'v>>( diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index 47915b4bd4e6c..f64d65cc6ad7a 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -11,7 +11,6 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::GenericArg; -use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::ty::{ self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, TyCtxt, }; @@ -83,9 +82,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { Res::Def(DefKind::TyParam, src_def_id) => { if let Some(param_local_id) = param.def_id.as_local() { let param_name = tcx.hir().ty_param_name(param_local_id); - let infcx = tcx.infer_ctxt().build(); - let param_type = - infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id)); + let param_type = tcx.type_of(param.def_id); if param_type.is_suggestable(tcx, false) { err.span_suggestion( tcx.def_span(src_def_id), diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 8215031063827..f204d59d00556 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -347,7 +347,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assert!(self_ty.is_some()); } } else { - assert!(self_ty.is_none() && parent_substs.is_empty()); + assert!(self_ty.is_none()); } let arg_count = Self::check_generic_arg_count( @@ -1821,7 +1821,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Check if we have an enum variant. let mut variant_resolution = None; - if let ty::Adt(adt_def, _) = qself_ty.kind() { + if let ty::Adt(adt_def, adt_substs) = qself_ty.kind() { if adt_def.is_enum() { let variant_def = adt_def .variants() @@ -1923,8 +1923,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, impl_) else { continue; }; - // FIXME(inherent_associated_types): This does not substitute parameters. - let ty = tcx.type_of(assoc_ty_did); + let item_substs = self.create_substs_for_associated_item( + span, + assoc_ty_did, + assoc_segment, + adt_substs, + ); + let ty = tcx.bound_type_of(assoc_ty_did).subst(tcx, item_substs); return Ok((ty, DefKind::AssocTy, assoc_ty_did)); } } diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs index ba58672e7595a..82a77416a190c 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_method.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs @@ -173,13 +173,11 @@ fn compare_predicate_entailment<'tcx>( impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs); debug!("compare_impl_method: trait_to_placeholder_substs={:?}", trait_to_placeholder_substs); - let impl_m_generics = tcx.generics_of(impl_m.def_id); - let trait_m_generics = tcx.generics_of(trait_m.def_id); let impl_m_predicates = tcx.predicates_of(impl_m.def_id); let trait_m_predicates = tcx.predicates_of(trait_m.def_id); // Check region bounds. - check_region_bounds_on_impl_item(tcx, impl_m, trait_m, &trait_m_generics, &impl_m_generics)?; + check_region_bounds_on_impl_item(tcx, impl_m, trait_m, false)?; // Create obligations for each predicate declared by the impl // definition in the context of the trait's parameter @@ -338,6 +336,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>( // First, check a few of the same thing as `compare_impl_method`, just so we don't ICE during substitutions later. compare_number_of_generics(tcx, impl_m, trait_m, tcx.hir().span_if_local(impl_m.def_id), true)?; compare_generic_param_kinds(tcx, impl_m, trait_m, true)?; + check_region_bounds_on_impl_item(tcx, impl_m, trait_m, true)?; let trait_to_impl_substs = impl_trait_ref.substs; @@ -722,12 +721,14 @@ fn check_region_bounds_on_impl_item<'tcx>( tcx: TyCtxt<'tcx>, impl_m: &ty::AssocItem, trait_m: &ty::AssocItem, - trait_generics: &ty::Generics, - impl_generics: &ty::Generics, + delay: bool, ) -> Result<(), ErrorGuaranteed> { - let trait_params = trait_generics.own_counts().lifetimes; + let impl_generics = tcx.generics_of(impl_m.def_id); let impl_params = impl_generics.own_counts().lifetimes; + let trait_generics = tcx.generics_of(trait_m.def_id); + let trait_params = trait_generics.own_counts().lifetimes; + debug!( "check_region_bounds_on_impl_item: \ trait_generics={:?} \ @@ -761,12 +762,16 @@ fn check_region_bounds_on_impl_item<'tcx>( None }; - let reported = tcx.sess.emit_err(LifetimesOrBoundsMismatchOnTrait { - span, - item_kind: assoc_item_kind_str(impl_m), - ident: impl_m.ident(tcx), - generics_span, - }); + let reported = tcx + .sess + .create_err(LifetimesOrBoundsMismatchOnTrait { + span, + item_kind: assoc_item_kind_str(impl_m), + ident: impl_m.ident(tcx), + generics_span, + }) + .emit_unless(delay); + return Err(reported); } @@ -1504,18 +1509,10 @@ fn compare_type_predicate_entailment<'tcx>( let trait_to_impl_substs = impl_substs.rebase_onto(tcx, impl_ty.container_id(tcx), impl_trait_ref.substs); - let impl_ty_generics = tcx.generics_of(impl_ty.def_id); - let trait_ty_generics = tcx.generics_of(trait_ty.def_id); let impl_ty_predicates = tcx.predicates_of(impl_ty.def_id); let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id); - check_region_bounds_on_impl_item( - tcx, - impl_ty, - trait_ty, - &trait_ty_generics, - &impl_ty_generics, - )?; + check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?; let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_substs); diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index ff32329e431b6..b315ebad4686c 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -241,17 +241,46 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h // scopes, meaning that temporaries cannot outlive them. // This ensures fixed size stacks. hir::ExprKind::Binary( - source_map::Spanned { node: hir::BinOpKind::And, .. }, - _, - ref r, - ) - | hir::ExprKind::Binary( - source_map::Spanned { node: hir::BinOpKind::Or, .. }, - _, + source_map::Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. }, + ref l, ref r, ) => { - // For shortcircuiting operators, mark the RHS as a terminating - // scope since it only executes conditionally. + // expr is a short circuiting operator (|| or &&). As its + // functionality can't be overridden by traits, it always + // processes bool sub-expressions. bools are Copy and thus we + // can drop any temporaries in evaluation (read) order + // (with the exception of potentially failing let expressions). + // We achieve this by enclosing the operands in a terminating + // scope, both the LHS and the RHS. + + // We optimize this a little in the presence of chains. + // Chains like a && b && c get lowered to AND(AND(a, b), c). + // In here, b and c are RHS, while a is the only LHS operand in + // that chain. This holds true for longer chains as well: the + // leading operand is always the only LHS operand that is not a + // binop itself. Putting a binop like AND(a, b) into a + // terminating scope is not useful, thus we only put the LHS + // into a terminating scope if it is not a binop. + + let terminate_lhs = match l.kind { + // let expressions can create temporaries that live on + hir::ExprKind::Let(_) => false, + // binops already drop their temporaries, so there is no + // need to put them into a terminating scope. + // This is purely an optimization to reduce the number of + // terminating scopes. + hir::ExprKind::Binary( + source_map::Spanned { + node: hir::BinOpKind::And | hir::BinOpKind::Or, .. + }, + .., + ) => false, + // otherwise: mark it as terminating + _ => true, + }; + if terminate_lhs { + terminating(l.hir_id.local_id); + } // `Let` expressions (in a let-chain) shouldn't be terminating, as their temporaries // should live beyond the immediate expression diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 7daed74e9de83..b065ace6bf5e1 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1544,7 +1544,7 @@ fn check_fn_or_method<'tcx>( check_where_clauses(wfcx, span, def_id); check_return_position_impl_trait_in_trait_bounds( - tcx, + wfcx, def_id, sig.output(), hir_decl.output.span(), @@ -1580,13 +1580,14 @@ fn check_fn_or_method<'tcx>( /// Basically `check_associated_type_bounds`, but separated for now and should be /// deduplicated when RPITITs get lowered into real associated items. -#[tracing::instrument(level = "trace", skip(tcx))] +#[tracing::instrument(level = "trace", skip(wfcx))] fn check_return_position_impl_trait_in_trait_bounds<'tcx>( - tcx: TyCtxt<'tcx>, + wfcx: &WfCheckingCtxt<'_, 'tcx>, fn_def_id: LocalDefId, fn_output: Ty<'tcx>, span: Span, ) { + let tcx = wfcx.tcx(); if let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id()) && assoc_item.container == ty::AssocItemContainer::TraitContainer { @@ -1596,22 +1597,20 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>( && tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder && tcx.impl_trait_in_trait_parent(proj.item_def_id) == fn_def_id.to_def_id() { - // Create a new context, since we want the opaque's ParamEnv and not the parent's. let span = tcx.def_span(proj.item_def_id); - enter_wf_checking_ctxt(tcx, span, proj.item_def_id.expect_local(), |wfcx| { - let bounds = wfcx.tcx().explicit_item_bounds(proj.item_def_id); - let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| { - let normalized_bound = wfcx.normalize(span, None, bound); - traits::wf::predicate_obligations( - wfcx.infcx, - wfcx.param_env, - wfcx.body_id, - normalized_bound, - bound_span, - ) - }); - wfcx.register_obligations(wf_obligations); + let bounds = wfcx.tcx().explicit_item_bounds(proj.item_def_id); + let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| { + let bound = ty::EarlyBinder(bound).subst(tcx, proj.substs); + let normalized_bound = wfcx.normalize(span, None, bound); + traits::wf::predicate_obligations( + wfcx.infcx, + wfcx.param_env, + wfcx.body_id, + normalized_bound, + bound_span, + ) }); + wfcx.register_obligations(wf_obligations); } } } diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs index d0c31733481b6..5749b04783ce4 100644 --- a/compiler/rustc_hir_analysis/src/check_unused.rs +++ b/compiler/rustc_hir_analysis/src/check_unused.rs @@ -56,25 +56,6 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) { let unused_extern_crates: FxHashMap = tcx .maybe_unused_extern_crates(()) .iter() - .filter(|&&(def_id, _)| { - // The `def_id` here actually was calculated during resolution (at least - // at the time of this writing) and is being shipped to us via a side - // channel of the tcx. There may have been extra expansion phases, - // however, which ended up removing the `def_id` *after* expansion. - // - // As a result we need to verify that `def_id` is indeed still valid for - // our AST and actually present in the HIR map. If it's not there then - // there's safely nothing to warn about, and otherwise we carry on with - // our execution. - // - // Note that if we carry through to the `extern_mod_stmt_cnum` query - // below it'll cause a panic because `def_id` is actually bogus at this - // point in time otherwise. - if tcx.hir().find(tcx.hir().local_def_id_to_hir_id(def_id)).is_none() { - return false; - } - true - }) .filter(|&&(def_id, _)| { tcx.extern_mod_stmt_cnum(def_id).map_or(true, |cnum| { !tcx.is_compiler_builtins(cnum) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index d623e72613944..b7084303aafb1 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -2073,6 +2073,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { } } + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE; + codegen_fn_attrs.inline = InlineAttr::Never; + } + // Weak lang items have the same semantics as "std internal" symbols in the // sense that they're preserved through all our LTO passes and only // strippable by the linker. diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 2460a23bb3f34..3791b2c8661a7 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1480,6 +1480,7 @@ impl<'a> State<'a> { fn_decl, body, fn_decl_span: _, + fn_arg_span: _, movability: _, def_id: _, }) => { diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 5d3419b3b6e66..429cb60ba2b61 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -456,10 +456,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .map(|ty| ArgKind::from_expected_ty(*ty, None)) .collect(); - let (closure_span, found_args) = match self.get_fn_like_arguments(expr_map_node) { - Some((sp, args)) => (Some(sp), args), - None => (None, Vec::new()), - }; + let (closure_span, closure_arg_span, found_args) = + match self.get_fn_like_arguments(expr_map_node) { + Some((sp, arg_sp, args)) => (Some(sp), arg_sp, args), + None => (None, None, Vec::new()), + }; let expected_span = expected_sig.cause_span.unwrap_or_else(|| self.tcx.def_span(expr_def_id)); self.report_arg_count_mismatch( @@ -468,6 +469,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_args, found_args, true, + closure_arg_span, ) .emit(); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 0c5bbb3e20be3..4a112e80f1d98 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -528,6 +528,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span); let ty = match res { Res::Err => { + self.suggest_assoc_method_call(segs); let e = self.tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted"); self.set_tainted_by_errors(e); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 86384c7b93e71..3078e0cbeda59 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1918,6 +1918,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { receiver: Option<&'tcx hir::Expr<'tcx>>, args: &'tcx [hir::Expr<'tcx>], ) -> bool { + // Do not call `fn_sig` on non-functions. + if !matches!( + self.tcx.def_kind(def_id), + DefKind::Fn | DefKind::AssocFn | DefKind::Variant | DefKind::Ctor(..) + ) { + return false; + } + let sig = self.tcx.fn_sig(def_id).skip_binder(); let args_referencing_param: Vec<_> = sig .inputs() diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index ea141e815bf4a..1e9b575213085 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -22,7 +22,7 @@ use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::{self, Span}; -use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; +use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt}; use std::cell::{Cell, RefCell}; use std::ops::Deref; @@ -162,6 +162,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { infcx: &self.infcx, typeck_results: Some(self.typeck_results.borrow()), fallback_has_occurred: self.fallback_has_occurred.get(), + normalize_fn_sig: Box::new(|fn_sig| { + if fn_sig.has_escaping_bound_vars() { + return fn_sig; + } + self.probe(|_| { + let ocx = ObligationCtxt::new_in_snapshot(self); + let normalized_fn_sig = + ocx.normalize(&ObligationCause::dummy(), self.param_env, fn_sig); + if ocx.select_all_or_error().is_empty() { + let normalized_fn_sig = self.resolve_vars_if_possible(normalized_fn_sig); + if !normalized_fn_sig.needs_infer() { + return normalized_fn_sig; + } + } + fn_sig + }) + }), } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index b9a8d16311c93..1daca464b4772 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -10,7 +10,7 @@ use rustc_hir::{ Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate, }; use rustc_hir_analysis::astconv::AstConv; -use rustc_infer::infer::{self, TyCtxtInferExt}; +use rustc_infer::infer; use rustc_infer::traits::{self, StatementAsExpression}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty}; @@ -921,19 +921,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = >::ast_ty_to_ty(self, ty); let bound_vars = self.tcx.late_bound_vars(fn_id); let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars)); - let ty = self.normalize(expr.span, ty); let ty = match self.tcx.asyncness(fn_id.owner) { - hir::IsAsync::Async => { - let infcx = self.tcx.infer_ctxt().build(); - infcx.get_impl_future_output_ty(ty).unwrap_or_else(|| { - span_bug!( - fn_decl.output.span(), - "failed to get output type of async function" - ) - }) - } + hir::IsAsync::Async => self.get_impl_future_output_ty(ty).unwrap_or_else(|| { + span_bug!(fn_decl.output.span(), "failed to get output type of async function") + }), hir::IsAsync::NotAsync => ty, }; + let ty = self.normalize(expr.span, ty); if self.can_coerce(found, ty) { err.multipart_suggestion( "you might have meant to return this value", diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs index 869ad07c00d61..b33e7b8d68cf9 100644 --- a/compiler/rustc_hir_typeck/src/inherited.rs +++ b/compiler/rustc_hir_typeck/src/inherited.rs @@ -1,7 +1,6 @@ use super::callee::DeferredCallResolution; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::HirIdMap; @@ -11,9 +10,7 @@ use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::LocalDefIdMap; use rustc_span::{self, Span}; -use rustc_trait_selection::traits::{ - self, ObligationCause, ObligationCtxt, TraitEngine, TraitEngineExt as _, -}; +use rustc_trait_selection::traits::{self, TraitEngine, TraitEngineExt as _}; use std::cell::RefCell; use std::ops::Deref; @@ -92,29 +89,7 @@ impl<'tcx> Inherited<'tcx> { infcx: tcx .infer_ctxt() .ignoring_regions() - .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)) - .with_normalize_fn_sig_for_diagnostic(Lrc::new(move |infcx, fn_sig| { - if fn_sig.has_escaping_bound_vars() { - return fn_sig; - } - infcx.probe(|_| { - let ocx = ObligationCtxt::new_in_snapshot(infcx); - let normalized_fn_sig = ocx.normalize( - &ObligationCause::dummy(), - // FIXME(compiler-errors): This is probably not the right param-env... - infcx.tcx.param_env(def_id), - fn_sig, - ); - if ocx.select_all_or_error().is_empty() { - let normalized_fn_sig = - infcx.resolve_vars_if_possible(normalized_fn_sig); - if !normalized_fn_sig.needs_infer() { - return normalized_fn_sig; - } - } - fn_sig - }) - })), + .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)), def_id, typeck_results: RefCell::new(ty::TypeckResults::new(hir_owner)), } diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index ebbd5eb1e6478..a2ca5c3b7b749 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -20,7 +20,7 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::{self, InferOk}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; -use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, Ty, TypeVisitable}; +use rustc_middle::ty::{self, GenericParamDefKind, Ty, TypeVisitable}; use rustc_span::symbol::Ident; use rustc_span::Span; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; @@ -217,7 +217,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // We probe again, taking all traits into account (not only those in scope). - let mut candidates = + let candidates = match self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::AllTraits) { // If we find a different result the caller probably forgot to import a trait. Ok(ref new_pick) if pick.differs_from(new_pick) => { @@ -236,7 +236,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .collect(), _ => Vec::new(), }; - candidates.retain(|candidate| *candidate != self.tcx.parent(result.callee.def_id)); return Err(IllegalSizedBound(candidates, needs_mut, span)); } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index c78a32c29dcda..ae299cc9d1370 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -9,7 +9,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::def::Namespace; use rustc_infer::infer::canonical::OriginalQueryValues; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -1876,6 +1875,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.tcx.erase_late_bound_regions(value) } + /// Determine if the given associated item type is relevant in the current context. + fn is_relevant_kind_for_mode(&self, kind: ty::AssocKind) -> bool { + match (self.mode, kind) { + (Mode::MethodCall, ty::AssocKind::Fn) => true, + (Mode::Path, ty::AssocKind::Const | ty::AssocKind::Fn) => true, + _ => false, + } + } + /// Finds the method with the appropriate name (or return type, as the case may be). If /// `allow_similar_names` is set, find methods with close-matching names. // The length of the returned iterator is nearly always 0 or 1 and this @@ -1888,7 +1896,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { .associated_items(def_id) .in_definition_order() .filter(|x| { - if x.kind.namespace() != Namespace::ValueNS { + if !self.is_relevant_kind_for_mode(x.kind) { return false; } match lev_distance_with_substrings(name.as_str(), x.name.as_str(), max_dist) @@ -1902,10 +1910,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } else { self.fcx .associated_value(def_id, name) + .filter(|x| self.is_relevant_kind_for_mode(x.kind)) .map_or_else(SmallVec::new, |x| SmallVec::from_buf([x])) } } else { - self.tcx.associated_items(def_id).in_definition_order().copied().collect() + self.tcx + .associated_items(def_id) + .in_definition_order() + .filter(|x| self.is_relevant_kind_for_mode(x.kind)) + .copied() + .collect() } } } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 727fab9e7aa1e..9ba4ddfd5cf7f 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -5,6 +5,7 @@ use crate::errors; use crate::FnCtxt; use rustc_ast::ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_errors::StashKey; use rustc_errors::{ pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, @@ -13,6 +14,8 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; +use rustc_hir::PatKind::Binding; +use rustc_hir::PathSegment; use rustc_hir::{ExprKind, Node, QPath}; use rustc_infer::infer::{ type_variable::{TypeVariableOrigin, TypeVariableOriginKind}, @@ -35,11 +38,11 @@ use rustc_trait_selection::traits::{ FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, }; -use std::cmp::Ordering; -use std::iter; - use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope}; use super::{CandidateSource, MethodError, NoMatchData}; +use rustc_hir::intravisit::Visitor; +use std::cmp::Ordering; +use std::iter; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool { @@ -1462,6 +1465,61 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } + /// For code `rect::area(...)`, + /// if `rect` is a local variable and `area` is a valid assoc method for it, + /// we try to suggest `rect.area()` + pub(crate) fn suggest_assoc_method_call(&self, segs: &[PathSegment<'_>]) { + debug!("suggest_assoc_method_call segs: {:?}", segs); + let [seg1, seg2] = segs else { return; }; + let Some(mut diag) = + self.tcx.sess.diagnostic().steal_diagnostic(seg1.ident.span, StashKey::CallAssocMethod) + else { return }; + + let map = self.infcx.tcx.hir(); + let body = map.body(rustc_hir::BodyId { hir_id: self.body_id }); + struct LetVisitor<'a> { + result: Option<&'a hir::Expr<'a>>, + ident_name: Symbol, + } + + impl<'v> Visitor<'v> for LetVisitor<'v> { + fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) { + if let hir::StmtKind::Local(hir::Local { pat, init, .. }) = &ex.kind { + if let Binding(_, _, ident, ..) = pat.kind && + ident.name == self.ident_name { + self.result = *init; + } + } + hir::intravisit::walk_stmt(self, ex); + } + } + + let mut visitor = LetVisitor { result: None, ident_name: seg1.ident.name }; + visitor.visit_body(&body); + + let parent = self.tcx.hir().get_parent_node(seg1.hir_id); + if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) && + let Some(expr) = visitor.result { + let self_ty = self.node_ty(expr.hir_id); + let probe = self.lookup_probe( + seg2.ident, + self_ty, + call_expr, + ProbeScope::TraitsInScope, + ); + if probe.is_ok() { + let sm = self.infcx.tcx.sess.source_map(); + diag.span_suggestion_verbose( + sm.span_extend_while(seg1.ident.span.shrink_to_hi(), |c| c == ':').unwrap(), + "you may have meant to call an instance method", + ".".to_string(), + Applicability::MaybeIncorrect + ); + } + } + diag.emit(); + } + /// Suggest calling a method on a field i.e. `a.field.bar()` instead of `a.bar()` fn suggest_calling_method_on_field( &self, diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 2483ab724a4e3..4429e4f43629a 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -77,10 +77,6 @@ impl<'tcx> InferCtxt<'tcx> { err_count_on_creation: self.err_count_on_creation, in_snapshot: self.in_snapshot.clone(), universe: self.universe.clone(), - normalize_fn_sig_for_diagnostic: self - .normalize_fn_sig_for_diagnostic - .as_ref() - .map(|f| f.clone()), intercrate: self.intercrate, } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index e2be8fb12d0d0..662136ca18df6 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -95,6 +95,7 @@ pub mod nice_region_error; pub struct TypeErrCtxt<'a, 'tcx> { pub infcx: &'a InferCtxt<'tcx>, pub typeck_results: Option>>, + pub normalize_fn_sig: Box) -> ty::PolyFnSig<'tcx> + 'a>, pub fallback_has_occurred: bool, } @@ -1007,22 +1008,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - fn normalize_fn_sig_for_diagnostic(&self, sig: ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> { - if let Some(normalize) = &self.normalize_fn_sig_for_diagnostic { - normalize(self, sig) - } else { - sig - } - } - /// Given two `fn` signatures highlight only sub-parts that are different. fn cmp_fn_sig( &self, sig1: &ty::PolyFnSig<'tcx>, sig2: &ty::PolyFnSig<'tcx>, ) -> (DiagnosticStyledString, DiagnosticStyledString) { - let sig1 = &self.normalize_fn_sig_for_diagnostic(*sig1); - let sig2 = &self.normalize_fn_sig_for_diagnostic(*sig2); + let sig1 = &(self.normalize_fn_sig)(*sig1); + let sig2 = &(self.normalize_fn_sig)(*sig2); let get_lifetimes = |sig| { use rustc_hir::def::Namespace; @@ -1262,7 +1255,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let num_display_types = consts_offset - regions_len; for (i, (ta1, ta2)) in type_arguments.take(num_display_types).enumerate() { let i = i + regions_len; - if ta1 == ta2 { + if ta1 == ta2 && !self.tcx.sess.verbose() { values.0.push_normal("_"); values.1.push_normal("_"); } else { @@ -1278,7 +1271,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let const_arguments = sub1.consts().zip(sub2.consts()); for (i, (ca1, ca2)) in const_arguments.enumerate() { let i = i + consts_offset; - if ca1 == ca2 { + if ca1 == ca2 && !self.tcx.sess.verbose() { values.0.push_normal("_"); values.1.push_normal("_"); } else { @@ -1457,7 +1450,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (ty::FnPtr(sig1), ty::FnPtr(sig2)) => self.cmp_fn_sig(sig1, sig2), _ => { - if t1 == t2 { + if t1 == t2 && !self.tcx.sess.verbose() { // The two types are the same, elide and don't highlight. (DiagnosticStyledString::normal("_"), DiagnosticStyledString::normal("_")) } else { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 2bcb47cc38399..2ce7cd8beba98 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -80,7 +80,6 @@ pub struct InferOk<'tcx, T> { } pub type InferResult<'tcx, T> = Result, TypeError<'tcx>>; -pub type Bound = Option; pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" pub type FixupResult<'tcx, T> = Result>; // "fixup result" @@ -334,9 +333,6 @@ pub struct InferCtxt<'tcx> { /// bound. universe: Cell, - normalize_fn_sig_for_diagnostic: - Option, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>, - /// During coherence we have to assume that other crates may add /// additional impls which we currently don't know about. /// @@ -573,8 +569,6 @@ pub struct InferCtxtBuilder<'tcx> { considering_regions: bool, /// Whether we are in coherence mode. intercrate: bool, - normalize_fn_sig_for_diagnostic: - Option, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>, } pub trait TyCtxtInferExt<'tcx> { @@ -587,7 +581,6 @@ impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { tcx: self, defining_use_anchor: DefiningAnchor::Error, considering_regions: true, - normalize_fn_sig_for_diagnostic: None, intercrate: false, } } @@ -615,14 +608,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> { self } - pub fn with_normalize_fn_sig_for_diagnostic( - mut self, - fun: Lrc, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>, - ) -> Self { - self.normalize_fn_sig_for_diagnostic = Some(fun); - self - } - /// Given a canonical value `C` as a starting point, create an /// inference context that contains each of the bound values /// within instantiated as a fresh variable. The `f` closure is @@ -644,13 +629,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { } pub fn build(&mut self) -> InferCtxt<'tcx> { - let InferCtxtBuilder { - tcx, - defining_use_anchor, - considering_regions, - ref normalize_fn_sig_for_diagnostic, - intercrate, - } = *self; + let InferCtxtBuilder { tcx, defining_use_anchor, considering_regions, intercrate } = *self; InferCtxt { tcx, defining_use_anchor, @@ -666,9 +645,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> { in_snapshot: Cell::new(false), skip_leak_check: Cell::new(false), universe: Cell::new(ty::UniverseIndex::ROOT), - normalize_fn_sig_for_diagnostic: normalize_fn_sig_for_diagnostic - .as_ref() - .map(|f| f.clone()), intercrate, } } @@ -709,7 +685,12 @@ impl<'tcx> InferCtxt<'tcx> { /// Creates a `TypeErrCtxt` for emitting various inference errors. /// During typeck, use `FnCtxt::err_ctxt` instead. pub fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> { - TypeErrCtxt { infcx: self, typeck_results: None, fallback_has_occurred: false } + TypeErrCtxt { + infcx: self, + typeck_results: None, + fallback_has_occurred: false, + normalize_fn_sig: Box::new(|fn_sig| fn_sig), + } } pub fn is_in_snapshot(&self) -> bool { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 7f1d21bf1d8b0..6b5b5df9e2a7d 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -207,10 +207,7 @@ pub fn register_plugins<'a>( }); } - let mut lint_store = rustc_lint::new_lint_store( - sess.opts.unstable_opts.no_interleave_lints, - sess.enable_internal_lints(), - ); + let mut lint_store = rustc_lint::new_lint_store(sess.enable_internal_lints()); register_lints(sess, &mut lint_store); let registrars = diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index a03e7b0dae527..a6205f4d3a531 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -666,7 +666,6 @@ fn test_unstable_options_tracking_hash() { untracked!(mir_pretty_relative_line_numbers, true); untracked!(nll_facts, true); untracked!(no_analysis, true); - untracked!(no_interleave_lints, true); untracked!(no_leak_check, true); untracked!(no_parallel_llvm, true); untracked!(parse_only, true); diff --git a/compiler/rustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml index ad685c2ad19f4..23294dc2e1b6a 100644 --- a/compiler/rustc_lexer/Cargo.toml +++ b/compiler/rustc_lexer/Cargo.toml @@ -19,4 +19,4 @@ unicode-xid = "0.2.0" unic-emoji-char = "0.9.0" [dev-dependencies] -expect-test = "1.0" +expect-test = "1.4.0" diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index a7a4d0ca52772..215df567e0e02 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -25,8 +25,6 @@ use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::Span; -use std::slice; - macro_rules! run_early_pass { ($cx:expr, $f:ident, $($args:expr),*) => ({ $cx.pass.$f(&$cx.context, $($args),*); }) } @@ -300,20 +298,14 @@ impl LintPass for EarlyLintPassObjects<'_> { } } -macro_rules! expand_early_lint_pass_impl_methods { - ([$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( - $(fn $name(&mut self, context: &EarlyContext<'_>, $($param: $arg),*) { - for obj in self.lints.iter_mut() { - obj.$name(context, $($param),*); - } - })* - ) -} - macro_rules! early_lint_pass_impl { - ([], [$($methods:tt)*]) => ( + ([], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( impl EarlyLintPass for EarlyLintPassObjects<'_> { - expand_early_lint_pass_impl_methods!([$($methods)*]); + $(fn $name(&mut self, context: &EarlyContext<'_>, $($param: $arg),*) { + for obj in self.lints.iter_mut() { + obj.$name(context, $($param),*); + } + })* } ) } @@ -371,87 +363,36 @@ impl<'a> EarlyCheckNode<'a> for (ast::NodeId, &'a [ast::Attribute], &'a [P( - sess: &Session, - warn_about_weird_lints: bool, - lint_store: &LintStore, - registered_tools: &RegisteredTools, - buffered: LintBuffer, - pass: impl EarlyLintPass, - check_node: impl EarlyCheckNode<'a>, -) -> LintBuffer { - let mut cx = EarlyContextAndPass { - context: EarlyContext::new( - sess, - warn_about_weird_lints, - lint_store, - registered_tools, - buffered, - ), - pass, - }; - - cx.with_lint_attrs(check_node.id(), check_node.attrs(), |cx| check_node.check(cx)); - cx.context.buffered -} - pub fn check_ast_node<'a>( sess: &Session, pre_expansion: bool, lint_store: &LintStore, registered_tools: &RegisteredTools, lint_buffer: Option, - builtin_lints: impl EarlyLintPass, + builtin_lints: impl EarlyLintPass + 'static, check_node: impl EarlyCheckNode<'a>, ) { let passes = if pre_expansion { &lint_store.pre_expansion_passes } else { &lint_store.early_passes }; let mut passes: Vec<_> = passes.iter().map(|p| (p)()).collect(); - let mut buffered = lint_buffer.unwrap_or_default(); - - if sess.opts.unstable_opts.no_interleave_lints { - for (i, pass) in passes.iter_mut().enumerate() { - buffered = - sess.prof.verbose_generic_activity_with_arg("run_lint", pass.name()).run(|| { - early_lint_node( - sess, - !pre_expansion && i == 0, - lint_store, - registered_tools, - buffered, - EarlyLintPassObjects { lints: slice::from_mut(pass) }, - check_node, - ) - }); - } - } else { - buffered = early_lint_node( + passes.push(Box::new(builtin_lints)); + + let mut cx = EarlyContextAndPass { + context: EarlyContext::new( sess, !pre_expansion, lint_store, registered_tools, - buffered, - builtin_lints, - check_node, - ); - - if !passes.is_empty() { - buffered = early_lint_node( - sess, - false, - lint_store, - registered_tools, - buffered, - EarlyLintPassObjects { lints: &mut passes[..] }, - check_node, - ); - } - } + lint_buffer.unwrap_or_default(), + ), + pass: EarlyLintPassObjects { lints: &mut passes[..] }, + }; + cx.with_lint_attrs(check_node.id(), check_node.attrs(), |cx| check_node.check(cx)); // All of the buffered lints should have been emitted at this point. // If not, that means that we somehow buffered a lint for a node id // that was not lint-checked (perhaps it doesn't exist?). This is a bug. - for (id, lints) in buffered.map { + for (id, lints) in cx.context.buffered.map { for early_lint in lints { sess.delay_span_bug( early_lint.span, diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 1d0b3f34d5d78..e1aedc26d1b0a 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -28,7 +28,6 @@ use rustc_span::Span; use std::any::Any; use std::cell::Cell; -use std::slice; /// Extract the `LintStore` from the query context. /// This function exists because we've erased `LintStore` as `dyn Any` in the context. @@ -313,45 +312,42 @@ impl LintPass for LateLintPassObjects<'_, '_> { } } -macro_rules! expand_late_lint_pass_impl_methods { - ([$hir:tt], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( - $(fn $name(&mut self, context: &LateContext<$hir>, $($param: $arg),*) { - for obj in self.lints.iter_mut() { - obj.$name(context, $($param),*); - } - })* - ) -} - macro_rules! late_lint_pass_impl { - ([], [$hir:tt], $methods:tt) => { + ([], [$hir:tt], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => { impl<$hir> LateLintPass<$hir> for LateLintPassObjects<'_, $hir> { - expand_late_lint_pass_impl_methods!([$hir], $methods); + $(fn $name(&mut self, context: &LateContext<$hir>, $($param: $arg),*) { + for obj in self.lints.iter_mut() { + obj.$name(context, $($param),*); + } + })* } }; } crate::late_lint_methods!(late_lint_pass_impl, [], ['tcx]); -fn late_lint_mod_pass<'tcx, T: LateLintPass<'tcx>>( +pub(super) fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( tcx: TyCtxt<'tcx>, module_def_id: LocalDefId, - pass: T, + builtin_lints: T, ) { - let effective_visibilities = &tcx.effective_visibilities(()); - let context = LateContext { tcx, enclosing_body: None, cached_typeck_results: Cell::new(None), param_env: ty::ParamEnv::empty(), - effective_visibilities, + effective_visibilities: &tcx.effective_visibilities(()), lint_store: unerased_lint_store(tcx), last_node_with_lint_attrs: tcx.hir().local_def_id_to_hir_id(module_def_id), generics: None, only_module: true, }; + let mut passes: Vec<_> = + unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)(tcx)).collect(); + passes.push(Box::new(builtin_lints)); + let pass = LateLintPassObjects { lints: &mut passes[..] }; + let mut cx = LateContextAndPass { context, pass }; let (module, _span, hir_id) = tcx.hir().get_module(module_def_id); @@ -365,46 +361,29 @@ fn late_lint_mod_pass<'tcx, T: LateLintPass<'tcx>>( } } -pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx>>( - tcx: TyCtxt<'tcx>, - module_def_id: LocalDefId, - builtin_lints: T, -) { - if tcx.sess.opts.unstable_opts.no_interleave_lints { - // These passes runs in late_lint_crate with -Z no_interleave_lints - return; - } - - late_lint_mod_pass(tcx, module_def_id, builtin_lints); - - let mut passes: Vec<_> = - unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)(tcx)).collect(); - - if !passes.is_empty() { - late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] }); - } -} - -fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T) { - let effective_visibilities = &tcx.effective_visibilities(()); - +fn late_lint_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>(tcx: TyCtxt<'tcx>, builtin_lints: T) { let context = LateContext { tcx, enclosing_body: None, cached_typeck_results: Cell::new(None), param_env: ty::ParamEnv::empty(), - effective_visibilities, + effective_visibilities: &tcx.effective_visibilities(()), lint_store: unerased_lint_store(tcx), last_node_with_lint_attrs: hir::CRATE_HIR_ID, generics: None, only_module: false, }; + let mut passes = + unerased_lint_store(tcx).late_passes.iter().map(|p| (p)(tcx)).collect::>(); + passes.push(Box::new(builtin_lints)); + let pass = LateLintPassObjects { lints: &mut passes[..] }; + let mut cx = LateContextAndPass { context, pass }; // Visit the whole crate. cx.with_lint_attrs(hir::CRATE_HIR_ID, |cx| { - // since the root module isn't visited as an item (because it isn't an + // Since the root module isn't visited as an item (because it isn't an // item), warn for it here. lint_callback!(cx, check_crate,); tcx.hir().walk_toplevel_module(cx); @@ -413,41 +392,8 @@ fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T) }) } -fn late_lint_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) { - let mut passes = - unerased_lint_store(tcx).late_passes.iter().map(|p| (p)(tcx)).collect::>(); - - if !tcx.sess.opts.unstable_opts.no_interleave_lints { - if !passes.is_empty() { - late_lint_pass_crate(tcx, LateLintPassObjects { lints: &mut passes[..] }); - } - - late_lint_pass_crate(tcx, builtin_lints); - } else { - for pass in &mut passes { - tcx.sess.prof.verbose_generic_activity_with_arg("run_late_lint", pass.name()).run( - || { - late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) }); - }, - ); - } - - let mut passes: Vec<_> = - unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)(tcx)).collect(); - - for pass in &mut passes { - tcx.sess - .prof - .verbose_generic_activity_with_arg("run_late_module_lint", pass.name()) - .run(|| { - late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) }); - }); - } - } -} - /// Performs lint checking on a crate. -pub fn check_crate<'tcx, T: LateLintPass<'tcx>>( +pub fn check_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>( tcx: TyCtxt<'tcx>, builtin_lints: impl FnOnce() -> T + Send, ) { diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index b6027476adfd9..10bae36e0fd3c 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -127,132 +127,116 @@ fn lint_mod(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { late::late_lint_mod(tcx, module_def_id, BuiltinCombinedModuleLateLintPass::new()); } -macro_rules! pre_expansion_lint_passes { - ($macro:path, $args:tt) => { - $macro!($args, [KeywordIdents: KeywordIdents,]); - }; -} - -macro_rules! early_lint_passes { - ($macro:path, $args:tt) => { - $macro!( - $args, - [ - UnusedParens: UnusedParens, - UnusedBraces: UnusedBraces, - UnusedImportBraces: UnusedImportBraces, - UnsafeCode: UnsafeCode, - SpecialModuleName: SpecialModuleName, - AnonymousParameters: AnonymousParameters, - EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(), - NonCamelCaseTypes: NonCamelCaseTypes, - DeprecatedAttr: DeprecatedAttr::new(), - WhileTrue: WhileTrue, - NonAsciiIdents: NonAsciiIdents, - HiddenUnicodeCodepoints: HiddenUnicodeCodepoints, - IncompleteFeatures: IncompleteFeatures, - RedundantSemicolons: RedundantSemicolons, - UnusedDocComment: UnusedDocComment, - UnexpectedCfgs: UnexpectedCfgs, - ] - ); - }; -} - -macro_rules! declare_combined_early_pass { - ([$name:ident], $passes:tt) => ( - early_lint_methods!(declare_combined_early_lint_pass, [pub $name, $passes]); - ) -} - -pre_expansion_lint_passes!(declare_combined_early_pass, [BuiltinCombinedPreExpansionLintPass]); -early_lint_passes!(declare_combined_early_pass, [BuiltinCombinedEarlyLintPass]); - -macro_rules! late_lint_passes { - ($macro:path, $args:tt) => { - $macro!( - $args, - [ - // Tracks state across modules - UnnameableTestItems: UnnameableTestItems::new(), - // Tracks attributes of parents - MissingDoc: MissingDoc::new(), - // Builds a global list of all impls of `Debug`. - // FIXME: Turn the computation of types which implement Debug into a query - // and change this to a module lint pass - MissingDebugImplementations: MissingDebugImplementations::default(), - // Keeps a global list of foreign declarations. - ClashingExternDeclarations: ClashingExternDeclarations::new(), - ] - ); - }; -} - -macro_rules! late_lint_mod_passes { - ($macro:path, $args:tt) => { - $macro!( - $args, - [ - ForLoopsOverFallibles: ForLoopsOverFallibles, - DerefIntoDynSupertrait: DerefIntoDynSupertrait, - HardwiredLints: HardwiredLints, - ImproperCTypesDeclarations: ImproperCTypesDeclarations, - ImproperCTypesDefinitions: ImproperCTypesDefinitions, - VariantSizeDifferences: VariantSizeDifferences, - BoxPointers: BoxPointers, - PathStatements: PathStatements, - LetUnderscore: LetUnderscore, - // Depends on referenced function signatures in expressions - UnusedResults: UnusedResults, - NonUpperCaseGlobals: NonUpperCaseGlobals, - NonShorthandFieldPatterns: NonShorthandFieldPatterns, - UnusedAllocation: UnusedAllocation, - // Depends on types used in type definitions - MissingCopyImplementations: MissingCopyImplementations, - // Depends on referenced function signatures in expressions - MutableTransmutes: MutableTransmutes, - TypeAliasBounds: TypeAliasBounds, - TrivialConstraints: TrivialConstraints, - TypeLimits: TypeLimits::new(), - NonSnakeCase: NonSnakeCase, - InvalidNoMangleItems: InvalidNoMangleItems, - // Depends on effective visibilities - UnreachablePub: UnreachablePub, - ExplicitOutlivesRequirements: ExplicitOutlivesRequirements, - InvalidValue: InvalidValue, - DerefNullPtr: DerefNullPtr, - // May Depend on constants elsewhere - UnusedBrokenConst: UnusedBrokenConst, - UnstableFeatures: UnstableFeatures, - ArrayIntoIter: ArrayIntoIter::default(), - DropTraitConstraints: DropTraitConstraints, - TemporaryCStringAsPtr: TemporaryCStringAsPtr, - NonPanicFmt: NonPanicFmt, - NoopMethodCall: NoopMethodCall, - EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums, - InvalidAtomicOrdering: InvalidAtomicOrdering, - NamedAsmLabels: NamedAsmLabels, - OpaqueHiddenInferredBound: OpaqueHiddenInferredBound, - ] - ); - }; -} - -macro_rules! declare_combined_late_pass { - ([$v:vis $name:ident], $passes:tt) => ( - late_lint_methods!(declare_combined_late_lint_pass, [$v $name, $passes], ['tcx]); - ) -} +early_lint_methods!( + declare_combined_early_lint_pass, + [ + pub BuiltinCombinedPreExpansionLintPass, + [ + KeywordIdents: KeywordIdents, + ] + ] +); + +early_lint_methods!( + declare_combined_early_lint_pass, + [ + pub BuiltinCombinedEarlyLintPass, + [ + UnusedParens: UnusedParens, + UnusedBraces: UnusedBraces, + UnusedImportBraces: UnusedImportBraces, + UnsafeCode: UnsafeCode, + SpecialModuleName: SpecialModuleName, + AnonymousParameters: AnonymousParameters, + EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(), + NonCamelCaseTypes: NonCamelCaseTypes, + DeprecatedAttr: DeprecatedAttr::new(), + WhileTrue: WhileTrue, + NonAsciiIdents: NonAsciiIdents, + HiddenUnicodeCodepoints: HiddenUnicodeCodepoints, + IncompleteFeatures: IncompleteFeatures, + RedundantSemicolons: RedundantSemicolons, + UnusedDocComment: UnusedDocComment, + UnexpectedCfgs: UnexpectedCfgs, + ] + ] +); // FIXME: Make a separate lint type which do not require typeck tables -late_lint_passes!(declare_combined_late_pass, [pub BuiltinCombinedLateLintPass]); - -late_lint_mod_passes!(declare_combined_late_pass, [BuiltinCombinedModuleLateLintPass]); - -pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> LintStore { +late_lint_methods!( + declare_combined_late_lint_pass, + [ + pub BuiltinCombinedLateLintPass, + [ + // Tracks state across modules + UnnameableTestItems: UnnameableTestItems::new(), + // Tracks attributes of parents + MissingDoc: MissingDoc::new(), + // Builds a global list of all impls of `Debug`. + // FIXME: Turn the computation of types which implement Debug into a query + // and change this to a module lint pass + MissingDebugImplementations: MissingDebugImplementations::default(), + // Keeps a global list of foreign declarations. + ClashingExternDeclarations: ClashingExternDeclarations::new(), + ] + ], + ['tcx] +); + +late_lint_methods!( + declare_combined_late_lint_pass, + [ + BuiltinCombinedModuleLateLintPass, + [ + ForLoopsOverFallibles: ForLoopsOverFallibles, + DerefIntoDynSupertrait: DerefIntoDynSupertrait, + HardwiredLints: HardwiredLints, + ImproperCTypesDeclarations: ImproperCTypesDeclarations, + ImproperCTypesDefinitions: ImproperCTypesDefinitions, + VariantSizeDifferences: VariantSizeDifferences, + BoxPointers: BoxPointers, + PathStatements: PathStatements, + LetUnderscore: LetUnderscore, + // Depends on referenced function signatures in expressions + UnusedResults: UnusedResults, + NonUpperCaseGlobals: NonUpperCaseGlobals, + NonShorthandFieldPatterns: NonShorthandFieldPatterns, + UnusedAllocation: UnusedAllocation, + // Depends on types used in type definitions + MissingCopyImplementations: MissingCopyImplementations, + // Depends on referenced function signatures in expressions + MutableTransmutes: MutableTransmutes, + TypeAliasBounds: TypeAliasBounds, + TrivialConstraints: TrivialConstraints, + TypeLimits: TypeLimits::new(), + NonSnakeCase: NonSnakeCase, + InvalidNoMangleItems: InvalidNoMangleItems, + // Depends on effective visibilities + UnreachablePub: UnreachablePub, + ExplicitOutlivesRequirements: ExplicitOutlivesRequirements, + InvalidValue: InvalidValue, + DerefNullPtr: DerefNullPtr, + // May Depend on constants elsewhere + UnusedBrokenConst: UnusedBrokenConst, + UnstableFeatures: UnstableFeatures, + ArrayIntoIter: ArrayIntoIter::default(), + DropTraitConstraints: DropTraitConstraints, + TemporaryCStringAsPtr: TemporaryCStringAsPtr, + NonPanicFmt: NonPanicFmt, + NoopMethodCall: NoopMethodCall, + EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums, + InvalidAtomicOrdering: InvalidAtomicOrdering, + NamedAsmLabels: NamedAsmLabels, + OpaqueHiddenInferredBound: OpaqueHiddenInferredBound, + ] + ], + ['tcx] +); + +pub fn new_lint_store(internal_lints: bool) -> LintStore { let mut lint_store = LintStore::new(); - register_builtins(&mut lint_store, no_interleave_lints); + register_builtins(&mut lint_store); if internal_lints { register_internals(&mut lint_store); } @@ -263,54 +247,17 @@ pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> LintSt /// Tell the `LintStore` about all the built-in lints (the ones /// defined in this crate and the ones defined in /// `rustc_session::lint::builtin`). -fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { +fn register_builtins(store: &mut LintStore) { macro_rules! add_lint_group { ($name:expr, $($lint:ident),*) => ( store.register_group(false, $name, None, vec![$(LintId::of($lint)),*]); ) } - macro_rules! register_early_pass { - ($method:ident, $ty:ident, $constructor:expr) => { - store.register_lints(&$ty::get_lints()); - store.$method(|| Box::new($constructor)); - }; - } - - macro_rules! register_late_pass { - ($method:ident, $ty:ident, $constructor:expr) => { - store.register_lints(&$ty::get_lints()); - store.$method(|_| Box::new($constructor)); - }; - } - - macro_rules! register_early_passes { - ($method:ident, [$($passes:ident: $constructor:expr,)*]) => ( - $( - register_early_pass!($method, $passes, $constructor); - )* - ) - } - - macro_rules! register_late_passes { - ($method:ident, [$($passes:ident: $constructor:expr,)*]) => ( - $( - register_late_pass!($method, $passes, $constructor); - )* - ) - } - - if no_interleave_lints { - pre_expansion_lint_passes!(register_early_passes, register_pre_expansion_pass); - early_lint_passes!(register_early_passes, register_early_pass); - late_lint_passes!(register_late_passes, register_late_pass); - late_lint_mod_passes!(register_late_passes, register_late_mod_pass); - } else { - store.register_lints(&BuiltinCombinedPreExpansionLintPass::get_lints()); - store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints()); - store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints()); - store.register_lints(&BuiltinCombinedLateLintPass::get_lints()); - } + store.register_lints(&BuiltinCombinedPreExpansionLintPass::get_lints()); + store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints()); + store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints()); + store.register_lints(&BuiltinCombinedLateLintPass::get_lints()); add_lint_group!( "nonstandard_style", diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index fc11d092ccb4b..2f53986139e05 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -1,7 +1,6 @@ use crate::context::{EarlyContext, LateContext}; use rustc_ast as ast; -use rustc_data_structures::sync; use rustc_hir as hir; use rustc_session::lint::builtin::HardwiredLints; use rustc_session::lint::LintPass; @@ -66,16 +65,10 @@ macro_rules! late_lint_methods { // FIXME: eliminate the duplication with `Visitor`. But this also // contains a few lint-specific methods with no equivalent in `Visitor`. -macro_rules! expand_lint_pass_methods { - ($context:ty, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( - $(#[inline(always)] fn $name(&mut self, _: $context, $(_: $arg),*) {})* - ) -} - macro_rules! declare_late_lint_pass { - ([], [$hir:tt], [$($methods:tt)*]) => ( + ([], [$hir:tt], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( pub trait LateLintPass<$hir>: LintPass { - expand_lint_pass_methods!(&LateContext<$hir>, [$($methods)*]); + $(#[inline(always)] fn $name(&mut self, _: &LateContext<$hir>, $(_: $arg),*) {})* } ) } @@ -175,16 +168,10 @@ macro_rules! early_lint_methods { ) } -macro_rules! expand_early_lint_pass_methods { - ($context:ty, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( - $(#[inline(always)] fn $name(&mut self, _: $context, $(_: $arg),*) {})* - ) -} - macro_rules! declare_early_lint_pass { - ([], [$($methods:tt)*]) => ( + ([], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( pub trait EarlyLintPass: LintPass { - expand_early_lint_pass_methods!(&EarlyContext<'_>, [$($methods)*]); + $(#[inline(always)] fn $name(&mut self, _: &EarlyContext<'_>, $(_: $arg),*) {})* } ) } @@ -243,5 +230,5 @@ macro_rules! declare_combined_early_lint_pass { } /// A lint pass boxed up as a trait object. -pub type EarlyLintPassObject = Box; -pub type LateLintPassObject<'tcx> = Box + sync::Send + 'tcx>; +pub type EarlyLintPassObject = Box; +pub type LateLintPassObject<'tcx> = Box + 'tcx>; diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index d35e4191cc0b1..79f06ac146c77 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -222,6 +222,7 @@ fn main() { .file("llvm-wrapper/RustWrapper.cpp") .file("llvm-wrapper/ArchiveWrapper.cpp") .file("llvm-wrapper/CoverageMappingWrapper.cpp") + .file("llvm-wrapper/SymbolWrapper.cpp") .file("llvm-wrapper/Linker.cpp") .cpp(true) .cpp_link_stdlib(None) // we handle this below diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 216c35d6da078..792d921c6a4f9 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1967,3 +1967,7 @@ extern "C" int32_t LLVMRustGetElementTypeArgIndex(LLVMValueRef CallSite) { #endif return -1; } + +extern "C" bool LLVMRustIsBitcode(char *ptr, size_t len) { + return identify_magic(StringRef(ptr, len)) == file_magic::bitcode; +} diff --git a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp new file mode 100644 index 0000000000000..974207e918cd6 --- /dev/null +++ b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp @@ -0,0 +1,96 @@ +// Derived from code in LLVM, which is: +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// Derived from: +// * https://github.com/llvm/llvm-project/blob/8ef3e895ad8ab1724e2b87cabad1dacdc7a397a3/llvm/include/llvm/Object/ArchiveWriter.h +// * https://github.com/llvm/llvm-project/blob/8ef3e895ad8ab1724e2b87cabad1dacdc7a397a3/llvm/lib/Object/ArchiveWriter.cpp + +#include "llvm/IR/LLVMContext.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/ADT/Optional.h" + +using namespace llvm; +using namespace llvm::sys; +using namespace llvm::object; + +static bool isArchiveSymbol(const object::BasicSymbolRef &S) { + Expected SymFlagsOrErr = S.getFlags(); + if (!SymFlagsOrErr) + // FIXME: Actually report errors helpfully. + report_fatal_error(SymFlagsOrErr.takeError()); + if (*SymFlagsOrErr & object::SymbolRef::SF_FormatSpecific) + return false; + if (!(*SymFlagsOrErr & object::SymbolRef::SF_Global)) + return false; + if (*SymFlagsOrErr & object::SymbolRef::SF_Undefined) + return false; + return true; +} + +typedef void *(*LLVMRustGetSymbolsCallback)(void *, const char *); +typedef void *(*LLVMRustGetSymbolsErrorCallback)(const char *); + +// Note: This is implemented in C++ instead of using the C api from Rust as IRObjectFile doesn't +// implement getSymbolName, only printSymbolName, which is inaccessible from the C api. +extern "C" void *LLVMRustGetSymbols( + char *BufPtr, size_t BufLen, void *State, LLVMRustGetSymbolsCallback Callback, + LLVMRustGetSymbolsErrorCallback ErrorCallback) { + std::unique_ptr Buf = + MemoryBuffer::getMemBuffer(StringRef(BufPtr, BufLen), StringRef("LLVMRustGetSymbolsObject"), + false); + SmallString<0> SymNameBuf; + raw_svector_ostream SymName(SymNameBuf); + + // In the scenario when LLVMContext is populated SymbolicFile will contain a + // reference to it, thus SymbolicFile should be destroyed first. + LLVMContext Context; + std::unique_ptr Obj; + + const file_magic Type = identify_magic(Buf->getBuffer()); + if (!object::SymbolicFile::isSymbolicFile(Type, &Context)) { + return 0; + } + + if (Type == file_magic::bitcode) { + auto ObjOrErr = object::SymbolicFile::createSymbolicFile( + Buf->getMemBufferRef(), file_magic::bitcode, &Context); + if (!ObjOrErr) { + Error E = ObjOrErr.takeError(); + SmallString<0> ErrorBuf; + raw_svector_ostream Error(ErrorBuf); + Error << E << '\0'; + return ErrorCallback(Error.str().data()); + } + Obj = std::move(*ObjOrErr); + } else { + auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf->getMemBufferRef()); + if (!ObjOrErr) { + Error E = ObjOrErr.takeError(); + SmallString<0> ErrorBuf; + raw_svector_ostream Error(ErrorBuf); + Error << E << '\0'; + return ErrorCallback(Error.str().data()); + } + Obj = std::move(*ObjOrErr); + } + + + for (const object::BasicSymbolRef &S : Obj->symbols()) { + if (!isArchiveSymbol(S)) + continue; + if (Error E = S.printName(SymName)) { + SmallString<0> ErrorBuf; + raw_svector_ostream Error(ErrorBuf); + Error << E << '\0'; + return ErrorCallback(Error.str().data()); + } + SymName << '\0'; + if (void *E = Callback(State, SymNameBuf.str().data())) { + return E; + } + SymNameBuf.clear(); + } + return 0; +} diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index be9821c00f507..684835d8c5c86 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -29,8 +29,8 @@ impl<'a> DiagnosticDerive<'a> { let DiagnosticDerive { mut structure, mut builder } = self; let implementation = builder.each_variant(&mut structure, |mut builder, variant| { - let preamble = builder.preamble(&variant); - let body = builder.body(&variant); + let preamble = builder.preamble(variant); + let body = builder.body(variant); let diag = &builder.parent.diag; let DiagnosticDeriveKind::Diagnostic { handler } = &builder.parent.kind else { @@ -39,7 +39,7 @@ impl<'a> DiagnosticDerive<'a> { let init = match builder.slug.value_ref() { None => { span_err(builder.span, "diagnostic slug not specified") - .help(&format!( + .help(format!( "specify the slug as the first argument to the `#[diag(...)]` \ attribute, such as `#[diag(hir_analysis_example_error)]`", )) @@ -48,10 +48,10 @@ impl<'a> DiagnosticDerive<'a> { } Some(slug) if let Some( Mismatch { slug_name, crate_name, slug_prefix }) = Mismatch::check(slug) => { span_err(slug.span().unwrap(), "diagnostic slug and crate name do not match") - .note(&format!( + .note(format!( "slug is `{slug_name}` but the crate name is `{crate_name}`" )) - .help(&format!( + .help(format!( "expected a slug starting with `{slug_prefix}_...`" )) .emit(); @@ -113,8 +113,8 @@ impl<'a> LintDiagnosticDerive<'a> { let LintDiagnosticDerive { mut structure, mut builder } = self; let implementation = builder.each_variant(&mut structure, |mut builder, variant| { - let preamble = builder.preamble(&variant); - let body = builder.body(&variant); + let preamble = builder.preamble(variant); + let body = builder.body(variant); let diag = &builder.parent.diag; let formatting_init = &builder.formatting_init; @@ -128,28 +128,28 @@ impl<'a> LintDiagnosticDerive<'a> { let msg = builder.each_variant(&mut structure, |mut builder, variant| { // Collect the slug by generating the preamble. - let _ = builder.preamble(&variant); + let _ = builder.preamble(variant); match builder.slug.value_ref() { None => { span_err(builder.span, "diagnostic slug not specified") - .help(&format!( + .help(format!( "specify the slug as the first argument to the attribute, such as \ `#[diag(compiletest_example)]`", )) .emit(); - return DiagnosticDeriveError::ErrorHandled.to_compile_error(); + DiagnosticDeriveError::ErrorHandled.to_compile_error() } Some(slug) if let Some( Mismatch { slug_name, crate_name, slug_prefix }) = Mismatch::check(slug) => { span_err(slug.span().unwrap(), "diagnostic slug and crate name do not match") - .note(&format!( + .note(format!( "slug is `{slug_name}` but the crate name is `{crate_name}`" )) - .help(&format!( + .help(format!( "expected a slug starting with `{slug_prefix}_...`" )) .emit(); - return DiagnosticDeriveError::ErrorHandled.to_compile_error(); + DiagnosticDeriveError::ErrorHandled.to_compile_error() } Some(slug) => { quote! { diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 3ea83fd09c794..9f2ac5112f1cd 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -100,7 +100,7 @@ impl DiagnosticDeriveBuilder { _ => variant.ast().ident.span().unwrap(), }; let builder = DiagnosticDeriveVariantBuilder { - parent: &self, + parent: self, span, field_map: build_field_mapping(variant), formatting_init: TokenStream::new(), @@ -211,7 +211,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { nested_iter.next(); } Some(NestedMeta::Meta(Meta::NameValue { .. })) => {} - Some(nested_attr) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| diag + Some(nested_attr) => throw_invalid_nested_attr!(attr, nested_attr, |diag| diag .help("a diagnostic slug is required as the first argument")), None => throw_invalid_attr!(attr, &meta, |diag| diag .help("a diagnostic slug is required as the first argument")), @@ -227,13 +227,13 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { .. })) => (value, path), NestedMeta::Meta(Meta::Path(_)) => { - invalid_nested_attr(attr, &nested_attr) + invalid_nested_attr(attr, nested_attr) .help("diagnostic slug must be the first argument") .emit(); continue; } _ => { - invalid_nested_attr(attr, &nested_attr).emit(); + invalid_nested_attr(attr, nested_attr).emit(); continue; } }; @@ -251,7 +251,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string())); }); } - _ => invalid_nested_attr(attr, &nested_attr) + _ => invalid_nested_attr(attr, nested_attr) .help("only `code` is a valid nested attributes following the slug") .emit(), } @@ -427,9 +427,9 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug)) } SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => { - if type_matches_path(&info.ty, &["rustc_span", "Span"]) { + if type_matches_path(info.ty, &["rustc_span", "Span"]) { Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug)) - } else if type_is_unit(&info.ty) { + } else if type_is_unit(info.ty) { Ok(self.add_subdiagnostic(&fn_ident, slug)) } else { report_type_error(attr, "`Span` or `()`")? diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index fa0ca5a52423a..446aebe4f83f5 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -409,7 +409,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { let mut code = None; for nested_attr in list.nested.iter() { let NestedMeta::Meta(ref meta) = nested_attr else { - throw_invalid_nested_attr!(attr, &nested_attr); + throw_invalid_nested_attr!(attr, nested_attr); }; let span = meta.span().unwrap(); @@ -427,7 +427,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { ); code.set_once((code_field, formatting_init), span); } - _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + _ => throw_invalid_nested_attr!(attr, nested_attr, |diag| { diag.help("`code` is the only valid nested attribute") }), } diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index dff088b9bdfa6..da90233523ca3 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -80,7 +80,7 @@ fn report_error_if_not_applied_to_ty( path: &[&str], ty_name: &str, ) -> Result<(), DiagnosticDeriveError> { - if !type_matches_path(&info.ty, path) { + if !type_matches_path(info.ty, path) { report_type_error(attr, ty_name)?; } @@ -105,8 +105,8 @@ pub(crate) fn report_error_if_not_applied_to_span( attr: &Attribute, info: &FieldInfo<'_>, ) -> Result<(), DiagnosticDeriveError> { - if !type_matches_path(&info.ty, &["rustc_span", "Span"]) - && !type_matches_path(&info.ty, &["rustc_errors", "MultiSpan"]) + if !type_matches_path(info.ty, &["rustc_span", "Span"]) + && !type_matches_path(info.ty, &["rustc_errors", "MultiSpan"]) { report_type_error(attr, "`Span` or `MultiSpan`")?; } @@ -686,7 +686,7 @@ impl SubdiagnosticKind { let meta = match nested_attr { NestedMeta::Meta(ref meta) => meta, NestedMeta::Lit(_) => { - invalid_nested_attr(attr, &nested_attr).emit(); + invalid_nested_attr(attr, nested_attr).emit(); continue; } }; @@ -698,7 +698,7 @@ impl SubdiagnosticKind { let string_value = match meta { Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => Some(value), - Meta::Path(_) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + Meta::Path(_) => throw_invalid_nested_attr!(attr, nested_attr, |diag| { diag.help("a diagnostic slug must be the first argument to the attribute") }), _ => None, @@ -720,7 +720,7 @@ impl SubdiagnosticKind { | SubdiagnosticKind::MultipartSuggestion { ref mut applicability, .. }, ) => { let Some(value) = string_value else { - invalid_nested_attr(attr, &nested_attr).emit(); + invalid_nested_attr(attr, nested_attr).emit(); continue; }; @@ -736,7 +736,7 @@ impl SubdiagnosticKind { | SubdiagnosticKind::MultipartSuggestion { .. }, ) => { let Some(value) = string_value else { - invalid_nested_attr(attr, &nested_attr).emit(); + invalid_nested_attr(attr, nested_attr).emit(); continue; }; @@ -752,19 +752,19 @@ impl SubdiagnosticKind { // Invalid nested attribute (_, SubdiagnosticKind::Suggestion { .. }) => { - invalid_nested_attr(attr, &nested_attr) + invalid_nested_attr(attr, nested_attr) .help( "only `style`, `code` and `applicability` are valid nested attributes", ) .emit(); } (_, SubdiagnosticKind::MultipartSuggestion { .. }) => { - invalid_nested_attr(attr, &nested_attr) + invalid_nested_attr(attr, nested_attr) .help("only `style` and `applicability` are valid nested attributes") .emit() } _ => { - invalid_nested_attr(attr, &nested_attr).emit(); + invalid_nested_attr(attr, nested_attr).emit(); } } } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 4617c17b1537e..1bd8f95350879 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1022,7 +1022,7 @@ impl<'hir> Map<'hir> { .. }) => { // Ensure that the returned span has the item's SyntaxContext. - fn_decl_span.find_ancestor_in_same_ctxt(*span).unwrap_or(*span) + fn_decl_span.find_ancestor_inside(*span).unwrap_or(*span) } _ => self.span_with_body(hir_id), }; diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 20dde64e51b01..a513444e1e08b 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -100,13 +100,9 @@ impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> { /// pass will be named after the type, and it will consist of a main /// loop that goes over each available MIR and applies `run_pass`. pub trait MirPass<'tcx> { - fn name(&self) -> Cow<'_, str> { + fn name(&self) -> &str { let name = std::any::type_name::(); - if let Some(tail) = name.rfind(':') { - Cow::from(&name[tail + 1..]) - } else { - Cow::from(name) - } + if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name } } /// Returns `true` if this pass is enabled with the current combination of compiler flags. @@ -182,35 +178,6 @@ impl RuntimePhase { } } -impl Display for MirPhase { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - MirPhase::Built => write!(f, "built"), - MirPhase::Analysis(p) => write!(f, "analysis-{}", p), - MirPhase::Runtime(p) => write!(f, "runtime-{}", p), - } - } -} - -impl Display for AnalysisPhase { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - AnalysisPhase::Initial => write!(f, "initial"), - AnalysisPhase::PostCleanup => write!(f, "post_cleanup"), - } - } -} - -impl Display for RuntimePhase { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - RuntimePhase::Initial => write!(f, "initial"), - RuntimePhase::PostCleanup => write!(f, "post_cleanup"), - RuntimePhase::Optimized => write!(f, "optimized"), - } - } -} - /// Where a specific `mir::Body` comes from. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)] @@ -368,7 +335,7 @@ impl<'tcx> Body<'tcx> { let mut body = Body { phase: MirPhase::Built, - pass_count: 1, + pass_count: 0, source, basic_blocks: BasicBlocks::new(basic_blocks), source_scopes, @@ -403,7 +370,7 @@ impl<'tcx> Body<'tcx> { pub fn new_cfg_only(basic_blocks: IndexVec>) -> Self { let mut body = Body { phase: MirPhase::Built, - pass_count: 1, + pass_count: 0, source: MirSource::item(CRATE_DEF_ID.to_def_id()), basic_blocks: BasicBlocks::new(basic_blocks), source_scopes: IndexVec::new(), diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 1cac656674d69..2a4ff4b8810db 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -16,7 +16,6 @@ use rustc_middle::mir::interpret::{ Pointer, Provenance, }; use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::MirSource; use rustc_middle::mir::*; use rustc_middle::ty::{self, TyCtxt}; use rustc_target::abi::Size; @@ -74,7 +73,7 @@ pub enum PassWhere { #[inline] pub fn dump_mir<'tcx, F>( tcx: TyCtxt<'tcx>, - pass_num: Option<&dyn Display>, + pass_num: bool, pass_name: &str, disambiguator: &dyn Display, body: &Body<'tcx>, @@ -111,7 +110,7 @@ pub fn dump_enabled<'tcx>(tcx: TyCtxt<'tcx>, pass_name: &str, def_id: DefId) -> fn dump_matched_mir_node<'tcx, F>( tcx: TyCtxt<'tcx>, - pass_num: Option<&dyn Display>, + pass_num: bool, pass_name: &str, disambiguator: &dyn Display, body: &Body<'tcx>, @@ -120,8 +119,7 @@ fn dump_matched_mir_node<'tcx, F>( F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, { let _: io::Result<()> = try { - let mut file = - create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, body.source)?; + let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, body)?; // see notes on #41697 above let def_path = ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id())); @@ -143,16 +141,14 @@ fn dump_matched_mir_node<'tcx, F>( if tcx.sess.opts.unstable_opts.dump_mir_graphviz { let _: io::Result<()> = try { - let mut file = - create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, body.source)?; + let mut file = create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, body)?; write_mir_fn_graphviz(tcx, body, false, &mut file)?; }; } if let Some(spanview) = tcx.sess.opts.unstable_opts.dump_mir_spanview { let _: io::Result<()> = try { - let file_basename = - dump_file_basename(tcx, pass_num, pass_name, disambiguator, body.source); + let file_basename = dump_file_basename(tcx, pass_num, pass_name, disambiguator, body); let mut file = create_dump_file_with_basename(tcx, &file_basename, "html")?; if body.source.def_id().is_local() { write_mir_fn_spanview(tcx, body, spanview, &file_basename, &mut file)?; @@ -165,11 +161,12 @@ fn dump_matched_mir_node<'tcx, F>( /// where we should dump a MIR representation output files. fn dump_file_basename<'tcx>( tcx: TyCtxt<'tcx>, - pass_num: Option<&dyn Display>, + pass_num: bool, pass_name: &str, disambiguator: &dyn Display, - source: MirSource<'tcx>, + body: &Body<'tcx>, ) -> String { + let source = body.source; let promotion_id = match source.promoted { Some(id) => format!("-{:?}", id), None => String::new(), @@ -178,9 +175,10 @@ fn dump_file_basename<'tcx>( let pass_num = if tcx.sess.opts.unstable_opts.dump_mir_exclude_pass_number { String::new() } else { - match pass_num { - None => ".-------".to_string(), - Some(pass_num) => format!(".{}", pass_num), + if pass_num { + format!(".{:03}-{:03}", body.phase.phase_index(), body.pass_count) + } else { + ".-------".to_string() } }; @@ -250,14 +248,14 @@ fn create_dump_file_with_basename( pub fn create_dump_file<'tcx>( tcx: TyCtxt<'tcx>, extension: &str, - pass_num: Option<&dyn Display>, + pass_num: bool, pass_name: &str, disambiguator: &dyn Display, - source: MirSource<'tcx>, + body: &Body<'tcx>, ) -> io::Result> { create_dump_file_with_basename( tcx, - &dump_file_basename(tcx, pass_num, pass_name, disambiguator, source), + &dump_file_basename(tcx, pass_num, pass_name, disambiguator, body), extension, ) } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index f2030b91b9b65..7d2a6bda56926 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -89,6 +89,19 @@ pub enum MirPhase { Runtime(RuntimePhase), } +impl MirPhase { + pub fn name(&self) -> &'static str { + match *self { + MirPhase::Built => "built", + MirPhase::Analysis(AnalysisPhase::Initial) => "analysis", + MirPhase::Analysis(AnalysisPhase::PostCleanup) => "analysis-post-cleanup", + MirPhase::Runtime(RuntimePhase::Initial) => "runtime", + MirPhase::Runtime(RuntimePhase::PostCleanup) => "runtime-post-cleanup", + MirPhase::Runtime(RuntimePhase::Optimized) => "runtime-optimized", + } + } +} + /// See [`MirPhase::Analysis`]. #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(HashStable)] diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index e1220320eea1b..d6dea0e9f30fa 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1109,6 +1109,7 @@ rustc_queries! { desc { |tcx| "looking up span for `{}`", tcx.def_path_str(def_id) } cache_on_disk_if { def_id.is_local() } separate_provide_extern + feedable } /// Gets the span for the identifier of the definition. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index a9a7a2c8b01cc..c5683a9db9473 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1507,7 +1507,9 @@ impl<'tcx> TyCtxt<'tcx> { self.def_path(def_id).to_string_no_crate_verbose() ) } +} +impl<'tcx> TyCtxtAt<'tcx> { /// Create a new definition within the incr. comp. engine. pub fn create_def( self, @@ -1536,9 +1538,13 @@ impl<'tcx> TyCtxt<'tcx> { // - this write will have happened before these queries are called. let def_id = self.definitions.write().create_def(parent, data); - TyCtxtFeed { tcx: self, def_id } + let feed = TyCtxtFeed { tcx: self.tcx, def_id }; + feed.def_span(self.span); + feed } +} +impl<'tcx> TyCtxt<'tcx> { pub fn iter_local_def_id(self) -> impl Iterator + 'tcx { // Create a dependency to the red node to be sure we re-execute this when the amount of // definitions change. diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 47c1379b308eb..a7fd1754960ab 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -344,12 +344,10 @@ macro_rules! define_feedable { match cached { Ok(old) => { - assert_eq!( - value, old, - "Trying to feed an already recorded value for query {} key={key:?}", + bug!( + "Trying to feed an already recorded value for query {} key={key:?}:\nold value: {old:?}\nnew value: {value:?}", stringify!($name), ); - return old; } Err(()) => (), } diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index f4562cdfb88dc..70b98e59a8bea 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -32,13 +32,23 @@ impl<'tcx> Value> for ty::SymbolName<'_> { } impl<'tcx> Value> for ty::Binder<'_, ty::FnSig<'_>> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self { + fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo]) -> Self { let err = tcx.ty_error(); - // FIXME(compiler-errors): It would be nice if we could get the - // query key, so we could at least generate a fn signature that - // has the right arity. + + let arity = if let Some(frame) = stack.get(0) + && frame.query.name == "fn_sig" + && let Some(def_id) = frame.query.def_id + && let Some(node) = tcx.hir().get_if_local(def_id) + && let Some(sig) = node.fn_sig() + { + sig.decl.inputs.len() + sig.decl.implicit_self.has_implicit_self() as usize + } else { + tcx.sess.abort_if_errors(); + unreachable!() + }; + let fn_sig = ty::Binder::dummy(tcx.mk_fn_sig( - [].into_iter(), + std::iter::repeat(err).take(arity), err, false, rustc_hir::Unsafety::Normal, diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs index 2412824efeb75..eb021f477573c 100644 --- a/compiler/rustc_mir_build/src/build/custom/mod.rs +++ b/compiler/rustc_mir_build/src/build/custom/mod.rs @@ -57,7 +57,7 @@ pub(super) fn build_custom_mir<'tcx>( is_polymorphic: false, tainted_by_errors: None, injection_phase: None, - pass_count: 1, + pass_count: 0, }; body.local_decls.push(LocalDecl::new(return_ty, return_ty_span)); diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index bc75645e7c957..6ddbe69e17e75 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -294,14 +294,7 @@ where None if tcx.sess.opts.unstable_opts.dump_mir_dataflow && dump_enabled(tcx, A::NAME, def_id) => { - create_dump_file( - tcx, - ".dot", - None, - A::NAME, - &pass_name.unwrap_or("-----"), - body.source, - )? + create_dump_file(tcx, ".dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)? } _ => return Ok(()), diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs index 0f8679b0bd69d..d6a298fade42e 100644 --- a/compiler/rustc_mir_transform/src/coverage/debug.rs +++ b/compiler/rustc_mir_transform/src/coverage/debug.rs @@ -638,7 +638,7 @@ pub(super) fn dump_coverage_spanview<'tcx>( let def_id = mir_source.def_id(); let span_viewables = span_viewables(tcx, mir_body, basic_coverage_blocks, &coverage_spans); - let mut file = create_dump_file(tcx, "html", None, pass_name, &0, mir_source) + let mut file = create_dump_file(tcx, "html", false, pass_name, &0, mir_body) .expect("Unexpected error creating MIR spanview HTML file"); let crate_name = tcx.crate_name(def_id.krate); let item_name = tcx.def_path(def_id).to_filename_friendly_no_crate(); @@ -739,7 +739,7 @@ pub(super) fn dump_coverage_graphviz<'tcx>( .join("\n ") )); } - let mut file = create_dump_file(tcx, "dot", None, pass_name, &0, mir_source) + let mut file = create_dump_file(tcx, "dot", false, pass_name, &0, mir_body) .expect("Unexpected error creating BasicCoverageBlock graphviz DOT file"); graphviz_writer .write_graphviz(tcx, &mut file) diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 8cd44ab82ccc4..97485c4f57b12 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -787,7 +787,7 @@ fn dest_prop_mir_dump<'body, 'tcx>( round: usize, ) { let mut reachable = None; - dump_mir(tcx, None, "DestinationPropagation-dataflow", &round, body, |pass_where, w| { + dump_mir(tcx, false, "DestinationPropagation-dataflow", &round, body, |pass_where, w| { let reachable = reachable.get_or_insert_with(|| traversal::reachable_as_bitset(body)); match pass_where { diff --git a/compiler/rustc_mir_transform/src/dump_mir.rs b/compiler/rustc_mir_transform/src/dump_mir.rs index 6b995141a2bef..778ae63c5a42e 100644 --- a/compiler/rustc_mir_transform/src/dump_mir.rs +++ b/compiler/rustc_mir_transform/src/dump_mir.rs @@ -1,6 +1,5 @@ //! This pass just dumps MIR at a specified point. -use std::borrow::Cow; use std::fs::File; use std::io; @@ -13,8 +12,8 @@ use rustc_session::config::{OutputFilenames, OutputType}; pub struct Marker(pub &'static str); impl<'tcx> MirPass<'tcx> for Marker { - fn name(&self) -> Cow<'_, str> { - Cow::Borrowed(self.0) + fn name(&self) -> &str { + self.0 } fn run_pass(&self, _tcx: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {} diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index ffe4d43bc88e8..8922298ecafcb 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1000,7 +1000,7 @@ fn create_generator_drop_shim<'tcx>( // unrelated code from the resume part of the function simplify::remove_dead_blocks(tcx, &mut body); - dump_mir(tcx, None, "generator_drop", &0, &body, |_, _| Ok(())); + dump_mir(tcx, false, "generator_drop", &0, &body, |_, _| Ok(())); body } @@ -1171,7 +1171,7 @@ fn create_generator_resume_function<'tcx>( // unrelated code from the drop part of the function simplify::remove_dead_blocks(tcx, body); - dump_mir(tcx, None, "generator_resume", &0, body, |_, _| Ok(())); + dump_mir(tcx, false, "generator_resume", &0, body, |_, _| Ok(())); } fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock { @@ -1394,14 +1394,14 @@ impl<'tcx> MirPass<'tcx> for StateTransform { // This is expanded to a drop ladder in `elaborate_generator_drops`. let drop_clean = insert_clean_drop(body); - dump_mir(tcx, None, "generator_pre-elab", &0, body, |_, _| Ok(())); + dump_mir(tcx, false, "generator_pre-elab", &0, body, |_, _| Ok(())); // Expand `drop(generator_struct)` to a drop ladder which destroys upvars. // If any upvars are moved out of, drop elaboration will handle upvar destruction. // However we need to also elaborate the code generated by `insert_clean_drop`. elaborate_generator_drops(tcx, body); - dump_mir(tcx, None, "generator_post-transform", &0, body, |_, _| Ok(())); + dump_mir(tcx, false, "generator_post-transform", &0, body, |_, _| Ok(())); // Create a copy of our MIR and use it to create the drop shim for the generator let drop_shim = create_generator_drop_shim(tcx, &transform, gen_ty, body, drop_clean); diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 9174f04887e42..bf670c5c26a77 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -363,10 +363,6 @@ impl<'tcx> Inliner<'tcx> { return Err("C variadic"); } - if callee_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { - return Err("naked"); - } - if callee_attrs.flags.contains(CodegenFnAttrFlags::COLD) { return Err("cold"); } diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index 27dbc3e22c97a..e1b65823a5a9c 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -1,5 +1,3 @@ -use std::borrow::Cow; - use rustc_middle::mir::{self, Body, MirPhase, RuntimePhase}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -8,13 +6,9 @@ use crate::{validate, MirPass}; /// Just like `MirPass`, except it cannot mutate `Body`. pub trait MirLint<'tcx> { - fn name(&self) -> Cow<'_, str> { + fn name(&self) -> &str { let name = std::any::type_name::(); - if let Some(tail) = name.rfind(':') { - Cow::from(&name[tail + 1..]) - } else { - Cow::from(name) - } + if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name } } fn is_enabled(&self, _sess: &Session) -> bool { @@ -32,7 +26,7 @@ impl<'tcx, T> MirPass<'tcx> for Lint where T: MirLint<'tcx>, { - fn name(&self) -> Cow<'_, str> { + fn name(&self) -> &str { self.0.name() } @@ -55,7 +49,7 @@ impl<'tcx, T> MirPass<'tcx> for WithMinOptLevel where T: MirPass<'tcx>, { - fn name(&self) -> Cow<'_, str> { + fn name(&self) -> &str { self.1.name() } @@ -146,10 +140,11 @@ fn run_passes_inner<'tcx>( } body.phase = new_phase; + body.pass_count = 0; dump_mir_for_phase_change(tcx, body); if validate || new_phase == MirPhase::Runtime(RuntimePhase::Optimized) { - validate_body(tcx, body, format!("after phase change to {}", new_phase)); + validate_body(tcx, body, format!("after phase change to {}", new_phase.name())); } body.pass_count = 1; @@ -166,11 +161,9 @@ pub fn dump_mir_for_pass<'tcx>( pass_name: &str, is_after: bool, ) { - let phase_index = body.phase.phase_index(); - mir::dump_mir( tcx, - Some(&format_args!("{:03}-{:03}", phase_index, body.pass_count)), + true, pass_name, if is_after { &"after" } else { &"before" }, body, @@ -179,14 +172,6 @@ pub fn dump_mir_for_pass<'tcx>( } pub fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { - let phase_index = body.phase.phase_index(); - - mir::dump_mir( - tcx, - Some(&format_args!("{:03}-000", phase_index)), - &format!("{}", body.phase), - &"after", - body, - |_, _| Ok(()), - ) + assert_eq!(body.pass_count, 0); + mir::dump_mir(tcx, true, body.phase.name(), &"after", body, |_, _| Ok(())) } diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 57d372fda5697..475e2ec9a1dea 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -35,7 +35,6 @@ use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Vis use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use smallvec::SmallVec; -use std::borrow::Cow; use std::convert::TryInto; pub struct SimplifyCfg { @@ -57,8 +56,8 @@ pub fn simplify_cfg<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { } impl<'tcx> MirPass<'tcx> for SimplifyCfg { - fn name(&self) -> Cow<'_, str> { - Cow::Borrowed(&self.label) + fn name(&self) -> &str { + &self.label } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs index 3bbae5b8976cc..405ebce4d2227 100644 --- a/compiler/rustc_mir_transform/src/simplify_branches.rs +++ b/compiler/rustc_mir_transform/src/simplify_branches.rs @@ -2,8 +2,6 @@ use crate::MirPass; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; -use std::borrow::Cow; - /// A pass that replaces a branch with a goto when its condition is known. pub struct SimplifyConstCondition { label: String, @@ -16,8 +14,8 @@ impl SimplifyConstCondition { } impl<'tcx> MirPass<'tcx> for SimplifyConstCondition { - fn name(&self) -> Cow<'_, str> { - Cow::Borrowed(&self.label) + fn name(&self) -> &str { + &self.label } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index e0443a697b504..fe3cfde2e6383 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2060,7 +2060,7 @@ impl<'a> Parser<'a> { }; let capture_clause = self.parse_capture_clause()?; - let fn_decl = self.parse_fn_block_decl()?; + let (fn_decl, fn_arg_span) = self.parse_fn_block_decl()?; let decl_hi = self.prev_token.span; let mut body = match fn_decl.output { FnRetTy::Default(_) => { @@ -2101,6 +2101,7 @@ impl<'a> Parser<'a> { fn_decl, body, fn_decl_span: lo.to(decl_hi), + fn_arg_span, })), ); @@ -2129,7 +2130,9 @@ impl<'a> Parser<'a> { } /// Parses the `|arg, arg|` header of a closure. - fn parse_fn_block_decl(&mut self) -> PResult<'a, P> { + fn parse_fn_block_decl(&mut self) -> PResult<'a, (P, Span)> { + let arg_start = self.token.span.lo(); + let inputs = if self.eat(&token::OrOr) { Vec::new() } else { @@ -2145,10 +2148,11 @@ impl<'a> Parser<'a> { self.expect_or()?; args }; + let arg_span = self.prev_token.span.with_lo(arg_start); let output = self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverReturnSign::Yes)?; - Ok(P(FnDecl { inputs, output })) + Ok((P(FnDecl { inputs, output }), arg_span)) } /// Parses a parameter in a closure header (e.g., `|arg, arg|`). diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index ff1ddfd97dfc6..42197e6379749 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -72,14 +72,22 @@ impl<'a> Parser<'a> { Ok(Some(if self.token.is_keyword(kw::Let) { self.parse_local_mk(lo, attrs, capture_semi, force_collect)? - } else if self.is_kw_followed_by_ident(kw::Mut) { - self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::MissingLet)? - } else if self.is_kw_followed_by_ident(kw::Auto) { + } else if self.is_kw_followed_by_ident(kw::Mut) && self.may_recover() { + self.recover_stmt_local_after_let(lo, attrs, InvalidVariableDeclarationSub::MissingLet)? + } else if self.is_kw_followed_by_ident(kw::Auto) && self.may_recover() { self.bump(); // `auto` - self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::UseLetNotAuto)? - } else if self.is_kw_followed_by_ident(sym::var) { + self.recover_stmt_local_after_let( + lo, + attrs, + InvalidVariableDeclarationSub::UseLetNotAuto, + )? + } else if self.is_kw_followed_by_ident(sym::var) && self.may_recover() { self.bump(); // `var` - self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::UseLetNotVar)? + self.recover_stmt_local_after_let( + lo, + attrs, + InvalidVariableDeclarationSub::UseLetNotVar, + )? } else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() { // We have avoided contextual keywords like `union`, items with `crate` visibility, // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something @@ -213,13 +221,21 @@ impl<'a> Parser<'a> { } } - fn recover_stmt_local( + fn recover_stmt_local_after_let( &mut self, lo: Span, attrs: AttrWrapper, subdiagnostic: fn(Span) -> InvalidVariableDeclarationSub, ) -> PResult<'a, Stmt> { - let stmt = self.recover_local_after_let(lo, attrs)?; + let stmt = + self.collect_tokens_trailing_token(attrs, ForceCollect::Yes, |this, attrs| { + let local = this.parse_local(attrs)?; + // FIXME - maybe capture semicolon in recovery? + Ok(( + this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Local(local)), + TrailingToken::None, + )) + })?; self.sess.emit_err(InvalidVariableDeclaration { span: lo, sub: subdiagnostic(lo) }); Ok(stmt) } @@ -243,17 +259,6 @@ impl<'a> Parser<'a> { }) } - fn recover_local_after_let(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a, Stmt> { - self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { - let local = this.parse_local(attrs)?; - // FIXME - maybe capture semicolon in recovery? - Ok(( - this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Local(local)), - TrailingToken::None, - )) - }) - } - /// Parses a local variable declaration. fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.prev_token.span; diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index e44857a023857..30d28ff345503 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -532,7 +532,8 @@ impl DepGraph { let mut edges = SmallVec::new(); K::read_deps(|task_deps| match task_deps { TaskDepsRef::Allow(deps) => edges.extend(deps.lock().reads.iter().copied()), - TaskDepsRef::Ignore | TaskDepsRef::Forbid => { + TaskDepsRef::Ignore => {} // During HIR lowering, we have no dependencies. + TaskDepsRef::Forbid => { panic!("Cannot summarize when dependencies are not recorded.") } }); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index bc3a710e84bd0..f6b6cf3a94c18 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1840,13 +1840,16 @@ impl<'a> Resolver<'a> { (format!("use of undeclared type `{}`", ident), suggestion) } else { - let suggestion = if ident.name == sym::alloc { - Some(( + let mut suggestion = None; + if ident.name == sym::alloc { + suggestion = Some(( vec![], String::from("add `extern crate alloc` to use the `alloc` crate"), Applicability::MaybeIncorrect, )) - } else { + } + + suggestion = suggestion.or_else(|| { self.find_similarly_named_module_or_crate(ident.name, &parent_scope.module).map( |sugg| { ( @@ -1856,7 +1859,7 @@ impl<'a> Resolver<'a> { ) }, ) - }; + }); (format!("use of undeclared crate or module `{}`", ident), suggestion) } } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index e6f4d7fcfcf06..b100a8c17cf39 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -4,7 +4,10 @@ use crate::diagnostics::{import_candidates, Suggestion}; use crate::Determinacy::{self, *}; use crate::Namespace::*; use crate::{module_to_string, names_to_string, ImportSuggestion}; -use crate::{AmbiguityKind, BindingKey, ModuleKind, ResolutionError, Resolver, Segment}; +use crate::{ + AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, ModuleKind, ResolutionError, + Resolver, Segment, +}; use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet}; use crate::{NameBinding, NameBindingKind, PathResult}; @@ -791,7 +794,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { match binding { Ok(binding) => { // Consistency checks, analogous to `finalize_macro_resolutions`. - let initial_res = source_bindings[ns].get().map(|initial_binding| { + let initial_binding = source_bindings[ns].get().map(|initial_binding| { all_ns_err = false; if let Some(target_binding) = target_bindings[ns].get() { if target.name == kw::Underscore @@ -805,12 +808,20 @@ impl<'a, 'b> ImportResolver<'a, 'b> { ); } } - initial_binding.res() + initial_binding }); let res = binding.res(); - if let Ok(initial_res) = initial_res { + if let Ok(initial_binding) = initial_binding { + let initial_res = initial_binding.res(); if res != initial_res && this.ambiguity_errors.is_empty() { - span_bug!(import.span, "inconsistent resolution for an import"); + this.ambiguity_errors.push(AmbiguityError { + kind: AmbiguityKind::Import, + ident, + b1: initial_binding, + b2: binding, + misc1: AmbiguityErrorMisc::None, + misc2: AmbiguityErrorMisc::None, + }); } } else if res != Res::Err && this.ambiguity_errors.is_empty() diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 2d2408c061ee2..51a53f7b37cc2 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3365,13 +3365,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Before we start looking for candidates, we have to get our hands // on the type user is trying to perform invocation on; basically: // we're transforming `HashMap::new` into just `HashMap`. - let path = match path.split_last() { + let prefix_path = match path.split_last() { Some((_, path)) if !path.is_empty() => path, _ => return Some(parent_err), }; let (mut err, candidates) = - this.smart_resolve_report_errors(path, path_span, PathSource::Type, None); + this.smart_resolve_report_errors(prefix_path, path_span, PathSource::Type, None); // There are two different error messages user might receive at // this point: @@ -3415,11 +3415,23 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if this.should_report_errs() { if candidates.is_empty() { - // When there is no suggested imports, we can just emit the error - // and suggestions immediately. Note that we bypass the usually error - // reporting routine (ie via `self.r.report_error`) because we need - // to post-process the `ResolutionError` above. - err.emit(); + if path.len() == 2 && prefix_path.len() == 1 { + // Delay to check whether methond name is an associated function or not + // ``` + // let foo = Foo {}; + // foo::bar(); // possibly suggest to foo.bar(); + //``` + err.stash( + prefix_path[0].ident.span, + rustc_errors::StashKey::CallAssocMethod, + ); + } else { + // When there is no suggested imports, we can just emit the error + // and suggestions immediately. Note that we bypass the usually error + // reporting routine (ie via `self.r.report_error`) because we need + // to post-process the `ResolutionError` above. + err.emit(); + } } else { // If there are suggested imports, the error reporting is delayed this.r.use_injections.push(UseError { @@ -3428,7 +3440,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { def_id, instead: false, suggestion: None, - path: path.into(), + path: prefix_path.into(), is_call: source.is_call(), }); } diff --git a/compiler/rustc_session/src/cgu_reuse_tracker.rs b/compiler/rustc_session/src/cgu_reuse_tracker.rs index 2336d99363fd3..8703e5754655f 100644 --- a/compiler/rustc_session/src/cgu_reuse_tracker.rs +++ b/compiler/rustc_session/src/cgu_reuse_tracker.rs @@ -121,7 +121,7 @@ impl CguReuseTracker { let at_least = if at_least { 1 } else { 0 }; IncorrectCguReuseType { span: error_span.0, - cgu_user_name: &cgu_user_name, + cgu_user_name, actual_reuse, expected_reuse, at_least, diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 927810351e958..d8c4b0845d0ac 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -622,7 +622,7 @@ impl OutputFilenames { /// should be placed on disk. pub fn output_path(&self, flavor: OutputType) -> PathBuf { let extension = flavor.extension(); - self.with_directory_and_extension(&self.out_directory, &extension) + self.with_directory_and_extension(&self.out_directory, extension) } /// Gets the path where a compilation artifact of the given type for the @@ -659,7 +659,7 @@ impl OutputFilenames { let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory); - self.with_directory_and_extension(&temps_directory, &extension) + self.with_directory_and_extension(temps_directory, &extension) } pub fn with_extension(&self, extension: &str) -> PathBuf { @@ -1159,7 +1159,7 @@ impl CrateCheckConfig { values_target_family .extend(target.options.families.iter().map(|family| Symbol::intern(family))); values_target_arch.insert(Symbol::intern(&target.arch)); - values_target_endian.insert(Symbol::intern(&target.options.endian.as_str())); + values_target_endian.insert(Symbol::intern(target.options.endian.as_str())); values_target_env.insert(Symbol::intern(&target.options.env)); values_target_abi.insert(Symbol::intern(&target.options.abi)); values_target_vendor.insert(Symbol::intern(&target.options.vendor)); @@ -1846,7 +1846,7 @@ pub fn parse_target_triple( match matches.opt_str("target") { Some(target) if target.ends_with(".json") => { let path = Path::new(&target); - TargetTriple::from_path(&path).unwrap_or_else(|_| { + TargetTriple::from_path(path).unwrap_or_else(|_| { early_error(error_format, &format!("target file {path:?} does not exist")) }) } @@ -1992,7 +1992,7 @@ fn parse_native_lib_modifiers( ) -> (NativeLibKind, Option) { let mut verbatim = None; for modifier in modifiers.split(',') { - let (modifier, value) = match modifier.strip_prefix(&['+', '-']) { + let (modifier, value) = match modifier.strip_prefix(['+', '-']) { Some(m) => (m, modifier.starts_with('+')), None => early_error( error_format, @@ -2421,7 +2421,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let mut search_paths = vec![]; for s in &matches.opt_strs("L") { - search_paths.push(SearchPath::from_cli_opt(&s, error_format)); + search_paths.push(SearchPath::from_cli_opt(s, error_format)); } let libs = parse_libs(matches, error_format); diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 9aa8a06c6d36e..8cb9e1a6f1ae8 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -317,7 +317,7 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: LitError::InvalidIntSuffix => { let suf = suffix.expect("suffix error with no suffix"); let suf = suf.as_str(); - if looks_like_width_suffix(&['i', 'u'], &suf) { + if looks_like_width_suffix(&['i', 'u'], suf) { // If it looks like a width, try to be helpful. sess.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() }); } else if let Some(fixed) = fix_base_capitalisation(suf) { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index f9ee202466f67..01a9361e78676 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1414,8 +1414,6 @@ options! { "run all passes except codegen; no output"), no_generate_arange_section: bool = (false, parse_no_flag, [TRACKED], "omit DWARF address ranges that give faster lookups"), - no_interleave_lints: bool = (false, parse_no_flag, [UNTRACKED], - "execute lints separately; allows benchmarking individual lints"), no_leak_check: bool = (false, parse_no_flag, [UNTRACKED], "disable the 'leak check' for subtyping; unsound, but useful for tests"), no_link: bool = (false, parse_no_flag, [TRACKED], diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs index 47aa4dfba42bb..d3c2c5113bcde 100644 --- a/compiler/rustc_span/src/analyze_source_file.rs +++ b/compiler/rustc_span/src/analyze_source_file.rs @@ -247,7 +247,7 @@ fn analyze_source_file_generic( // The slow path: // This is either ASCII control character "DEL" or the beginning of // a multibyte char. Just decode to `char`. - let c = (&src[i..]).chars().next().unwrap(); + let c = src[i..].chars().next().unwrap(); char_len = c.len_utf8(); let pos = BytePos::from_usize(i) + output_offset; diff --git a/compiler/rustc_span/src/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs index fdabf404a37fb..886112769a977 100644 --- a/compiler/rustc_span/src/caching_source_map_view.rs +++ b/compiler/rustc_span/src/caching_source_map_view.rs @@ -165,7 +165,7 @@ impl<'sm> CachingSourceMapView<'sm> { Some(new_file_and_idx) } else { let file = &self.line_cache[oldest].file; - if !file_contains(&file, span_data.hi) { + if !file_contains(file, span_data.hi) { return None; } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 99a8b03fa39ad..038699154c727 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -381,7 +381,7 @@ impl HygieneData { } pub fn with T>(f: F) -> T { - with_session_globals(|session_globals| f(&mut *session_globals.hygiene_data.borrow_mut())) + with_session_globals(|session_globals| f(&mut session_globals.hygiene_data.borrow_mut())) } #[inline] diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 1065cd384a94d..cef4c6f79cefd 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -238,7 +238,7 @@ impl RealFileName { pub fn remapped_path_if_available(&self) -> &Path { match self { RealFileName::LocalPath(p) - | RealFileName::Remapped { local_path: _, virtual_name: p } => &p, + | RealFileName::Remapped { local_path: _, virtual_name: p } => p, } } diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index b3de674159409..f0e91e5a6a917 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -166,5 +166,5 @@ impl SpanInterner { // If an interner exists, return it. Otherwise, prepare a fresh one. #[inline] fn with_span_interner T>(f: F) -> T { - crate::with_session_globals(|session_globals| f(&mut *session_globals.span_interner.lock())) + crate::with_session_globals(|session_globals| f(&mut session_globals.span_interner.lock())) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 663cf65d1a510..9e446c96db319 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1877,7 +1877,7 @@ impl Encodable for Symbol { impl Decodable for Symbol { #[inline] default fn decode(d: &mut D) -> Symbol { - Symbol::intern(&d.read_str()) + Symbol::intern(d.read_str()) } } diff --git a/compiler/rustc_target/src/abi/call/sparc64.rs b/compiler/rustc_target/src/abi/call/sparc64.rs index ec8f20fe69216..c8b6ac5ae25b2 100644 --- a/compiler/rustc_target/src/abi/call/sparc64.rs +++ b/compiler/rustc_target/src/abi/call/sparc64.rs @@ -78,7 +78,7 @@ fn arg_scalar_pair( where C: HasDataLayout, { - data = arg_scalar(cx, &scalar1, offset, data); + data = arg_scalar(cx, scalar1, offset, data); match (scalar1.primitive(), scalar2.primitive()) { (abi::F32, _) => offset += Reg::f32().size, (_, abi::F64) => offset += Reg::f64().size, @@ -90,7 +90,7 @@ where if (offset.bytes() % 4) != 0 && scalar2.primitive().is_float() { offset += Size::from_bytes(4 - (offset.bytes() % 4)); } - data = arg_scalar(cx, &scalar2, offset, data); + data = arg_scalar(cx, scalar2, offset, data); return data; } diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs index 0f6bbc323174c..e72cab629ff19 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs @@ -1,4 +1,4 @@ -use super::apple_base::{macos_link_env_remove, macos_llvm_target, opts, Arch}; +use super::apple_base::{macos_llvm_target, opts, Arch}; use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub fn target() -> Target { @@ -10,8 +10,6 @@ pub fn target() -> Target { // FIXME: The leak sanitizer currently fails the tests, see #88132. base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD; - base.link_env_remove.to_mut().extend(macos_link_env_remove()); - Target { // Clang automatically chooses a more specific target based on // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work diff --git a/compiler/rustc_target/src/spec/apple/tests.rs b/compiler/rustc_target/src/spec/apple/tests.rs index d062b36742d60..3c90a5e7e93ea 100644 --- a/compiler/rustc_target/src/spec/apple/tests.rs +++ b/compiler/rustc_target/src/spec/apple/tests.rs @@ -1,6 +1,6 @@ use crate::spec::{ - aarch64_apple_ios_sim, aarch64_apple_watchos_sim, x86_64_apple_ios, x86_64_apple_tvos, - x86_64_apple_watchos_sim, + aarch64_apple_darwin, aarch64_apple_ios_sim, aarch64_apple_watchos_sim, i686_apple_darwin, + x86_64_apple_darwin, x86_64_apple_ios, x86_64_apple_tvos, x86_64_apple_watchos_sim, }; #[test] @@ -18,3 +18,18 @@ fn simulator_targets_set_abi() { assert_eq!(target.abi, "sim") } } + +#[test] +fn macos_link_environment_unmodified() { + let all_macos_targets = [ + aarch64_apple_darwin::target(), + i686_apple_darwin::target(), + x86_64_apple_darwin::target(), + ]; + + for target in all_macos_targets { + // macOS targets should only remove information for cross-compiling, but never + // for the host. + assert_eq!(target.link_env_remove, crate::spec::cvs!["IPHONEOS_DEPLOYMENT_TARGET"]); + } +} diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs index 23c826cb1bda2..7f8160b5dec62 100644 --- a/compiler/rustc_target/src/spec/apple_base.rs +++ b/compiler/rustc_target/src/spec/apple_base.rs @@ -72,16 +72,6 @@ impl Arch { Arm64_sim => "apple-a12", } } - - fn link_env_remove(self) -> StaticCow<[StaticCow]> { - match self { - Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | I686 | X86_64 | X86_64_sim - | Arm64_sim => { - cvs!["MACOSX_DEPLOYMENT_TARGET"] - } - X86_64_macabi | Arm64_macabi => cvs!["IPHONEOS_DEPLOYMENT_TARGET"], - } - } } fn pre_link_args(os: &'static str, arch: Arch, abi: &'static str) -> LinkArgs { @@ -140,7 +130,7 @@ pub fn opts(os: &'static str, arch: Arch) -> TargetOptions { abi: abi.into(), os: os.into(), cpu: arch.target_cpu().into(), - link_env_remove: arch.link_env_remove(), + link_env_remove: link_env_remove(arch, os), vendor: "apple".into(), linker_flavor: LinkerFlavor::Darwin(Cc::Yes, Lld::No), // macOS has -dead_strip, which doesn't rely on function_sections @@ -211,20 +201,38 @@ pub fn macos_llvm_target(arch: Arch) -> String { format!("{}-apple-macosx{}.{}.0", arch.target_name(), major, minor) } -pub fn macos_link_env_remove() -> Vec> { - let mut env_remove = Vec::with_capacity(2); - // Remove the `SDKROOT` environment variable if it's clearly set for the wrong platform, which - // may occur when we're linking a custom build script while targeting iOS for example. - if let Ok(sdkroot) = env::var("SDKROOT") { - if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("iPhoneSimulator.platform") { - env_remove.push("SDKROOT".into()) +fn link_env_remove(arch: Arch, os: &'static str) -> StaticCow<[StaticCow]> { + // Apple platforms only officially support macOS as a host for any compilation. + // + // If building for macOS, we go ahead and remove any erronous environment state + // that's only applicable to cross-OS compilation. Always leave anything for the + // host OS alone though. + if os == "macos" { + let mut env_remove = Vec::with_capacity(2); + // Remove the `SDKROOT` environment variable if it's clearly set for the wrong platform, which + // may occur when we're linking a custom build script while targeting iOS for example. + if let Ok(sdkroot) = env::var("SDKROOT") { + if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("iPhoneSimulator.platform") + { + env_remove.push("SDKROOT".into()) + } + } + // Additionally, `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at + // "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld", + // although this is apparently ignored when using the linker at "/usr/bin/ld". + env_remove.push("IPHONEOS_DEPLOYMENT_TARGET".into()); + env_remove.into() + } else { + // Otherwise if cross-compiling for a different OS/SDK, remove any part + // of the linking environment that's wrong and reversed. + match arch { + Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | I686 | X86_64 | X86_64_sim + | Arm64_sim => { + cvs!["MACOSX_DEPLOYMENT_TARGET"] + } + X86_64_macabi | Arm64_macabi => cvs!["IPHONEOS_DEPLOYMENT_TARGET"], } } - // Additionally, `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at - // "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld", - // although this is apparently ignored when using the linker at "/usr/bin/ld". - env_remove.push("IPHONEOS_DEPLOYMENT_TARGET".into()); - env_remove } fn ios_deployment_target() -> (u32, u32) { diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs index 8b968af5eccff..ad22467ba9c89 100644 --- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs @@ -1,4 +1,4 @@ -use super::apple_base::{macos_link_env_remove, macos_llvm_target, opts, Arch}; +use super::apple_base::{macos_llvm_target, opts, Arch}; use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions}; pub fn target() -> Target { @@ -7,7 +7,6 @@ pub fn target() -> Target { let mut base = opts("macos", arch); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m32"]); - base.link_env_remove.to_mut().extend(macos_link_env_remove()); base.stack_probes = StackProbeType::X86; base.frame_pointer = FramePointer::Always; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 78315afa75956..d05b8aa420067 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2658,7 +2658,7 @@ impl Target { // Additionally look in the sysroot under `lib/rustlib//target.json` // as a fallback. - let rustlib_path = crate::target_rustlib_path(&sysroot, &target_triple); + let rustlib_path = crate::target_rustlib_path(sysroot, target_triple); let p = PathBuf::from_iter([ Path::new(sysroot), Path::new(&rustlib_path), diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs index c053031612ce5..9a3e7a8050025 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs @@ -1,4 +1,4 @@ -use super::apple_base::{macos_link_env_remove, macos_llvm_target, opts, Arch}; +use super::apple_base::{macos_llvm_target, opts, Arch}; use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet}; use crate::spec::{StackProbeType, Target, TargetOptions}; @@ -8,7 +8,6 @@ pub fn target() -> Target { base.max_atomic_width = Some(128); // core2 supports cmpxchg16b base.frame_pointer = FramePointer::Always; base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m64"]); - base.link_env_remove.to_mut().extend(macos_link_env_remove()); base.stack_probes = StackProbeType::X86; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD; diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 99724fb28db11..899e30275a052 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -11,8 +11,8 @@ use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::util::impl_subject_and_oblig; use crate::traits::SkipLeakCheck; use crate::traits::{ - self, Normalized, Obligation, ObligationCause, ObligationCtxt, PredicateObligation, - PredicateObligations, SelectionContext, + self, Obligation, ObligationCause, ObligationCtxt, PredicateObligation, PredicateObligations, + SelectionContext, }; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::Diagnostic; @@ -30,6 +30,8 @@ use std::fmt::Debug; use std::iter; use std::ops::ControlFlow; +use super::NormalizeExt; + /// Whether we do the orphan check relative to this crate or /// to some remote crate. #[derive(Copy, Clone, Debug)] @@ -128,8 +130,8 @@ fn with_fresh_ty_vars<'cx, 'tcx>( predicates: tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs).predicates, }; - let Normalized { value: mut header, obligations } = - traits::normalize(selcx, param_env, ObligationCause::dummy(), header); + let InferOk { value: mut header, obligations } = + selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(header); header.predicates.extend(obligations.into_iter().map(|o| o.predicate)); header diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 64d01ddb09a49..c028e89e4ea29 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -112,6 +112,24 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { self.register_infer_ok_obligations(infer_ok) } + /// Makes `expected <: actual`. + pub fn eq_exp( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + a_is_expected: bool, + a: T, + b: T, + ) -> Result<(), TypeError<'tcx>> + where + T: ToTrace<'tcx>, + { + self.infcx + .at(cause, param_env) + .eq_exp(a_is_expected, a, b) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + pub fn eq>( &self, cause: &ObligationCause<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 049b24b39975d..3379279dd1544 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -9,7 +9,7 @@ use super::{ }; use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use crate::infer::{self, InferCtxt, TyCtxtInferExt}; +use crate::infer::{self, InferCtxt}; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::query::normalize::QueryNormalizeExt as _; use crate::traits::specialize::to_pretty_impl_header; @@ -71,7 +71,7 @@ pub trait InferCtxtExt<'tcx> { /// returns a span and `ArgKind` information that describes the /// arguments it expects. This can be supplied to /// `report_arg_count_mismatch`. - fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec)>; + fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option, Vec)>; /// Reports an error when the number of arguments needed by a /// trait match doesn't match the number that the expression @@ -83,6 +83,7 @@ pub trait InferCtxtExt<'tcx> { expected_args: Vec, found_args: Vec, is_closure: bool, + closure_pipe_span: Option, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce` @@ -135,15 +136,16 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { /// returns a span and `ArgKind` information that describes the /// arguments it expects. This can be supplied to /// `report_arg_count_mismatch`. - fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec)> { + fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option, Vec)> { let sm = self.tcx.sess.source_map(); let hir = self.tcx.hir(); Some(match node { Node::Expr(&hir::Expr { - kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }), + kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, fn_arg_span, .. }), .. }) => ( fn_decl_span, + fn_arg_span, hir.body(body) .params .iter() @@ -174,6 +176,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { kind: hir::TraitItemKind::Fn(ref sig, _), .. }) => ( sig.span, + None, sig.decl .inputs .iter() @@ -188,7 +191,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { ), Node::Ctor(ref variant_data) => { let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id)); - (span, vec![ArgKind::empty(); variant_data.fields().len()]) + (span, None, vec![ArgKind::empty(); variant_data.fields().len()]) } _ => panic!("non-FnLike node found: {:?}", node), }) @@ -204,6 +207,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { expected_args: Vec, found_args: Vec, is_closure: bool, + closure_arg_span: Option, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let kind = if is_closure { "closure" } else { "function" }; @@ -241,24 +245,13 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { if let Some(found_span) = found_span { err.span_label(found_span, format!("takes {}", found_str)); - // move |_| { ... } - // ^^^^^^^^-- def_span - // - // move |_| { ... } - // ^^^^^-- prefix - let prefix_span = self.tcx.sess.source_map().span_until_non_whitespace(found_span); - // move |_| { ... } - // ^^^-- pipe_span - let pipe_span = - if let Some(span) = found_span.trim_start(prefix_span) { span } else { found_span }; - // Suggest to take and ignore the arguments with expected_args_length `_`s if // found arguments is empty (assume the user just wants to ignore args in this case). // For example, if `expected_args_length` is 2, suggest `|_, _|`. if found_args.is_empty() && is_closure { let underscores = vec!["_"; expected_args.len()].join(", "); err.span_suggestion_verbose( - pipe_span, + closure_arg_span.unwrap_or(found_span), &format!( "consider changing the closure to take and ignore the expected argument{}", pluralize!(expected_args.len()) @@ -1252,13 +1245,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { obligation.cause.code(), ) } else { - let (closure_span, found) = found_did + let (closure_span, closure_arg_span, found) = found_did .and_then(|did| { let node = self.tcx.hir().get_if_local(did)?; - let (found_span, found) = self.get_fn_like_arguments(node)?; - Some((Some(found_span), found)) + let (found_span, closure_arg_span, found) = + self.get_fn_like_arguments(node)?; + Some((Some(found_span), closure_arg_span, found)) }) - .unwrap_or((found_span, found)); + .unwrap_or((found_span, None, found)); self.report_arg_count_mismatch( span, @@ -1266,6 +1260,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { expected, found, found_trait_ty.is_closure(), + closure_arg_span, ) } } @@ -1577,32 +1572,26 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } self.probe(|_| { - let mut err = error.err; - let mut values = None; + let ocx = ObligationCtxt::new_in_snapshot(self); // try to find the mismatched types to report the error with. // // this can fail if the problem was higher-ranked, in which // cause I have no idea for a good error message. let bound_predicate = predicate.kind(); - if let ty::PredicateKind::Clause(ty::Clause::Projection(data)) = + let (values, err) = if let ty::PredicateKind::Clause(ty::Clause::Projection(data)) = bound_predicate.skip_binder() { - let mut selcx = SelectionContext::new(self); let data = self.replace_bound_vars_with_fresh_vars( obligation.cause.span, infer::LateBoundRegionConversionTime::HigherRankedType, bound_predicate.rebind(data), ); - let mut obligations = vec![]; - // FIXME(normalization): Change this to use `At::normalize` - let normalized_ty = super::normalize_projection_type( - &mut selcx, + let normalized_ty = ocx.normalize( + &obligation.cause, obligation.param_env, - data.projection_ty, - obligation.cause.clone(), - 0, - &mut obligations, + self.tcx + .mk_projection(data.projection_ty.item_def_id, data.projection_ty.substs), ); debug!(?obligation.cause, ?obligation.param_env); @@ -1618,19 +1607,34 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::ObjectCastObligation(..) | ObligationCauseCode::OpaqueType ); - if let Err(new_err) = self.at(&obligation.cause, obligation.param_env).eq_exp( + let expected_ty = data.term.ty().unwrap(); + + // constrain inference variables a bit more to nested obligations from normalize so + // we can have more helpful errors. + ocx.select_where_possible(); + + if let Err(new_err) = ocx.eq_exp( + &obligation.cause, + obligation.param_env, is_normalized_ty_expected, normalized_ty, - data.term, + expected_ty, ) { - values = Some((data, is_normalized_ty_expected, normalized_ty, data.term)); - err = new_err; + (Some((data, is_normalized_ty_expected, normalized_ty, expected_ty)), new_err) + } else { + (None, error.err) } - } + } else { + (None, error.err) + }; let msg = values .and_then(|(predicate, _, normalized_ty, expected_ty)| { - self.maybe_detailed_projection_msg(predicate, normalized_ty, expected_ty) + self.maybe_detailed_projection_msg( + predicate, + normalized_ty.into(), + expected_ty.into(), + ) }) .unwrap_or_else(|| format!("type mismatch resolving `{}`", predicate)); let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}"); @@ -1672,11 +1676,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { &mut diag, &obligation.cause, secondary_span, - values.map(|(_, is_normalized_ty_expected, normalized_ty, term)| { + values.map(|(_, is_normalized_ty_expected, normalized_ty, expected_ty)| { infer::ValuePairs::Terms(ExpectedFound::new( is_normalized_ty_expected, - normalized_ty, - term, + normalized_ty.into(), + expected_ty.into(), )) }), err, @@ -1930,14 +1934,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { return report(normalized_impl_candidates, err); } - let normalize = |candidate| { - let infcx = self.tcx.infer_ctxt().build(); - infcx - .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) - .query_normalize(candidate) - .map_or(candidate, |normalized| normalized.value) - }; - // Sort impl candidates so that ordering is consistent for UI tests. // because the ordering of `impl_candidates` may not be deterministic: // https://github.com/rust-lang/rust/pull/57475#issuecomment-455519507 @@ -1947,7 +1943,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut normalized_impl_candidates_and_similarities = impl_candidates .into_iter() .map(|ImplCandidate { trait_ref, similarity }| { - let normalized = normalize(trait_ref); + // FIXME(compiler-errors): This should be using `NormalizeExt::normalize` + let normalized = self + .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) + .query_normalize(trait_ref) + .map_or(trait_ref, |normalized| normalized.value); (similarity, normalized) }) .collect::>(); diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 371367f0deb3e..c6818a4e57d42 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -56,7 +56,6 @@ pub use self::object_safety::astconv_object_safety_violations; pub use self::object_safety::is_vtable_safe_method; pub use self::object_safety::MethodViolationCode; pub use self::object_safety::ObjectSafetyViolation; -pub(crate) use self::project::{normalize, normalize_to}; pub use self::project::{normalize_projection_type, NormalizeExt}; pub use self::select::{EvaluationCache, SelectionCache, SelectionContext}; pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError}; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 113803cd1790a..051660be9c474 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -50,6 +50,10 @@ pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::ProjectionTy<'tcx>> pub(super) struct InProgress; pub trait NormalizeExt<'tcx> { + /// Normalize a value using the `AssocTypeNormalizer`. + /// + /// This normalization should be used when the type contains inference variables or the + /// projection may be fallible. fn normalize>(&self, t: T) -> InferOk<'tcx, T>; } @@ -57,7 +61,7 @@ impl<'tcx> NormalizeExt<'tcx> for At<'_, 'tcx> { fn normalize>(&self, value: T) -> InferOk<'tcx, T> { let mut selcx = SelectionContext::new(self.infcx); let Normalized { value, obligations } = - normalize(&mut selcx, self.param_env, self.cause.clone(), value); + normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value); InferOk { value, obligations } } } @@ -303,37 +307,6 @@ fn project_and_unify_type<'cx, 'tcx>( } } -/// Normalizes any associated type projections in `value`, replacing -/// them with a fully resolved type where possible. The return value -/// combines the normalized result and any additional obligations that -/// were incurred as result. -pub(crate) fn normalize<'a, 'b, 'tcx, T>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - value: T, -) -> Normalized<'tcx, T> -where - T: TypeFoldable<'tcx>, -{ - let mut obligations = Vec::new(); - let value = normalize_to(selcx, param_env, cause, value, &mut obligations); - Normalized { value, obligations } -} - -pub(crate) fn normalize_to<'a, 'b, 'tcx, T>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - value: T, - obligations: &mut Vec>, -) -> T -where - T: TypeFoldable<'tcx>, -{ - normalize_with_depth_to(selcx, param_env, cause, 0, value, obligations) -} - /// As `normalize`, but with a custom depth. pub(crate) fn normalize_with_depth<'a, 'b, 'tcx, T>( selcx: &'a mut SelectionContext<'b, 'tcx>, @@ -2324,10 +2297,11 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( }, )); - let ty = super::normalize_to( + let ty = normalize_with_depth_to( selcx, obligation.param_env, cause.clone(), + obligation.recursion_depth + 1, tcx.bound_trait_impl_trait_tys(impl_fn_def_id) .map_bound(|tys| { tys.map_or_else(|_| tcx.ty_error(), |tys| tys[&obligation.predicate.item_def_id]) diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 1aed66308709e..f899321fc01e1 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -23,6 +23,13 @@ use super::NoSolution; pub use rustc_middle::traits::query::NormalizationResult; pub trait QueryNormalizeExt<'tcx> { + /// Normalize a value using the `QueryNormalizer`. + /// + /// This normalization should *only* be used when the projection does not + /// have possible ambiguity or may not be well-formed. + /// + /// After codegen, when lifetimes do not matter, it is preferable to instead + /// use [`TyCtxt::normalize_erasing_regions`], which wraps this procedure. fn query_normalize(&self, value: T) -> Result, NoSolution> where T: TypeFoldable<'tcx>; diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index fe5135661b5f8..e4b70f0d2ffa7 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -203,7 +203,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // type/region parameters. let self_ty = obligation.self_ty().skip_binder(); match self_ty.kind() { - ty::Generator(..) => { + // async constructs get lowered to a special kind of generator that + // should *not* `impl Generator`. + ty::Generator(did, ..) if !self.tcx().generator_is_async(*did) => { debug!(?self_ty, ?obligation, "assemble_generator_candidates",); candidates.vec.push(GeneratorCandidate); @@ -223,6 +225,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) { let self_ty = obligation.self_ty().skip_binder(); if let ty::Generator(did, ..) = self_ty.kind() { + // async constructs get lowered to a special kind of generator that + // should directly `impl Future`. if self.tcx().generator_is_async(*did) { debug!(?self_ty, ?obligation, "assemble_future_candidates",); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 515f3a3498886..8835f2cc1b97a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -371,23 +371,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if !candidate_set.ambiguous && no_candidates_apply { let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; - let self_ty = trait_ref.self_ty(); - let (trait_desc, self_desc) = with_no_trimmed_paths!({ - let trait_desc = trait_ref.print_only_trait_path().to_string(); - let self_desc = if self_ty.has_concrete_skeleton() { - Some(self_ty.to_string()) + if !trait_ref.references_error() { + let self_ty = trait_ref.self_ty(); + let (trait_desc, self_desc) = with_no_trimmed_paths!({ + let trait_desc = trait_ref.print_only_trait_path().to_string(); + let self_desc = if self_ty.has_concrete_skeleton() { + Some(self_ty.to_string()) + } else { + None + }; + (trait_desc, self_desc) + }); + let cause = if let Conflict::Upstream = conflict { + IntercrateAmbiguityCause::UpstreamCrateUpdate { + trait_desc, + self_desc, + } } else { - None + IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } }; - (trait_desc, self_desc) - }); - let cause = if let Conflict::Upstream = conflict { - IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } - } else { - IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } - }; - debug!(?cause, "evaluate_stack: pushing cause"); - self.intercrate_ambiguity_causes.as_mut().unwrap().insert(cause); + debug!(?cause, "evaluate_stack: pushing cause"); + self.intercrate_ambiguity_causes.as_mut().unwrap().insert(cause); + } } } } diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index ee8032ad6f0f7..4866c53e7d521 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -2699,12 +2699,18 @@ impl IndexMut for VecDeque { #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator for VecDeque { + #[inline] fn from_iter>(iter: I) -> VecDeque { - let iterator = iter.into_iter(); - let (lower, _) = iterator.size_hint(); - let mut deq = VecDeque::with_capacity(lower); - deq.extend(iterator); - deq + // Since converting is O(1) now, might as well re-use that logic + // (including things like the `vec::IntoIter`→`Vec` specialization) + // especially as that could save us some monomorphiziation work + // if one uses the same iterators (like slice ones) with both. + return from_iter_via_vec(iter.into_iter()); + + #[inline] + fn from_iter_via_vec(iter: impl Iterator) -> VecDeque { + Vec::from_iter(iter).into() + } } } @@ -2791,6 +2797,7 @@ impl From> for VecDeque { /// In its current implementation, this is a very cheap /// conversion. This isn't yet a guarantee though, and /// shouldn't be relied on. + #[inline] fn from(other: Vec) -> Self { let (ptr, len, cap, alloc) = other.into_raw_parts_with_alloc(); Self { head: 0, len, buf: unsafe { RawVec::from_raw_parts_in(ptr, cap, alloc) } } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index e147af2ce39c6..ba34ab6800fad 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1070,7 +1070,8 @@ impl Vec { /// Converts the vector into [`Box<[T]>`][owned slice]. /// - /// Note that this will drop any excess capacity. + /// If the vector has excess capacity, its items will be moved into a + /// newly-allocated buffer with exactly the right capacity. /// /// [owned slice]: Box /// @@ -3223,6 +3224,14 @@ impl From> for Box<[T], A> { /// ``` /// assert_eq!(Box::from(vec![1, 2, 3]), vec![1, 2, 3].into_boxed_slice()); /// ``` + /// + /// Any excess capacity is removed: + /// ``` + /// let mut vec = Vec::with_capacity(10); + /// vec.extend([1, 2, 3]); + /// + /// assert_eq!(Box::from(vec), vec![1, 2, 3].into_boxed_slice()); + /// ``` fn from(v: Vec) -> Self { v.into_boxed_slice() } diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 141cbc7669b0b..6a339b338d990 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1249,12 +1249,11 @@ macro_rules! nonzero_bits { /// # Examples /// /// ``` - /// #![feature(nonzero_bits)] #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// #[doc = concat!("assert_eq!(", stringify!($Ty), "::BITS, ", stringify!($Int), "::BITS);")] /// ``` - #[unstable(feature = "nonzero_bits", issue = "94881")] + #[stable(feature = "nonzero_bits", since = "CURRENT_RUSTC_VERSION")] pub const BITS: u32 = <$Int>::BITS; } )+ diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 4fd1eb234137f..a704a00faaafa 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -38,10 +38,9 @@ use crate::panic::{Location, PanicInfo}; /// site as much as possible (so that `panic!()` has as low an impact /// on (e.g.) the inlining of other functions as possible), by moving /// the actual formatting into this shared place. -#[cold] // If panic_immediate_abort, inline the abort call, // otherwise avoid inlining because of it is cold path. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] #[lang = "panic_fmt"] // needed for const-evaluated panics @@ -67,8 +66,7 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { /// Like panic_fmt, but without unwinding and track_caller to reduce the impact on codesize. /// Also just works on `str`, as a `fmt::Arguments` needs more space to be passed. -#[cold] -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[rustc_nounwind] pub fn panic_str_nounwind(msg: &'static str) -> ! { @@ -96,10 +94,9 @@ pub fn panic_str_nounwind(msg: &'static str) -> ! { // above. /// The underlying implementation of libcore's `panic!` macro when no formatting is used. -#[cold] // never inline unless panic_immediate_abort to avoid code // bloat at the call sites as much as possible -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] #[rustc_const_unstable(feature = "core_panic", issue = "none")] @@ -138,8 +135,8 @@ pub const fn panic_display(x: &T) -> ! { panic_fmt(format_args!("{}", *x)); } -#[cold] -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] +#[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] #[lang = "panic_bounds_check"] // needed by codegen for panic on OOB array/slice access fn panic_bounds_check(index: usize, len: usize) -> ! { @@ -154,8 +151,8 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { /// /// This function is called directly by the codegen backend, and must not have /// any extra arguments (including those synthesized by track_caller). -#[cold] -#[inline(never)] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] +#[cfg_attr(feature = "panic_immediate_abort", inline)] #[lang = "panic_no_unwind"] // needed by codegen for panic in nounwind function #[rustc_nounwind] fn panic_no_unwind() -> ! { @@ -185,7 +182,8 @@ pub enum AssertKind { } /// Internal function for `assert_eq!` and `assert_ne!` macros -#[cold] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] +#[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] #[doc(hidden)] pub fn assert_failed( @@ -202,7 +200,8 @@ where } /// Internal function for `assert_match!` -#[cold] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] +#[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] #[doc(hidden)] pub fn assert_matches_failed( @@ -221,6 +220,8 @@ pub fn assert_matches_failed( } /// Non-generic version of the above functions, to avoid code bloat. +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] +#[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] fn assert_failed_inner( kind: AssertKind, diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 6d2f7330d5db5..c295a0e06458d 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -31,9 +31,8 @@ where } } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] -#[cold] #[track_caller] #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] const fn slice_start_index_len_fail(index: usize, len: usize) -> ! { @@ -48,19 +47,20 @@ const fn slice_start_index_len_fail(index: usize, len: usize) -> ! { } // FIXME const-hack +#[inline] #[track_caller] fn slice_start_index_len_fail_rt(index: usize, len: usize) -> ! { panic!("range start index {index} out of range for slice of length {len}"); } +#[inline] #[track_caller] const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! { panic!("slice start index is out of range for slice"); } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] -#[cold] #[track_caller] #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] const fn slice_end_index_len_fail(index: usize, len: usize) -> ! { @@ -71,19 +71,20 @@ const fn slice_end_index_len_fail(index: usize, len: usize) -> ! { } // FIXME const-hack +#[inline] #[track_caller] fn slice_end_index_len_fail_rt(index: usize, len: usize) -> ! { panic!("range end index {index} out of range for slice of length {len}"); } +#[inline] #[track_caller] const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! { panic!("slice end index is out of range for slice"); } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] -#[cold] #[track_caller] #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] const fn slice_index_order_fail(index: usize, end: usize) -> ! { @@ -92,27 +93,27 @@ const fn slice_index_order_fail(index: usize, end: usize) -> ! { } // FIXME const-hack +#[inline] #[track_caller] fn slice_index_order_fail_rt(index: usize, end: usize) -> ! { panic!("slice index starts at {index} but ends at {end}"); } +#[inline] #[track_caller] const fn slice_index_order_fail_ct(_: usize, _: usize) -> ! { panic!("slice index start is larger than end"); } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] -#[cold] #[track_caller] const fn slice_start_index_overflow_fail() -> ! { panic!("attempted to index slice from after maximum usize"); } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] -#[cold] #[track_caller] const fn slice_end_index_overflow_fail() -> ! { panic!("attempted to index slice up to maximum usize"); diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 0660e03c1a821..f357d505fe89c 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -510,8 +510,9 @@ impl File { /// # Errors /// /// This function will return an error if the file is not opened for writing. - /// Also, std::io::ErrorKind::InvalidInput will be returned if the desired - /// length would cause an overflow due to the implementation specifics. + /// Also, [`std::io::ErrorKind::InvalidInput`](crate::io::ErrorKind::InvalidInput) + /// will be returned if the desired length would cause an overflow due to + /// the implementation specifics. /// /// # Examples /// diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index d4976a469cc15..1039835bbbdfe 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -594,8 +594,8 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! { // lang item for CTFE panic support // never inline unless panic_immediate_abort to avoid code // bloat at the call sites as much as possible -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] -#[cold] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] +#[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] #[rustc_do_not_const_check] // hooked by const-eval pub const fn begin_panic(msg: M) -> ! { diff --git a/library/test/src/cli.rs b/library/test/src/cli.rs index 8be32183fe780..524658bce139d 100644 --- a/library/test/src/cli.rs +++ b/library/test/src/cli.rs @@ -26,6 +26,10 @@ pub struct TestOpts { pub test_threads: Option, pub skip: Vec, pub time_options: Option, + /// Stop at first failing test. + /// May run a few more tests due to threading, but will + /// abort as soon as possible. + pub fail_fast: bool, pub options: Options, } @@ -296,6 +300,7 @@ fn parse_opts_impl(matches: getopts::Matches) -> OptRes { skip, time_options, options, + fail_fast: false, }; Ok(test_opts) diff --git a/library/test/src/console.rs b/library/test/src/console.rs index 8cb88016b23ad..a3c39f71f08b8 100644 --- a/library/test/src/console.rs +++ b/library/test/src/console.rs @@ -293,7 +293,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec) -> io::Resu run_tests(opts, tests, |x| on_test_event(&x, &mut st, &mut *out))?; st.exec_time = start_time.map(|t| TestSuiteExecTime(t.elapsed())); - assert!(st.current_test_count() == st.total); + assert!(opts.fail_fast || st.current_test_count() == st.total); out.write_run_finish(&st) } diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 27320e8dbc5ad..256c9e8d141e0 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -384,8 +384,17 @@ where let mut completed_test = rx.recv().unwrap(); RunningTest { join_handle }.join(&mut completed_test); + let fail_fast = match completed_test.result { + TrIgnored | TrOk | TrBench(_) => false, + TrFailed | TrFailedMsg(_) | TrTimedFail => opts.fail_fast, + }; + let event = TestEvent::TeResult(completed_test); notify_about_test_event(event)?; + + if fail_fast { + return Ok(()); + } } } else { while pending > 0 || !remaining.is_empty() { @@ -431,9 +440,20 @@ where let running_test = running_tests.remove(&completed_test.id).unwrap(); running_test.join(&mut completed_test); + let fail_fast = match completed_test.result { + TrIgnored | TrOk | TrBench(_) => false, + TrFailed | TrFailedMsg(_) | TrTimedFail => opts.fail_fast, + }; + let event = TestEvent::TeResult(completed_test); notify_about_test_event(event)?; pending -= 1; + + if fail_fast { + // Prevent remaining test threads from panicking + std::mem::forget(rx); + return Ok(()); + } } } diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs index 7b2e6707f9d11..3a0260f86cf5d 100644 --- a/library/test/src/tests.rs +++ b/library/test/src/tests.rs @@ -51,6 +51,7 @@ impl TestOpts { skip: vec![], time_options: None, options: Options::new(), + fail_fast: false, } } } diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index fe8a028dfd3ad..efe8ae3169fc2 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -11,15 +11,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -108,18 +99,18 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cpufeatures" -version = "0.2.2" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" dependencies = [ "libc", ] [[package]] name = "crossbeam-channel" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" dependencies = [ "cfg-if", "crossbeam-utils", @@ -127,9 +118,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -138,26 +129,24 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.8" +version = "0.9.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "lazy_static", "memoffset", "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.8" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" dependencies = [ "cfg-if", - "lazy_static", ] [[package]] @@ -379,9 +368,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" -version = "0.6.5" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" dependencies = [ "autocfg", ] @@ -447,14 +436,14 @@ checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" [[package]] name = "pretty_assertions" -version = "0.7.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cab0e7c02cf376875e9335e0ba1da535775beb5450d21e1dffca068818ed98b" +checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" dependencies = [ - "ansi_term", "ctor", "diff", "output_vt100", + "yansi", ] [[package]] @@ -477,11 +466,10 @@ dependencies = [ [[package]] name = "rayon" -version = "1.5.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" +checksum = "1e060280438193c554f654141c9ea9417886713b7acd75974c85b18a69a88e0b" dependencies = [ - "autocfg", "crossbeam-deque", "either", "rayon-core", @@ -489,9 +477,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.9.3" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" +checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -803,3 +791,9 @@ checksum = "c179869f34fc7c01830d3ce7ea2086bc3a07e0d35289b667d0a8bf910258926c" dependencies = [ "lzma-sys", ] + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 8751a71caf1b4..ccc7ec1fce9f0 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -72,7 +72,7 @@ features = [ ] [dev-dependencies] -pretty_assertions = "0.7" +pretty_assertions = "1.2" [features] build-metrics = ["sysinfo"] diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index a3d1893afbb65..d69bced0b28db 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -647,10 +647,23 @@ impl Build { if !update(true).status().map_or(false, |status| status.success()) { self.run(&mut update(false)); } - self.run(Command::new("git").args(&["stash", "push"]).current_dir(&absolute_path)); + + // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error). + let has_local_modifications = !self.try_run( + Command::new("git") + .args(&["diff-index", "--quiet", "HEAD"]) + .current_dir(&absolute_path), + ); + if has_local_modifications { + self.run(Command::new("git").args(&["stash", "push"]).current_dir(&absolute_path)); + } + self.run(Command::new("git").args(&["reset", "-q", "--hard"]).current_dir(&absolute_path)); self.run(Command::new("git").args(&["clean", "-qdfx"]).current_dir(&absolute_path)); - self.run(Command::new("git").args(&["stash", "pop"]).current_dir(absolute_path)); + + if has_local_modifications { + self.run(Command::new("git").args(&["stash", "pop"]).current_dir(absolute_path)); + } } /// If any submodule has been initialized already, sync it unconditionally. diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 10de2e8d5eaa8..75e44fe49874a 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -77,7 +77,7 @@ x--expand-yaml-anchors--remove: <<: *base-job - &job-macos-xl - os: macos-latest # We don't have an XL builder for this + os: macos-12-xl <<: *base-job - &job-windows-xl diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 1e7b4fe15b68c..0271c27b4f522 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -32,7 +32,7 @@ features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] rayon = "1.5.1" [dev-dependencies] -expect-test = "1.0" +expect-test = "1.4.0" [features] jemalloc = [] diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 80909919ba2b6..2a2a9470d25c0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -12,7 +12,7 @@ pub(crate) mod utils; use rustc_ast as ast; use rustc_attr as attr; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, IndexEntry}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; @@ -598,47 +598,105 @@ pub(crate) fn clean_generics<'tcx>( }) .collect::>(); + let mut bound_predicates = FxIndexMap::default(); + let mut region_predicates = FxIndexMap::default(); + let mut eq_predicates = ThinVec::default(); + for pred in gens.predicates.iter().filter_map(|x| clean_where_predicate(x, cx)) { + match pred { + WherePredicate::BoundPredicate { ty, bounds, bound_params } => { + match bound_predicates.entry(ty) { + IndexEntry::Vacant(v) => { + v.insert((bounds, bound_params)); + } + IndexEntry::Occupied(mut o) => { + // we merge both bounds. + for bound in bounds { + if !o.get().0.contains(&bound) { + o.get_mut().0.push(bound); + } + } + for bound_param in bound_params { + if !o.get().1.contains(&bound_param) { + o.get_mut().1.push(bound_param); + } + } + } + } + } + WherePredicate::RegionPredicate { lifetime, bounds } => { + match region_predicates.entry(lifetime) { + IndexEntry::Vacant(v) => { + v.insert(bounds); + } + IndexEntry::Occupied(mut o) => { + // we merge both bounds. + for bound in bounds { + if !o.get().contains(&bound) { + o.get_mut().push(bound); + } + } + } + } + } + WherePredicate::EqPredicate { lhs, rhs, bound_params } => { + eq_predicates.push(WherePredicate::EqPredicate { lhs, rhs, bound_params }); + } + } + } + let mut params = ThinVec::with_capacity(gens.params.len()); + // In this loop, we gather the generic parameters (`<'a, B: 'a>`) and check if they have + // bounds in the where predicates. If so, we move their bounds into the where predicates + // while also preventing duplicates. for p in gens.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) { - let p = clean_generic_param(cx, Some(gens), p); + let mut p = clean_generic_param(cx, Some(gens), p); + match &mut p.kind { + GenericParamDefKind::Lifetime { ref mut outlives } => { + if let Some(region_pred) = region_predicates.get_mut(&Lifetime(p.name)) { + // We merge bounds in the `where` clause. + for outlive in outlives.drain(..) { + let outlive = GenericBound::Outlives(outlive); + if !region_pred.contains(&outlive) { + region_pred.push(outlive); + } + } + } + } + GenericParamDefKind::Type { bounds, synthetic: false, .. } => { + if let Some(bound_pred) = bound_predicates.get_mut(&Type::Generic(p.name)) { + // We merge bounds in the `where` clause. + for bound in bounds.drain(..) { + if !bound_pred.0.contains(&bound) { + bound_pred.0.push(bound); + } + } + } + } + GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { + // nothing to do here. + } + } params.push(p); } params.extend(impl_trait_params); - let mut generics = Generics { + Generics { params, - where_predicates: gens - .predicates - .iter() - .filter_map(|x| clean_where_predicate(x, cx)) + where_predicates: bound_predicates + .into_iter() + .map(|(ty, (bounds, bound_params))| WherePredicate::BoundPredicate { + ty, + bounds, + bound_params, + }) + .chain( + region_predicates + .into_iter() + .map(|(lifetime, bounds)| WherePredicate::RegionPredicate { lifetime, bounds }), + ) + .chain(eq_predicates.into_iter()) .collect(), - }; - - // Some duplicates are generated for ?Sized bounds between type params and where - // predicates. The point in here is to move the bounds definitions from type params - // to where predicates when such cases occur. - for where_pred in &mut generics.where_predicates { - match *where_pred { - WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds, .. } => { - if bounds.is_empty() { - for param in &mut generics.params { - match param.kind { - GenericParamDefKind::Lifetime { .. } => {} - GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => { - if ¶m.name == name { - mem::swap(bounds, ty_bounds); - break; - } - } - GenericParamDefKind::Const { .. } => {} - } - } - } - } - _ => continue, - } } - generics } fn clean_ty_generics<'tcx>( diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 6bff2cd2f1aa0..f44797fe55f17 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -908,6 +908,7 @@ so that we can apply CSS-filters to change the arrow color in themes */ .popover { position: absolute; + top: 100%; right: 0; z-index: 2; display: block; @@ -1357,22 +1358,24 @@ a.test-arrow:hover { } #settings-menu, #help-button { margin-left: 4px; - outline: none; + display: flex; } #settings-menu > a, #help-button > a, #copy-path { width: 33px; - line-height: 1.5; } #settings-menu > a, #help-button > a { - padding: 5px; - height: 100%; - display: block; + display: flex; + align-items: center; + justify-content: center; background-color: var(--button-background-color); border: 1px solid var(--border-color); border-radius: 2px; color: var(--settings-button-color); + /* Rare exception to specifying font sizes in rem. Since this is acting + as an icon, it's okay to specify their sizes in pixels. */ + font-size: 20px; } #settings-menu > a:hover, #settings-menu > a:focus, @@ -1408,14 +1411,6 @@ a.test-arrow:hover { animation: rotating 2s linear infinite; } -#help-button > a { - text-align: center; - /* Rare exception to specifying font sizes in rem. Since this is acting - as an icon, it's okay to specify their sizes in pixels. */ - font-size: 20px; - padding-top: 2px; -} - kbd { display: inline-block; padding: 3px 5px; @@ -1590,17 +1585,11 @@ details.rustdoc-toggle[open] > summary.hideme > span { display: none; } -details.rustdoc-toggle[open] > summary::before, -details.rustdoc-toggle[open] > summary.hideme::before { +details.rustdoc-toggle[open] > summary::before { background: url("toggle-minus-31bbd6e4c77f5c96.svg") no-repeat top left; - width: 16px; - height: 16px; - display: inline-block; - content: ""; } -details.rustdoc-toggle[open] > summary::after, -details.rustdoc-toggle[open] > summary.hideme::after { +details.rustdoc-toggle[open] > summary::after { content: "Collapse"; } @@ -1658,10 +1647,6 @@ in storage.js content: "Since "; } - #copy-path { - display: none; - } - /* Hide the logo and item name from the sidebar. Those are displayed in the mobile-topbar instead. */ .sidebar .sidebar-logo, @@ -1795,8 +1780,8 @@ in storage.js border-bottom: 1px solid; } - /* We don't display the help button on mobile devices. */ - #help-button { + /* We don't display these buttons on mobile devices. */ + #copy-path, #help-button { display: none; } diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 83be1a16eb2c4..1196f944faad2 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -99,53 +99,6 @@ impl<'tcx> JsonRenderer<'tcx> { }) .unwrap_or_default() } - - fn get_trait_items(&mut self) -> Vec<(types::Id, types::Item)> { - debug!("Adding foreign trait items"); - Rc::clone(&self.cache) - .traits - .iter() - .filter_map(|(&id, trait_item)| { - // only need to synthesize items for external traits - if !id.is_local() { - for item in &trait_item.items { - trace!("Adding subitem to {id:?}: {:?}", item.item_id); - self.item(item.clone()).unwrap(); - } - let item_id = from_item_id(id.into(), self.tcx); - Some(( - item_id.clone(), - types::Item { - id: item_id, - crate_id: id.krate.as_u32(), - name: self - .cache - .paths - .get(&id) - .unwrap_or_else(|| { - self.cache - .external_paths - .get(&id) - .expect("Trait should either be in local or external paths") - }) - .0 - .last() - .map(|s| s.to_string()), - visibility: types::Visibility::Public, - inner: types::ItemEnum::Trait(trait_item.clone().into_tcx(self.tcx)), - span: None, - docs: Default::default(), - links: Default::default(), - attrs: Default::default(), - deprecation: Default::default(), - }, - )) - } else { - None - } - }) - .collect() - } } impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { @@ -276,11 +229,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { let e = ExternalCrate { crate_num: LOCAL_CRATE }; - // FIXME(adotinthevoid): Remove this, as it's not consistent with not - // inlining foreign items. - let foreign_trait_items = self.get_trait_items(); - let mut index = (*self.index).clone().into_inner(); - index.extend(foreign_trait_items); + let index = (*self.index).clone().into_inner(); debug!("Constructing Output"); // This needs to be the default HashMap for compatibility with the public interface for diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 1a84ec650474d..6d34f484754c7 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -781,10 +781,7 @@ fn main_args(at_args: &[String]) -> MainResult { let sess = compiler.session(); if sess.opts.describe_lints { - let mut lint_store = rustc_lint::new_lint_store( - sess.opts.unstable_opts.no_interleave_lints, - sess.enable_internal_lints(), - ); + let mut lint_store = rustc_lint::new_lint_store(sess.enable_internal_lints()); let registered_lints = if let Some(register_lints) = compiler.register_lints() { register_lints(sess, &mut lint_store); true diff --git a/src/librustdoc/passes/bare_urls.rs b/src/librustdoc/passes/bare_urls.rs deleted file mode 100644 index 7ff3ccef945c2..0000000000000 --- a/src/librustdoc/passes/bare_urls.rs +++ /dev/null @@ -1,110 +0,0 @@ -//! Detects links that are not linkified, e.g., in Markdown such as `Go to https://example.com/.` -//! Suggests wrapping the link with angle brackets: `Go to .` to linkify it. -use super::Pass; -use crate::clean::*; -use crate::core::DocContext; -use crate::html::markdown::main_body_opts; -use crate::visit::DocVisitor; -use core::ops::Range; -use pulldown_cmark::{Event, Parser, Tag}; -use regex::Regex; -use rustc_errors::Applicability; -use std::mem; -use std::sync::LazyLock; - -pub(crate) const CHECK_BARE_URLS: Pass = Pass { - name: "check-bare-urls", - run: check_bare_urls, - description: "detects URLs that are not hyperlinks", -}; - -static URL_REGEX: LazyLock = LazyLock::new(|| { - Regex::new(concat!( - r"https?://", // url scheme - r"([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)+", // one or more subdomains - r"[a-zA-Z]{2,63}", // root domain - r"\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)" // optional query or url fragments - )) - .expect("failed to build regex") -}); - -struct BareUrlsLinter<'a, 'tcx> { - cx: &'a mut DocContext<'tcx>, -} - -impl<'a, 'tcx> BareUrlsLinter<'a, 'tcx> { - fn find_raw_urls( - &self, - text: &str, - range: Range, - f: &impl Fn(&DocContext<'_>, &str, &str, Range), - ) { - trace!("looking for raw urls in {}", text); - // For now, we only check "full" URLs (meaning, starting with "http://" or "https://"). - for match_ in URL_REGEX.find_iter(text) { - let url = match_.as_str(); - let url_range = match_.range(); - f( - self.cx, - "this URL is not a hyperlink", - url, - Range { start: range.start + url_range.start, end: range.start + url_range.end }, - ); - } - } -} - -pub(crate) fn check_bare_urls(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - BareUrlsLinter { cx }.visit_crate(&krate); - krate -} - -impl<'a, 'tcx> DocVisitor for BareUrlsLinter<'a, 'tcx> { - fn visit_item(&mut self, item: &Item) { - let Some(hir_id) = DocContext::as_local_hir_id(self.cx.tcx, item.item_id) - else { - // If non-local, no need to check anything. - return; - }; - let dox = item.attrs.collapsed_doc_value().unwrap_or_default(); - if !dox.is_empty() { - let report_diag = |cx: &DocContext<'_>, msg: &str, url: &str, range: Range| { - let sp = super::source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs) - .unwrap_or_else(|| item.attr_span(cx.tcx)); - cx.tcx.struct_span_lint_hir(crate::lint::BARE_URLS, hir_id, sp, msg, |lint| { - lint.note("bare URLs are not automatically turned into clickable links") - .span_suggestion( - sp, - "use an automatic link instead", - format!("<{}>", url), - Applicability::MachineApplicable, - ) - }); - }; - - let mut p = Parser::new_ext(&dox, main_body_opts()).into_offset_iter(); - - while let Some((event, range)) = p.next() { - match event { - Event::Text(s) => self.find_raw_urls(&s, range, &report_diag), - // We don't want to check the text inside code blocks or links. - Event::Start(tag @ (Tag::CodeBlock(_) | Tag::Link(..))) => { - while let Some((event, _)) = p.next() { - match event { - Event::End(end) - if mem::discriminant(&end) == mem::discriminant(&tag) => - { - break; - } - _ => {} - } - } - } - _ => {} - } - } - } - - self.visit_item_recur(item) - } -} diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs deleted file mode 100644 index 2e651b5387419..0000000000000 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ /dev/null @@ -1,209 +0,0 @@ -//! Validates syntax inside Rust code blocks (\`\`\`rust). -use rustc_data_structures::sync::{Lock, Lrc}; -use rustc_errors::{ - emitter::Emitter, - translation::{to_fluent_args, Translate}, - Applicability, Diagnostic, Handler, LazyFallbackBundle, -}; -use rustc_parse::parse_stream_from_source_str; -use rustc_session::parse::ParseSess; -use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId}; -use rustc_span::source_map::{FilePathMapping, SourceMap}; -use rustc_span::{FileName, InnerSpan, DUMMY_SP}; - -use crate::clean; -use crate::core::DocContext; -use crate::html::markdown::{self, RustCodeBlock}; -use crate::passes::Pass; -use crate::visit::DocVisitor; - -pub(crate) const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass { - name: "check-code-block-syntax", - run: check_code_block_syntax, - description: "validates syntax inside Rust code blocks", -}; - -pub(crate) fn check_code_block_syntax( - krate: clean::Crate, - cx: &mut DocContext<'_>, -) -> clean::Crate { - SyntaxChecker { cx }.visit_crate(&krate); - krate -} - -struct SyntaxChecker<'a, 'tcx> { - cx: &'a DocContext<'tcx>, -} - -impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { - fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeBlock) { - let buffer = Lrc::new(Lock::new(Buffer::default())); - let fallback_bundle = - rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false); - let emitter = BufferEmitter { buffer: Lrc::clone(&buffer), fallback_bundle }; - - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let handler = Handler::with_emitter(false, None, Box::new(emitter)); - let source = dox[code_block.code].to_owned(); - let sess = ParseSess::with_span_handler(handler, sm); - - let edition = code_block.lang_string.edition.unwrap_or_else(|| self.cx.tcx.sess.edition()); - let expn_data = ExpnData::default( - ExpnKind::AstPass(AstPass::TestHarness), - DUMMY_SP, - edition, - None, - None, - ); - let expn_id = - self.cx.tcx.with_stable_hashing_context(|hcx| LocalExpnId::fresh(expn_data, hcx)); - let span = DUMMY_SP.fresh_expansion(expn_id); - - let is_empty = rustc_driver::catch_fatal_errors(|| { - parse_stream_from_source_str( - FileName::Custom(String::from("doctest")), - source, - &sess, - Some(span), - ) - .is_empty() - }) - .unwrap_or(false); - let buffer = buffer.borrow(); - - if !buffer.has_errors && !is_empty { - // No errors in a non-empty program. - return; - } - - let Some(local_id) = item.item_id.as_def_id().and_then(|x| x.as_local()) - else { - // We don't need to check the syntax for other crates so returning - // without doing anything should not be a problem. - return; - }; - - let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_id); - let empty_block = code_block.lang_string == Default::default() && code_block.is_fenced; - let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None; - - // The span and whether it is precise or not. - let (sp, precise_span) = match super::source_span_for_markdown_range( - self.cx.tcx, - dox, - &code_block.range, - &item.attrs, - ) { - Some(sp) => (sp, true), - None => (item.attr_span(self.cx.tcx), false), - }; - - let msg = if buffer.has_errors { - "could not parse code block as Rust code" - } else { - "Rust code block is empty" - }; - - // Finally build and emit the completed diagnostic. - // All points of divergence have been handled earlier so this can be - // done the same way whether the span is precise or not. - self.cx.tcx.struct_span_lint_hir( - crate::lint::INVALID_RUST_CODEBLOCKS, - hir_id, - sp, - msg, - |lint| { - let explanation = if is_ignore { - "`ignore` code blocks require valid Rust code for syntax highlighting; \ - mark blocks that do not contain Rust code as text" - } else { - "mark blocks that do not contain Rust code as text" - }; - - if precise_span { - if is_ignore { - // giving an accurate suggestion is hard because `ignore` might not have come first in the list. - // just give a `help` instead. - lint.span_help( - sp.from_inner(InnerSpan::new(0, 3)), - &format!("{}: ```text", explanation), - ); - } else if empty_block { - lint.span_suggestion( - sp.from_inner(InnerSpan::new(0, 3)).shrink_to_hi(), - explanation, - "text", - Applicability::MachineApplicable, - ); - } - } else if empty_block || is_ignore { - lint.help(&format!("{}: ```text", explanation)); - } - - // FIXME(#67563): Provide more context for these errors by displaying the spans inline. - for message in buffer.messages.iter() { - lint.note(message); - } - - lint - }, - ); - } -} - -impl<'a, 'tcx> DocVisitor for SyntaxChecker<'a, 'tcx> { - fn visit_item(&mut self, item: &clean::Item) { - if let Some(dox) = &item.attrs.collapsed_doc_value() { - let sp = item.attr_span(self.cx.tcx); - let extra = crate::html::markdown::ExtraInfo::new_did( - self.cx.tcx, - item.item_id.expect_def_id(), - sp, - ); - for code_block in markdown::rust_code_blocks(dox, &extra) { - self.check_rust_syntax(item, dox, code_block); - } - } - - self.visit_item_recur(item) - } -} - -#[derive(Default)] -struct Buffer { - messages: Vec, - has_errors: bool, -} - -struct BufferEmitter { - buffer: Lrc>, - fallback_bundle: LazyFallbackBundle, -} - -impl Translate for BufferEmitter { - fn fluent_bundle(&self) -> Option<&Lrc> { - None - } - - fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle { - &**self.fallback_bundle - } -} - -impl Emitter for BufferEmitter { - fn emit_diagnostic(&mut self, diag: &Diagnostic) { - let mut buffer = self.buffer.borrow_mut(); - - let fluent_args = to_fluent_args(diag.args()); - let translated_main_message = self.translate_message(&diag.message[0].0, &fluent_args); - - buffer.messages.push(format!("error from rustc: {}", translated_main_message)); - if diag.is_error() { - buffer.has_errors = true; - } - } - - fn source_map(&self) -> Option<&Lrc> { - None - } -} diff --git a/src/librustdoc/passes/lint.rs b/src/librustdoc/passes/lint.rs new file mode 100644 index 0000000000000..97031c4f028f4 --- /dev/null +++ b/src/librustdoc/passes/lint.rs @@ -0,0 +1,33 @@ +//! Runs several rustdoc lints, consolidating them into a single pass for +//! efficiency and simplicity. + +mod bare_urls; +mod check_code_block_syntax; +mod html_tags; + +use super::Pass; +use crate::clean::*; +use crate::core::DocContext; +use crate::visit::DocVisitor; + +pub(crate) const RUN_LINTS: Pass = + Pass { name: "run-lints", run: run_lints, description: "runs some of rustdoc's lints" }; + +struct Linter<'a, 'tcx> { + cx: &'a mut DocContext<'tcx>, +} + +pub(crate) fn run_lints(krate: Crate, cx: &mut DocContext<'_>) -> Crate { + Linter { cx }.visit_crate(&krate); + krate +} + +impl<'a, 'tcx> DocVisitor for Linter<'a, 'tcx> { + fn visit_item(&mut self, item: &Item) { + bare_urls::visit_item(self.cx, item); + check_code_block_syntax::visit_item(self.cx, item); + html_tags::visit_item(self.cx, item); + + self.visit_item_recur(item) + } +} diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs new file mode 100644 index 0000000000000..423230cfe381e --- /dev/null +++ b/src/librustdoc/passes/lint/bare_urls.rs @@ -0,0 +1,89 @@ +//! Detects links that are not linkified, e.g., in Markdown such as `Go to https://example.com/.` +//! Suggests wrapping the link with angle brackets: `Go to .` to linkify it. + +use crate::clean::*; +use crate::core::DocContext; +use crate::html::markdown::main_body_opts; +use crate::passes::source_span_for_markdown_range; +use core::ops::Range; +use pulldown_cmark::{Event, Parser, Tag}; +use regex::Regex; +use rustc_errors::Applicability; +use std::mem; +use std::sync::LazyLock; + +pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item) { + let Some(hir_id) = DocContext::as_local_hir_id(cx.tcx, item.item_id) + else { + // If non-local, no need to check anything. + return; + }; + let dox = item.attrs.collapsed_doc_value().unwrap_or_default(); + if !dox.is_empty() { + let report_diag = |cx: &DocContext<'_>, msg: &str, url: &str, range: Range| { + let sp = source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs) + .unwrap_or_else(|| item.attr_span(cx.tcx)); + cx.tcx.struct_span_lint_hir(crate::lint::BARE_URLS, hir_id, sp, msg, |lint| { + lint.note("bare URLs are not automatically turned into clickable links") + .span_suggestion( + sp, + "use an automatic link instead", + format!("<{}>", url), + Applicability::MachineApplicable, + ) + }); + }; + + let mut p = Parser::new_ext(&dox, main_body_opts()).into_offset_iter(); + + while let Some((event, range)) = p.next() { + match event { + Event::Text(s) => find_raw_urls(cx, &s, range, &report_diag), + // We don't want to check the text inside code blocks or links. + Event::Start(tag @ (Tag::CodeBlock(_) | Tag::Link(..))) => { + while let Some((event, _)) = p.next() { + match event { + Event::End(end) + if mem::discriminant(&end) == mem::discriminant(&tag) => + { + break; + } + _ => {} + } + } + } + _ => {} + } + } + } +} + +static URL_REGEX: LazyLock = LazyLock::new(|| { + Regex::new(concat!( + r"https?://", // url scheme + r"([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)+", // one or more subdomains + r"[a-zA-Z]{2,63}", // root domain + r"\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)" // optional query or url fragments + )) + .expect("failed to build regex") +}); + +fn find_raw_urls( + cx: &DocContext<'_>, + text: &str, + range: Range, + f: &impl Fn(&DocContext<'_>, &str, &str, Range), +) { + trace!("looking for raw urls in {}", text); + // For now, we only check "full" URLs (meaning, starting with "http://" or "https://"). + for match_ in URL_REGEX.find_iter(text) { + let url = match_.as_str(); + let url_range = match_.range(); + f( + cx, + "this URL is not a hyperlink", + url, + Range { start: range.start + url_range.start, end: range.start + url_range.end }, + ); + } +} diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs new file mode 100644 index 0000000000000..5aa4f238b2d14 --- /dev/null +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -0,0 +1,170 @@ +//! Validates syntax inside Rust code blocks (\`\`\`rust). +use rustc_data_structures::sync::{Lock, Lrc}; +use rustc_errors::{ + emitter::Emitter, + translation::{to_fluent_args, Translate}, + Applicability, Diagnostic, Handler, LazyFallbackBundle, +}; +use rustc_parse::parse_stream_from_source_str; +use rustc_session::parse::ParseSess; +use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId}; +use rustc_span::source_map::{FilePathMapping, SourceMap}; +use rustc_span::{FileName, InnerSpan, DUMMY_SP}; + +use crate::clean; +use crate::core::DocContext; +use crate::html::markdown::{self, RustCodeBlock}; +use crate::passes::source_span_for_markdown_range; + +pub(crate) fn visit_item(cx: &DocContext<'_>, item: &clean::Item) { + if let Some(dox) = &item.attrs.collapsed_doc_value() { + let sp = item.attr_span(cx.tcx); + let extra = + crate::html::markdown::ExtraInfo::new_did(cx.tcx, item.item_id.expect_def_id(), sp); + for code_block in markdown::rust_code_blocks(dox, &extra) { + check_rust_syntax(cx, item, dox, code_block); + } + } +} + +fn check_rust_syntax( + cx: &DocContext<'_>, + item: &clean::Item, + dox: &str, + code_block: RustCodeBlock, +) { + let buffer = Lrc::new(Lock::new(Buffer::default())); + let fallback_bundle = + rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false); + let emitter = BufferEmitter { buffer: Lrc::clone(&buffer), fallback_bundle }; + + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let handler = Handler::with_emitter(false, None, Box::new(emitter)); + let source = dox[code_block.code].to_owned(); + let sess = ParseSess::with_span_handler(handler, sm); + + let edition = code_block.lang_string.edition.unwrap_or_else(|| cx.tcx.sess.edition()); + let expn_data = + ExpnData::default(ExpnKind::AstPass(AstPass::TestHarness), DUMMY_SP, edition, None, None); + let expn_id = cx.tcx.with_stable_hashing_context(|hcx| LocalExpnId::fresh(expn_data, hcx)); + let span = DUMMY_SP.fresh_expansion(expn_id); + + let is_empty = rustc_driver::catch_fatal_errors(|| { + parse_stream_from_source_str( + FileName::Custom(String::from("doctest")), + source, + &sess, + Some(span), + ) + .is_empty() + }) + .unwrap_or(false); + let buffer = buffer.borrow(); + + if !buffer.has_errors && !is_empty { + // No errors in a non-empty program. + return; + } + + let Some(local_id) = item.item_id.as_def_id().and_then(|x| x.as_local()) + else { + // We don't need to check the syntax for other crates so returning + // without doing anything should not be a problem. + return; + }; + + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id); + let empty_block = code_block.lang_string == Default::default() && code_block.is_fenced; + let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None; + + // The span and whether it is precise or not. + let (sp, precise_span) = + match source_span_for_markdown_range(cx.tcx, dox, &code_block.range, &item.attrs) { + Some(sp) => (sp, true), + None => (item.attr_span(cx.tcx), false), + }; + + let msg = if buffer.has_errors { + "could not parse code block as Rust code" + } else { + "Rust code block is empty" + }; + + // Finally build and emit the completed diagnostic. + // All points of divergence have been handled earlier so this can be + // done the same way whether the span is precise or not. + cx.tcx.struct_span_lint_hir(crate::lint::INVALID_RUST_CODEBLOCKS, hir_id, sp, msg, |lint| { + let explanation = if is_ignore { + "`ignore` code blocks require valid Rust code for syntax highlighting; \ + mark blocks that do not contain Rust code as text" + } else { + "mark blocks that do not contain Rust code as text" + }; + + if precise_span { + if is_ignore { + // giving an accurate suggestion is hard because `ignore` might not have come first in the list. + // just give a `help` instead. + lint.span_help( + sp.from_inner(InnerSpan::new(0, 3)), + &format!("{}: ```text", explanation), + ); + } else if empty_block { + lint.span_suggestion( + sp.from_inner(InnerSpan::new(0, 3)).shrink_to_hi(), + explanation, + "text", + Applicability::MachineApplicable, + ); + } + } else if empty_block || is_ignore { + lint.help(&format!("{}: ```text", explanation)); + } + + // FIXME(#67563): Provide more context for these errors by displaying the spans inline. + for message in buffer.messages.iter() { + lint.note(message); + } + + lint + }); +} + +#[derive(Default)] +struct Buffer { + messages: Vec, + has_errors: bool, +} + +struct BufferEmitter { + buffer: Lrc>, + fallback_bundle: LazyFallbackBundle, +} + +impl Translate for BufferEmitter { + fn fluent_bundle(&self) -> Option<&Lrc> { + None + } + + fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle { + &**self.fallback_bundle + } +} + +impl Emitter for BufferEmitter { + fn emit_diagnostic(&mut self, diag: &Diagnostic) { + let mut buffer = self.buffer.borrow_mut(); + + let fluent_args = to_fluent_args(diag.args()); + let translated_main_message = self.translate_message(&diag.message[0].0, &fluent_args); + + buffer.messages.push(format!("error from rustc: {}", translated_main_message)); + if diag.is_error() { + buffer.has_errors = true; + } + } + + fn source_map(&self) -> Option<&Lrc> { + None + } +} diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs similarity index 58% rename from src/librustdoc/passes/html_tags.rs rename to src/librustdoc/passes/lint/html_tags.rs index a89ed7c7ed454..070c0aab5868b 100644 --- a/src/librustdoc/passes/html_tags.rs +++ b/src/librustdoc/passes/lint/html_tags.rs @@ -1,9 +1,8 @@ //! Detects invalid HTML (like an unclosed ``) in doc comments. -use super::Pass; use crate::clean::*; use crate::core::DocContext; use crate::html::markdown::main_body_opts; -use crate::visit::DocVisitor; +use crate::passes::source_span_for_markdown_range; use pulldown_cmark::{BrokenLink, Event, LinkType, Parser, Tag}; @@ -11,20 +10,150 @@ use std::iter::Peekable; use std::ops::Range; use std::str::CharIndices; -pub(crate) const CHECK_INVALID_HTML_TAGS: Pass = Pass { - name: "check-invalid-html-tags", - run: check_invalid_html_tags, - description: "detects invalid HTML tags in doc comments", -}; +pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { + let tcx = cx.tcx; + let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id) + // If non-local, no need to check anything. + else { return }; + let dox = item.attrs.collapsed_doc_value().unwrap_or_default(); + if !dox.is_empty() { + let report_diag = |msg: &str, range: &Range, is_open_tag: bool| { + let sp = match source_span_for_markdown_range(tcx, &dox, range, &item.attrs) { + Some(sp) => sp, + None => item.attr_span(tcx), + }; + tcx.struct_span_lint_hir(crate::lint::INVALID_HTML_TAGS, hir_id, sp, msg, |lint| { + use rustc_lint_defs::Applicability; + // If a tag looks like ``, it might actually be a generic. + // We don't try to detect stuff `` because that's not valid HTML, + // and we don't try to detect stuff `` because that's not valid Rust. + let mut generics_end = range.end; + if let Some(Some(mut generics_start)) = (is_open_tag + && dox[..generics_end].ends_with('>')) + .then(|| extract_path_backwards(&dox, range.start)) + { + while generics_start != 0 + && generics_end < dox.len() + && dox.as_bytes()[generics_start - 1] == b'<' + && dox.as_bytes()[generics_end] == b'>' + { + generics_end += 1; + generics_start -= 1; + if let Some(new_start) = extract_path_backwards(&dox, generics_start) { + generics_start = new_start; + } + if let Some(new_end) = extract_path_forward(&dox, generics_end) { + generics_end = new_end; + } + } + if let Some(new_end) = extract_path_forward(&dox, generics_end) { + generics_end = new_end; + } + let generics_sp = match source_span_for_markdown_range( + tcx, + &dox, + &(generics_start..generics_end), + &item.attrs, + ) { + Some(sp) => sp, + None => item.attr_span(tcx), + }; + // Sometimes, we only extract part of a path. For example, consider this: + // + // <[u32] as IntoIter>::Item + // ^^^^^ unclosed HTML tag `u32` + // + // We don't have any code for parsing fully-qualified trait paths. + // In theory, we could add it, but doing it correctly would require + // parsing the entire path grammar, which is problematic because of + // overlap between the path grammar and Markdown. + // + // The example above shows that ambiguity. Is `[u32]` intended to be an + // intra-doc link to the u32 primitive, or is it intended to be a slice? + // + // If the below conditional were removed, we would suggest this, which is + // not what the user probably wants. + // + // <[u32] as `IntoIter`>::Item + // + // We know that the user actually wants to wrap the whole thing in a code + // block, but the only reason we know that is because `u32` does not, in + // fact, implement IntoIter. If the example looks like this: + // + // <[Vec] as IntoIter::Item + // + // The ideal fix would be significantly different. + if (generics_start > 0 && dox.as_bytes()[generics_start - 1] == b'<') + || (generics_end < dox.len() && dox.as_bytes()[generics_end] == b'>') + { + return lint; + } + // multipart form is chosen here because ``Vec`` would be confusing. + lint.multipart_suggestion( + "try marking as source code", + vec![ + (generics_sp.shrink_to_lo(), String::from("`")), + (generics_sp.shrink_to_hi(), String::from("`")), + ], + Applicability::MaybeIncorrect, + ); + } -struct InvalidHtmlTagsLinter<'a, 'tcx> { - cx: &'a mut DocContext<'tcx>, -} + lint + }); + }; + + let mut tags = Vec::new(); + let mut is_in_comment = None; + let mut in_code_block = false; + + let link_names = item.link_names(&cx.cache); -pub(crate) fn check_invalid_html_tags(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - let mut coll = InvalidHtmlTagsLinter { cx }; - coll.visit_crate(&krate); - krate + let mut replacer = |broken_link: BrokenLink<'_>| { + if let Some(link) = + link_names.iter().find(|link| *link.original_text == *broken_link.reference) + { + Some((link.href.as_str().into(), link.new_text.as_str().into())) + } else if matches!( + &broken_link.link_type, + LinkType::Reference | LinkType::ReferenceUnknown + ) { + // If the link is shaped [like][this], suppress any broken HTML in the [this] part. + // The `broken_intra_doc_links` will report typos in there anyway. + Some(( + broken_link.reference.to_string().into(), + broken_link.reference.to_string().into(), + )) + } else { + None + } + }; + + let p = Parser::new_with_broken_link_callback(&dox, main_body_opts(), Some(&mut replacer)) + .into_offset_iter(); + + for (event, range) in p { + match event { + Event::Start(Tag::CodeBlock(_)) => in_code_block = true, + Event::Html(text) if !in_code_block => { + extract_tags(&mut tags, &text, range, &mut is_in_comment, &report_diag) + } + Event::End(Tag::CodeBlock(_)) => in_code_block = false, + _ => {} + } + } + + for (tag, range) in tags.iter().filter(|(t, _)| { + let t = t.to_lowercase(); + !ALLOWED_UNCLOSED.contains(&t.as_str()) + }) { + report_diag(&format!("unclosed HTML tag `{}`", tag), range, true); + } + + if let Some(range) = is_in_comment { + report_diag("Unclosed HTML comment", &range, false); + } + } } const ALLOWED_UNCLOSED: &[&str] = &[ @@ -276,155 +405,3 @@ fn extract_tags( } } } - -impl<'a, 'tcx> DocVisitor for InvalidHtmlTagsLinter<'a, 'tcx> { - fn visit_item(&mut self, item: &Item) { - let tcx = self.cx.tcx; - let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id) - // If non-local, no need to check anything. - else { return }; - let dox = item.attrs.collapsed_doc_value().unwrap_or_default(); - if !dox.is_empty() { - let report_diag = |msg: &str, range: &Range, is_open_tag: bool| { - let sp = match super::source_span_for_markdown_range(tcx, &dox, range, &item.attrs) - { - Some(sp) => sp, - None => item.attr_span(tcx), - }; - tcx.struct_span_lint_hir(crate::lint::INVALID_HTML_TAGS, hir_id, sp, msg, |lint| { - use rustc_lint_defs::Applicability; - // If a tag looks like ``, it might actually be a generic. - // We don't try to detect stuff `` because that's not valid HTML, - // and we don't try to detect stuff `` because that's not valid Rust. - let mut generics_end = range.end; - if let Some(Some(mut generics_start)) = (is_open_tag - && dox[..generics_end].ends_with('>')) - .then(|| extract_path_backwards(&dox, range.start)) - { - while generics_start != 0 - && generics_end < dox.len() - && dox.as_bytes()[generics_start - 1] == b'<' - && dox.as_bytes()[generics_end] == b'>' - { - generics_end += 1; - generics_start -= 1; - if let Some(new_start) = extract_path_backwards(&dox, generics_start) { - generics_start = new_start; - } - if let Some(new_end) = extract_path_forward(&dox, generics_end) { - generics_end = new_end; - } - } - if let Some(new_end) = extract_path_forward(&dox, generics_end) { - generics_end = new_end; - } - let generics_sp = match super::source_span_for_markdown_range( - tcx, - &dox, - &(generics_start..generics_end), - &item.attrs, - ) { - Some(sp) => sp, - None => item.attr_span(tcx), - }; - // Sometimes, we only extract part of a path. For example, consider this: - // - // <[u32] as IntoIter>::Item - // ^^^^^ unclosed HTML tag `u32` - // - // We don't have any code for parsing fully-qualified trait paths. - // In theory, we could add it, but doing it correctly would require - // parsing the entire path grammar, which is problematic because of - // overlap between the path grammar and Markdown. - // - // The example above shows that ambiguity. Is `[u32]` intended to be an - // intra-doc link to the u32 primitive, or is it intended to be a slice? - // - // If the below conditional were removed, we would suggest this, which is - // not what the user probably wants. - // - // <[u32] as `IntoIter`>::Item - // - // We know that the user actually wants to wrap the whole thing in a code - // block, but the only reason we know that is because `u32` does not, in - // fact, implement IntoIter. If the example looks like this: - // - // <[Vec] as IntoIter::Item - // - // The ideal fix would be significantly different. - if (generics_start > 0 && dox.as_bytes()[generics_start - 1] == b'<') - || (generics_end < dox.len() && dox.as_bytes()[generics_end] == b'>') - { - return lint; - } - // multipart form is chosen here because ``Vec`` would be confusing. - lint.multipart_suggestion( - "try marking as source code", - vec![ - (generics_sp.shrink_to_lo(), String::from("`")), - (generics_sp.shrink_to_hi(), String::from("`")), - ], - Applicability::MaybeIncorrect, - ); - } - - lint - }); - }; - - let mut tags = Vec::new(); - let mut is_in_comment = None; - let mut in_code_block = false; - - let link_names = item.link_names(&self.cx.cache); - - let mut replacer = |broken_link: BrokenLink<'_>| { - if let Some(link) = - link_names.iter().find(|link| *link.original_text == *broken_link.reference) - { - Some((link.href.as_str().into(), link.new_text.as_str().into())) - } else if matches!( - &broken_link.link_type, - LinkType::Reference | LinkType::ReferenceUnknown - ) { - // If the link is shaped [like][this], suppress any broken HTML in the [this] part. - // The `broken_intra_doc_links` will report typos in there anyway. - Some(( - broken_link.reference.to_string().into(), - broken_link.reference.to_string().into(), - )) - } else { - None - } - }; - - let p = - Parser::new_with_broken_link_callback(&dox, main_body_opts(), Some(&mut replacer)) - .into_offset_iter(); - - for (event, range) in p { - match event { - Event::Start(Tag::CodeBlock(_)) => in_code_block = true, - Event::Html(text) if !in_code_block => { - extract_tags(&mut tags, &text, range, &mut is_in_comment, &report_diag) - } - Event::End(Tag::CodeBlock(_)) => in_code_block = false, - _ => {} - } - } - - for (tag, range) in tags.iter().filter(|(t, _)| { - let t = t.to_lowercase(); - !ALLOWED_UNCLOSED.contains(&t.as_str()) - }) { - report_diag(&format!("unclosed HTML tag `{}`", tag), range, true); - } - - if let Some(range) = is_in_comment { - report_diag("Unclosed HTML comment", &range, false); - } - } - - self.visit_item_recur(item) - } -} diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index f81b38ea39574..634e70ec97a0d 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -12,9 +12,6 @@ use crate::core::DocContext; mod stripper; pub(crate) use stripper::*; -mod bare_urls; -pub(crate) use self::bare_urls::CHECK_BARE_URLS; - mod strip_hidden; pub(crate) use self::strip_hidden::STRIP_HIDDEN; @@ -36,14 +33,11 @@ pub(crate) use self::check_doc_test_visibility::CHECK_DOC_TEST_VISIBILITY; mod collect_trait_impls; pub(crate) use self::collect_trait_impls::COLLECT_TRAIT_IMPLS; -mod check_code_block_syntax; -pub(crate) use self::check_code_block_syntax::CHECK_CODE_BLOCK_SYNTAX; - mod calculate_doc_coverage; pub(crate) use self::calculate_doc_coverage::CALCULATE_DOC_COVERAGE; -mod html_tags; -pub(crate) use self::html_tags::CHECK_INVALID_HTML_TAGS; +mod lint; +pub(crate) use self::lint::RUN_LINTS; /// A single pass over the cleaned documentation. /// @@ -82,11 +76,9 @@ pub(crate) const PASSES: &[Pass] = &[ STRIP_PRIV_IMPORTS, PROPAGATE_DOC_CFG, COLLECT_INTRA_DOC_LINKS, - CHECK_CODE_BLOCK_SYNTAX, COLLECT_TRAIT_IMPLS, CALCULATE_DOC_COVERAGE, - CHECK_INVALID_HTML_TAGS, - CHECK_BARE_URLS, + RUN_LINTS, ]; /// The list of passes run by default. @@ -97,10 +89,8 @@ pub(crate) const DEFAULT_PASSES: &[ConditionalPass] = &[ ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate), ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate), ConditionalPass::always(COLLECT_INTRA_DOC_LINKS), - ConditionalPass::always(CHECK_CODE_BLOCK_SYNTAX), - ConditionalPass::always(CHECK_INVALID_HTML_TAGS), ConditionalPass::always(PROPAGATE_DOC_CFG), - ConditionalPass::always(CHECK_BARE_URLS), + ConditionalPass::always(RUN_LINTS), ]; /// The list of default passes run when `--doc-coverage` is passed to rustdoc. diff --git a/src/test/assembly/asm/aarch64-el2vmsa.rs b/src/test/assembly/asm/aarch64-el2vmsa.rs new file mode 100644 index 0000000000000..1908ffb8ff3f0 --- /dev/null +++ b/src/test/assembly/asm/aarch64-el2vmsa.rs @@ -0,0 +1,37 @@ +// assembly-output: emit-asm +// compile-flags: --target aarch64-unknown-linux-gnu +// needs-llvm-components: aarch64 + +#![feature(no_core, lang_items, rustc_attrs)] +#![crate_type = "rlib"] +#![no_core] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} + +#[lang = "sized"] +trait Sized {} + +// CHECK-LABEL: ttbr0_el2: +#[no_mangle] +pub fn ttbr0_el2() { + // CHECK: //APP + // CHECK-NEXT: msr TTBR0_EL2, x0 + // CHECK-NEXT: //NO_APP + unsafe { + asm!("msr ttbr0_el2, x0"); + } +} + +// CHECK-LABEL: vttbr_el2: +#[no_mangle] +pub fn vttbr_el2() { + // CHECK: //APP + // CHECK-NEXT: msr VTTBR_EL2, x0 + // CHECK-NEXT: //NO_APP + unsafe { + asm!("msr vttbr_el2, x0"); + } +} diff --git a/src/test/assembly/sparc-struct-abi.rs b/src/test/assembly/sparc-struct-abi.rs index 6a898b2974a65..6309dd420ffa4 100644 --- a/src/test/assembly/sparc-struct-abi.rs +++ b/src/test/assembly/sparc-struct-abi.rs @@ -44,12 +44,16 @@ pub unsafe extern "C" fn callee(arg: Franta) { tst_use(arg.b); tst_use(arg.c); tst_use(arg.d); + tail_call_avoidance_fn(); } extern "C" { fn opaque_callee(arg: Franta, intarg: i32); fn tst_use(arg: f32); fn clobber(); + // This exists so that post-https://reviews.llvm.org/D138741 LLVM doesn't + // tail-call away some of our assertions. + fn tail_call_avoidance_fn(); } #[no_mangle] @@ -62,4 +66,5 @@ pub unsafe extern "C" fn caller() { // CHECK: call opaque_callee // CHECK: mov 3, %o2 opaque_callee(Franta { a: 1.0, b: 2.0, c: 3.0, d: 4.0 }, 3); + tail_call_avoidance_fn(); } diff --git a/src/test/codegen/enum-match.rs b/src/test/codegen/enum-match.rs index efab189fd7b8f..44f1b408d21b8 100644 --- a/src/test/codegen/enum-match.rs +++ b/src/test/codegen/enum-match.rs @@ -34,11 +34,8 @@ pub enum Enum1 { // CHECK: define i8 @match1{{.*}} // CHECK-NEXT: start: -// CHECK-NEXT: %1 = icmp ugt i8 %0, 1 -// CHECK-NEXT: %2 = zext i8 %0 to i64 -// CHECK-NEXT: %3 = add nsw i64 %2, -1 -// CHECK-NEXT: %_2 = select i1 %1, i64 %3, i64 0 -// CHECK-NEXT: switch i64 %_2, label {{.*}} [ +// CHECK-NEXT: %1 = {{.*}}call i8 @llvm.usub.sat.i8(i8 %0, i8 1) +// CHECK-NEXT: switch i8 %1, label {{.*}} [ #[no_mangle] pub fn match1(e: Enum1) -> u8 { use Enum1::*; diff --git a/src/test/codegen/naked-nocoverage.rs b/src/test/codegen/naked-nocoverage.rs new file mode 100644 index 0000000000000..91a6260bf2aa2 --- /dev/null +++ b/src/test/codegen/naked-nocoverage.rs @@ -0,0 +1,19 @@ +// Checks that naked functions are not instrumented by -Cinstrument-coverage. +// Regression test for issue #105170. +// +// needs-asm-support +// needs-profiler-support +// compile-flags: -Cinstrument-coverage +#![crate_type = "lib"] +#![feature(naked_functions)] +use std::arch::asm; + +#[naked] +#[no_mangle] +pub unsafe extern "C" fn f() { + // CHECK: define void @f() + // CHECK-NEXT: start: + // CHECK-NEXT: call void asm + // CHECK-NEXT: unreachable + asm!("", options(noreturn)); +} diff --git a/src/test/run-make/macos-deployment-target/Makefile b/src/test/run-make/macos-deployment-target/Makefile new file mode 100644 index 0000000000000..70fca04365378 --- /dev/null +++ b/src/test/run-make/macos-deployment-target/Makefile @@ -0,0 +1,21 @@ +# only-macos +# +# Check that a set deployment target actually makes it to the linker. +# This is important since its a compatibility hazard. The linker will +# generate load commands differently based on what minimum OS it can assume. + +include ../../run-make-fulldeps/tools.mk + +ifeq ($(strip $(shell uname -m)),arm64) + GREP_PATTERN = "minos 11.0" +else + GREP_PATTERN = "version 10.9" +endif + +OUT_FILE=$(TMPDIR)/with_deployment_target.dylib +all: + env MACOSX_DEPLOYMENT_TARGET=10.9 $(RUSTC) with_deployment_target.rs -o $(OUT_FILE) +# XXX: The check is for either the x86_64 minimum OR the aarch64 minimum (M1 starts at macOS 11). +# They also use different load commands, so we let that change with each too. The aarch64 check +# isn't as robust as the x86 one, but testing both seems unneeded. + vtool -show-build $(OUT_FILE) | $(CGREP) -e $(GREP_PATTERN) diff --git a/src/test/run-make/macos-deployment-target/with_deployment_target.rs b/src/test/run-make/macos-deployment-target/with_deployment_target.rs new file mode 100644 index 0000000000000..342fe0ecbcfcd --- /dev/null +++ b/src/test/run-make/macos-deployment-target/with_deployment_target.rs @@ -0,0 +1,4 @@ +#![crate_type = "cdylib"] + +#[allow(dead_code)] +fn something_and_nothing() {} diff --git a/src/test/rustdoc-json/intra-doc-links/auxiliary/enum_variant_in_trait_method.rs b/src/test/rustdoc-json/intra-doc-links/auxiliary/enum_variant_in_trait_method.rs new file mode 100644 index 0000000000000..bfe85f59e8179 --- /dev/null +++ b/src/test/rustdoc-json/intra-doc-links/auxiliary/enum_variant_in_trait_method.rs @@ -0,0 +1,8 @@ +pub trait Trait { + /// [`Enum::Variant`] + fn method() {} +} + +pub enum Enum { + Variant, +} diff --git a/src/test/rustdoc-json/intra-doc-links/foreign_variant.rs b/src/test/rustdoc-json/intra-doc-links/foreign_variant.rs new file mode 100644 index 0000000000000..e296823133868 --- /dev/null +++ b/src/test/rustdoc-json/intra-doc-links/foreign_variant.rs @@ -0,0 +1,13 @@ +// Regression test for +// aux-build: enum_variant_in_trait_method.rs + +extern crate enum_variant_in_trait_method; + +pub struct Local; + +/// local impl +impl enum_variant_in_trait_method::Trait for Local {} + +// @!has "$.index[*][?(@.name == 'Trait')]" +// @!has "$.index[*][?(@.name == 'method')]" +// @count "$.index[*][?(@.docs == 'local impl')].inner.items[*]" 0 diff --git a/src/test/rustdoc-json/reexport/auxiliary/trait_with_docs.rs b/src/test/rustdoc-json/reexport/auxiliary/trait_with_docs.rs new file mode 100644 index 0000000000000..1e87966b28aea --- /dev/null +++ b/src/test/rustdoc-json/reexport/auxiliary/trait_with_docs.rs @@ -0,0 +1,2 @@ +/// The Docs +pub trait HasDocs {} diff --git a/src/test/rustdoc-json/reexport/synthesize_trait_with_docs.rs b/src/test/rustdoc-json/reexport/synthesize_trait_with_docs.rs new file mode 100644 index 0000000000000..25a7c08d68922 --- /dev/null +++ b/src/test/rustdoc-json/reexport/synthesize_trait_with_docs.rs @@ -0,0 +1,10 @@ +// Regression test for +// aux-build: trait_with_docs.rs + +extern crate trait_with_docs; + +pub struct Local; + +impl trait_with_docs::HasDocs for Local {} + +// @!has "$.index[*][?(@.name == 'HasDocs')]" diff --git a/src/test/rustdoc-json/traits/uses_extern_trait.rs b/src/test/rustdoc-json/traits/uses_extern_trait.rs index a4add43c6a174..55a51f739ab23 100644 --- a/src/test/rustdoc-json/traits/uses_extern_trait.rs +++ b/src/test/rustdoc-json/traits/uses_extern_trait.rs @@ -1,12 +1,5 @@ #![no_std] pub fn drop_default(_x: T) {} -// FIXME(adotinthevoid): Theses shouldn't be here -// @has "$.index[*][?(@.name=='Debug')]" - -// Debug may have several items. All we depend on here the that `fmt` is first. See -// https://github.com/rust-lang/rust/pull/104525#issuecomment-1331087852 for why we -// can't use [*]. - -// @set Debug_fmt = "$.index[*][?(@.name=='Debug')].inner.items[0]" -// @has "$.index[*][?(@.name=='fmt')].id" $Debug_fmt +// @!has "$.index[*][?(@.name=='Debug')]" +// @!has "$.index[*][?(@.name=='Default')]" diff --git a/src/test/rustdoc-ui/issue-91713.stdout b/src/test/rustdoc-ui/issue-91713.stdout index a19e452b459e1..1678352436315 100644 --- a/src/test/rustdoc-ui/issue-91713.stdout +++ b/src/test/rustdoc-ui/issue-91713.stdout @@ -5,11 +5,9 @@ check_doc_test_visibility - run various visibility-related lints on doctests strip-priv-imports - strips all private import statements (`use`, `extern crate`) from a crate propagate-doc-cfg - propagates `#[doc(cfg(...))]` to child items collect-intra-doc-links - resolves intra-doc links -check-code-block-syntax - validates syntax inside Rust code blocks collect-trait-impls - retrieves trait impls for items in the crate calculate-doc-coverage - counts the number of items with and without documentation -check-invalid-html-tags - detects invalid HTML tags in doc comments - check-bare-urls - detects URLs that are not hyperlinks + run-lints - runs some of rustdoc's lints Default passes for rustdoc: collect-trait-impls @@ -18,10 +16,8 @@ check_doc_test_visibility strip-private (when not --document-private-items) strip-priv-imports (when --document-private-items) collect-intra-doc-links -check-code-block-syntax -check-invalid-html-tags propagate-doc-cfg - check-bare-urls + run-lints Passes run with `--show-coverage`: strip-hidden (when not --document-hidden-items) diff --git a/src/test/rustdoc-ui/z-help.stdout b/src/test/rustdoc-ui/z-help.stdout index 22e3782132288..5515480309867 100644 --- a/src/test/rustdoc-ui/z-help.stdout +++ b/src/test/rustdoc-ui/z-help.stdout @@ -90,7 +90,6 @@ -Z no-analysis=val -- parse and expand the source, but run no analysis -Z no-codegen=val -- run all passes except codegen; no output -Z no-generate-arange-section=val -- omit DWARF address ranges that give faster lookups - -Z no-interleave-lints=val -- execute lints separately; allows benchmarking individual lints -Z no-leak-check=val -- disable the 'leak check' for subtyping; unsound, but useful for tests -Z no-link=val -- compile without linking -Z no-parallel-llvm=val -- run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO) diff --git a/src/test/rustdoc/bounds-in-multiple-parts.rs b/src/test/rustdoc/bounds-in-multiple-parts.rs new file mode 100644 index 0000000000000..279e3c148887e --- /dev/null +++ b/src/test/rustdoc/bounds-in-multiple-parts.rs @@ -0,0 +1,20 @@ +#![crate_name = "foo"] + +pub trait Eq {} +pub trait Eq2 {} + +// Checking that "where predicates" and "generics params" are merged. +// @has 'foo/trait.T.html' +// @has - "//*[@id='tymethod.f']/h4" "fn f<'a, 'b, 'c, T>()where Self: Eq, T: Eq + 'a, 'c: 'b + 'a," +pub trait T { + fn f<'a, 'b, 'c: 'a, T: Eq + 'a>() + where Self: Eq, Self: Eq, T: Eq, 'c: 'b; +} + +// Checking that a duplicated "where predicate" is removed. +// @has 'foo/trait.T2.html' +// @has - "//*[@id='tymethod.f']/h4" "fn f()where Self: Eq + Eq2, T: Eq2 + Eq," +pub trait T2 { + fn f() + where Self: Eq, Self: Eq2, T: Eq2; +} diff --git a/src/test/rustdoc/impl-parts.rs b/src/test/rustdoc/impl-parts.rs index 7b931727e446d..90cbb77cb6b60 100644 --- a/src/test/rustdoc/impl-parts.rs +++ b/src/test/rustdoc/impl-parts.rs @@ -6,7 +6,7 @@ pub auto trait AnAutoTrait {} pub struct Foo { field: T } // @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ -// "impl !AnAutoTrait for Foowhere T: Sync," +// "impl !AnAutoTrait for Foowhere T: Sync + Clone," // @has impl_parts/trait.AnAutoTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \ -// "impl !AnAutoTrait for Foowhere T: Sync," +// "impl !AnAutoTrait for Foowhere T: Sync + Clone," impl !AnAutoTrait for Foo where T: Sync {} diff --git a/src/test/rustdoc/rfc-2632-const-trait-impl.rs b/src/test/rustdoc/rfc-2632-const-trait-impl.rs index 602ee1b1b1fca..7ed9d6729b647 100644 --- a/src/test/rustdoc/rfc-2632-const-trait-impl.rs +++ b/src/test/rustdoc/rfc-2632-const-trait-impl.rs @@ -61,7 +61,7 @@ impl S { // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/a[@class="trait"]' 'Clone' // @!has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where"]' '~const' // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Clone' - pub const fn foo() + pub const fn foo() where B: ~const Clone + ~const Destruct, { diff --git a/src/test/rustdoc/whitespace-after-where-clause.enum.html b/src/test/rustdoc/whitespace-after-where-clause.enum.html index c74866f4a10b8..f7663e4616ae6 100644 --- a/src/test/rustdoc/whitespace-after-where-clause.enum.html +++ b/src/test/rustdoc/whitespace-after-where-clause.enum.html @@ -1,4 +1,4 @@ -
pub enum Cow<'a, B: ?Sized + 'a>where
    B: ToOwned<dyn Clone>,
{ +
pub enum Cow<'a, B>where
    B: ToOwned<dyn Clone> + ?Sized + 'a,
{ Borrowed(&'a B), Whatever(u32), }
\ No newline at end of file diff --git a/src/test/rustdoc/whitespace-after-where-clause.struct.html b/src/test/rustdoc/whitespace-after-where-clause.struct.html index 1ba1367d20f72..fa3f224e7ad0f 100644 --- a/src/test/rustdoc/whitespace-after-where-clause.struct.html +++ b/src/test/rustdoc/whitespace-after-where-clause.struct.html @@ -1,4 +1,4 @@ -
pub struct Struct<'a, B: ?Sized + 'a>where
    B: ToOwned<dyn Clone>,
{ +
pub struct Struct<'a, B>where
    B: ToOwned<dyn Clone> + ?Sized + 'a,
{ pub a: &'a B, pub b: u32, }
\ No newline at end of file diff --git a/src/test/rustdoc/whitespace-after-where-clause.union.html b/src/test/rustdoc/whitespace-after-where-clause.union.html index 0dfb6407d45f1..7bb177debc3a8 100644 --- a/src/test/rustdoc/whitespace-after-where-clause.union.html +++ b/src/test/rustdoc/whitespace-after-where-clause.union.html @@ -1,3 +1,3 @@ -
pub union Union<'a, B: ?Sized + 'a>where
    B: ToOwned<dyn Clone>,
{ +
pub union Union<'a, B>where
    B: ToOwned<dyn Clone> + ?Sized + 'a,
{ /* private fields */ }
\ No newline at end of file diff --git a/src/test/ui-fulldeps/lint-plugin-cmdline-load.stderr b/src/test/ui-fulldeps/lint-plugin-cmdline-load.stderr index 981631494fafd..82679c9e10a10 100644 --- a/src/test/ui-fulldeps/lint-plugin-cmdline-load.stderr +++ b/src/test/ui-fulldeps/lint-plugin-cmdline-load.stderr @@ -1,11 +1,3 @@ -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> :1:1 - | -LL | plugin(lint_plugin_test) - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - warning: item is named 'lintme' --> $DIR/lint-plugin-cmdline-load.rs:8:1 | @@ -14,5 +6,13 @@ LL | fn lintme() { } | = note: `#[warn(test_lint)]` on by default +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 + --> :1:1 + | +LL | plugin(lint_plugin_test) + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version + | + = note: `#[warn(deprecated)]` on by default + warning: 2 warnings emitted diff --git a/src/test/ui-fulldeps/lint-plugin-deny-attr.stderr b/src/test/ui-fulldeps/lint-plugin-deny-attr.stderr index b9774c044623c..5e8891bf1f1ac 100644 --- a/src/test/ui-fulldeps/lint-plugin-deny-attr.stderr +++ b/src/test/ui-fulldeps/lint-plugin-deny-attr.stderr @@ -1,11 +1,3 @@ -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/lint-plugin-deny-attr.rs:5:1 - | -LL | #![plugin(lint_plugin_test)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - error: item is named 'lintme' --> $DIR/lint-plugin-deny-attr.rs:9:1 | @@ -18,5 +10,13 @@ note: the lint level is defined here LL | #![deny(test_lint)] | ^^^^^^^^^ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 + --> $DIR/lint-plugin-deny-attr.rs:5:1 + | +LL | #![plugin(lint_plugin_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version + | + = note: `#[warn(deprecated)]` on by default + error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui-fulldeps/lint-plugin-deny-cmdline.stderr b/src/test/ui-fulldeps/lint-plugin-deny-cmdline.stderr index cbabb09f6a596..d5d6b5352145c 100644 --- a/src/test/ui-fulldeps/lint-plugin-deny-cmdline.stderr +++ b/src/test/ui-fulldeps/lint-plugin-deny-cmdline.stderr @@ -1,11 +1,3 @@ -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/lint-plugin-deny-cmdline.rs:6:1 - | -LL | #![plugin(lint_plugin_test)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - error: item is named 'lintme' --> $DIR/lint-plugin-deny-cmdline.rs:9:1 | @@ -14,5 +6,13 @@ LL | fn lintme() { } | = note: requested on the command line with `-D test-lint` +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 + --> $DIR/lint-plugin-deny-cmdline.rs:6:1 + | +LL | #![plugin(lint_plugin_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version + | + = note: `#[warn(deprecated)]` on by default + error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui-fulldeps/lint-plugin-forbid-attrs.rs b/src/test/ui-fulldeps/lint-plugin-forbid-attrs.rs index 4833f6971c171..cf31b3ec1587e 100644 --- a/src/test/ui-fulldeps/lint-plugin-forbid-attrs.rs +++ b/src/test/ui-fulldeps/lint-plugin-forbid-attrs.rs @@ -11,7 +11,6 @@ fn lintme() {} //~ ERROR item is named 'lintme' #[allow(test_lint)] //~^ ERROR allow(test_lint) incompatible //~| ERROR allow(test_lint) incompatible -//~| ERROR allow(test_lint) incompatible pub fn main() { lintme(); } diff --git a/src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr b/src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr index e11a4f8449352..ae34b25cc2f80 100644 --- a/src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr +++ b/src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr @@ -7,23 +7,6 @@ LL | #![forbid(test_lint)] LL | #[allow(test_lint)] | ^^^^^^^^^ overruled by previous forbid -error[E0453]: allow(test_lint) incompatible with previous forbid - --> $DIR/lint-plugin-forbid-attrs.rs:11:9 - | -LL | #![forbid(test_lint)] - | --------- `forbid` level set here -... -LL | #[allow(test_lint)] - | ^^^^^^^^^ overruled by previous forbid - -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/lint-plugin-forbid-attrs.rs:5:1 - | -LL | #![plugin(lint_plugin_test)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - error: item is named 'lintme' --> $DIR/lint-plugin-forbid-attrs.rs:9:1 | @@ -45,6 +28,14 @@ LL | #![forbid(test_lint)] LL | #[allow(test_lint)] | ^^^^^^^^^ overruled by previous forbid -error: aborting due to 4 previous errors; 1 warning emitted +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 + --> $DIR/lint-plugin-forbid-attrs.rs:5:1 + | +LL | #![plugin(lint_plugin_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version + | + = note: `#[warn(deprecated)]` on by default + +error: aborting due to 3 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0453`. diff --git a/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.rs b/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.rs index ce034ee38d70c..b9d1aa85a6930 100644 --- a/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.rs +++ b/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.rs @@ -9,7 +9,7 @@ fn lintme() { } //~ ERROR item is named 'lintme' #[allow(test_lint)] //~ ERROR allow(test_lint) incompatible //~| ERROR allow(test_lint) incompatible - //~| ERROR allow(test_lint) + pub fn main() { lintme(); } diff --git a/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr b/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr index 09c19af617a29..491c4d2064681 100644 --- a/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr +++ b/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr @@ -6,22 +6,6 @@ LL | #[allow(test_lint)] | = note: `forbid` lint level was set on command line -error[E0453]: allow(test_lint) incompatible with previous forbid - --> $DIR/lint-plugin-forbid-cmdline.rs:10:9 - | -LL | #[allow(test_lint)] - | ^^^^^^^^^ overruled by previous forbid - | - = note: `forbid` lint level was set on command line - -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/lint-plugin-forbid-cmdline.rs:6:1 - | -LL | #![plugin(lint_plugin_test)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - error: item is named 'lintme' --> $DIR/lint-plugin-forbid-cmdline.rs:8:1 | @@ -38,6 +22,14 @@ LL | #[allow(test_lint)] | = note: `forbid` lint level was set on command line -error: aborting due to 4 previous errors; 1 warning emitted +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 + --> $DIR/lint-plugin-forbid-cmdline.rs:6:1 + | +LL | #![plugin(lint_plugin_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version + | + = note: `#[warn(deprecated)]` on by default + +error: aborting due to 3 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0453`. diff --git a/src/test/ui-fulldeps/lint-plugin.stderr b/src/test/ui-fulldeps/lint-plugin.stderr index 765832071cbea..dd5d3d72ecf39 100644 --- a/src/test/ui-fulldeps/lint-plugin.stderr +++ b/src/test/ui-fulldeps/lint-plugin.stderr @@ -1,11 +1,3 @@ -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/lint-plugin.rs:5:1 - | -LL | #![plugin(lint_plugin_test)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - warning: item is named 'lintme' --> $DIR/lint-plugin.rs:8:1 | @@ -14,5 +6,13 @@ LL | fn lintme() { } | = note: `#[warn(test_lint)]` on by default +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 + --> $DIR/lint-plugin.rs:5:1 + | +LL | #![plugin(lint_plugin_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version + | + = note: `#[warn(deprecated)]` on by default + warning: 2 warnings emitted diff --git a/src/test/ui-fulldeps/lint-tool-cmdline-allow.stderr b/src/test/ui-fulldeps/lint-tool-cmdline-allow.stderr index b4fb9e22da417..b060e3a3e38b4 100644 --- a/src/test/ui-fulldeps/lint-tool-cmdline-allow.stderr +++ b/src/test/ui-fulldeps/lint-tool-cmdline-allow.stderr @@ -6,18 +6,6 @@ warning: lint name `test_lint` is deprecated and does not have an effect anymore | = note: requested on the command line with `-A test_lint` -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/lint-tool-cmdline-allow.rs:7:1 - | -LL | #![plugin(lint_tool_test)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint - | - = note: requested on the command line with `-A test_lint` - warning: item is named 'lintme' --> $DIR/lint-tool-cmdline-allow.rs:9:1 | @@ -26,9 +14,17 @@ LL | fn lintme() {} | = note: `#[warn(clippy::test_lint)]` on by default +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 + --> $DIR/lint-tool-cmdline-allow.rs:7:1 + | +LL | #![plugin(lint_tool_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version + | + = note: `#[warn(deprecated)]` on by default + warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint | = note: requested on the command line with `-A test_lint` -warning: 6 warnings emitted +warning: 5 warnings emitted diff --git a/src/test/ui-fulldeps/lint-tool-test.rs b/src/test/ui-fulldeps/lint-tool-test.rs index 0d04eb6fcfa96..f92bcd213b844 100644 --- a/src/test/ui-fulldeps/lint-tool-test.rs +++ b/src/test/ui-fulldeps/lint-tool-test.rs @@ -10,12 +10,10 @@ //~^ WARNING lint name `test_lint` is deprecated and may not have an effect in the future //~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future //~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future -//~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future #![deny(clippy_group)] //~^ WARNING lint name `clippy_group` is deprecated and may not have an effect in the future //~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future //~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future -//~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future fn lintme() { } //~ ERROR item is named 'lintme' @@ -32,7 +30,6 @@ pub fn main() { //~^ WARNING lint name `test_group` is deprecated and may not have an effect in the future //~| WARNING lint name `test_group` is deprecated and may not have an effect in the future //~| WARNING lint name `test_group` is deprecated and may not have an effect in the future -//~| WARNING lint name `test_group` is deprecated and may not have an effect in the future #[deny(this_lint_does_not_exist)] //~ WARNING unknown lint: `this_lint_does_not_exist` fn hello() { fn lintmetoo() { } diff --git a/src/test/ui-fulldeps/lint-tool-test.stderr b/src/test/ui-fulldeps/lint-tool-test.stderr index af9b8dedc73af..027cf8f80cff2 100644 --- a/src/test/ui-fulldeps/lint-tool-test.stderr +++ b/src/test/ui-fulldeps/lint-tool-test.stderr @@ -7,13 +7,13 @@ LL | #![cfg_attr(foo, warn(test_lint))] = note: `#[warn(renamed_and_removed_lints)]` on by default warning: lint name `clippy_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:14:9 + --> $DIR/lint-tool-test.rs:13:9 | LL | #![deny(clippy_group)] | ^^^^^^^^^^^^ help: change it to: `clippy::group` warning: lint name `test_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:31:9 + --> $DIR/lint-tool-test.rs:29:9 | LL | #[allow(test_group)] | ^^^^^^^^^^ help: change it to: `clippy::test_group` @@ -25,60 +25,26 @@ LL | #![cfg_attr(foo, warn(test_lint))] | ^^^^^^^^^ help: change it to: `clippy::test_lint` warning: lint name `clippy_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:14:9 - | -LL | #![deny(clippy_group)] - | ^^^^^^^^^^^^ help: change it to: `clippy::group` - -warning: lint name `test_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:31:9 - | -LL | #[allow(test_group)] - | ^^^^^^^^^^ help: change it to: `clippy::test_group` - -warning: unknown lint: `this_lint_does_not_exist` - --> $DIR/lint-tool-test.rs:36:8 - | -LL | #[deny(this_lint_does_not_exist)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(unknown_lints)]` on by default - -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/lint-tool-test.rs:6:1 - | -LL | #![plugin(lint_tool_test)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -warning: lint name `test_lint` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:9:23 - | -LL | #![cfg_attr(foo, warn(test_lint))] - | ^^^^^^^^^ help: change it to: `clippy::test_lint` - -warning: lint name `clippy_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:14:9 + --> $DIR/lint-tool-test.rs:13:9 | LL | #![deny(clippy_group)] | ^^^^^^^^^^^^ help: change it to: `clippy::group` error: item is named 'lintme' - --> $DIR/lint-tool-test.rs:20:1 + --> $DIR/lint-tool-test.rs:18:1 | LL | fn lintme() { } | ^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/lint-tool-test.rs:14:9 + --> $DIR/lint-tool-test.rs:13:9 | LL | #![deny(clippy_group)] | ^^^^^^^^^^^^ = note: `#[deny(clippy::test_lint)]` implied by `#[deny(clippy::group)]` error: item is named 'lintmetoo' - --> $DIR/lint-tool-test.rs:28:5 + --> $DIR/lint-tool-test.rs:26:5 | LL | fn lintmetoo() { } | ^^^^^^^^^^^^^^^^^^ @@ -86,11 +52,27 @@ LL | fn lintmetoo() { } = note: `#[deny(clippy::test_group)]` implied by `#[deny(clippy::group)]` warning: lint name `test_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:31:9 + --> $DIR/lint-tool-test.rs:29:9 | LL | #[allow(test_group)] | ^^^^^^^^^^ help: change it to: `clippy::test_group` +warning: unknown lint: `this_lint_does_not_exist` + --> $DIR/lint-tool-test.rs:33:8 + | +LL | #[deny(this_lint_does_not_exist)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unknown_lints)]` on by default + +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 + --> $DIR/lint-tool-test.rs:6:1 + | +LL | #![plugin(lint_tool_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version + | + = note: `#[warn(deprecated)]` on by default + warning: lint name `test_lint` is deprecated and may not have an effect in the future. --> $DIR/lint-tool-test.rs:9:23 | @@ -98,16 +80,16 @@ LL | #![cfg_attr(foo, warn(test_lint))] | ^^^^^^^^^ help: change it to: `clippy::test_lint` warning: lint name `clippy_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:14:9 + --> $DIR/lint-tool-test.rs:13:9 | LL | #![deny(clippy_group)] | ^^^^^^^^^^^^ help: change it to: `clippy::group` warning: lint name `test_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:31:9 + --> $DIR/lint-tool-test.rs:29:9 | LL | #[allow(test_group)] | ^^^^^^^^^^ help: change it to: `clippy::test_group` -error: aborting due to 2 previous errors; 14 warnings emitted +error: aborting due to 2 previous errors; 11 warnings emitted diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index d6dc179da7f98..a93ba87470a9c 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -126,6 +126,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P)) { fn_decl: decl.clone(), body: e, fn_decl_span: DUMMY_SP, + fn_arg_span: DUMMY_SP, }))) }); } diff --git a/src/test/ui/associated-consts/issue-47814.rs b/src/test/ui/associated-consts/issue-47814.rs new file mode 100644 index 0000000000000..a28b1c00113c9 --- /dev/null +++ b/src/test/ui/associated-consts/issue-47814.rs @@ -0,0 +1,14 @@ +struct ArpIPv4<'a> { + s: &'a u8 +} + +impl<'a> ArpIPv4<'a> { + const LENGTH: usize = 20; + + pub fn to_buffer() -> [u8; Self::LENGTH] { + //~^ ERROR: generic `Self` types are currently not permitted in anonymous constants + unimplemented!() + } +} + +fn main() {} diff --git a/src/test/ui/associated-consts/issue-47814.stderr b/src/test/ui/associated-consts/issue-47814.stderr new file mode 100644 index 0000000000000..2e4ddb81166b4 --- /dev/null +++ b/src/test/ui/associated-consts/issue-47814.stderr @@ -0,0 +1,14 @@ +error: generic `Self` types are currently not permitted in anonymous constants + --> $DIR/issue-47814.rs:8:32 + | +LL | pub fn to_buffer() -> [u8; Self::LENGTH] { + | ^^^^ + | +note: not a concrete type + --> $DIR/issue-47814.rs:5:10 + | +LL | impl<'a> ArpIPv4<'a> { + | ^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/associated-inherent-types/struct-generics.rs b/src/test/ui/associated-inherent-types/struct-generics.rs new file mode 100644 index 0000000000000..8952b37917308 --- /dev/null +++ b/src/test/ui/associated-inherent-types/struct-generics.rs @@ -0,0 +1,15 @@ +// check-pass + +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +struct S(T); + +impl S { + type P = T; +} + +fn main() { + type A = S<()>::P; + let _: A = (); +} diff --git a/src/test/ui/async-await/generator-not-future.rs b/src/test/ui/async-await/generator-not-future.rs new file mode 100644 index 0000000000000..37d7cfa6fb7a3 --- /dev/null +++ b/src/test/ui/async-await/generator-not-future.rs @@ -0,0 +1,45 @@ +// edition:2018 +#![feature(generators, generator_trait)] + +use std::future::Future; +use std::ops::Generator; + +async fn async_fn() {} +fn returns_async_block() -> impl Future { + async {} +} +fn returns_generator() -> impl Generator<(), Yield = (), Return = ()> { + || { + let _: () = yield (); + } +} + +fn takes_future(_f: impl Future) {} +fn takes_generator(_g: impl Generator) {} + +fn main() { + // okay: + takes_future(async_fn()); + takes_future(returns_async_block()); + takes_future(async {}); + takes_generator(returns_generator()); + takes_generator(|| { + let _: () = yield (); + }); + + // async futures are not generators: + takes_generator(async_fn()); + //~^ ERROR the trait bound + takes_generator(returns_async_block()); + //~^ ERROR the trait bound + takes_generator(async {}); + //~^ ERROR the trait bound + + // generators are not futures: + takes_future(returns_generator()); + //~^ ERROR is not a future + takes_future(|ctx| { + //~^ ERROR is not a future + ctx = yield (); + }); +} diff --git a/src/test/ui/async-await/generator-not-future.stderr b/src/test/ui/async-await/generator-not-future.stderr new file mode 100644 index 0000000000000..1b81b461f0aad --- /dev/null +++ b/src/test/ui/async-await/generator-not-future.stderr @@ -0,0 +1,81 @@ +error[E0277]: the trait bound `impl Future: Generator<_>` is not satisfied + --> $DIR/generator-not-future.rs:31:21 + | +LL | takes_generator(async_fn()); + | --------------- ^^^^^^^^^^ the trait `Generator<_>` is not implemented for `impl Future` + | | + | required by a bound introduced by this call + | +note: required by a bound in `takes_generator` + --> $DIR/generator-not-future.rs:18:39 + | +LL | fn takes_generator(_g: impl Generator) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_generator` + +error[E0277]: the trait bound `impl Future: Generator<_>` is not satisfied + --> $DIR/generator-not-future.rs:33:21 + | +LL | takes_generator(returns_async_block()); + | --------------- ^^^^^^^^^^^^^^^^^^^^^ the trait `Generator<_>` is not implemented for `impl Future` + | | + | required by a bound introduced by this call + | +note: required by a bound in `takes_generator` + --> $DIR/generator-not-future.rs:18:39 + | +LL | fn takes_generator(_g: impl Generator) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_generator` + +error[E0277]: the trait bound `[async block@$DIR/generator-not-future.rs:35:21: 35:29]: Generator<_>` is not satisfied + --> $DIR/generator-not-future.rs:35:21 + | +LL | takes_generator(async {}); + | --------------- ^^^^^^^^ the trait `Generator<_>` is not implemented for `[async block@$DIR/generator-not-future.rs:35:21: 35:29]` + | | + | required by a bound introduced by this call + | +note: required by a bound in `takes_generator` + --> $DIR/generator-not-future.rs:18:39 + | +LL | fn takes_generator(_g: impl Generator) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_generator` + +error[E0277]: `impl Generator` is not a future + --> $DIR/generator-not-future.rs:39:18 + | +LL | takes_future(returns_generator()); + | ------------ ^^^^^^^^^^^^^^^^^^^ `impl Generator` is not a future + | | + | required by a bound introduced by this call + | + = help: the trait `Future` is not implemented for `impl Generator` + = note: impl Generator must be a future or must implement `IntoFuture` to be awaited +note: required by a bound in `takes_future` + --> $DIR/generator-not-future.rs:17:26 + | +LL | fn takes_future(_f: impl Future) {} + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_future` + +error[E0277]: `[generator@$DIR/generator-not-future.rs:41:18: 41:23]` is not a future + --> $DIR/generator-not-future.rs:41:18 + | +LL | takes_future(|ctx| { + | _____------------_^ + | | | + | | required by a bound introduced by this call +LL | | +LL | | ctx = yield (); +LL | | }); + | |_____^ `[generator@$DIR/generator-not-future.rs:41:18: 41:23]` is not a future + | + = help: the trait `Future` is not implemented for `[generator@$DIR/generator-not-future.rs:41:18: 41:23]` + = note: [generator@$DIR/generator-not-future.rs:41:18: 41:23] must be a future or must implement `IntoFuture` to be awaited +note: required by a bound in `takes_future` + --> $DIR/generator-not-future.rs:17:26 + | +LL | fn takes_future(_f: impl Future) {} + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_future` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/in-trait/async-generics-and-bounds.stderr b/src/test/ui/async-await/in-trait/async-generics-and-bounds.stderr index 5c8d64fc6cb4c..f1f0d7e5907d3 100644 --- a/src/test/ui/async-await/in-trait/async-generics-and-bounds.stderr +++ b/src/test/ui/async-await/in-trait/async-generics-and-bounds.stderr @@ -4,11 +4,11 @@ error[E0311]: the parameter type `U` may not live long enough LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^^^ | -note: the parameter type `U` must be valid for the anonymous lifetime as defined here... +note: the parameter type `U` must be valid for the anonymous lifetime defined here... --> $DIR/async-generics-and-bounds.rs:12:18 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; - | ^ + | ^^^^^ note: ...so that the reference type `&(T, U)` does not outlive the data it points at --> $DIR/async-generics-and-bounds.rs:12:28 | @@ -21,11 +21,11 @@ error[E0311]: the parameter type `T` may not live long enough LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^^^ | -note: the parameter type `T` must be valid for the anonymous lifetime as defined here... +note: the parameter type `T` must be valid for the anonymous lifetime defined here... --> $DIR/async-generics-and-bounds.rs:12:18 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; - | ^ + | ^^^^^ note: ...so that the reference type `&(T, U)` does not outlive the data it points at --> $DIR/async-generics-and-bounds.rs:12:28 | diff --git a/src/test/ui/async-await/in-trait/async-generics.stderr b/src/test/ui/async-await/in-trait/async-generics.stderr index 6ae73d9e3a601..2f05564564cd2 100644 --- a/src/test/ui/async-await/in-trait/async-generics.stderr +++ b/src/test/ui/async-await/in-trait/async-generics.stderr @@ -4,11 +4,11 @@ error[E0311]: the parameter type `U` may not live long enough LL | async fn foo(&self) -> &(T, U); | ^^^^^^^ | -note: the parameter type `U` must be valid for the anonymous lifetime as defined here... +note: the parameter type `U` must be valid for the anonymous lifetime defined here... --> $DIR/async-generics.rs:9:18 | LL | async fn foo(&self) -> &(T, U); - | ^ + | ^^^^^ note: ...so that the reference type `&(T, U)` does not outlive the data it points at --> $DIR/async-generics.rs:9:28 | @@ -21,11 +21,11 @@ error[E0311]: the parameter type `T` may not live long enough LL | async fn foo(&self) -> &(T, U); | ^^^^^^^ | -note: the parameter type `T` must be valid for the anonymous lifetime as defined here... +note: the parameter type `T` must be valid for the anonymous lifetime defined here... --> $DIR/async-generics.rs:9:18 | LL | async fn foo(&self) -> &(T, U); - | ^ + | ^^^^^ note: ...so that the reference type `&(T, U)` does not outlive the data it points at --> $DIR/async-generics.rs:9:28 | diff --git a/src/test/ui/async-await/in-trait/async-lifetimes-and-bounds.rs b/src/test/ui/async-await/in-trait/async-lifetimes-and-bounds.rs index 3f7448cecd157..d5481d277e40a 100644 --- a/src/test/ui/async-await/in-trait/async-lifetimes-and-bounds.rs +++ b/src/test/ui/async-await/in-trait/async-lifetimes-and-bounds.rs @@ -1,5 +1,4 @@ -// check-fail -// known-bug: #102682 +// check-pass // edition: 2021 #![feature(async_fn_in_trait)] diff --git a/src/test/ui/async-await/in-trait/async-lifetimes-and-bounds.stderr b/src/test/ui/async-await/in-trait/async-lifetimes-and-bounds.stderr deleted file mode 100644 index 0f02420274333..0000000000000 --- a/src/test/ui/async-await/in-trait/async-lifetimes-and-bounds.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0309]: the parameter type `Self` may not live long enough - --> $DIR/async-lifetimes-and-bounds.rs:11:43 - | -LL | async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T) where T: Debug + Sized; - | ^^^^^^^^^^^^^^^^^ - | - = help: consider adding an explicit lifetime bound `Self: 'a`... - = note: ...so that the reference type `&'a Self` does not outlive the data it points at - -error[E0309]: the parameter type `T` may not live long enough - --> $DIR/async-lifetimes-and-bounds.rs:11:43 - | -LL | async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T) where T: Debug + Sized; - | ^^^^^^^^^^^^^^^^^ ...so that the reference type `&'b T` does not outlive the data it points at - | -help: consider adding an explicit lifetime bound... - | -LL | trait MyTrait<'a, 'b, T: 'b> { - | ++++ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/async-await/in-trait/async-lifetimes.rs b/src/test/ui/async-await/in-trait/async-lifetimes.rs index acbac471cf7e8..f298e45d2390b 100644 --- a/src/test/ui/async-await/in-trait/async-lifetimes.rs +++ b/src/test/ui/async-await/in-trait/async-lifetimes.rs @@ -1,5 +1,4 @@ -// check-fail -// known-bug: #102682 +// check-pass // edition: 2021 #![feature(async_fn_in_trait)] diff --git a/src/test/ui/async-await/in-trait/async-lifetimes.stderr b/src/test/ui/async-await/in-trait/async-lifetimes.stderr deleted file mode 100644 index 9a7d294bb1766..0000000000000 --- a/src/test/ui/async-await/in-trait/async-lifetimes.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0309]: the parameter type `Self` may not live long enough - --> $DIR/async-lifetimes.rs:9:43 - | -LL | async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T); - | ^^^^^^^^^^^^^^^^^ - | - = help: consider adding an explicit lifetime bound `Self: 'a`... - = note: ...so that the reference type `&'a Self` does not outlive the data it points at - -error[E0309]: the parameter type `T` may not live long enough - --> $DIR/async-lifetimes.rs:9:43 - | -LL | async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T); - | ^^^^^^^^^^^^^^^^^ ...so that the reference type `&'b T` does not outlive the data it points at - | -help: consider adding an explicit lifetime bound... - | -LL | trait MyTrait<'a, 'b, T: 'b> { - | ++++ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/async-await/in-trait/implied-bounds.rs b/src/test/ui/async-await/in-trait/implied-bounds.rs new file mode 100644 index 0000000000000..52bceb3cc5cd6 --- /dev/null +++ b/src/test/ui/async-await/in-trait/implied-bounds.rs @@ -0,0 +1,13 @@ +// check-pass +// edition: 2021 + +#![feature(async_fn_in_trait)] +#![allow(incomplete_features)] + +trait TcpStack { + type Connection<'a>: Sized where Self: 'a; + fn connect<'a>(&'a self) -> Self::Connection<'a>; + async fn async_connect<'a>(&'a self) -> Self::Connection<'a>; +} + +fn main() {} diff --git a/src/test/ui/async-await/in-trait/lifetime-mismatch.rs b/src/test/ui/async-await/in-trait/lifetime-mismatch.rs new file mode 100644 index 0000000000000..45ede193c0fc6 --- /dev/null +++ b/src/test/ui/async-await/in-trait/lifetime-mismatch.rs @@ -0,0 +1,20 @@ +// edition:2021 + +#![feature(async_fn_in_trait)] +//~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + +trait MyTrait { + async fn foo<'a>(&self); + async fn bar(&self); +} + +impl MyTrait for i32 { + async fn foo(&self) {} + //~^ ERROR lifetime parameters or bounds on method `foo` do not match the trait declaration + + async fn bar(&self) { + self.foo(); + } +} + +fn main() {} diff --git a/src/test/ui/async-await/in-trait/lifetime-mismatch.stderr b/src/test/ui/async-await/in-trait/lifetime-mismatch.stderr new file mode 100644 index 0000000000000..d87adcc78b6c8 --- /dev/null +++ b/src/test/ui/async-await/in-trait/lifetime-mismatch.stderr @@ -0,0 +1,21 @@ +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/lifetime-mismatch.rs:3:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration + --> $DIR/lifetime-mismatch.rs:12:17 + | +LL | async fn foo<'a>(&self); + | ---- lifetimes in impl do not match this method in trait +... +LL | async fn foo(&self) {} + | ^ lifetimes do not match method in trait + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0195`. diff --git a/src/test/ui/attributes/unused-item-in-attr.rs b/src/test/ui/attributes/unused-item-in-attr.rs new file mode 100644 index 0000000000000..70dcd5413f1ee --- /dev/null +++ b/src/test/ui/attributes/unused-item-in-attr.rs @@ -0,0 +1,6 @@ +#[w = { extern crate alloc; }] +//~^ ERROR unexpected expression: `{ +//~| ERROR cannot find attribute `w` in this scope +fn f() {} + +fn main() {} diff --git a/src/test/ui/attributes/unused-item-in-attr.stderr b/src/test/ui/attributes/unused-item-in-attr.stderr new file mode 100644 index 0000000000000..92a8f58582136 --- /dev/null +++ b/src/test/ui/attributes/unused-item-in-attr.stderr @@ -0,0 +1,16 @@ +error: unexpected expression: `{ + extern crate alloc; + }` + --> $DIR/unused-item-in-attr.rs:1:7 + | +LL | #[w = { extern crate alloc; }] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: cannot find attribute `w` in this scope + --> $DIR/unused-item-in-attr.rs:1:3 + | +LL | #[w = { extern crate alloc; }] + | ^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/drop/drop_order.rs b/src/test/ui/drop/drop_order.rs index 42385216ae765..5ce1fd54a9e62 100644 --- a/src/test/ui/drop/drop_order.rs +++ b/src/test/ui/drop/drop_order.rs @@ -43,7 +43,7 @@ impl DropOrderCollector { } if { - if self.option_loud_drop(7).is_some() && self.option_loud_drop(6).is_some() { + if self.option_loud_drop(6).is_some() && self.option_loud_drop(7).is_some() { self.loud_drop(8); true } else { @@ -118,17 +118,85 @@ impl DropOrderCollector { } } + fn and_chain(&self) { + // issue-103107 + if self.option_loud_drop(1).is_some() // 1 + && self.option_loud_drop(2).is_some() // 2 + && self.option_loud_drop(3).is_some() // 3 + && self.option_loud_drop(4).is_some() // 4 + && self.option_loud_drop(5).is_some() // 5 + { + self.print(6); // 6 + } + + let _ = self.option_loud_drop(7).is_some() // 1 + && self.option_loud_drop(8).is_some() // 2 + && self.option_loud_drop(9).is_some(); // 3 + self.print(10); // 4 + + // Test associativity + if self.option_loud_drop(11).is_some() // 1 + && (self.option_loud_drop(12).is_some() // 2 + && self.option_loud_drop(13).is_some() // 3 + && self.option_loud_drop(14).is_some()) // 4 + && self.option_loud_drop(15).is_some() // 5 + { + self.print(16); // 6 + } + } + + fn or_chain(&self) { + // issue-103107 + if self.option_loud_drop(1).is_none() // 1 + || self.option_loud_drop(2).is_none() // 2 + || self.option_loud_drop(3).is_none() // 3 + || self.option_loud_drop(4).is_none() // 4 + || self.option_loud_drop(5).is_some() // 5 + { + self.print(6); // 6 + } + + let _ = self.option_loud_drop(7).is_none() // 1 + || self.option_loud_drop(8).is_none() // 2 + || self.option_loud_drop(9).is_none(); // 3 + self.print(10); // 4 + + // Test associativity + if self.option_loud_drop(11).is_none() // 1 + || (self.option_loud_drop(12).is_none() // 2 + || self.option_loud_drop(13).is_none() // 3 + || self.option_loud_drop(14).is_none()) // 4 + || self.option_loud_drop(15).is_some() // 5 + { + self.print(16); // 6 + } + } + + fn mixed_and_or_chain(&self) { + // issue-103107 + if self.option_loud_drop(1).is_none() // 1 + || self.option_loud_drop(2).is_none() // 2 + || self.option_loud_drop(3).is_some() // 3 + && self.option_loud_drop(4).is_some() // 4 + && self.option_loud_drop(5).is_none() // 5 + || self.option_loud_drop(6).is_none() // 6 + || self.option_loud_drop(7).is_some() // 7 + { + self.print(8); // 8 + } + } + fn let_chain(&self) { // take the "then" branch - if self.option_loud_drop(2).is_some() // 2 - && self.option_loud_drop(1).is_some() // 1 + if self.option_loud_drop(1).is_some() // 1 + && self.option_loud_drop(2).is_some() // 2 && let Some(_d) = self.option_loud_drop(4) { // 4 self.print(3); // 3 } // take the "else" branch - if self.option_loud_drop(6).is_some() // 2 - && self.option_loud_drop(5).is_some() // 1 + if self.option_loud_drop(5).is_some() // 1 + && self.option_loud_drop(6).is_some() // 2 && let None = self.option_loud_drop(8) { // 4 unreachable!(); } else { @@ -152,8 +220,8 @@ impl DropOrderCollector { } // let exprs last - if self.option_loud_drop(20).is_some() // 2 - && self.option_loud_drop(19).is_some() // 1 + if self.option_loud_drop(19).is_some() // 1 + && self.option_loud_drop(20).is_some() // 2 && let Some(_d) = self.option_loud_drop(23) // 5 && let Some(_e) = self.option_loud_drop(22) { // 4 self.print(21); // 3 @@ -187,6 +255,21 @@ fn main() { collector.if_(); collector.assert_sorted(); + println!("-- and chain --"); + let collector = DropOrderCollector::default(); + collector.and_chain(); + collector.assert_sorted(); + + println!("-- or chain --"); + let collector = DropOrderCollector::default(); + collector.or_chain(); + collector.assert_sorted(); + + println!("-- mixed and/or chain --"); + let collector = DropOrderCollector::default(); + collector.mixed_and_or_chain(); + collector.assert_sorted(); + println!("-- if let --"); let collector = DropOrderCollector::default(); collector.if_let(); diff --git a/src/test/ui/drop/issue-103107.rs b/src/test/ui/drop/issue-103107.rs new file mode 100644 index 0000000000000..5f447595662ed --- /dev/null +++ b/src/test/ui/drop/issue-103107.rs @@ -0,0 +1,37 @@ +// check-pass +// compile-flags: -Z validate-mir + +struct Foo<'a>(&'a mut u32); + +impl<'a> Drop for Foo<'a> { + fn drop(&mut self) { + *self.0 = 0; + } +} + +fn and() { + let mut foo = 0; + // This used to compile also before the fix + if true && *Foo(&mut foo).0 == 0 && ({ foo = 0; true}) {} + + // This used to fail before the fix + if *Foo(&mut foo).0 == 0 && ({ foo = 0; true}) {} + + println!("{foo}"); +} + +fn or() { + let mut foo = 0; + // This used to compile also before the fix + if false || *Foo(&mut foo).0 == 1 || ({ foo = 0; true}) {} + + // This used to fail before the fix + if *Foo(&mut foo).0 == 1 || ({ foo = 0; true}) {} + + println!("{foo}"); +} + +fn main() { + and(); + or(); +} diff --git a/src/test/ui/enum-discriminant/issue-104519.rs b/src/test/ui/enum-discriminant/issue-104519.rs new file mode 100644 index 0000000000000..c4630f76b3a13 --- /dev/null +++ b/src/test/ui/enum-discriminant/issue-104519.rs @@ -0,0 +1,36 @@ +// run-pass +#![allow(dead_code)] + +enum OpenResult { + Ok(()), + Err(()), + TransportErr(TransportErr), +} + +#[repr(i32)] +enum TransportErr { + UnknownMethod = -2, +} + +#[inline(never)] +fn some_match(result: OpenResult) -> u8 { + match result { + OpenResult::Ok(()) => 0, + _ => 1, + } +} + +fn main() { + let result = OpenResult::Ok(()); + assert_eq!(some_match(result), 0); + + let result = OpenResult::Ok(()); + match result { + OpenResult::Ok(()) => (), + _ => unreachable!("message a"), + } + match result { + OpenResult::Ok(()) => (), + _ => unreachable!("message b"), + } +} diff --git a/src/test/ui/fn/signature-error-reporting-under-verbose.rs b/src/test/ui/fn/signature-error-reporting-under-verbose.rs new file mode 100644 index 0000000000000..d7a8c95e8b2ab --- /dev/null +++ b/src/test/ui/fn/signature-error-reporting-under-verbose.rs @@ -0,0 +1,15 @@ +// compile-flags: -Zverbose + +fn foo(_: i32, _: i32) {} + +fn needs_ptr(_: fn(i32, u32)) {} +//~^ NOTE function defined here +//~| NOTE + +fn main() { + needs_ptr(foo); + //~^ ERROR mismatched types + //~| NOTE expected `u32`, found `i32` + //~| NOTE expected fn pointer `fn(i32, u32)` + //~| NOTE arguments to this function are incorrect +} diff --git a/src/test/ui/fn/signature-error-reporting-under-verbose.stderr b/src/test/ui/fn/signature-error-reporting-under-verbose.stderr new file mode 100644 index 0000000000000..6260fc8dcec52 --- /dev/null +++ b/src/test/ui/fn/signature-error-reporting-under-verbose.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/signature-error-reporting-under-verbose.rs:10:15 + | +LL | needs_ptr(foo); + | --------- ^^^ expected `u32`, found `i32` + | | + | arguments to this function are incorrect + | + = note: expected fn pointer `fn(i32, u32)` + found fn item `fn(i32, i32) {foo}` +note: function defined here + --> $DIR/signature-error-reporting-under-verbose.rs:5:4 + | +LL | fn needs_ptr(_: fn(i32, u32)) {} + | ^^^^^^^^^ --------------- + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/impl-trait/in-trait/where-clause.rs b/src/test/ui/impl-trait/in-trait/where-clause.rs new file mode 100644 index 0000000000000..87bac519cf304 --- /dev/null +++ b/src/test/ui/impl-trait/in-trait/where-clause.rs @@ -0,0 +1,24 @@ +// check-pass +// edition: 2021 + +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +use std::fmt::Debug; + +trait Foo { + fn foo<'a>(&'a self) -> impl Debug + where + Item: 'a; +} + +impl Foo for D { + fn foo<'a>(&'a self) -> impl Debug + where + Item: 'a, + { + self.clone() + } +} + +fn main() {} diff --git a/src/test/ui/inline-const/expr-with-block-err.rs b/src/test/ui/inline-const/expr-with-block-err.rs new file mode 100644 index 0000000000000..f7547742ddcbe --- /dev/null +++ b/src/test/ui/inline-const/expr-with-block-err.rs @@ -0,0 +1,6 @@ +#![feature(inline_const)] + +fn main() { + const { 2 } - const { 1 }; + //~^ ERROR mismatched types +} diff --git a/src/test/ui/inline-const/expr-with-block-err.stderr b/src/test/ui/inline-const/expr-with-block-err.stderr new file mode 100644 index 0000000000000..6f7408f4e2a6a --- /dev/null +++ b/src/test/ui/inline-const/expr-with-block-err.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/expr-with-block-err.rs:4:13 + | +LL | const { 2 } - const { 1 }; + | ^ expected `()`, found integer + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/inline-const/expr-with-block.rs b/src/test/ui/inline-const/expr-with-block.rs new file mode 100644 index 0000000000000..391872476fccd --- /dev/null +++ b/src/test/ui/inline-const/expr-with-block.rs @@ -0,0 +1,10 @@ +// check-pass +#![feature(inline_const)] +fn main() { + match true { + true => const {} + false => () + } + const {} + () +} diff --git a/src/test/ui/issues/issue-35976.rs b/src/test/ui/issues/issue-35976.rs index d075794d9946f..aa6f74cb5d45a 100644 --- a/src/test/ui/issues/issue-35976.rs +++ b/src/test/ui/issues/issue-35976.rs @@ -1,5 +1,9 @@ +// revisions: imported unimported +//[imported] check-pass + mod private { pub trait Future { + //[unimported]~^^ HELP perhaps add a `use` for it fn wait(&self) where Self: Sized; } @@ -8,13 +12,13 @@ mod private { } } -//use private::Future; +#[cfg(imported)] +use private::Future; fn bar(arg: Box) { + // Importing the trait means that we don't autoderef `Box` arg.wait(); - //~^ ERROR the `wait` method cannot be invoked on a trait object + //[unimported]~^ ERROR the `wait` method cannot be invoked on a trait object } -fn main() { - -} +fn main() {} diff --git a/src/test/ui/issues/issue-35976.stderr b/src/test/ui/issues/issue-35976.unimported.stderr similarity index 63% rename from src/test/ui/issues/issue-35976.stderr rename to src/test/ui/issues/issue-35976.unimported.stderr index fe16f97b9d0f5..5d61bb8ea3799 100644 --- a/src/test/ui/issues/issue-35976.stderr +++ b/src/test/ui/issues/issue-35976.unimported.stderr @@ -1,11 +1,16 @@ error: the `wait` method cannot be invoked on a trait object - --> $DIR/issue-35976.rs:14:9 + --> $DIR/issue-35976.rs:20:9 | LL | fn wait(&self) where Self: Sized; | ----- this has a `Sized` requirement ... LL | arg.wait(); | ^^^^ + | +help: another candidate was found in the following trait, perhaps add a `use` for it: + | +LL | use private::Future; + | error: aborting due to previous error diff --git a/src/test/ui/lint/issue-97094.nointerleaved.stderr b/src/test/ui/lint/issue-97094.nointerleaved.stderr deleted file mode 100644 index a2581658920b9..0000000000000 --- a/src/test/ui/lint/issue-97094.nointerleaved.stderr +++ /dev/null @@ -1,53 +0,0 @@ -error: unknown lint: `nonex_lint_top_level` - --> $DIR/issue-97094.rs:14:26 - | -LL | #![cfg_attr(all(), allow(nonex_lint_top_level))] - | ^^^^^^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/issue-97094.rs:10:9 - | -LL | #![deny(warnings)] - | ^^^^^^^^ - = note: `#[deny(unknown_lints)]` implied by `#[deny(warnings)]` - -error: lint `bare_trait_object` has been renamed to `bare_trait_objects` - --> $DIR/issue-97094.rs:16:26 - | -LL | #![cfg_attr(all(), allow(bare_trait_object))] - | ^^^^^^^^^^^^^^^^^ help: use the new name: `bare_trait_objects` - | - = note: `#[deny(renamed_and_removed_lints)]` implied by `#[deny(warnings)]` - -error: unknown lint: `nonex_lint_mod` - --> $DIR/issue-97094.rs:19:25 - | -LL | #[cfg_attr(all(), allow(nonex_lint_mod))] - | ^^^^^^^^^^^^^^ - -error: unknown lint: `nonex_lint_mod_inner` - --> $DIR/issue-97094.rs:22:30 - | -LL | #![cfg_attr(all(), allow(nonex_lint_mod_inner))] - | ^^^^^^^^^^^^^^^^^^^^ - -error: unknown lint: `nonex_lint_fn` - --> $DIR/issue-97094.rs:26:25 - | -LL | #[cfg_attr(all(), allow(nonex_lint_fn))] - | ^^^^^^^^^^^^^ - -error: unknown lint: `nonex_lint_in_macro` - --> $DIR/issue-97094.rs:37:29 - | -LL | #[cfg_attr(all(), allow(nonex_lint_in_macro))] - | ^^^^^^^^^^^^^^^^^^^ - -error: unknown lint: `nonex_lint_fn` - --> $DIR/issue-97094.rs:56:13 - | -LL | #[allow(nonex_lint_fn)] - | ^^^^^^^^^^^^^ - -error: aborting due to 7 previous errors - diff --git a/src/test/ui/lint/issue-97094.rs b/src/test/ui/lint/issue-97094.rs index aeaead1bd11bd..22525ca11ae04 100644 --- a/src/test/ui/lint/issue-97094.rs +++ b/src/test/ui/lint/issue-97094.rs @@ -1,12 +1,3 @@ -// revisions: interleaved nointerleaved -// [nointerleaved]compile-flags: -Z no-interleave-lints - -// This test has two revisions because the logic change -// needed to make this test pass had to be adjusted -// for no-interleave-lints. Should the debug option -// be removed one day, please don't remove this -// test entirely, just remove the revision from it. - #![deny(warnings)] // Ensure that unknown lints inside cfg-attr's are linted for diff --git a/src/test/ui/lint/issue-97094.interleaved.stderr b/src/test/ui/lint/issue-97094.stderr similarity index 84% rename from src/test/ui/lint/issue-97094.interleaved.stderr rename to src/test/ui/lint/issue-97094.stderr index a2581658920b9..1a0a3eaf25077 100644 --- a/src/test/ui/lint/issue-97094.interleaved.stderr +++ b/src/test/ui/lint/issue-97094.stderr @@ -1,18 +1,18 @@ error: unknown lint: `nonex_lint_top_level` - --> $DIR/issue-97094.rs:14:26 + --> $DIR/issue-97094.rs:5:26 | LL | #![cfg_attr(all(), allow(nonex_lint_top_level))] | ^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/issue-97094.rs:10:9 + --> $DIR/issue-97094.rs:1:9 | LL | #![deny(warnings)] | ^^^^^^^^ = note: `#[deny(unknown_lints)]` implied by `#[deny(warnings)]` error: lint `bare_trait_object` has been renamed to `bare_trait_objects` - --> $DIR/issue-97094.rs:16:26 + --> $DIR/issue-97094.rs:7:26 | LL | #![cfg_attr(all(), allow(bare_trait_object))] | ^^^^^^^^^^^^^^^^^ help: use the new name: `bare_trait_objects` @@ -20,31 +20,31 @@ LL | #![cfg_attr(all(), allow(bare_trait_object))] = note: `#[deny(renamed_and_removed_lints)]` implied by `#[deny(warnings)]` error: unknown lint: `nonex_lint_mod` - --> $DIR/issue-97094.rs:19:25 + --> $DIR/issue-97094.rs:10:25 | LL | #[cfg_attr(all(), allow(nonex_lint_mod))] | ^^^^^^^^^^^^^^ error: unknown lint: `nonex_lint_mod_inner` - --> $DIR/issue-97094.rs:22:30 + --> $DIR/issue-97094.rs:13:30 | LL | #![cfg_attr(all(), allow(nonex_lint_mod_inner))] | ^^^^^^^^^^^^^^^^^^^^ error: unknown lint: `nonex_lint_fn` - --> $DIR/issue-97094.rs:26:25 + --> $DIR/issue-97094.rs:17:25 | LL | #[cfg_attr(all(), allow(nonex_lint_fn))] | ^^^^^^^^^^^^^ error: unknown lint: `nonex_lint_in_macro` - --> $DIR/issue-97094.rs:37:29 + --> $DIR/issue-97094.rs:28:29 | LL | #[cfg_attr(all(), allow(nonex_lint_in_macro))] | ^^^^^^^^^^^^^^^^^^^ error: unknown lint: `nonex_lint_fn` - --> $DIR/issue-97094.rs:56:13 + --> $DIR/issue-97094.rs:47:13 | LL | #[allow(nonex_lint_fn)] | ^^^^^^^^^^^^^ diff --git a/src/test/ui/macros/issue-103529.rs b/src/test/ui/macros/issue-103529.rs new file mode 100644 index 0000000000000..fa05baed7fc8e --- /dev/null +++ b/src/test/ui/macros/issue-103529.rs @@ -0,0 +1,13 @@ +macro_rules! m { + ($s:stmt) => {} +} + +m! { mut x } +//~^ ERROR expected expression, found keyword `mut` +//~| ERROR expected a statement +m! { auto x } +//~^ ERROR invalid variable declaration +m! { var x } +//~^ ERROR invalid variable declaration + +fn main() {} diff --git a/src/test/ui/macros/issue-103529.stderr b/src/test/ui/macros/issue-103529.stderr new file mode 100644 index 0000000000000..61e322afc7709 --- /dev/null +++ b/src/test/ui/macros/issue-103529.stderr @@ -0,0 +1,39 @@ +error: expected expression, found keyword `mut` + --> $DIR/issue-103529.rs:5:6 + | +LL | m! { mut x } + | ^^^ expected expression + +error: expected a statement + --> $DIR/issue-103529.rs:5:10 + | +LL | ($s:stmt) => {} + | ------- while parsing argument for this `stmt` macro fragment +... +LL | m! { mut x } + | ^ + +error: invalid variable declaration + --> $DIR/issue-103529.rs:8:6 + | +LL | m! { auto x } + | ^^^^ + | +help: write `let` instead of `auto` to introduce a new variable + | +LL | m! { let x } + | ~~~ + +error: invalid variable declaration + --> $DIR/issue-103529.rs:10:6 + | +LL | m! { var x } + | ^^^ + | +help: write `let` instead of `var` to introduce a new variable + | +LL | m! { let x } + | ~~~ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/query-system/fn-sig-cycle-arity.rs b/src/test/ui/query-system/fn-sig-cycle-arity.rs new file mode 100644 index 0000000000000..7a9b8469c9e19 --- /dev/null +++ b/src/test/ui/query-system/fn-sig-cycle-arity.rs @@ -0,0 +1,8 @@ +trait Dancer { + fn dance(&self) -> _ { + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types + self.dance() + } +} + +fn main() {} diff --git a/src/test/ui/query-system/fn-sig-cycle-arity.stderr b/src/test/ui/query-system/fn-sig-cycle-arity.stderr new file mode 100644 index 0000000000000..67e0c2545515e --- /dev/null +++ b/src/test/ui/query-system/fn-sig-cycle-arity.stderr @@ -0,0 +1,9 @@ +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/fn-sig-cycle-arity.rs:2:24 + | +LL | fn dance(&self) -> _ { + | ^ not allowed in type signatures + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0121`. diff --git a/src/test/ui/resolve/bad-module.stderr b/src/test/ui/resolve/bad-module.stderr index 581a661981460..558760c6793ab 100644 --- a/src/test/ui/resolve/bad-module.stderr +++ b/src/test/ui/resolve/bad-module.stderr @@ -1,15 +1,15 @@ -error[E0433]: failed to resolve: use of undeclared crate or module `thing` - --> $DIR/bad-module.rs:2:15 - | -LL | let foo = thing::len(Vec::new()); - | ^^^^^ use of undeclared crate or module `thing` - error[E0433]: failed to resolve: use of undeclared crate or module `foo` --> $DIR/bad-module.rs:5:15 | LL | let foo = foo::bar::baz(); | ^^^ use of undeclared crate or module `foo` +error[E0433]: failed to resolve: use of undeclared crate or module `thing` + --> $DIR/bad-module.rs:2:15 + | +LL | let foo = thing::len(Vec::new()); + | ^^^^^ use of undeclared crate or module `thing` + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/ui/resolve/issue-101749-2.rs b/src/test/ui/resolve/issue-101749-2.rs new file mode 100644 index 0000000000000..4d3d469447c2b --- /dev/null +++ b/src/test/ui/resolve/issue-101749-2.rs @@ -0,0 +1,16 @@ +struct Rectangle { + width: i32, + height: i32, +} +impl Rectangle { + fn new(width: i32, height: i32) -> Self { + Self { width, height } + } +} + +fn main() { + let rect = Rectangle::new(3, 4); + // `area` is not implemented for `Rectangle`, so this should not suggest + let _ = rect::area(); + //~^ ERROR failed to resolve: use of undeclared crate or module `rect` +} diff --git a/src/test/ui/resolve/issue-101749-2.stderr b/src/test/ui/resolve/issue-101749-2.stderr new file mode 100644 index 0000000000000..370d4b14540d6 --- /dev/null +++ b/src/test/ui/resolve/issue-101749-2.stderr @@ -0,0 +1,9 @@ +error[E0433]: failed to resolve: use of undeclared crate or module `rect` + --> $DIR/issue-101749-2.rs:14:13 + | +LL | let _ = rect::area(); + | ^^^^ use of undeclared crate or module `rect` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/ui/resolve/issue-101749.fixed b/src/test/ui/resolve/issue-101749.fixed new file mode 100644 index 0000000000000..3e5544296e462 --- /dev/null +++ b/src/test/ui/resolve/issue-101749.fixed @@ -0,0 +1,19 @@ +// run-rustfix +struct Rectangle { + width: i32, + height: i32, +} +impl Rectangle { + fn new(width: i32, height: i32) -> Self { + Self { width, height } + } + fn area(&self) -> i32 { + self.height * self.width + } +} + +fn main() { + let rect = Rectangle::new(3, 4); + let _ = rect.area(); + //~^ ERROR failed to resolve: use of undeclared crate or module `rect` +} diff --git a/src/test/ui/resolve/issue-101749.rs b/src/test/ui/resolve/issue-101749.rs new file mode 100644 index 0000000000000..fd67ccab6fa75 --- /dev/null +++ b/src/test/ui/resolve/issue-101749.rs @@ -0,0 +1,19 @@ +// run-rustfix +struct Rectangle { + width: i32, + height: i32, +} +impl Rectangle { + fn new(width: i32, height: i32) -> Self { + Self { width, height } + } + fn area(&self) -> i32 { + self.height * self.width + } +} + +fn main() { + let rect = Rectangle::new(3, 4); + let _ = rect::area(); + //~^ ERROR failed to resolve: use of undeclared crate or module `rect` +} diff --git a/src/test/ui/resolve/issue-101749.stderr b/src/test/ui/resolve/issue-101749.stderr new file mode 100644 index 0000000000000..dd29d7fc05103 --- /dev/null +++ b/src/test/ui/resolve/issue-101749.stderr @@ -0,0 +1,14 @@ +error[E0433]: failed to resolve: use of undeclared crate or module `rect` + --> $DIR/issue-101749.rs:17:13 + | +LL | let _ = rect::area(); + | ^^^^ use of undeclared crate or module `rect` + | +help: you may have meant to call an instance method + | +LL | let _ = rect.area(); + | ~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/ui/resolve/issue-105069.rs b/src/test/ui/resolve/issue-105069.rs new file mode 100644 index 0000000000000..73455cf7711c6 --- /dev/null +++ b/src/test/ui/resolve/issue-105069.rs @@ -0,0 +1,11 @@ +use self::A::*; +use V; //~ ERROR `V` is ambiguous +use self::B::*; +enum A { + V +} +enum B { + V +} + +fn main() {} diff --git a/src/test/ui/resolve/issue-105069.stderr b/src/test/ui/resolve/issue-105069.stderr new file mode 100644 index 0000000000000..1e6c9c6e2dc34 --- /dev/null +++ b/src/test/ui/resolve/issue-105069.stderr @@ -0,0 +1,21 @@ +error[E0659]: `V` is ambiguous + --> $DIR/issue-105069.rs:2:5 + | +LL | use V; + | ^ ambiguous name + | + = note: ambiguous because of multiple potential import sources +note: `V` could refer to the variant imported here + --> $DIR/issue-105069.rs:1:5 + | +LL | use self::A::*; + | ^^^^^^^^^^ +note: `V` could also refer to the variant imported here + --> $DIR/issue-105069.rs:3:5 + | +LL | use self::B::*; + | ^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0659`. diff --git a/src/test/ui/resolve/issue-24968.stderr b/src/test/ui/resolve/issue-24968.stderr index 7e539d258048e..82f5a1d5b57b3 100644 --- a/src/test/ui/resolve/issue-24968.stderr +++ b/src/test/ui/resolve/issue-24968.stderr @@ -1,15 +1,3 @@ -error[E0433]: failed to resolve: `Self` is only available in impls, traits, and type definitions - --> $DIR/issue-24968.rs:21:19 - | -LL | const FOO2: u32 = Self::bar(); - | ^^^^ `Self` is only available in impls, traits, and type definitions - -error[E0433]: failed to resolve: `Self` is only available in impls, traits, and type definitions - --> $DIR/issue-24968.rs:27:22 - | -LL | static FOO_S2: u32 = Self::bar(); - | ^^^^ `Self` is only available in impls, traits, and type definitions - error[E0411]: cannot find type `Self` in this scope --> $DIR/issue-24968.rs:3:11 | @@ -51,6 +39,18 @@ LL | static FOO_S: Self = 0; | | | `Self` not allowed in a static item +error[E0433]: failed to resolve: `Self` is only available in impls, traits, and type definitions + --> $DIR/issue-24968.rs:21:19 + | +LL | const FOO2: u32 = Self::bar(); + | ^^^^ `Self` is only available in impls, traits, and type definitions + +error[E0433]: failed to resolve: `Self` is only available in impls, traits, and type definitions + --> $DIR/issue-24968.rs:27:22 + | +LL | static FOO_S2: u32 = Self::bar(); + | ^^^^ `Self` is only available in impls, traits, and type definitions + error: aborting due to 7 previous errors Some errors have detailed explanations: E0411, E0433. diff --git a/src/test/ui/resolve/typo-suggestion-mistyped-in-path.stderr b/src/test/ui/resolve/typo-suggestion-mistyped-in-path.stderr index ff7cf531c06dd..89b69e1409967 100644 --- a/src/test/ui/resolve/typo-suggestion-mistyped-in-path.stderr +++ b/src/test/ui/resolve/typo-suggestion-mistyped-in-path.stderr @@ -1,3 +1,24 @@ +error[E0433]: failed to resolve: could not find `Struc` in `module` + --> $DIR/typo-suggestion-mistyped-in-path.rs:35:13 + | +LL | module::Struc::foo(); + | ^^^^^ + | | + | could not find `Struc` in `module` + | help: a struct with a similar name exists: `Struct` + +error[E0599]: no function or associated item named `fob` found for struct `Struct` in the current scope + --> $DIR/typo-suggestion-mistyped-in-path.rs:23:13 + | +LL | struct Struct; + | ------------- function or associated item `fob` not found for this struct +... +LL | Struct::fob(); + | ^^^ + | | + | function or associated item not found in `Struct` + | help: there is an associated function with a similar name: `foo` + error[E0433]: failed to resolve: use of undeclared type `Struc` --> $DIR/typo-suggestion-mistyped-in-path.rs:27:5 | @@ -18,15 +39,6 @@ help: there is a crate or module with a similar name LL | module::foo(); | ~~~~~~ -error[E0433]: failed to resolve: could not find `Struc` in `module` - --> $DIR/typo-suggestion-mistyped-in-path.rs:35:13 - | -LL | module::Struc::foo(); - | ^^^^^ - | | - | could not find `Struc` in `module` - | help: a struct with a similar name exists: `Struct` - error[E0433]: failed to resolve: use of undeclared type `Trai` --> $DIR/typo-suggestion-mistyped-in-path.rs:39:5 | @@ -36,18 +48,6 @@ LL | Trai::foo(); | use of undeclared type `Trai` | help: a trait with a similar name exists: `Trait` -error[E0599]: no function or associated item named `fob` found for struct `Struct` in the current scope - --> $DIR/typo-suggestion-mistyped-in-path.rs:23:13 - | -LL | struct Struct; - | ------------- function or associated item `fob` not found for this struct -... -LL | Struct::fob(); - | ^^^ - | | - | function or associated item not found in `Struct` - | help: there is an associated function with a similar name: `foo` - error: aborting due to 5 previous errors Some errors have detailed explanations: E0433, E0599. diff --git a/src/test/ui/resolve/use_suggestion.stderr b/src/test/ui/resolve/use_suggestion.stderr index 58cb659e82203..54ad853831f36 100644 --- a/src/test/ui/resolve/use_suggestion.stderr +++ b/src/test/ui/resolve/use_suggestion.stderr @@ -1,9 +1,3 @@ -error[E0433]: failed to resolve: use of undeclared type `GooMap` - --> $DIR/use_suggestion.rs:3:14 - | -LL | let x2 = GooMap::new(); - | ^^^^^^ use of undeclared type `GooMap` - error[E0433]: failed to resolve: use of undeclared type `HashMap` --> $DIR/use_suggestion.rs:2:14 | @@ -32,6 +26,12 @@ error[E0412]: cannot find type `GooMap` in this scope LL | let y2: GooMap; | ^^^^^^ not found in this scope +error[E0433]: failed to resolve: use of undeclared type `GooMap` + --> $DIR/use_suggestion.rs:3:14 + | +LL | let x2 = GooMap::new(); + | ^^^^^^ use of undeclared type `GooMap` + error: aborting due to 4 previous errors Some errors have detailed explanations: E0412, E0433. diff --git a/src/test/ui/return/tail-expr-as-potential-return.rs b/src/test/ui/return/tail-expr-as-potential-return.rs index 2c3610fb24d4e..f46e088b85f72 100644 --- a/src/test/ui/return/tail-expr-as-potential-return.rs +++ b/src/test/ui/return/tail-expr-as-potential-return.rs @@ -12,7 +12,6 @@ // edition:2018 fn main() { - let _ = foo(true); } fn foo(x: bool) -> Result { @@ -30,3 +29,19 @@ async fn bar(x: bool) -> Result { } Ok(42.0) } + +trait Identity { + type Out; +} + +impl Identity for T { + type Out = T; +} + +async fn foo2() -> i32 { + if true { + 1i32 //~ ERROR mismatched types + //| HELP you might have meant to return this value + } + 0 +} diff --git a/src/test/ui/return/tail-expr-as-potential-return.stderr b/src/test/ui/return/tail-expr-as-potential-return.stderr index dec1cbc4624ef..9183b4599ba6d 100644 --- a/src/test/ui/return/tail-expr-as-potential-return.stderr +++ b/src/test/ui/return/tail-expr-as-potential-return.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/tail-expr-as-potential-return.rs:28:9 + --> $DIR/tail-expr-as-potential-return.rs:27:9 | LL | / if x { LL | | Err(42) @@ -16,7 +16,22 @@ LL | return Err(42); | ++++++ + error[E0308]: mismatched types - --> $DIR/tail-expr-as-potential-return.rs:20:9 + --> $DIR/tail-expr-as-potential-return.rs:43:9 + | +LL | / if true { +LL | | 1i32 + | | ^^^^ expected `()`, found `i32` +LL | | //| HELP you might have meant to return this value +LL | | } + | |_____- expected this to be `()` + | +help: you might have meant to return this value + | +LL | return 1i32; + | ++++++ + + +error[E0308]: mismatched types + --> $DIR/tail-expr-as-potential-return.rs:19:9 | LL | / if x { LL | | Err(42) @@ -32,6 +47,6 @@ help: you might have meant to return this value LL | return Err(42); | ++++++ + -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-79450.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-79450.rs new file mode 100644 index 0000000000000..b604c65d75100 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/issue-79450.rs @@ -0,0 +1,20 @@ +#![feature(const_fmt_arguments_new)] +#![feature(const_trait_impl)] + +#[const_trait] +trait Tr { + fn req(&self); + + fn prov(&self) { + println!("lul"); //~ ERROR: cannot call non-const fn `_print` in constant functions + self.req(); + } +} + +struct S; + +impl const Tr for S { + fn req(&self) {} +} + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-79450.stderr b/src/test/ui/rfc-2632-const-trait-impl/issue-79450.stderr new file mode 100644 index 0000000000000..082c0333fbfcd --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/issue-79450.stderr @@ -0,0 +1,12 @@ +error[E0015]: cannot call non-const fn `_print` in constant functions + --> $DIR/issue-79450.rs:9:9 + | +LL | println!("lul"); + | ^^^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/suggestions/assoc-const-as-fn.rs b/src/test/ui/suggestions/assoc-const-as-fn.rs new file mode 100644 index 0000000000000..4b4595dd5e6a5 --- /dev/null +++ b/src/test/ui/suggestions/assoc-const-as-fn.rs @@ -0,0 +1,18 @@ +unsafe fn pointer(v: usize, w: u32) {} + +pub trait UniformScalar {} +impl UniformScalar for u32 {} + +pub trait GlUniformScalar: UniformScalar { + const FACTORY: unsafe fn(usize, Self) -> (); +} +impl GlUniformScalar for u32 { + const FACTORY: unsafe fn(usize, Self) -> () = pointer; +} + +pub fn foo(value: T) { + ::FACTORY(1, value); + //~^ ERROR the trait bound `T: GlUniformScalar` is not satisfied +} + +fn main() {} diff --git a/src/test/ui/suggestions/assoc-const-as-fn.stderr b/src/test/ui/suggestions/assoc-const-as-fn.stderr new file mode 100644 index 0000000000000..fa74068785827 --- /dev/null +++ b/src/test/ui/suggestions/assoc-const-as-fn.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `T: GlUniformScalar` is not satisfied + --> $DIR/assoc-const-as-fn.rs:14:5 + | +LL | ::FACTORY(1, value); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `GlUniformScalar` is not implemented for `T` + | +help: consider further restricting this bound + | +LL | pub fn foo(value: T) { + | +++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/crate-or-module-typo.stderr b/src/test/ui/suggestions/crate-or-module-typo.stderr index e8250c9fa5ff4..98b88b4fb9202 100644 --- a/src/test/ui/suggestions/crate-or-module-typo.stderr +++ b/src/test/ui/suggestions/crate-or-module-typo.stderr @@ -20,12 +20,6 @@ help: there is a crate or module with a similar name LL | use bar::bar; | ~~~ -error[E0433]: failed to resolve: use of undeclared crate or module `bar` - --> $DIR/crate-or-module-typo.rs:6:20 - | -LL | pub fn bar() { bar::baz(); } - | ^^^ use of undeclared crate or module `bar` - error[E0433]: failed to resolve: use of undeclared crate or module `st` --> $DIR/crate-or-module-typo.rs:14:10 | @@ -37,6 +31,12 @@ help: there is a crate or module with a similar name LL | bar: std::cell::Cell | ~~~ +error[E0433]: failed to resolve: use of undeclared crate or module `bar` + --> $DIR/crate-or-module-typo.rs:6:20 + | +LL | pub fn bar() { bar::baz(); } + | ^^^ use of undeclared crate or module `bar` + error: aborting due to 4 previous errors Some errors have detailed explanations: E0432, E0433. diff --git a/src/test/ui/suggestions/dont-suggest-ufcs-for-const.stderr b/src/test/ui/suggestions/dont-suggest-ufcs-for-const.stderr index 04e0511d788ed..0d9543e0b8fa2 100644 --- a/src/test/ui/suggestions/dont-suggest-ufcs-for-const.stderr +++ b/src/test/ui/suggestions/dont-suggest-ufcs-for-const.stderr @@ -2,13 +2,7 @@ error[E0599]: no method named `MAX` found for type `u32` in the current scope --> $DIR/dont-suggest-ufcs-for-const.rs:2:11 | LL | 1_u32.MAX(); - | ------^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `u32::MAX()` - | - = note: found the following associated functions; to be used as methods, functions must have a `self` parameter - = note: the candidate is defined in an impl for the type `u32` + | ^^^ method not found in `u32` error: aborting due to previous error diff --git a/src/test/ui/trait-bounds/impl-bound-with-references-error.rs b/src/test/ui/trait-bounds/impl-bound-with-references-error.rs new file mode 100644 index 0000000000000..e5d0a1aaed049 --- /dev/null +++ b/src/test/ui/trait-bounds/impl-bound-with-references-error.rs @@ -0,0 +1,20 @@ +// Regression test for #105138. +// This test ensures that the compiler does not add note +// for implementation of trait whose inner type is erroneous. + +pub enum LabelText { + Plain, +} + +impl From for LabelText +//~^ ERROR conflicting implementations of trait `From` for type `LabelText` [E0119] +where + T: Into>, + //~^ ERROR cannot find type `Cow` in this scope [E0412] +{ + fn from(text: T) -> Self { + LabelText::Plain(text.into()) + } +} + +fn main() {} diff --git a/src/test/ui/trait-bounds/impl-bound-with-references-error.stderr b/src/test/ui/trait-bounds/impl-bound-with-references-error.stderr new file mode 100644 index 0000000000000..95fd6bd504cdd --- /dev/null +++ b/src/test/ui/trait-bounds/impl-bound-with-references-error.stderr @@ -0,0 +1,24 @@ +error[E0412]: cannot find type `Cow` in this scope + --> $DIR/impl-bound-with-references-error.rs:12:13 + | +LL | T: Into>, + | ^^^ not found in this scope + | +help: consider importing this enum + | +LL | use std::borrow::Cow; + | + +error[E0119]: conflicting implementations of trait `From` for type `LabelText` + --> $DIR/impl-bound-with-references-error.rs:9:1 + | +LL | impl From for LabelText + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl From for T; + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0119, E0412. +For more information about an error, try `rustc --explain E0119`. diff --git a/src/tools/cargo b/src/tools/cargo index e027c4b5d25af..f6e737b1e3386 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit e027c4b5d25af2119b1956fac42863b9b3242744 +Subproject commit f6e737b1e3386adb89333bf06a01f68a91ac5306 diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 519da685f940a..91c701a5ddd2e 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -514,6 +514,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts { options: test::Options::new(), time_options: None, force_run_in_process: false, + fail_fast: std::env::var_os("RUSTC_TEST_FAIL_FAST").is_some(), } } diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index 5046ab9c7cbc1..e15f5fe3ccc96 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -60,6 +60,8 @@ impl<'a> Validator<'a> { fn check_item(&mut self, id: &'a Id) { if let Some(item) = &self.krate.index.get(id) { + item.links.values().for_each(|id| self.add_any_id(id)); + match &item.inner { ItemEnum::Import(x) => self.check_import(x), ItemEnum::Union(x) => self.check_union(x), @@ -376,6 +378,10 @@ impl<'a> Validator<'a> { } } + fn add_any_id(&mut self, id: &'a Id) { + self.add_id_checked(id, |_| true, "any kind of item"); + } + fn add_field_id(&mut self, id: &'a Id) { self.add_id_checked(id, Kind::is_struct_field, "StructField"); } @@ -446,3 +452,6 @@ fn set_remove(set: &mut HashSet) -> Option { None } } + +#[cfg(test)] +mod tests; diff --git a/src/tools/jsondoclint/src/validator/tests.rs b/src/tools/jsondoclint/src/validator/tests.rs new file mode 100644 index 0000000000000..c4aeee9c53b76 --- /dev/null +++ b/src/tools/jsondoclint/src/validator/tests.rs @@ -0,0 +1,50 @@ +use std::collections::HashMap; + +use rustdoc_json_types::{Crate, Item, Visibility}; + +use super::*; + +#[track_caller] +fn check(krate: &Crate, errs: &[Error]) { + let mut validator = Validator::new(krate); + validator.check_crate(); + + assert_eq!(errs, &validator.errs[..]); +} + +fn id(s: &str) -> Id { + Id(s.to_owned()) +} + +#[test] +fn errors_on_missing_links() { + let k = Crate { + root: id("0"), + crate_version: None, + includes_private: false, + index: HashMap::from_iter([( + id("0"), + Item { + name: Some("root".to_owned()), + id: id(""), + crate_id: 0, + span: None, + visibility: Visibility::Public, + docs: None, + links: HashMap::from_iter([("Not Found".to_owned(), id("1"))]), + attrs: vec![], + deprecation: None, + inner: ItemEnum::Module(Module { + is_crate: true, + items: vec![], + is_stripped: false, + }), + }, + )]), + paths: HashMap::new(), + external_crates: HashMap::new(), + format_version: rustdoc_json_types::FORMAT_VERSION, + }; + + check(&k, &[Error { kind: ErrorKind::NotFound, id: id("1") }]); +} diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 0a6b9417cc2e2..8dd18ae98e6d6 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -cef44f53034eac46be3a0e3eec7b2b3d4ef5140b +203c8765ea33c65d888febe0e8219c4bb11b0d89 diff --git a/src/tools/rustfmt/src/closures.rs b/src/tools/rustfmt/src/closures.rs index 423c3a997f53d..244d4427c5623 100644 --- a/src/tools/rustfmt/src/closures.rs +++ b/src/tools/rustfmt/src/closures.rs @@ -335,6 +335,7 @@ pub(crate) fn rewrite_last_closure( ref fn_decl, ref body, fn_decl_span: _, + fn_arg_span: _, } = **closure; let body = match body.kind { ast::ExprKind::Block(ref block, _) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index a7f4016728416..ff7a219d9bd85 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -31,23 +31,25 @@ const LICENSES: &[&str] = &[ /// tooling. It is _crucial_ that no exception crates be dependencies /// of the Rust runtime (std/test). const EXCEPTIONS: &[(&str, &str)] = &[ - ("mdbook", "MPL-2.0"), // mdbook - ("openssl", "Apache-2.0"), // cargo, mdbook - ("colored", "MPL-2.0"), // rustfmt - ("ryu", "Apache-2.0 OR BSL-1.0"), // cargo/... (because of serde) - ("bytesize", "Apache-2.0"), // cargo - ("im-rc", "MPL-2.0+"), // cargo - ("sized-chunks", "MPL-2.0+"), // cargo via im-rc - ("bitmaps", "MPL-2.0+"), // cargo via im-rc - ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot - ("snap", "BSD-3-Clause"), // rustc + ("ar_archive_writer", "Apache-2.0 WITH LLVM-exception"), // rustc + ("mdbook", "MPL-2.0"), // mdbook + ("openssl", "Apache-2.0"), // cargo, mdbook + ("colored", "MPL-2.0"), // rustfmt + ("ryu", "Apache-2.0 OR BSL-1.0"), // cargo/... (because of serde) + ("bytesize", "Apache-2.0"), // cargo + ("im-rc", "MPL-2.0+"), // cargo + ("sized-chunks", "MPL-2.0+"), // cargo via im-rc + ("bitmaps", "MPL-2.0+"), // cargo via im-rc + ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot + ("snap", "BSD-3-Clause"), // rustc ("fluent-langneg", "Apache-2.0"), // rustc (fluent translations) - ("self_cell", "Apache-2.0"), // rustc (fluent translations) + ("self_cell", "Apache-2.0"), // rustc (fluent translations) // FIXME: this dependency violates the documentation comment above: ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target ("dunce", "CC0-1.0"), // cargo (dev dependency) ("similar", "Apache-2.0"), // cargo (dev dependency) ("normalize-line-endings", "Apache-2.0"), // cargo (dev dependency) + ("dissimilar", "Apache-2.0"), // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps) ]; const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[ @@ -86,6 +88,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "aho-corasick", "annotate-snippets", "ansi_term", + "ar_archive_writer", "arrayvec", "atty", "autocfg", @@ -110,9 +113,9 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "cstr", "datafrog", "derive_more", - "difference", "digest", "displaydoc", + "dissimilar", "dlmalloc", "either", "ena", @@ -276,7 +279,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ "ahash", "anyhow", - "ar", "arrayvec", "autocfg", "bumpalo",