diff options
840 files changed, 13896 insertions, 7550 deletions
diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000000..63027b87815 --- /dev/null +++ b/.clang-format @@ -0,0 +1 @@ +BasedOnStyle: LLVM diff --git a/.reuse/dep5 b/.reuse/dep5 index 06afec2b3fa..0e2650ff2c0 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -29,6 +29,7 @@ Files: compiler/* x x.ps1 x.py + .clang-format .editorconfig .git-blame-ignore-revs .gitattributes diff --git a/Cargo.lock b/Cargo.lock index 241a37588b4..c7d2857b463 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -229,6 +229,12 @@ dependencies = [ ] [[package]] +name = "ar" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d67af77d68a931ecd5cbd8a3b5987d63a1d1d1278f7f6a60ae33db485cdebb69" + +[[package]] name = "ar_archive_writer" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3394,6 +3400,8 @@ dependencies = [ name = "run_make_support" version = "0.2.0" dependencies = [ + "ar", + "bstr", "gimli 0.28.1", "object 0.34.0", "regex", @@ -3454,6 +3462,13 @@ dependencies = [ ] [[package]] +name = "rustc-perf-wrapper" +version = "0.1.0" +dependencies = [ + "clap", +] + +[[package]] name = "rustc-rayon" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4668,6 +4683,8 @@ name = "rustc_smir" version = "0.0.0" dependencies = [ "rustc_abi", + "rustc_ast", + "rustc_ast_pretty", "rustc_data_structures", "rustc_hir", "rustc_middle", @@ -5627,6 +5644,7 @@ dependencies = [ "regex", "rustc-hash", "semver", + "similar", "termcolor", "walkdir", ] diff --git a/Cargo.toml b/Cargo.toml index c17ea99d037..93c520b0d68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ members = [ "src/tools/rustdoc-gui-test", "src/tools/opt-dist", "src/tools/coverage-dump", + "src/tools/rustc-perf-wrapper", ] exclude = [ diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 4a3ce0e0c30..f5e79c04d78 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1454,7 +1454,10 @@ pub enum ExprKind { Block(P<Block>, Option<Label>), /// An `async` block (`async move { ... }`), /// or a `gen` block (`gen move { ... }`) - Gen(CaptureBy, P<Block>, GenBlockKind), + /// + /// The span is the "decl", which is the header before the body `{ }` + /// including the `asyng`/`gen` keywords and possibly `move`. + Gen(CaptureBy, P<Block>, GenBlockKind, Span), /// An await expression (`my_future.await`). Span is of await keyword. Await(P<Expr>, Span), diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 676a2377c3b..593c78df3cd 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -327,7 +327,8 @@ impl MetaItem { I: Iterator<Item = &'a TokenTree>, { // FIXME: Share code with `parse_path`. - let path = match tokens.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref() { + let tt = tokens.next().map(|tt| TokenTree::uninterpolate(tt)); + let path = match tt.as_deref() { Some(&TokenTree::Token( Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span }, _, @@ -368,6 +369,12 @@ impl MetaItem { token::Nonterminal::NtPath(path) => (**path).clone(), _ => return None, }, + Some(TokenTree::Token( + Token { kind: token::OpenDelim(_) | token::CloseDelim(_), .. }, + _, + )) => { + panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tt); + } _ => return None, }; let list_closing_paren_pos = tokens.peek().map(|tt| tt.span().hi()); diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index ed8bf58eb23..27e781a5a63 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -402,10 +402,10 @@ fn visit_attr_args<T: MutVisitor>(args: &mut AttrArgs, vis: &mut T) { AttrArgs::Empty => {} AttrArgs::Delimited(args) => visit_delim_args(args, vis), AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => { - vis.visit_span(eq_span); vis.visit_expr(expr); + vis.visit_span(eq_span); } - AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => { + AttrArgs::Eq(_eq_span, AttrArgsEq::Hir(lit)) => { unreachable!("in literal form when visiting mac args eq: {:?}", lit) } } @@ -414,13 +414,13 @@ fn visit_attr_args<T: MutVisitor>(args: &mut AttrArgs, vis: &mut T) { // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. fn visit_delim_args<T: MutVisitor>(args: &mut DelimArgs, vis: &mut T) { let DelimArgs { dspan, delim: _, tokens } = args; - visit_delim_span(dspan, vis); visit_tts(tokens, vis); + visit_delim_span(dspan, vis); } -pub fn visit_delim_span<T: MutVisitor>(dspan: &mut DelimSpan, vis: &mut T) { - vis.visit_span(&mut dspan.open); - vis.visit_span(&mut dspan.close); +pub fn visit_delim_span<T: MutVisitor>(DelimSpan { open, close }: &mut DelimSpan, vis: &mut T) { + vis.visit_span(open); + vis.visit_span(close); } pub fn noop_flat_map_pat_field<T: MutVisitor>( @@ -441,11 +441,12 @@ fn noop_visit_use_tree<T: MutVisitor>(use_tree: &mut UseTree, vis: &mut T) { vis.visit_path(prefix); match kind { UseTreeKind::Simple(rename) => visit_opt(rename, |rename| vis.visit_ident(rename)), - UseTreeKind::Nested { items, .. } => { + UseTreeKind::Nested { items, span } => { for (tree, id) in items { vis.visit_id(id); vis.visit_use_tree(tree); } + vis.visit_span(span); } UseTreeKind::Glob => {} } @@ -486,12 +487,9 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) { let Ty { id, kind, span, tokens } = ty.deref_mut(); vis.visit_id(id); match kind { - TyKind::Infer - | TyKind::ImplicitSelf - | TyKind::Err(_) - | TyKind::Dummy - | TyKind::Never - | TyKind::CVarArgs => {} + TyKind::Err(_guar) => {} + TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Never | TyKind::CVarArgs => { + } TyKind::Slice(ty) => vis.visit_ty(ty), TyKind::Ptr(mt) => vis.visit_mt(mt), TyKind::Ref(lt, mt) => { @@ -533,8 +531,8 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) { fields.flat_map_in_place(|field| vis.flat_map_field_def(field)); } } - vis.visit_span(span); visit_lazy_tts(tokens, vis); + vis.visit_span(span); } fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis: &mut T) { @@ -550,8 +548,8 @@ pub fn noop_flat_map_variant<T: MutVisitor>( let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant; visitor.visit_id(id); visit_attrs(attrs, visitor); - visitor.visit_ident(ident); visitor.visit_vis(vis); + visitor.visit_ident(ident); visitor.visit_variant_data(data); visit_opt(disr_expr, |disr_expr| visitor.visit_anon_const(disr_expr)); visitor.visit_span(span); @@ -563,13 +561,13 @@ fn noop_visit_ident<T: MutVisitor>(Ident { name: _, span }: &mut Ident, vis: &mu } fn noop_visit_path<T: MutVisitor>(Path { segments, span, tokens }: &mut Path, vis: &mut T) { - vis.visit_span(span); for PathSegment { ident, id, args } in segments { vis.visit_id(id); vis.visit_ident(ident); visit_opt(args, |args| vis.visit_generic_args(args)); } visit_lazy_tts(tokens, vis); + vis.visit_span(span); } fn noop_visit_qself<T: MutVisitor>(qself: &mut Option<P<QSelf>>, vis: &mut T) { @@ -611,10 +609,11 @@ fn noop_visit_parenthesized_parameter_data<T: MutVisitor>( args: &mut ParenthesizedArgs, vis: &mut T, ) { - let ParenthesizedArgs { inputs, output, span, .. } = args; + let ParenthesizedArgs { inputs, output, span, inputs_span } = args; visit_thin_vec(inputs, |input| vis.visit_ty(input)); noop_visit_fn_ret_ty(output, vis); vis.visit_span(span); + vis.visit_span(inputs_span); } fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) { @@ -633,9 +632,9 @@ fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) { vis.visit_block(els); } } - vis.visit_span(span); - visit_opt(colon_sp, |sp| vis.visit_span(sp)); visit_lazy_tts(tokens, vis); + visit_opt(colon_sp, |sp| vis.visit_span(sp)); + vis.visit_span(span); } fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) { @@ -651,7 +650,7 @@ fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) { visit_lazy_tts(tokens, vis); visit_lazy_tts(attr_tokens, vis); } - AttrKind::DocComment(..) => {} + AttrKind::DocComment(_kind, _sym) => {} } vis.visit_span(span); } @@ -689,34 +688,24 @@ pub fn noop_flat_map_param<T: MutVisitor>(mut param: Param, vis: &mut T) -> Smal vis.visit_id(id); visit_attrs(attrs, vis); vis.visit_pat(pat); - vis.visit_span(span); vis.visit_ty(ty); + vis.visit_span(span); smallvec![param] } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. fn visit_attr_tt<T: MutVisitor>(tt: &mut AttrTokenTree, vis: &mut T) { match tt { - AttrTokenTree::Token(token, _) => { + AttrTokenTree::Token(token, _spacing) => { visit_token(token, vis); } - AttrTokenTree::Delimited(DelimSpan { open, close }, _spacing, _delim, tts) => { - vis.visit_span(open); - vis.visit_span(close); + AttrTokenTree::Delimited(dspan, _spacing, _delim, tts) => { visit_attr_tts(tts, vis); + visit_delim_span(dspan, vis); } - AttrTokenTree::Attributes(data) => { - for attr in &mut *data.attrs { - match &mut attr.kind { - AttrKind::Normal(normal) => { - visit_lazy_tts(&mut normal.tokens, vis); - } - AttrKind::DocComment(..) => { - vis.visit_span(&mut attr.span); - } - } - } - visit_lazy_tts_opt_mut(Some(&mut data.tokens), vis); + AttrTokenTree::Attributes(AttributesData { attrs, tokens }) => { + visit_attrs(attrs, vis); + visit_lazy_tts_opt_mut(Some(tokens), vis); } } } @@ -724,13 +713,12 @@ fn visit_attr_tt<T: MutVisitor>(tt: &mut AttrTokenTree, vis: &mut T) { // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. fn visit_tt<T: MutVisitor>(tt: &mut TokenTree, vis: &mut T) { match tt { - TokenTree::Token(token, _) => { + TokenTree::Token(token, _spacing) => { visit_token(token, vis); } - TokenTree::Delimited(DelimSpan { open, close }, _spacing, _delim, tts) => { - vis.visit_span(open); - vis.visit_span(close); + TokenTree::Delimited(dspan, _spacing, _delim, tts) => { visit_tts(tts, vis); + visit_delim_span(dspan, vis); } } } @@ -771,7 +759,7 @@ fn visit_lazy_tts<T: MutVisitor>(lazy_tts: &mut Option<LazyAttrTokenStream>, vis pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) { let Token { kind, span } = t; match kind { - token::Ident(name, _) | token::Lifetime(name) => { + token::Ident(name, _ /*raw*/) | token::Lifetime(name) => { let mut ident = Ident::new(*name, *span); vis.visit_ident(&mut ident); *name = ident.name; @@ -918,10 +906,11 @@ fn noop_visit_param_bound<T: MutVisitor>(pb: &mut GenericBound, vis: &mut T) { match pb { GenericBound::Trait(ty, _modifier) => vis.visit_poly_trait_ref(ty), GenericBound::Outlives(lifetime) => noop_visit_lifetime(lifetime, vis), - GenericBound::Use(args, _) => { + GenericBound::Use(args, span) => { for arg in args { vis.visit_precise_capturing_arg(arg); } + vis.visit_span(span); } } } @@ -946,9 +935,6 @@ pub fn noop_flat_map_generic_param<T: MutVisitor>( vis.visit_id(id); visit_attrs(attrs, vis); vis.visit_ident(ident); - if let Some(colon_span) = colon_span { - vis.visit_span(colon_span); - } visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis)); match kind { GenericParamKind::Lifetime => {} @@ -960,6 +946,9 @@ pub fn noop_flat_map_generic_param<T: MutVisitor>( visit_opt(default, |default| vis.visit_anon_const(default)); } } + if let Some(colon_span) = colon_span { + vis.visit_span(colon_span); + } smallvec![param] } @@ -979,6 +968,14 @@ fn noop_visit_generics<T: MutVisitor>(generics: &mut Generics, vis: &mut T) { vis.visit_span(span); } +fn noop_visit_ty_alias_where_clauses<T: MutVisitor>(tawcs: &mut TyAliasWhereClauses, vis: &mut T) { + let TyAliasWhereClauses { before, after, split: _ } = tawcs; + let TyAliasWhereClause { has_where_token: _, span: span_before } = before; + let TyAliasWhereClause { has_where_token: _, span: span_after } = after; + vis.visit_span(span_before); + vis.visit_span(span_after); +} + fn noop_visit_where_clause<T: MutVisitor>(wc: &mut WhereClause, vis: &mut T) { let WhereClause { has_where_token: _, predicates, span } = wc; visit_thin_vec(predicates, |predicate| vis.visit_where_predicate(predicate)); @@ -989,29 +986,29 @@ fn noop_visit_where_predicate<T: MutVisitor>(pred: &mut WherePredicate, vis: &mu match pred { WherePredicate::BoundPredicate(bp) => { let WhereBoundPredicate { span, bound_generic_params, bounded_ty, bounds } = bp; - vis.visit_span(span); bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_ty(bounded_ty); visit_vec(bounds, |bound| vis.visit_param_bound(bound)); + vis.visit_span(span); } WherePredicate::RegionPredicate(rp) => { let WhereRegionPredicate { span, lifetime, bounds } = rp; - vis.visit_span(span); noop_visit_lifetime(lifetime, vis); visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis)); + vis.visit_span(span); } WherePredicate::EqPredicate(ep) => { let WhereEqPredicate { span, lhs_ty, rhs_ty } = ep; - vis.visit_span(span); vis.visit_ty(lhs_ty); vis.visit_ty(rhs_ty); + vis.visit_span(span); } } } fn noop_visit_variant_data<T: MutVisitor>(vdata: &mut VariantData, vis: &mut T) { match vdata { - VariantData::Struct { fields, .. } => { + VariantData::Struct { fields, recovered: _ } => { fields.flat_map_in_place(|field| vis.flat_map_field_def(field)); } VariantData::Tuple(fields, id) => { @@ -1041,10 +1038,10 @@ pub fn noop_flat_map_field_def<T: MutVisitor>( let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _ } = &mut fd; visitor.visit_id(id); visit_attrs(attrs, visitor); - visitor.visit_span(span); - visit_opt(ident, |ident| visitor.visit_ident(ident)); visitor.visit_vis(vis); + visit_opt(ident, |ident| visitor.visit_ident(ident)); visitor.visit_ty(ty); + visitor.visit_span(span); smallvec![fd] } @@ -1069,8 +1066,8 @@ pub fn noop_visit_block<T: MutVisitor>(block: &mut P<Block>, vis: &mut T) { let Block { id, stmts, rules: _, span, tokens, could_be_bare_literal: _ } = block.deref_mut(); vis.visit_id(id); stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt)); - vis.visit_span(span); visit_lazy_tts(tokens, vis); + vis.visit_span(span); } pub fn noop_visit_item_kind(kind: &mut impl NoopVisitItemKind, vis: &mut impl MutVisitor) { @@ -1091,45 +1088,37 @@ impl NoopVisitItemKind for ItemKind { } ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => { visit_defaultness(defaultness, vis); - visit_fn_sig(sig, vis); vis.visit_generics(generics); + visit_fn_sig(sig, vis); visit_opt(body, |body| vis.visit_block(body)); } ItemKind::Mod(safety, mod_kind) => { visit_safety(safety, vis); match mod_kind { ModKind::Loaded(items, _inline, ModSpans { inner_span, inject_use_span }) => { + items.flat_map_in_place(|item| vis.flat_map_item(item)); vis.visit_span(inner_span); vis.visit_span(inject_use_span); - items.flat_map_in_place(|item| vis.flat_map_item(item)); } ModKind::Unloaded => {} } } ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm), ItemKind::GlobalAsm(asm) => vis.visit_inline_asm(asm), - ItemKind::TyAlias(box TyAlias { - defaultness, - generics, - where_clauses, - bounds, - ty, - .. - }) => { + ItemKind::TyAlias(box TyAlias { defaultness, generics, where_clauses, bounds, ty }) => { visit_defaultness(defaultness, vis); vis.visit_generics(generics); - vis.visit_span(&mut where_clauses.before.span); - vis.visit_span(&mut where_clauses.after.span); visit_bounds(bounds, vis); visit_opt(ty, |ty| vis.visit_ty(ty)); + noop_visit_ty_alias_where_clauses(where_clauses, vis); } ItemKind::Enum(EnumDef { variants }, generics) => { - variants.flat_map_in_place(|variant| vis.flat_map_variant(variant)); vis.visit_generics(generics); + variants.flat_map_in_place(|variant| vis.flat_map_variant(variant)); } ItemKind::Struct(variant_data, generics) | ItemKind::Union(variant_data, generics) => { - vis.visit_variant_data(variant_data); vis.visit_generics(generics); + vis.visit_variant_data(variant_data); } ItemKind::Impl(box Impl { defaultness, @@ -1217,14 +1206,12 @@ impl NoopVisitItemKind for AssocItemKind { where_clauses, bounds, ty, - .. }) => { visit_defaultness(defaultness, visitor); visitor.visit_generics(generics); - visitor.visit_span(&mut where_clauses.before.span); - visitor.visit_span(&mut where_clauses.after.span); visit_bounds(bounds, visitor); visit_opt(ty, |ty| visitor.visit_ty(ty)); + noop_visit_ty_alias_where_clauses(where_clauses, visitor); } AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac), AssocItemKind::Delegation(box Delegation { @@ -1302,8 +1289,8 @@ pub fn noop_flat_map_item<K: NoopVisitItemKind>( visitor.visit_vis(vis); visitor.visit_ident(ident); kind.noop_visit(visitor); - visitor.visit_span(span); visit_lazy_tts(tokens, visitor); + visitor.visit_span(span); smallvec![item] } @@ -1326,14 +1313,12 @@ impl NoopVisitItemKind for ForeignItemKind { where_clauses, bounds, ty, - .. }) => { visit_defaultness(defaultness, visitor); visitor.visit_generics(generics); - visitor.visit_span(&mut where_clauses.before.span); - visitor.visit_span(&mut where_clauses.after.span); visit_bounds(bounds, visitor); visit_opt(ty, |ty| visitor.visit_ty(ty)); + noop_visit_ty_alias_where_clauses(where_clauses, visitor); } ForeignItemKind::MacCall(mac) => visitor.visit_mac_call(mac), } @@ -1344,7 +1329,8 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) { let Pat { id, kind, span, tokens } = pat.deref_mut(); vis.visit_id(id); match kind { - PatKind::Wild | PatKind::Rest | PatKind::Never | PatKind::Err(_) => {} + PatKind::Err(_guar) => {} + PatKind::Wild | PatKind::Rest | PatKind::Never => {} PatKind::Ident(_binding_mode, ident, sub) => { vis.visit_ident(ident); visit_opt(sub, |sub| vis.visit_pat(sub)); @@ -1378,8 +1364,8 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) { PatKind::Paren(inner) => vis.visit_pat(inner), PatKind::MacCall(mac) => vis.visit_mac_call(mac), } - vis.visit_span(span); visit_lazy_tts(tokens, vis); + vis.visit_span(span); } fn noop_visit_anon_const<T: MutVisitor>(AnonConst { id, value }: &mut AnonConst, vis: &mut T) { @@ -1388,13 +1374,22 @@ fn noop_visit_anon_const<T: MutVisitor>(AnonConst { id, value }: &mut AnonConst, } fn noop_visit_inline_asm<T: MutVisitor>(asm: &mut InlineAsm, vis: &mut T) { - for (op, _) in &mut asm.operands { + // FIXME: Visit spans inside all this currently ignored stuff. + let InlineAsm { + template: _, + template_strs: _, + operands, + clobber_abis: _, + options: _, + line_spans: _, + } = asm; + for (op, span) in operands { match op { - InlineAsmOperand::In { expr, .. } - | InlineAsmOperand::Out { expr: Some(expr), .. } - | InlineAsmOperand::InOut { expr, .. } => vis.visit_expr(expr), - InlineAsmOperand::Out { expr: None, .. } => {} - InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => { + InlineAsmOperand::In { expr, reg: _ } + | InlineAsmOperand::Out { expr: Some(expr), reg: _, late: _ } + | InlineAsmOperand::InOut { expr, reg: _, late: _ } => vis.visit_expr(expr), + InlineAsmOperand::Out { expr: None, reg: _, late: _ } => {} + InlineAsmOperand::SplitInOut { in_expr, out_expr, reg: _, late: _ } => { vis.visit_expr(in_expr); if let Some(out_expr) = out_expr { vis.visit_expr(out_expr); @@ -1404,6 +1399,7 @@ fn noop_visit_inline_asm<T: MutVisitor>(asm: &mut InlineAsm, vis: &mut T) { InlineAsmOperand::Sym { sym } => vis.visit_inline_asm_sym(sym), InlineAsmOperand::Label { block } => vis.visit_block(block), } + vis.visit_span(span); } } @@ -1417,12 +1413,18 @@ fn noop_visit_inline_asm_sym<T: MutVisitor>( } fn noop_visit_format_args<T: MutVisitor>(fmt: &mut FormatArgs, vis: &mut T) { - for arg in fmt.arguments.all_args_mut() { - if let FormatArgumentKind::Named(name) = &mut arg.kind { - vis.visit_ident(name); + // FIXME: visit the template exhaustively. + let FormatArgs { span, template: _, arguments } = fmt; + for FormatArgument { kind, expr } in arguments.all_args_mut() { + match kind { + FormatArgumentKind::Named(ident) | FormatArgumentKind::Captured(ident) => { + vis.visit_ident(ident) + } + FormatArgumentKind::Normal => {} } - vis.visit_expr(&mut arg.expr); + vis.visit_expr(expr); } + vis.visit_span(span); } pub fn noop_visit_expr<T: MutVisitor>( @@ -1451,10 +1453,10 @@ pub fn noop_visit_expr<T: MutVisitor>( args: call_args, span, }) => { + vis.visit_method_receiver_expr(receiver); vis.visit_id(id); vis.visit_ident(ident); visit_opt(seg_args, |args| vis.visit_generic_args(args)); - vis.visit_method_receiver_expr(receiver); visit_thin_exprs(call_args, vis); vis.visit_span(span); } @@ -1471,10 +1473,11 @@ pub fn noop_visit_expr<T: MutVisitor>( vis.visit_expr(expr); vis.visit_ty(ty); } - ExprKind::AddrOf(_, _, ohs) => vis.visit_expr(ohs), - ExprKind::Let(pat, scrutinee, _, _) => { + ExprKind::AddrOf(_kind, _mut, ohs) => vis.visit_expr(ohs), + ExprKind::Let(pat, scrutinee, span, _recovered) => { vis.visit_pat(pat); vis.visit_expr(scrutinee); + vis.visit_span(span); } ExprKind::If(cond, tr, fl) => { vis.visit_expr(cond); @@ -1482,19 +1485,19 @@ pub fn noop_visit_expr<T: MutVisitor>( visit_opt(fl, |fl| ensure_sufficient_stack(|| vis.visit_expr(fl))); } ExprKind::While(cond, body, label) => { + visit_opt(label, |label| vis.visit_label(label)); vis.visit_expr(cond); vis.visit_block(body); - visit_opt(label, |label| vis.visit_label(label)); } ExprKind::ForLoop { pat, iter, body, label, kind: _ } => { + visit_opt(label, |label| vis.visit_label(label)); vis.visit_pat(pat); vis.visit_expr(iter); vis.visit_block(body); - visit_opt(label, |label| vis.visit_label(label)); } ExprKind::Loop(body, label, span) => { - vis.visit_block(body); visit_opt(label, |label| vis.visit_label(label)); + vis.visit_block(body); vis.visit_span(span); } ExprKind::Match(expr, arms, _kind) => { @@ -1522,11 +1525,12 @@ pub fn noop_visit_expr<T: MutVisitor>( vis.visit_span(fn_arg_span); } ExprKind::Block(blk, label) => { - vis.visit_block(blk); visit_opt(label, |label| vis.visit_label(label)); + vis.visit_block(blk); } - ExprKind::Gen(_capture_by, body, _) => { + ExprKind::Gen(_capture_by, body, _kind, decl_span) => { vis.visit_block(body); + vis.visit_span(decl_span); } ExprKind::Await(expr, await_kw_span) => { vis.visit_expr(expr); @@ -1601,10 +1605,13 @@ pub fn noop_visit_expr<T: MutVisitor>( } ExprKind::Try(expr) => vis.visit_expr(expr), ExprKind::TryBlock(body) => vis.visit_block(body), - ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err(_) | ExprKind::Dummy => {} + ExprKind::Lit(_token) => {} + ExprKind::IncludedBytes(_bytes) => {} + ExprKind::Err(_guar) => {} + ExprKind::Dummy => {} } - vis.visit_span(span); visit_lazy_tts(tokens, vis); + vis.visit_span(span); } pub fn noop_filter_map_expr<T: MutVisitor>(mut e: P<Expr>, vis: &mut T) -> Option<P<Expr>> { @@ -1619,7 +1626,6 @@ pub fn noop_flat_map_stmt<T: MutVisitor>( vis: &mut T, ) -> SmallVec<[Stmt; 1]> { vis.visit_id(&mut id); - vis.visit_span(&mut span); let stmts: SmallVec<_> = noop_flat_map_stmt_kind(kind, vis) .into_iter() .map(|kind| Stmt { id, kind, span }) @@ -1630,6 +1636,7 @@ pub fn noop_flat_map_stmt<T: MutVisitor>( the visitor should implement custom statement visiting" ); } + vis.visit_span(&mut span); stmts } @@ -1654,14 +1661,16 @@ fn noop_flat_map_stmt_kind<T: MutVisitor>(kind: StmtKind, vis: &mut T) -> SmallV } fn noop_visit_vis<T: MutVisitor>(visibility: &mut Visibility, vis: &mut T) { - match &mut visibility.kind { + let Visibility { kind, span, tokens } = visibility; + match kind { VisibilityKind::Public | VisibilityKind::Inherited => {} VisibilityKind::Restricted { path, id, shorthand: _ } => { vis.visit_id(id); vis.visit_path(path); } } - vis.visit_span(&mut visibility.span); + visit_lazy_tts(tokens, vis); + vis.visit_span(span); } fn noop_visit_capture_by<T: MutVisitor>(capture_by: &mut CaptureBy, vis: &mut T) { diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 3d46415507d..b4ddbe20689 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -224,7 +224,7 @@ impl AttrTokenStream { // Inner attributes are only supported on extern blocks, functions, // impls, and modules. All of these have their inner attributes // placed at the beginning of the rightmost outermost braced group: - // e.g. fn foo() { #![my_attr} } + // e.g. fn foo() { #![my_attr] } // // Therefore, we can insert them back into the right location // without needing to do any extra position tracking. diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index e2ef0542bf9..26cb04d4d47 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -14,6 +14,7 @@ //! those that are created by the expansion of a macro. use crate::ast::*; +use crate::ptr::P; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -298,40 +299,45 @@ pub trait Visitor<'ast>: Sized { } pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::Result { - walk_list!(visitor, visit_attribute, &krate.attrs); - walk_list!(visitor, visit_item, &krate.items); + let Crate { attrs, items, spans: _, id: _, is_placeholder: _ } = krate; + walk_list!(visitor, visit_attribute, attrs); + walk_list!(visitor, visit_item, items); V::Result::output() } pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) -> V::Result { - walk_list!(visitor, visit_attribute, &local.attrs); - try_visit!(visitor.visit_pat(&local.pat)); - visit_opt!(visitor, visit_ty, &local.ty); - if let Some((init, els)) = local.kind.init_else_opt() { + let Local { id: _, pat, ty, kind, span: _, colon_sp: _, attrs, tokens: _ } = local; + walk_list!(visitor, visit_attribute, attrs); + try_visit!(visitor.visit_pat(pat)); + visit_opt!(visitor, visit_ty, ty); + if let Some((init, els)) = kind.init_else_opt() { try_visit!(visitor.visit_expr(init)); visit_opt!(visitor, visit_block, els); } V::Result::output() } -pub fn walk_label<'a, V: Visitor<'a>>(visitor: &mut V, label: &'a Label) -> V::Result { - visitor.visit_ident(label.ident) +pub fn walk_label<'a, V: Visitor<'a>>(visitor: &mut V, Label { ident }: &'a Label) -> V::Result { + visitor.visit_ident(*ident) } pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime) -> V::Result { - visitor.visit_ident(lifetime.ident) + let Lifetime { id: _, ident } = lifetime; + visitor.visit_ident(*ident) } pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, trait_ref: &'a PolyTraitRef) -> V::Result where V: Visitor<'a>, { - walk_list!(visitor, visit_generic_param, &trait_ref.bound_generic_params); - visitor.visit_trait_ref(&trait_ref.trait_ref) + let PolyTraitRef { bound_generic_params, trait_ref, span: _ } = trait_ref; + walk_list!(visitor, visit_generic_param, bound_generic_params); + visitor.visit_trait_ref(trait_ref) } pub fn walk_trait_ref<'a, V: Visitor<'a>>(visitor: &mut V, trait_ref: &'a TraitRef) -> V::Result { - visitor.visit_path(&trait_ref.path, trait_ref.ref_id) + let TraitRef { path, ref_id } = trait_ref; + visitor.visit_path(path, *ref_id) } impl WalkItemKind for ItemKind { @@ -341,9 +347,10 @@ impl WalkItemKind for ItemKind { _ctxt: AssocCtxt, visitor: &mut V, ) -> V::Result { + let Item { id, span, vis, ident, .. } = item; match self { - ItemKind::ExternCrate(_) => {} - ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, item.id, false)), + ItemKind::ExternCrate(_rename) => {} + ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, *id, false)), ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); @@ -354,9 +361,8 @@ impl WalkItemKind for ItemKind { visit_opt!(visitor, visit_expr, expr); } ItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => { - let kind = - FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref()); - try_visit!(visitor.visit_fn(kind, item.span, item.id)); + let kind = FnKind::Fn(FnCtxt::Free, *ident, sig, vis, generics, body.as_deref()); + try_visit!(visitor.visit_fn(kind, *span, *id)); } ItemKind::Mod(_unsafety, mod_kind) => match mod_kind { ModKind::Loaded(items, _inline, _inner_span) => { @@ -364,11 +370,17 @@ impl WalkItemKind for ItemKind { } ModKind::Unloaded => {} }, - ItemKind::ForeignMod(foreign_module) => { - walk_list!(visitor, visit_foreign_item, &foreign_module.items); + ItemKind::ForeignMod(ForeignMod { safety: _, abi: _, items }) => { + walk_list!(visitor, visit_foreign_item, items); } ItemKind::GlobalAsm(asm) => try_visit!(visitor.visit_inline_asm(asm)), - ItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => { + ItemKind::TyAlias(box TyAlias { + generics, + bounds, + ty, + defaultness: _, + where_clauses: _, + }) => { try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); visit_opt!(visitor, visit_ty, ty); @@ -407,7 +419,7 @@ impl WalkItemKind for ItemKind { walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); } ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)), - ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, item.id)), + ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, *id)), ItemKind::Delegation(box Delegation { id, qself, @@ -416,18 +428,14 @@ impl WalkItemKind for ItemKind { body, from_glob: _, }) => { - if let Some(qself) = qself { - try_visit!(visitor.visit_ty(&qself.ty)); - } + try_visit!(walk_qself(visitor, qself)); try_visit!(visitor.visit_path(path, *id)); visit_opt!(visitor, visit_ident, *rename); visit_opt!(visitor, visit_block, body); } ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { - if let Some(qself) = qself { - try_visit!(visitor.visit_ty(&qself.ty)); - } - try_visit!(visitor.visit_path(prefix, item.id)); + try_visit!(walk_qself(visitor, qself)); + try_visit!(visitor.visit_path(prefix, *id)); if let Some(suffixes) = suffixes { for (ident, rename) in suffixes { visitor.visit_ident(*ident); @@ -452,9 +460,9 @@ pub fn walk_item<'a, V: Visitor<'a>>( pub fn walk_enum_def<'a, V: Visitor<'a>>( visitor: &mut V, - enum_definition: &'a EnumDef, + EnumDef { variants }: &'a EnumDef, ) -> V::Result { - walk_list!(visitor, visit_variant, &enum_definition.variants); + walk_list!(visitor, visit_variant, variants); V::Result::output() } @@ -462,48 +470,52 @@ pub fn walk_variant<'a, V: Visitor<'a>>(visitor: &mut V, variant: &'a Variant) - where V: Visitor<'a>, { - walk_list!(visitor, visit_attribute, &variant.attrs); - try_visit!(visitor.visit_ident(variant.ident)); - try_visit!(visitor.visit_vis(&variant.vis)); - try_visit!(visitor.visit_variant_data(&variant.data)); - visit_opt!(visitor, visit_variant_discr, &variant.disr_expr); + let Variant { attrs, id: _, span: _, vis, ident, data, disr_expr, is_placeholder: _ } = variant; + walk_list!(visitor, visit_attribute, attrs); + try_visit!(visitor.visit_vis(vis)); + try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_variant_data(data)); + visit_opt!(visitor, visit_variant_discr, disr_expr); V::Result::output() } pub fn walk_expr_field<'a, V: Visitor<'a>>(visitor: &mut V, f: &'a ExprField) -> V::Result { - walk_list!(visitor, visit_attribute, &f.attrs); - try_visit!(visitor.visit_expr(&f.expr)); - try_visit!(visitor.visit_ident(f.ident)); + let ExprField { attrs, id: _, span: _, ident, expr, is_shorthand: _, is_placeholder: _ } = f; + walk_list!(visitor, visit_attribute, attrs); + try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_expr(expr)); V::Result::output() } pub fn walk_pat_field<'a, V: Visitor<'a>>(visitor: &mut V, fp: &'a PatField) -> V::Result { - walk_list!(visitor, visit_attribute, &fp.attrs); - try_visit!(visitor.visit_ident(fp.ident)); - try_visit!(visitor.visit_pat(&fp.pat)); + let PatField { ident, pat, is_shorthand: _, attrs, id: _, span: _, is_placeholder: _ } = fp; + walk_list!(visitor, visit_attribute, attrs); + try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_pat(pat)); V::Result::output() } pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { - match &typ.kind { + let Ty { id, kind, span: _, tokens: _ } = typ; + match kind { TyKind::Slice(ty) | TyKind::Paren(ty) => try_visit!(visitor.visit_ty(ty)), - TyKind::Ptr(mutable_type) => try_visit!(visitor.visit_ty(&mutable_type.ty)), - TyKind::Ref(opt_lifetime, mutable_type) => { + TyKind::Ptr(MutTy { ty, mutbl: _ }) => try_visit!(visitor.visit_ty(ty)), + TyKind::Ref(opt_lifetime, MutTy { ty, mutbl: _ }) => { visit_opt!(visitor, visit_lifetime, opt_lifetime, LifetimeCtxt::Ref); - try_visit!(visitor.visit_ty(&mutable_type.ty)); + try_visit!(visitor.visit_ty(ty)); } TyKind::Tup(tuple_element_types) => { walk_list!(visitor, visit_ty, tuple_element_types); } TyKind::BareFn(function_declaration) => { - walk_list!(visitor, visit_generic_param, &function_declaration.generic_params); - try_visit!(walk_fn_decl(visitor, &function_declaration.decl)); + let BareFnTy { safety: _, ext: _, generic_params, decl, decl_span: _ } = + &**function_declaration; + walk_list!(visitor, visit_generic_param, generic_params); + try_visit!(walk_fn_decl(visitor, decl)); } TyKind::Path(maybe_qself, path) => { - if let Some(qself) = maybe_qself { - try_visit!(visitor.visit_ty(&qself.ty)); - } - try_visit!(visitor.visit_path(path, typ.id)); + try_visit!(walk_qself(visitor, maybe_qself)); + try_visit!(visitor.visit_path(path, *id)); } TyKind::Pat(ty, pat) => { try_visit!(visitor.visit_ty(ty)); @@ -513,25 +525,35 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { try_visit!(visitor.visit_ty(ty)); try_visit!(visitor.visit_anon_const(length)); } - TyKind::TraitObject(bounds, ..) => { + TyKind::TraitObject(bounds, _syntax) => { walk_list!(visitor, visit_param_bound, bounds, BoundKind::TraitObject); } - TyKind::ImplTrait(_, bounds) => { + TyKind::ImplTrait(_id, bounds) => { walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl); } TyKind::Typeof(expression) => try_visit!(visitor.visit_anon_const(expression)), - TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Err(_) => {} + TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy => {} + TyKind::Err(_guar) => {} TyKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)), TyKind::Never | TyKind::CVarArgs => {} - TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => { + TyKind::AnonStruct(_id, ref fields) | TyKind::AnonUnion(_id, ref fields) => { walk_list!(visitor, visit_field_def, fields); } } V::Result::output() } +fn walk_qself<'a, V: Visitor<'a>>(visitor: &mut V, qself: &'a Option<P<QSelf>>) -> V::Result { + if let Some(qself) = qself { + let QSelf { ty, path_span: _, position: _ } = &**qself; + try_visit!(visitor.visit_ty(ty)); + } + V::Result::output() +} + pub fn walk_path<'a, V: Visitor<'a>>(visitor: &mut V, path: &'a Path) -> V::Result { - walk_list!(visitor, visit_path_segment, &path.segments); + let Path { span: _, segments, tokens: _ } = path; + walk_list!(visitor, visit_path_segment, segments); V::Result::output() } @@ -540,14 +562,15 @@ pub fn walk_use_tree<'a, V: Visitor<'a>>( use_tree: &'a UseTree, id: NodeId, ) -> V::Result { - try_visit!(visitor.visit_path(&use_tree.prefix, id)); - match use_tree.kind { + let UseTree { prefix, kind, span: _ } = use_tree; + try_visit!(visitor.visit_path(prefix, id)); + match kind { UseTreeKind::Simple(rename) => { // The extra IDs are handled during AST lowering. - visit_opt!(visitor, visit_ident, rename); + visit_opt!(visitor, visit_ident, *rename); } UseTreeKind::Glob => {} - UseTreeKind::Nested { ref items, .. } => { + UseTreeKind::Nested { ref items, span: _ } => { for &(ref nested_tree, nested_id) in items { try_visit!(visitor.visit_use_tree(nested_tree, nested_id, true)); } @@ -560,8 +583,9 @@ pub fn walk_path_segment<'a, V: Visitor<'a>>( visitor: &mut V, segment: &'a PathSegment, ) -> V::Result { - try_visit!(visitor.visit_ident(segment.ident)); - visit_opt!(visitor, visit_generic_args, &segment.args); + let PathSegment { ident, id: _, args } = segment; + try_visit!(visitor.visit_ident(*ident)); + visit_opt!(visitor, visit_generic_args, args); V::Result::output() } @@ -570,8 +594,8 @@ where V: Visitor<'a>, { match generic_args { - GenericArgs::AngleBracketed(data) => { - for arg in &data.args { + GenericArgs::AngleBracketed(AngleBracketedArgs { span: _, args }) => { + for arg in args { match arg { AngleBracketedArg::Arg(a) => try_visit!(visitor.visit_generic_arg(a)), AngleBracketedArg::Constraint(c) => { @@ -581,8 +605,9 @@ where } } GenericArgs::Parenthesized(data) => { - walk_list!(visitor, visit_ty, &data.inputs); - try_visit!(visitor.visit_fn_ret_ty(&data.output)); + let ParenthesizedArgs { span: _, inputs, inputs_span: _, output } = data; + walk_list!(visitor, visit_ty, inputs); + try_visit!(visitor.visit_fn_ret_ty(output)); } } V::Result::output() @@ -603,9 +628,10 @@ pub fn walk_assoc_item_constraint<'a, V: Visitor<'a>>( visitor: &mut V, constraint: &'a AssocItemConstraint, ) -> V::Result { - try_visit!(visitor.visit_ident(constraint.ident)); - visit_opt!(visitor, visit_generic_args, &constraint.gen_args); - match &constraint.kind { + let AssocItemConstraint { id: _, ident, gen_args, kind, span: _ } = constraint; + try_visit!(visitor.visit_ident(*ident)); + visit_opt!(visitor, visit_generic_args, gen_args); + match kind { AssocItemConstraintKind::Equality { term } => match term { Term::Ty(ty) => try_visit!(visitor.visit_ty(ty)), Term::Const(c) => try_visit!(visitor.visit_anon_const(c)), @@ -618,43 +644,39 @@ pub fn walk_assoc_item_constraint<'a, V: Visitor<'a>>( } pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Result { - match &pattern.kind { + let Pat { id, kind, span: _, tokens: _ } = pattern; + match kind { PatKind::TupleStruct(opt_qself, path, elems) => { - if let Some(qself) = opt_qself { - try_visit!(visitor.visit_ty(&qself.ty)); - } - try_visit!(visitor.visit_path(path, pattern.id)); + try_visit!(walk_qself(visitor, opt_qself)); + try_visit!(visitor.visit_path(path, *id)); walk_list!(visitor, visit_pat, elems); } PatKind::Path(opt_qself, path) => { - if let Some(qself) = opt_qself { - try_visit!(visitor.visit_ty(&qself.ty)); - } - try_visit!(visitor.visit_path(path, pattern.id)) + try_visit!(walk_qself(visitor, opt_qself)); + try_visit!(visitor.visit_path(path, *id)) } - PatKind::Struct(opt_qself, path, fields, _) => { - if let Some(qself) = opt_qself { - try_visit!(visitor.visit_ty(&qself.ty)); - } - try_visit!(visitor.visit_path(path, pattern.id)); + PatKind::Struct(opt_qself, path, fields, _rest) => { + try_visit!(walk_qself(visitor, opt_qself)); + try_visit!(visitor.visit_path(path, *id)); walk_list!(visitor, visit_pat_field, fields); } - PatKind::Box(subpattern) - | PatKind::Deref(subpattern) - | PatKind::Ref(subpattern, _) - | PatKind::Paren(subpattern) => { + PatKind::Box(subpattern) | PatKind::Deref(subpattern) | PatKind::Paren(subpattern) => { + try_visit!(visitor.visit_pat(subpattern)); + } + PatKind::Ref(subpattern, _ /*mutbl*/) => { try_visit!(visitor.visit_pat(subpattern)); } - PatKind::Ident(_, ident, optional_subpattern) => { + PatKind::Ident(_bmode, ident, optional_subpattern) => { try_visit!(visitor.visit_ident(*ident)); visit_opt!(visitor, visit_pat, optional_subpattern); } PatKind::Lit(expression) => try_visit!(visitor.visit_expr(expression)), - PatKind::Range(lower_bound, upper_bound, _) => { + PatKind::Range(lower_bound, upper_bound, _end) => { visit_opt!(visitor, visit_expr, lower_bound); visit_opt!(visitor, visit_expr, upper_bound); } - PatKind::Wild | PatKind::Rest | PatKind::Never | PatKind::Err(_) => {} + PatKind::Wild | PatKind::Rest | PatKind::Never => {} + PatKind::Err(_guar) => {} PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => { walk_list!(visitor, visit_pat, elems); } @@ -680,7 +702,13 @@ impl WalkItemKind for ForeignItemKind { let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body.as_deref()); try_visit!(visitor.visit_fn(kind, span, id)); } - ForeignItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => { + ForeignItemKind::TyAlias(box TyAlias { + generics, + bounds, + ty, + defaultness: _, + where_clauses: _, + }) => { try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); visit_opt!(visitor, visit_ty, ty); @@ -697,7 +725,7 @@ pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericB match bound { GenericBound::Trait(typ, _modifier) => visitor.visit_poly_trait_ref(typ), GenericBound::Outlives(lifetime) => visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound), - GenericBound::Use(args, _) => { + GenericBound::Use(args, _span) => { walk_list!(visitor, visit_precise_capturing_arg, args); V::Result::output() } @@ -722,13 +750,15 @@ pub fn walk_generic_param<'a, V: Visitor<'a>>( visitor: &mut V, param: &'a GenericParam, ) -> V::Result { - walk_list!(visitor, visit_attribute, ¶m.attrs); - try_visit!(visitor.visit_ident(param.ident)); - walk_list!(visitor, visit_param_bound, ¶m.bounds, BoundKind::Bound); - match ¶m.kind { + let GenericParam { id: _, ident, attrs, bounds, is_placeholder: _, kind, colon_span: _ } = + param; + walk_list!(visitor, visit_attribute, attrs); + try_visit!(visitor.visit_ident(*ident)); + walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); + match kind { GenericParamKind::Lifetime => (), GenericParamKind::Type { default } => visit_opt!(visitor, visit_ty, default), - GenericParamKind::Const { ty, default, .. } => { + GenericParamKind::Const { ty, default, kw_span: _ } => { try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_anon_const, default); } @@ -737,8 +767,10 @@ pub fn walk_generic_param<'a, V: Visitor<'a>>( } pub fn walk_generics<'a, V: Visitor<'a>>(visitor: &mut V, generics: &'a Generics) -> V::Result { - walk_list!(visitor, visit_generic_param, &generics.params); - walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates); + let Generics { params, where_clause, span: _ } = generics; + let WhereClause { has_where_token: _, predicates, span: _ } = where_clause; + walk_list!(visitor, visit_generic_param, params); + walk_list!(visitor, visit_where_predicate, predicates); V::Result::output() } @@ -764,17 +796,17 @@ pub fn walk_where_predicate<'a, V: Visitor<'a>>( bounded_ty, bounds, bound_generic_params, - .. + span: _, }) => { + walk_list!(visitor, visit_generic_param, bound_generic_params); try_visit!(visitor.visit_ty(bounded_ty)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); - walk_list!(visitor, visit_generic_param, bound_generic_params); } - WherePredicate::RegionPredicate(WhereRegionPredicate { lifetime, bounds, .. }) => { + WherePredicate::RegionPredicate(WhereRegionPredicate { lifetime, bounds, span: _ }) => { try_visit!(visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); } - WherePredicate::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty, .. }) => { + WherePredicate::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty, span: _ }) => { try_visit!(visitor.visit_ty(lhs_ty)); try_visit!(visitor.visit_ty(rhs_ty)); } @@ -783,26 +815,28 @@ pub fn walk_where_predicate<'a, V: Visitor<'a>>( } pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FnRetTy) -> V::Result { - if let FnRetTy::Ty(output_ty) = ret_ty { - try_visit!(visitor.visit_ty(output_ty)); + match ret_ty { + FnRetTy::Default(_span) => {} + FnRetTy::Ty(output_ty) => try_visit!(visitor.visit_ty(output_ty)), } V::Result::output() } pub fn walk_fn_decl<'a, V: Visitor<'a>>( visitor: &mut V, - function_declaration: &'a FnDecl, + FnDecl { inputs, output }: &'a FnDecl, ) -> V::Result { - walk_list!(visitor, visit_param, &function_declaration.inputs); - visitor.visit_fn_ret_ty(&function_declaration.output) + walk_list!(visitor, visit_param, inputs); + visitor.visit_fn_ret_ty(output) } pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Result { match kind { - FnKind::Fn(_, _, sig, _, generics, body) => { + FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span: _ }, _vis, generics, body) => { + // Identifier and visibility are visited as a part of the item. + try_visit!(visitor.visit_fn_header(header)); try_visit!(visitor.visit_generics(generics)); - try_visit!(visitor.visit_fn_header(&sig.header)); - try_visit!(walk_fn_decl(visitor, &sig.decl)); + try_visit!(walk_fn_decl(visitor, decl)); visit_opt!(visitor, visit_block, body); } FnKind::Closure(binder, decl, body) => { @@ -833,7 +867,13 @@ impl WalkItemKind for AssocItemKind { FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref()); try_visit!(visitor.visit_fn(kind, span, id)); } - AssocItemKind::Type(box TyAlias { generics, bounds, ty, .. }) => { + AssocItemKind::Type(box TyAlias { + generics, + bounds, + ty, + defaultness: _, + where_clauses: _, + }) => { try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); visit_opt!(visitor, visit_ty, ty); @@ -849,18 +889,14 @@ impl WalkItemKind for AssocItemKind { body, from_glob: _, }) => { - if let Some(qself) = qself { - try_visit!(visitor.visit_ty(&qself.ty)); - } + try_visit!(walk_qself(visitor, qself)); try_visit!(visitor.visit_path(path, *id)); visit_opt!(visitor, visit_ident, *rename); visit_opt!(visitor, visit_block, body); } AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { - if let Some(qself) = qself { - try_visit!(visitor.visit_ty(&qself.ty)); - } - try_visit!(visitor.visit_path(prefix, item.id)); + try_visit!(walk_qself(visitor, qself)); + try_visit!(visitor.visit_path(prefix, id)); if let Some(suffixes) = suffixes { for (ident, rename) in suffixes { visitor.visit_ident(*ident); @@ -898,20 +934,23 @@ pub fn walk_struct_def<'a, V: Visitor<'a>>( } pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef) -> V::Result { - walk_list!(visitor, visit_attribute, &field.attrs); - try_visit!(visitor.visit_vis(&field.vis)); - visit_opt!(visitor, visit_ident, field.ident); - try_visit!(visitor.visit_ty(&field.ty)); + let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _ } = field; + walk_list!(visitor, visit_attribute, attrs); + try_visit!(visitor.visit_vis(vis)); + visit_opt!(visitor, visit_ident, *ident); + try_visit!(visitor.visit_ty(ty)); V::Result::output() } pub fn walk_block<'a, V: Visitor<'a>>(visitor: &mut V, block: &'a Block) -> V::Result { - walk_list!(visitor, visit_stmt, &block.stmts); + let Block { stmts, id: _, rules: _, span: _, tokens: _, could_be_bare_literal: _ } = block; + walk_list!(visitor, visit_stmt, stmts); V::Result::output() } pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) -> V::Result { - match &statement.kind { + let Stmt { id: _, kind, span: _ } = statement; + match kind { StmtKind::Let(local) => try_visit!(visitor.visit_local(local)), StmtKind::Item(item) => try_visit!(visitor.visit_item(item)), StmtKind::Expr(expr) | StmtKind::Semi(expr) => try_visit!(visitor.visit_expr(expr)), @@ -926,25 +965,37 @@ pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) -> V: } pub fn walk_mac<'a, V: Visitor<'a>>(visitor: &mut V, mac: &'a MacCall) -> V::Result { - visitor.visit_path(&mac.path, DUMMY_NODE_ID) + let MacCall { path, args: _ } = mac; + visitor.visit_path(path, DUMMY_NODE_ID) } pub fn walk_anon_const<'a, V: Visitor<'a>>(visitor: &mut V, constant: &'a AnonConst) -> V::Result { - visitor.visit_expr(&constant.value) + let AnonConst { id: _, value } = constant; + visitor.visit_expr(value) } pub fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm) -> V::Result { - for (op, _) in &asm.operands { + let InlineAsm { + template: _, + template_strs: _, + operands, + clobber_abis: _, + options: _, + line_spans: _, + } = asm; + for (op, _span) in operands { match op { - InlineAsmOperand::In { expr, .. } - | InlineAsmOperand::Out { expr: Some(expr), .. } - | InlineAsmOperand::InOut { expr, .. } => try_visit!(visitor.visit_expr(expr)), - InlineAsmOperand::Out { expr: None, .. } => {} - InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => { + InlineAsmOperand::In { expr, reg: _ } + | InlineAsmOperand::Out { expr: Some(expr), reg: _, late: _ } + | InlineAsmOperand::InOut { expr, reg: _, late: _ } => { + try_visit!(visitor.visit_expr(expr)) + } + InlineAsmOperand::Out { expr: None, reg: _, late: _ } => {} + InlineAsmOperand::SplitInOut { in_expr, out_expr, reg: _, late: _ } => { try_visit!(visitor.visit_expr(in_expr)); visit_opt!(visitor, visit_expr, out_expr); } - InlineAsmOperand::Const { anon_const, .. } => { + InlineAsmOperand::Const { anon_const } => { try_visit!(visitor.visit_anon_const(anon_const)) } InlineAsmOperand::Sym { sym } => try_visit!(visitor.visit_inline_asm_sym(sym)), @@ -956,28 +1007,30 @@ pub fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm) pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>( visitor: &mut V, - sym: &'a InlineAsmSym, + InlineAsmSym { id, qself, path }: &'a InlineAsmSym, ) -> V::Result { - if let Some(qself) = &sym.qself { - try_visit!(visitor.visit_ty(&qself.ty)); - } - visitor.visit_path(&sym.path, sym.id) + try_visit!(walk_qself(visitor, qself)); + visitor.visit_path(path, *id) } pub fn walk_format_args<'a, V: Visitor<'a>>(visitor: &mut V, fmt: &'a FormatArgs) -> V::Result { - for arg in fmt.arguments.all_args() { - if let FormatArgumentKind::Named(name) = arg.kind { - try_visit!(visitor.visit_ident(name)); + let FormatArgs { span: _, template: _, arguments } = fmt; + for FormatArgument { kind, expr } in arguments.all_args() { + match kind { + FormatArgumentKind::Named(ident) | FormatArgumentKind::Captured(ident) => { + try_visit!(visitor.visit_ident(*ident)) + } + FormatArgumentKind::Normal => {} } - try_visit!(visitor.visit_expr(&arg.expr)); + try_visit!(visitor.visit_expr(expr)); } V::Result::output() } pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V::Result { - walk_list!(visitor, visit_attribute, &expression.attrs); - - match &expression.kind { + let Expr { id, kind, span, attrs, tokens: _ } = expression; + walk_list!(visitor, visit_attribute, attrs); + match kind { ExprKind::Array(subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); } @@ -987,12 +1040,11 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V try_visit!(visitor.visit_anon_const(count)); } ExprKind::Struct(se) => { - if let Some(qself) = &se.qself { - try_visit!(visitor.visit_ty(&qself.ty)); - } - try_visit!(visitor.visit_path(&se.path, expression.id)); - walk_list!(visitor, visit_expr_field, &se.fields); - match &se.rest { + let StructExpr { qself, path, fields, rest } = &**se; + try_visit!(walk_qself(visitor, qself)); + try_visit!(visitor.visit_path(path, *id)); + walk_list!(visitor, visit_expr_field, fields); + match rest { StructRest::Base(expr) => try_visit!(visitor.visit_expr(expr)), StructRest::Rest(_span) => {} StructRest::None => {} @@ -1006,22 +1058,25 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V walk_list!(visitor, visit_expr, arguments); } ExprKind::MethodCall(box MethodCall { seg, receiver, args, span: _ }) => { - try_visit!(visitor.visit_path_segment(seg)); try_visit!(visitor.visit_expr(receiver)); + try_visit!(visitor.visit_path_segment(seg)); walk_list!(visitor, visit_expr, args); } - ExprKind::Binary(_, left_expression, right_expression) => { + ExprKind::Binary(_op, left_expression, right_expression) => { try_visit!(visitor.visit_expr(left_expression)); try_visit!(visitor.visit_expr(right_expression)); } - ExprKind::AddrOf(_, _, subexpression) | ExprKind::Unary(_, subexpression) => { + ExprKind::AddrOf(_kind, _mutbl, subexpression) => { + try_visit!(visitor.visit_expr(subexpression)); + } + ExprKind::Unary(_op, subexpression) => { try_visit!(visitor.visit_expr(subexpression)); } ExprKind::Cast(subexpression, typ) | ExprKind::Type(subexpression, typ) => { try_visit!(visitor.visit_expr(subexpression)); try_visit!(visitor.visit_ty(typ)); } - ExprKind::Let(pat, expr, _, _) => { + ExprKind::Let(pat, expr, _span, _recovered) => { try_visit!(visitor.visit_pat(pat)); try_visit!(visitor.visit_expr(expr)); } @@ -1041,7 +1096,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V try_visit!(visitor.visit_expr(iter)); try_visit!(visitor.visit_block(body)); } - ExprKind::Loop(block, opt_label, _) => { + ExprKind::Loop(block, opt_label, _span) => { visit_opt!(visitor, visit_label, opt_label); try_visit!(visitor.visit_block(block)); } @@ -1061,23 +1116,19 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V fn_arg_span: _, }) => { try_visit!(visitor.visit_capture_by(capture_clause)); - try_visit!(visitor.visit_fn( - FnKind::Closure(binder, fn_decl, body), - expression.span, - expression.id - )) + try_visit!(visitor.visit_fn(FnKind::Closure(binder, fn_decl, body), *span, *id)) } ExprKind::Block(block, opt_label) => { visit_opt!(visitor, visit_label, opt_label); try_visit!(visitor.visit_block(block)); } - ExprKind::Gen(_, body, _) => try_visit!(visitor.visit_block(body)), - ExprKind::Await(expr, _) => try_visit!(visitor.visit_expr(expr)), - ExprKind::Assign(lhs, rhs, _) => { + ExprKind::Gen(_capt, body, _kind, _decl_span) => try_visit!(visitor.visit_block(body)), + ExprKind::Await(expr, _span) => try_visit!(visitor.visit_expr(expr)), + ExprKind::Assign(lhs, rhs, _span) => { try_visit!(visitor.visit_expr(lhs)); try_visit!(visitor.visit_expr(rhs)); } - ExprKind::AssignOp(_, left_expression, right_expression) => { + ExprKind::AssignOp(_op, left_expression, right_expression) => { try_visit!(visitor.visit_expr(left_expression)); try_visit!(visitor.visit_expr(right_expression)); } @@ -1085,20 +1136,18 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V try_visit!(visitor.visit_expr(subexpression)); try_visit!(visitor.visit_ident(*ident)); } - ExprKind::Index(main_expression, index_expression, _) => { + ExprKind::Index(main_expression, index_expression, _span) => { try_visit!(visitor.visit_expr(main_expression)); try_visit!(visitor.visit_expr(index_expression)); } - ExprKind::Range(start, end, _) => { + ExprKind::Range(start, end, _limit) => { visit_opt!(visitor, visit_expr, start); visit_opt!(visitor, visit_expr, end); } ExprKind::Underscore => {} ExprKind::Path(maybe_qself, path) => { - if let Some(qself) = maybe_qself { - try_visit!(visitor.visit_ty(&qself.ty)); - } - try_visit!(visitor.visit_path(path, expression.id)); + try_visit!(walk_qself(visitor, maybe_qself)); + try_visit!(visitor.visit_path(path, *id)); } ExprKind::Break(opt_label, opt_expr) => { visit_opt!(visitor, visit_label, opt_label); @@ -1127,38 +1176,53 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V } ExprKind::Try(subexpression) => try_visit!(visitor.visit_expr(subexpression)), ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)), - ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err(_) | ExprKind::Dummy => {} + ExprKind::Lit(_token) => {} + ExprKind::IncludedBytes(_bytes) => {} + ExprKind::Err(_guar) => {} + ExprKind::Dummy => {} } visitor.visit_expr_post(expression) } pub fn walk_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Param) -> V::Result { - walk_list!(visitor, visit_attribute, ¶m.attrs); - try_visit!(visitor.visit_pat(¶m.pat)); - try_visit!(visitor.visit_ty(¶m.ty)); + let Param { attrs, ty, pat, id: _, span: _, is_placeholder: _ } = param; + walk_list!(visitor, visit_attribute, attrs); + try_visit!(visitor.visit_pat(pat)); + try_visit!(visitor.visit_ty(ty)); V::Result::output() } pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) -> V::Result { - walk_list!(visitor, visit_attribute, &arm.attrs); - try_visit!(visitor.visit_pat(&arm.pat)); - visit_opt!(visitor, visit_expr, &arm.guard); - visit_opt!(visitor, visit_expr, &arm.body); + let Arm { attrs, pat, guard, body, span: _, id: _, is_placeholder: _ } = arm; + walk_list!(visitor, visit_attribute, attrs); + try_visit!(visitor.visit_pat(pat)); + visit_opt!(visitor, visit_expr, guard); + visit_opt!(visitor, visit_expr, body); V::Result::output() } pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) -> V::Result { - if let VisibilityKind::Restricted { ref path, id, shorthand: _ } = vis.kind { - try_visit!(visitor.visit_path(path, id)); + let Visibility { kind, span: _, tokens: _ } = vis; + match kind { + VisibilityKind::Restricted { path, id, shorthand: _ } => { + try_visit!(visitor.visit_path(path, *id)); + } + VisibilityKind::Public | VisibilityKind::Inherited => {} } V::Result::output() } pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) -> V::Result { - match &attr.kind { - AttrKind::Normal(normal) => try_visit!(walk_attr_args(visitor, &normal.item.args)), - AttrKind::DocComment(..) => {} + let Attribute { kind, id: _, style: _, span: _ } = attr; + match kind { + AttrKind::Normal(normal) => { + let NormalAttr { item, tokens: _ } = &**normal; + let AttrItem { unsafety: _, path, args, tokens: _ } = item; + try_visit!(visitor.visit_path(path, DUMMY_NODE_ID)); + try_visit!(walk_attr_args(visitor, args)); + } + AttrKind::DocComment(_kind, _sym) => {} } V::Result::output() } @@ -1166,9 +1230,9 @@ pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) pub fn walk_attr_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a AttrArgs) -> V::Result { match args { AttrArgs::Empty => {} - AttrArgs::Delimited(_) => {} + AttrArgs::Delimited(_args) => {} AttrArgs::Eq(_eq_span, AttrArgsEq::Ast(expr)) => try_visit!(visitor.visit_expr(expr)), - AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => { + AttrArgs::Eq(_eq_span, AttrArgsEq::Hir(lit)) => { unreachable!("in literal form when walking mac args eq: {:?}", lit) } } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 79cff0fbcd2..218fa974022 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -103,7 +103,6 @@ impl<'hir> LoweringContext<'_, 'hir> { ParamMode::Optional, ParenthesizedGenericArgs::Err, ImplTraitContext::Disallowed(ImplTraitPosition::Path), - None, // Method calls can't have bound modifiers None, )); @@ -227,7 +226,7 @@ impl<'hir> LoweringContext<'_, 'hir> { *fn_arg_span, ), }, - ExprKind::Gen(capture_clause, block, genblock_kind) => { + ExprKind::Gen(capture_clause, block, genblock_kind, decl_span) => { let desugaring_kind = match genblock_kind { GenBlockKind::Async => hir::CoroutineDesugaring::Async, GenBlockKind::Gen => hir::CoroutineDesugaring::Gen, @@ -237,6 +236,7 @@ impl<'hir> LoweringContext<'_, 'hir> { *capture_clause, e.id, None, + *decl_span, e.span, desugaring_kind, hir::CoroutineSource::Block, @@ -616,6 +616,7 @@ impl<'hir> LoweringContext<'_, 'hir> { capture_clause: CaptureBy, closure_node_id: NodeId, return_ty: Option<hir::FnRetTy<'hir>>, + fn_decl_span: Span, span: Span, desugaring_kind: hir::CoroutineDesugaring, coroutine_source: hir::CoroutineSource, @@ -692,7 +693,7 @@ impl<'hir> LoweringContext<'_, 'hir> { bound_generic_params: &[], fn_decl, body, - fn_decl_span: self.lower_span(span), + fn_decl_span: self.lower_span(fn_decl_span), fn_arg_span: None, kind: hir::ClosureKind::Coroutine(coroutine_kind), constness: hir::Constness::NotConst, @@ -1083,6 +1084,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( &inner_decl, |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)), + fn_decl_span, body.span, coroutine_kind, hir::CoroutineSource::Closure, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 4c7e8c24d32..d59ac576629 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -56,7 +56,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { owner: NodeId, f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>, ) { - let mut lctx = LoweringContext::new(self.tcx, self.resolver); + let mut lctx = LoweringContext::new(self.tcx, self.resolver, self.ast_index); lctx.with_hir_id_owner(owner, |lctx| f(lctx)); for (def_id, info) in lctx.children { @@ -190,6 +190,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, (ty, body_id)) = self.lower_generics( generics, Const::No, + false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -211,6 +212,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // declaration (decl), not the return types. let coroutine_kind = header.coroutine_kind; let body_id = this.lower_maybe_coroutine_body( + *fn_sig_span, span, hir_id, decl, @@ -220,7 +222,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let itctx = ImplTraitContext::Universal; let (generics, decl) = - this.lower_generics(generics, header.constness, id, itctx, |this| { + this.lower_generics(generics, header.constness, false, id, itctx, |this| { this.lower_fn_decl( decl, id, @@ -264,6 +266,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, ty) = self.lower_generics( &generics, Const::No, + false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| match ty { @@ -292,6 +295,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, variants) = self.lower_generics( generics, Const::No, + false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -306,6 +310,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, struct_def) = self.lower_generics( generics, Const::No, + false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, struct_def), @@ -316,6 +321,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, vdata) = self.lower_generics( generics, Const::No, + false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, vdata), @@ -347,12 +353,9 @@ impl<'hir> LoweringContext<'_, 'hir> { // parent lifetime. let itctx = ImplTraitContext::Universal; let (generics, (trait_ref, lowered_ty)) = - self.lower_generics(ast_generics, *constness, id, itctx, |this| { + self.lower_generics(ast_generics, Const::No, false, id, itctx, |this| { let modifiers = TraitBoundModifiers { - constness: match *constness { - Const::Yes(span) => BoundConstness::Maybe(span), - Const::No => BoundConstness::Never, - }, + constness: BoundConstness::Never, asyncness: BoundAsyncness::Normal, // we don't use this in bound lowering polarity: BoundPolarity::Positive, @@ -388,6 +391,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(*s)), }; hir::ItemKind::Impl(self.arena.alloc(hir::Impl { + constness: self.lower_constness(*constness), safety: self.lower_safety(*safety, hir::Safety::Safe), polarity, defaultness, @@ -399,15 +403,10 @@ impl<'hir> LoweringContext<'_, 'hir> { })) } ItemKind::Trait(box Trait { is_auto, safety, generics, bounds, items }) => { - // FIXME(const_trait_impl, effects, fee1-dead) this should be simplified if possible - let constness = attrs - .unwrap_or(&[]) - .iter() - .find(|x| x.has_name(sym::const_trait)) - .map_or(Const::No, |x| Const::Yes(x.span)); let (generics, (safety, items, bounds)) = self.lower_generics( generics, - constness, + Const::No, + false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -428,6 +427,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, bounds) = self.lower_generics( generics, Const::No, + false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -608,30 +608,45 @@ impl<'hir> LoweringContext<'_, 'hir> { // This is used to track which lifetimes have already been defined, // and which need to be replicated when lowering an async fn. - let generics = match parent_hir.node().expect_item().kind { + let parent_item = parent_hir.node().expect_item(); + let constness = match parent_item.kind { hir::ItemKind::Impl(impl_) => { self.is_in_trait_impl = impl_.of_trait.is_some(); - &impl_.generics + // N.B. the impl should always lower to methods that have `const host: bool` params if the trait + // is const. It doesn't matter whether the `impl` itself is const. Disallowing const fn from + // calling non-const impls are done through associated types. + if let Some(def_id) = impl_.of_trait.and_then(|tr| tr.trait_def_id()) { + if let Some(local_def) = def_id.as_local() { + match &self.ast_index[local_def] { + AstOwner::Item(ast::Item { attrs, .. }) => attrs + .iter() + .find(|attr| attr.has_name(sym::const_trait)) + .map_or(Const::No, |attr| Const::Yes(attr.span)), + _ => Const::No, + } + } else { + self.tcx + .get_attr(def_id, sym::const_trait) + .map_or(Const::No, |attr| Const::Yes(attr.span)) + } + } else { + Const::No + } } - hir::ItemKind::Trait(_, _, generics, _, _) => generics, + hir::ItemKind::Trait(_, _, _, _, _) => parent_hir + .attrs + .get(parent_item.hir_id().local_id) + .iter() + .find(|attr| attr.has_name(sym::const_trait)) + .map_or(Const::No, |attr| Const::Yes(attr.span)), kind => { span_bug!(item.span, "assoc item has unexpected kind of parent: {}", kind.descr()) } }; - if self.tcx.features().effects { - self.host_param_id = generics - .params - .iter() - .find(|param| { - matches!(param.kind, hir::GenericParamKind::Const { is_host_effect: true, .. }) - }) - .map(|param| param.def_id); - } - match ctxt { - AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item)), - AssocCtxt::Impl => hir::OwnerNode::ImplItem(self.lower_impl_item(item)), + AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item, constness)), + AssocCtxt::Impl => hir::OwnerNode::ImplItem(self.lower_impl_item(item, constness)), } } @@ -647,7 +662,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let fdec = &sig.decl; let itctx = ImplTraitContext::Universal; let (generics, (fn_dec, fn_args)) = - self.lower_generics(generics, Const::No, i.id, itctx, |this| { + self.lower_generics(generics, Const::No, false, i.id, itctx, |this| { ( // Disallow `impl Trait` in foreign items. this.lower_fn_decl( @@ -764,7 +779,11 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { + fn lower_trait_item( + &mut self, + i: &AssocItem, + trait_constness: Const, + ) -> &'hir hir::TraitItem<'hir> { let hir_id = self.lower_node_id(i.id); self.lower_attrs(hir_id, &i.attrs); let trait_item_def_id = hir_id.expect_owner(); @@ -774,6 +793,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, kind) = self.lower_generics( generics, Const::No, + false, i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -794,11 +814,13 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, FnDeclKind::Trait, sig.header.coroutine_kind, + trait_constness, ); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false) } AssocItemKind::Fn(box Fn { sig, generics, body: Some(body), .. }) => { let body_id = self.lower_maybe_coroutine_body( + sig.span, i.span, hir_id, &sig.decl, @@ -811,6 +833,7 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, FnDeclKind::Trait, sig.header.coroutine_kind, + trait_constness, ); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true) } @@ -820,6 +843,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, kind) = self.lower_generics( &generics, Const::No, + false, i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -892,7 +916,11 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr(span, hir::ExprKind::Err(guar)) } - fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> { + fn lower_impl_item( + &mut self, + i: &AssocItem, + constness_of_trait: Const, + ) -> &'hir hir::ImplItem<'hir> { // Since `default impl` is not yet implemented, this is always true in impls. let has_value = true; let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); @@ -903,6 +931,7 @@ impl<'hir> LoweringContext<'_, 'hir> { AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics( generics, Const::No, + false, i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -915,6 +944,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ), AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => { let body_id = self.lower_maybe_coroutine_body( + sig.span, i.span, hir_id, &sig.decl, @@ -927,6 +957,7 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent }, sig.header.coroutine_kind, + constness_of_trait, ); (generics, hir::ImplItemKind::Fn(sig, body_id)) @@ -937,6 +968,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_generics( &generics, Const::No, + false, i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| match ty { @@ -1111,6 +1143,7 @@ impl<'hir> LoweringContext<'_, 'hir> { /// `gen {}` block as appropriate. fn lower_maybe_coroutine_body( &mut self, + fn_decl_span: Span, span: Span, fn_id: hir::HirId, decl: &FnDecl, @@ -1124,6 +1157,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( decl, |this| this.lower_block_expr(body), + fn_decl_span, body.span, coroutine_kind, hir::CoroutineSource::Fn, @@ -1145,6 +1179,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, decl: &FnDecl, lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::Expr<'hir>, + fn_decl_span: Span, body_span: Span, coroutine_kind: CoroutineKind, coroutine_source: hir::CoroutineSource, @@ -1315,13 +1350,6 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let closure_id = coroutine_kind.closure_id(); - let span = if let FnRetTy::Default(span) = decl.output - && matches!(coroutine_source, rustc_hir::CoroutineSource::Closure) - { - body_span.with_lo(span.lo()) - } else { - body_span - }; let coroutine_expr = self.make_desugared_coroutine_expr( // The default capture mode here is by-ref. Later on during upvar analysis, // we will force the captured arguments to by-move, but for async closures, @@ -1330,7 +1358,8 @@ impl<'hir> LoweringContext<'_, 'hir> { CaptureBy::Ref, closure_id, None, - span, + fn_decl_span, + body_span, desugaring_kind, coroutine_source, mkbody, @@ -1352,15 +1381,18 @@ impl<'hir> LoweringContext<'_, 'hir> { id: NodeId, kind: FnDeclKind, coroutine_kind: Option<CoroutineKind>, + parent_constness: Const, ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) { let header = self.lower_fn_header(sig.header); // Don't pass along the user-provided constness of trait associated functions; we don't want to // synthesize a host effect param for them. We reject `const` on them during AST validation. - let constness = if kind == FnDeclKind::Inherent { sig.header.constness } else { Const::No }; + let constness = + if kind == FnDeclKind::Inherent { sig.header.constness } else { parent_constness }; let itctx = ImplTraitContext::Universal; - let (generics, decl) = self.lower_generics(generics, constness, id, itctx, |this| { - this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind) - }); + let (generics, decl) = + self.lower_generics(generics, constness, kind == FnDeclKind::Impl, id, itctx, |this| { + this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind) + }); (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) } @@ -1436,6 +1468,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, generics: &Generics, constness: Const, + force_append_constness: bool, parent_node_id: NodeId, itctx: ImplTraitContext, f: impl FnOnce(&mut Self) -> T, @@ -1496,7 +1529,9 @@ impl<'hir> LoweringContext<'_, 'hir> { // if the effects feature is enabled. This needs to be done before we lower where // clauses since where clauses need to bind to the DefId of the host param let host_param_parts = if let Const::Yes(span) = constness - && self.tcx.features().effects + // if this comes from implementing a `const` trait, we must force constness to be appended + // to the impl item, no matter whether effects is enabled. + && (self.tcx.features().effects || force_append_constness) { let span = self.lower_span(span); let param_node_id = self.next_node_id(); @@ -1609,6 +1644,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }), )), )), + // FIXME(effects) we might not need a default. default: Some(self.arena.alloc(hir::AnonConst { def_id: anon_const, hir_id: const_id, @@ -1616,6 +1652,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span, })), is_host_effect: true, + synthetic: true, }, colon_span: None, pure_wrt_drop: false, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 0a06304fcec..8fba46625ab 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -142,14 +142,19 @@ struct LoweringContext<'a, 'hir> { generics_def_id_map: Vec<LocalDefIdMap<LocalDefId>>, host_param_id: Option<LocalDefId>, + ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>, } impl<'a, 'hir> LoweringContext<'a, 'hir> { - fn new(tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering) -> Self { + fn new( + tcx: TyCtxt<'hir>, + resolver: &'a mut ResolverAstLowering, + ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>, + ) -> Self { Self { // Pseudo-globals. tcx, - resolver: resolver, + resolver, arena: tcx.hir_arena, // HirId handling. @@ -185,6 +190,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { allow_async_iterator: [sym::gen_future, sym::async_iterator].into(), generics_def_id_map: Default::default(), host_param_id: None, + ast_index, } } @@ -2135,7 +2141,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param: &GenericParam, source: hir::GenericParamSource, ) -> hir::GenericParam<'hir> { - let (name, kind) = self.lower_generic_param_kind(param, source); + let (name, kind) = self.lower_generic_param_kind( + param, + source, + attr::contains_name(¶m.attrs, sym::rustc_runtime), + ); let hir_id = self.lower_node_id(param.id); self.lower_attrs(hir_id, ¶m.attrs); @@ -2155,6 +2165,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, param: &GenericParam, source: hir::GenericParamSource, + is_host_effect: bool, ) -> (hir::ParamName, hir::GenericParamKind<'hir>) { match ¶m.kind { GenericParamKind::Lifetime => { @@ -2220,7 +2231,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ( hir::ParamName::Plain(self.lower_ident(param.ident)), - hir::GenericParamKind::Const { ty, default, is_host_effect: false }, + hir::GenericParamKind::Const { ty, default, is_host_effect, synthetic: false }, ) } } @@ -2607,78 +2618,6 @@ struct GenericArgsCtor<'hir> { } impl<'hir> GenericArgsCtor<'hir> { - fn push_constness( - &mut self, - lcx: &mut LoweringContext<'_, 'hir>, - constness: ast::BoundConstness, - ) { - if !lcx.tcx.features().effects { - return; - } - - let (span, body) = match constness { - BoundConstness::Never => return, - BoundConstness::Always(span) => { - let span = lcx.lower_span(span); - - let body = hir::ExprKind::Lit( - lcx.arena.alloc(hir::Lit { node: LitKind::Bool(false), span }), - ); - - (span, body) - } - BoundConstness::Maybe(span) => { - let span = lcx.lower_span(span); - - let Some(host_param_id) = lcx.host_param_id else { - lcx.dcx().span_delayed_bug( - span, - "no host param id for call in const yet no errors reported", - ); - return; - }; - - let hir_id = lcx.next_id(); - let res = Res::Def(DefKind::ConstParam, host_param_id.to_def_id()); - let body = hir::ExprKind::Path(hir::QPath::Resolved( - None, - lcx.arena.alloc(hir::Path { - span, - res, - segments: arena_vec![ - lcx; - hir::PathSegment::new( - Ident { name: sym::host, span }, - hir_id, - res - ) - ], - }), - )); - - (span, body) - } - }; - let body = lcx.lower_body(|lcx| (&[], lcx.expr(span, body))); - - let id = lcx.next_node_id(); - let hir_id = lcx.next_id(); - - let def_id = lcx.create_def( - lcx.current_hir_id_owner.def_id, - id, - kw::Empty, - DefKind::AnonConst, - span, - ); - - lcx.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); - self.args.push(hir::GenericArg::Const(hir::ConstArg { - value: lcx.arena.alloc(hir::AnonConst { def_id, hir_id, body, span }), - is_desugared_from_effects: true, - })) - } - fn is_empty(&self) -> bool { self.args.is_empty() && self.constraints.is_empty() diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 9d38e1e6784..9a1ca703699 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -107,8 +107,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param_mode, parenthesized_generic_args, itctx, - // if this is the last segment, add constness to the trait path - if i == proj_start - 1 { modifiers.map(|m| m.constness) } else { None }, bound_modifier_allowed_features.clone(), ) }, @@ -165,7 +163,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ParenthesizedGenericArgs::Err, itctx, None, - None, )); let qpath = hir::QPath::TypeRelative(ty, hir_segment); @@ -208,7 +205,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ParenthesizedGenericArgs::Err, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, - None, ) })), span: self.lower_span(p.span), @@ -222,7 +218,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param_mode: ParamMode, parenthesized_generic_args: ParenthesizedGenericArgs, itctx: ImplTraitContext, - constness: Option<ast::BoundConstness>, // Additional features ungated with a bound modifier like `async`. // This is passed down to the implicit associated type binding in // parenthesized bounds. @@ -289,10 +284,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) }; - if let Some(constness) = constness { - generic_args.push_constness(self, constness); - } - let has_lifetimes = generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))); diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index ba4b6130b60..022f953c6e7 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1,10 +1,20 @@ -// Validate AST before lowering it to HIR. -// -// This pass is supposed to catch things that fit into AST data structures, -// but not permitted by the language. It runs after expansion when AST is frozen, -// so it can check for erroneous constructions produced by syntax extensions. -// This pass is supposed to perform only simple checks not requiring name resolution -// or type checking or some other kind of complex analysis. +//! Validate AST before lowering it to HIR. +//! +//! This pass intends to check that the constructed AST is *syntactically valid* to allow the rest +//! of the compiler to assume that the AST is valid. These checks cannot be performed during parsing +//! because attribute macros are allowed to accept certain pieces of invalid syntax such as a +//! function without body outside of a trait definition: +//! +//! ```ignore (illustrative) +//! #[my_attribute] +//! mod foo { +//! fn missing_body(); +//! } +//! ``` +//! +//! These checks are run post-expansion, after AST is frozen, to be able to check for erroneous +//! constructions produced by proc macros. This pass is only intended for simple checks that do not +//! require name resolution or type checking, or other kinds of complex analysis. use itertools::{Either, Itertools}; use rustc_ast::ptr::P; @@ -459,13 +469,18 @@ impl<'a> AstValidator<'a> { fn check_item_safety(&self, span: Span, safety: Safety) { match self.extern_mod_safety { Some(extern_safety) => { - if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_)) - && (extern_safety == Safety::Default || !self.features.unsafe_extern_blocks) - { - self.dcx().emit_err(errors::InvalidSafetyOnExtern { - item_span: span, - block: self.current_extern_span().shrink_to_lo(), - }); + if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_)) { + if extern_safety == Safety::Default { + self.dcx().emit_err(errors::InvalidSafetyOnExtern { + item_span: span, + block: Some(self.current_extern_span().shrink_to_lo()), + }); + } else if !self.features.unsafe_extern_blocks { + self.dcx().emit_err(errors::InvalidSafetyOnExtern { + item_span: span, + block: None, + }); + } } } None => { @@ -1088,7 +1103,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } } else if let &Safety::Unsafe(span) = safety { - this.dcx().emit_err(errors::UnsafeItem { span, kind: "extern block" }); + let mut diag = this + .dcx() + .create_err(errors::UnsafeItem { span, kind: "extern block" }); + rustc_session::parse::add_feature_diagnostics( + &mut diag, + self.session, + sym::unsafe_extern_blocks, + ); + diag.emit(); } if abi.is_none() { diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 965d8fac712..bfb90476450 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -222,7 +222,7 @@ pub struct InvalidSafetyOnExtern { #[primary_span] pub item_span: Span, #[suggestion(code = "unsafe ", applicability = "machine-applicable", style = "verbose")] - pub block: Span, + pub block: Option<Span>, } #[derive(Diagnostic)] diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index f2f6594e686..3d1f43a3766 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -540,7 +540,7 @@ impl<'a> State<'a> { self.ibox(0); self.print_block_with_attrs(blk, attrs); } - ast::ExprKind::Gen(capture_clause, blk, kind) => { + ast::ExprKind::Gen(capture_clause, blk, kind, _decl_span) => { self.word_nbsp(kind.modifier()); self.print_capture_clause(*capture_clause); // cbox/ibox in analogy to the `ExprKind::Block` arm above diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 1cc7fee718e..c26bbb926ea 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1288,7 +1288,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { return false; } // Try to find predicates on *generic params* that would allow copying `ty` - let suggestion = + let mut suggestion = if let Some(symbol) = tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { format!(": {symbol}.clone()") } else { @@ -1296,6 +1296,8 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { }; let mut sugg = Vec::with_capacity(2); let mut inner_expr = expr; + let mut is_raw_ptr = false; + let typeck_result = self.infcx.tcx.typeck(self.mir_def_id()); // Remove uses of `&` and `*` when suggesting `.clone()`. while let hir::ExprKind::AddrOf(.., inner) | hir::ExprKind::Unary(hir::UnOp::Deref, inner) = &inner_expr.kind @@ -1306,14 +1308,32 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { return false; } inner_expr = inner; + if let Some(inner_type) = typeck_result.node_type_opt(inner.hir_id) { + if matches!(inner_type.kind(), ty::RawPtr(..)) { + is_raw_ptr = true; + break; + } + } } - if inner_expr.span.lo() != expr.span.lo() { + // Cloning the raw pointer doesn't make sense in some cases and would cause a type mismatch error. (see #126863) + if inner_expr.span.lo() != expr.span.lo() && !is_raw_ptr { + // Remove "(*" or "(&" sugg.push((expr.span.with_hi(inner_expr.span.lo()), String::new())); } + // Check whether `expr` is surrounded by parentheses or not. let span = if inner_expr.span.hi() != expr.span.hi() { // Account for `(*x)` to suggest `x.clone()`. - expr.span.with_lo(inner_expr.span.hi()) + if is_raw_ptr { + expr.span.shrink_to_hi() + } else { + // Remove the close parenthesis ")" + expr.span.with_lo(inner_expr.span.hi()) + } } else { + if is_raw_ptr { + sugg.push((expr.span.shrink_to_lo(), "(".to_string())); + suggestion = ").clone()".to_string(); + } expr.span.shrink_to_hi() }; sugg.push((span, suggestion)); diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 12fa4c4f5ee..407b83d4977 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -639,12 +639,27 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { fn add_borrow_suggestions(&self, err: &mut Diag<'_>, span: Span) { match self.infcx.tcx.sess.source_map().span_to_snippet(span) { Ok(snippet) if snippet.starts_with('*') => { - err.span_suggestion_verbose( - span.with_hi(span.lo() + BytePos(1)), - "consider removing the dereference here", - String::new(), - Applicability::MaybeIncorrect, - ); + let sp = span.with_lo(span.lo() + BytePos(1)); + let inner = self.find_expr(sp); + let mut is_raw_ptr = false; + if let Some(inner) = inner { + let typck_result = self.infcx.tcx.typeck(self.mir_def_id()); + if let Some(inner_type) = typck_result.node_type_opt(inner.hir_id) { + if matches!(inner_type.kind(), ty::RawPtr(..)) { + is_raw_ptr = true; + } + } + } + // If the `inner` is a raw pointer, do not suggest removing the "*", see #126863 + // FIXME: need to check whether the assigned object can be a raw pointer, see `tests/ui/borrowck/issue-20801.rs`. + if !is_raw_ptr { + err.span_suggestion_verbose( + span.with_hi(span.lo() + BytePos(1)), + "consider removing the dereference here", + String::new(), + Applicability::MaybeIncorrect, + ); + } } _ => { err.span_suggestion_verbose( diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index a98cb6f0f76..c664891dad5 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -298,7 +298,7 @@ impl<'cx, 'a> Context<'cx, 'a> { // sync with the `rfc-2011-nicer-assert-messages/all-expr-kinds.rs` test. ExprKind::Assign(_, _, _) | ExprKind::AssignOp(_, _, _) - | ExprKind::Gen(_, _, _) + | ExprKind::Gen(_, _, _, _) | ExprKind::Await(_, _) | ExprKind::Block(_, _) | ExprKind::Break(_, _) diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 8ac59605bc1..f8d93666145 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -5,6 +5,7 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(lint_reasons))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] @@ -12,7 +13,6 @@ #![feature(decl_macro)] #![feature(if_let_guard)] #![feature(let_chains)] -#![feature(lint_reasons)] #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] #![feature(rustdoc_internals)] diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 548c23cc794..230fe4f5871 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -28,6 +28,19 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { global // TODO(antoyo): set linkage. } + + pub fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> { + if value.get_type() == self.bool_type.make_pointer() { + if let Some(pointee) = typ.get_pointee() { + if pointee.dyncast_vector().is_some() { + panic!() + } + } + } + // NOTE: since bitcast makes a value non-constant, don't bitcast if not necessary as some + // SIMD builtins require a constant value. + self.bitcast_if_needed(value, typ) + } } pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> RValue<'gcc> { @@ -239,19 +252,6 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { const_alloc_to_gcc(self, alloc) } - fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> { - if value.get_type() == self.bool_type.make_pointer() { - if let Some(pointee) = typ.get_pointee() { - if pointee.dyncast_vector().is_some() { - panic!() - } - } - } - // NOTE: since bitcast makes a value non-constant, don't bitcast if not necessary as some - // SIMD builtins require a constant value. - self.bitcast_if_needed(value, typ) - } - fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { self.context .new_array_access(None, base_addr, self.const_usize(offset.bytes())) diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 4a1f5188a80..6231b09552c 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -27,7 +27,6 @@ use crate::callee::get_fn; use crate::common::SignType; pub struct CodegenCx<'gcc, 'tcx> { - pub check_overflow: bool, pub codegen_unit: &'tcx CodegenUnit<'tcx>, pub context: &'gcc Context<'gcc>, @@ -134,8 +133,6 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { tcx: TyCtxt<'tcx>, supports_128bit_integers: bool, ) -> Self { - let check_overflow = tcx.sess.overflow_checks(); - let create_type = |ctype, rust_type| { let layout = tcx.layout_of(ParamEnv::reveal_all().and(rust_type)).unwrap(); let align = layout.align.abi.bytes(); @@ -271,7 +268,6 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } let mut cx = Self { - check_overflow, codegen_unit, context, current_func: RefCell::new(None), @@ -511,10 +507,6 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { &self.tcx.sess } - fn check_overflow(&self) -> bool { - self.check_overflow - } - fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx> { self.codegen_unit } diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs index 68471b028be..4caff2e6310 100644 --- a/compiler/rustc_codegen_gcc/src/type_.rs +++ b/compiler/rustc_codegen_gcc/src/type_.rs @@ -89,13 +89,34 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { ty::FloatTy::F128 => self.type_f128(), } } -} -impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { - fn type_i1(&self) -> Type<'gcc> { + pub fn type_i1(&self) -> Type<'gcc> { self.bool_type } + pub fn type_struct(&self, fields: &[Type<'gcc>], packed: bool) -> Type<'gcc> { + let types = fields.to_vec(); + if let Some(typ) = self.struct_types.borrow().get(fields) { + return *typ; + } + let fields: Vec<_> = fields + .iter() + .enumerate() + .map(|(index, field)| { + self.context.new_field(None, *field, format!("field{}_TODO", index)) + }) + .collect(); + let typ = self.context.new_struct_type(None, "struct", &fields).as_type(); + if packed { + #[cfg(feature = "master")] + typ.set_packed(); + } + self.struct_types.borrow_mut().insert(types, typ); + typ + } +} + +impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn type_i8(&self) -> Type<'gcc> { self.i8_type } @@ -131,7 +152,7 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn type_f64(&self) -> Type<'gcc> { self.double_type } - + fn type_f128(&self) -> Type<'gcc> { unimplemented!("f16_f128") } @@ -140,27 +161,6 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { self.context.new_function_pointer_type(None, return_type, params, false) } - fn type_struct(&self, fields: &[Type<'gcc>], packed: bool) -> Type<'gcc> { - let types = fields.to_vec(); - if let Some(typ) = self.struct_types.borrow().get(fields) { - return *typ; - } - let fields: Vec<_> = fields - .iter() - .enumerate() - .map(|(index, field)| { - self.context.new_field(None, *field, format!("field{}_TODO", index)) - }) - .collect(); - let typ = self.context.new_struct_type(None, "struct", &fields).as_type(); - if packed { - #[cfg(feature = "master")] - typ.set_packed(); - } - self.struct_types.borrow_mut().insert(types, typ); - typ - } - fn type_kind(&self, typ: Type<'gcc>) -> TypeKind { if self.is_int_type_or_bool(typ) { TypeKind::Integer diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 48693895da1..cd82894af18 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -2,7 +2,7 @@ use rustc_codegen_ssa::traits::*; use rustc_hir::def_id::DefId; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry}; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::{FunctionReturn, OptLevel}; use rustc_span::symbol::sym; @@ -53,6 +53,34 @@ fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll } } +#[inline] +fn patchable_function_entry_attrs<'ll>( + cx: &CodegenCx<'ll, '_>, + attr: Option<PatchableFunctionEntry>, +) -> SmallVec<[&'ll Attribute; 2]> { + let mut attrs = SmallVec::new(); + let patchable_spec = attr.unwrap_or_else(|| { + PatchableFunctionEntry::from_config(cx.tcx.sess.opts.unstable_opts.patchable_function_entry) + }); + let entry = patchable_spec.entry(); + let prefix = patchable_spec.prefix(); + if entry > 0 { + attrs.push(llvm::CreateAttrStringValue( + cx.llcx, + "patchable-function-entry", + &format!("{}", entry), + )); + } + if prefix > 0 { + attrs.push(llvm::CreateAttrStringValue( + cx.llcx, + "patchable-function-prefix", + &format!("{}", prefix), + )); + } + attrs +} + /// Get LLVM sanitize attributes. #[inline] pub fn sanitize_attrs<'ll>( @@ -421,6 +449,7 @@ pub fn from_fn_attrs<'ll, 'tcx>( llvm::set_alignment(llfn, align); } to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize)); + to_add.extend(patchable_function_entry_attrs(cx, codegen_fn_attrs.patchable_function_entry)); // Always annotate functions with the target-cpu they are compiled for. // Without this, ThinLTO won't inline Rust functions into Clang generated diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 4ffc92eb633..d42c6ed827a 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -329,10 +329,6 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { const_alloc_to_llvm(self, alloc, /*static*/ false) } - fn const_bitcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value { - self.const_bitcast(val, ty) - } - fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { unsafe { llvm::LLVMConstInBoundsGEP2( diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 7d92888feee..1a8e8efdae5 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -3,6 +3,7 @@ use crate::back::write::to_llvm_code_model; use crate::callee::get_fn; use crate::coverageinfo; use crate::debuginfo; +use crate::debuginfo::metadata::apply_vcall_visibility_metadata; use crate::llvm; use crate::llvm_util; use crate::type_::Type; @@ -43,7 +44,6 @@ use std::str; /// All other LLVM data structures in the `CodegenCx` are tied to that `llvm::Context`. pub struct CodegenCx<'ll, 'tcx> { pub tcx: TyCtxt<'tcx>, - pub check_overflow: bool, pub use_dll_storage_attrs: bool, pub tls_model: llvm::ThreadLocalMode, @@ -441,8 +441,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { // start) and then strongly recommending static linkage on Windows! let use_dll_storage_attrs = tcx.sess.target.is_like_windows; - let check_overflow = tcx.sess.overflow_checks(); - let tls_model = to_llvm_tls_model(tcx.sess.tls_model()); let (llcx, llmod) = (&*llvm_module.llcx, llvm_module.llmod()); @@ -466,7 +464,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { CodegenCx { tcx, - check_overflow, use_dll_storage_attrs, tls_model, llmod, @@ -522,6 +519,15 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { &self.vtables } + fn apply_vcall_visibility_metadata( + &self, + ty: Ty<'tcx>, + poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, + vtable: &'ll Value, + ) { + apply_vcall_visibility_metadata(self, ty, poly_trait_ref, vtable); + } + fn get_fn(&self, instance: Instance<'tcx>) -> &'ll Value { get_fn(self, instance) } @@ -596,10 +602,6 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { self.tcx.sess } - fn check_overflow(&self) -> bool { - self.check_overflow - } - fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx> { self.codegen_unit } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 8de4e0effad..742bfd76590 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1449,12 +1449,18 @@ fn build_vtable_type_di_node<'ll, 'tcx>( .di_node } -fn vcall_visibility_metadata<'ll, 'tcx>( +pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, trait_ref: Option<PolyExistentialTraitRef<'tcx>>, vtable: &'ll Value, ) { + // FIXME(flip1995): The virtual function elimination optimization only works with full LTO in + // LLVM at the moment. + if !cx.sess().opts.unstable_opts.virtual_function_elimination || cx.sess().lto() != Lto::Fat { + return; + } + enum VCallVisibility { Public = 0, LinkageUnit = 1, @@ -1531,12 +1537,6 @@ pub fn create_vtable_di_node<'ll, 'tcx>( poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, vtable: &'ll Value, ) { - // FIXME(flip1995): The virtual function elimination optimization only works with full LTO in - // LLVM at the moment. - if cx.sess().opts.unstable_opts.virtual_function_elimination && cx.sess().lto() == Lto::Fat { - vcall_visibility_metadata(cx, ty, poly_trait_ref, vtable); - } - if cx.dbg_cx.is_none() { return; } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 4b7a2643007..ed0989a0ba4 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -274,10 +274,11 @@ impl CodegenBackend for LlvmCodegenBackend { |tcx, ()| llvm_util::global_llvm_features(tcx.sess, true) } - fn print(&self, req: &PrintRequest, out: &mut dyn PrintBackendInfo, sess: &Session) { + fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) { + use std::fmt::Write; match req.kind { PrintKind::RelocationModels => { - writeln!(out, "Available relocation models:"); + writeln!(out, "Available relocation models:").unwrap(); for name in &[ "static", "pic", @@ -288,25 +289,25 @@ impl CodegenBackend for LlvmCodegenBackend { "ropi-rwpi", "default", ] { - writeln!(out, " {name}"); + writeln!(out, " {name}").unwrap(); } - writeln!(out); + writeln!(out).unwrap(); } PrintKind::CodeModels => { - writeln!(out, "Available code models:"); + writeln!(out, "Available code models:").unwrap(); for name in &["tiny", "small", "kernel", "medium", "large"] { - writeln!(out, " {name}"); + writeln!(out, " {name}").unwrap(); } - writeln!(out); + writeln!(out).unwrap(); } PrintKind::TlsModels => { - writeln!(out, "Available TLS models:"); + writeln!(out, "Available TLS models:").unwrap(); for name in &["global-dynamic", "local-dynamic", "initial-exec", "local-exec", "emulated"] { - writeln!(out, " {name}"); + writeln!(out, " {name}").unwrap(); } - writeln!(out); + writeln!(out).unwrap(); } PrintKind::StackProtectorStrategies => { writeln!( @@ -332,7 +333,8 @@ impl CodegenBackend for LlvmCodegenBackend { none Do not generate stack canaries. "# - ); + ) + .unwrap(); } _other => llvm_util::print(req, out, sess), } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 7e0f264a4ae..0e89e66be49 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -6,7 +6,6 @@ use crate::errors::{ use crate::llvm; use libc::c_int; use rustc_codegen_ssa::base::wants_wasm_eh; -use rustc_codegen_ssa::traits::PrintBackendInfo; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::small_c_str::SmallCStr; use rustc_fs_util::path_to_c_string; @@ -18,6 +17,7 @@ use rustc_target::spec::{MergeFunctions, PanicStrategy}; use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES; use std::ffi::{c_char, c_void, CStr, CString}; +use std::fmt::Write; use std::path::Path; use std::ptr; use std::slice; @@ -372,7 +372,7 @@ fn llvm_target_features(tm: &llvm::TargetMachine) -> Vec<(&str, &str)> { ret } -fn print_target_features(out: &mut dyn PrintBackendInfo, sess: &Session, tm: &llvm::TargetMachine) { +fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMachine) { let mut llvm_target_features = llvm_target_features(tm); let mut known_llvm_target_features = FxHashSet::<&'static str>::default(); let mut rustc_target_features = sess @@ -412,24 +412,26 @@ fn print_target_features(out: &mut dyn PrintBackendInfo, sess: &Session, tm: &ll .max() .unwrap_or(0); - writeln!(out, "Features supported by rustc for this target:"); + writeln!(out, "Features supported by rustc for this target:").unwrap(); for (feature, desc) in &rustc_target_features { - writeln!(out, " {feature:max_feature_len$} - {desc}."); + writeln!(out, " {feature:max_feature_len$} - {desc}.").unwrap(); } - writeln!(out, "\nCode-generation features supported by LLVM for this target:"); + writeln!(out, "\nCode-generation features supported by LLVM for this target:").unwrap(); for (feature, desc) in &llvm_target_features { - writeln!(out, " {feature:max_feature_len$} - {desc}."); + writeln!(out, " {feature:max_feature_len$} - {desc}.").unwrap(); } if llvm_target_features.is_empty() { - writeln!(out, " Target features listing is not supported by this LLVM version."); + writeln!(out, " Target features listing is not supported by this LLVM version.") + .unwrap(); } - writeln!(out, "\nUse +feature to enable a feature, or -feature to disable it."); - writeln!(out, "For example, rustc -C target-cpu=mycpu -C target-feature=+feature1,-feature2\n"); - writeln!(out, "Code-generation features cannot be used in cfg or #[target_feature],"); - writeln!(out, "and may be renamed or removed in a future version of LLVM or rustc.\n"); + writeln!(out, "\nUse +feature to enable a feature, or -feature to disable it.").unwrap(); + writeln!(out, "For example, rustc -C target-cpu=mycpu -C target-feature=+feature1,-feature2\n") + .unwrap(); + writeln!(out, "Code-generation features cannot be used in cfg or #[target_feature],").unwrap(); + writeln!(out, "and may be renamed or removed in a future version of LLVM or rustc.\n").unwrap(); } -pub(crate) fn print(req: &PrintRequest, mut out: &mut dyn PrintBackendInfo, sess: &Session) { +pub(crate) fn print(req: &PrintRequest, mut out: &mut String, sess: &Session) { require_inited(); let tm = create_informational_target_machine(sess); match req.kind { @@ -440,9 +442,9 @@ pub(crate) fn print(req: &PrintRequest, mut out: &mut dyn PrintBackendInfo, sess let cpu_cstring = CString::new(handle_native(sess.target.cpu.as_ref())) .unwrap_or_else(|e| bug!("failed to convert to cstring: {}", e)); unsafe extern "C" fn callback(out: *mut c_void, string: *const c_char, len: usize) { - let out = &mut *(out as *mut &mut dyn PrintBackendInfo); + let out = &mut *(out as *mut &mut String); let bytes = slice::from_raw_parts(string as *const u8, len); - write!(out, "{}", String::from_utf8_lossy(bytes)); + write!(out, "{}", String::from_utf8_lossy(bytes)).unwrap(); } unsafe { llvm::LLVMRustPrintTargetCPUs( diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index a00f09dc40d..f1141c57ced 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -127,13 +127,24 @@ impl<'ll> CodegenCx<'ll, '_> { pub(crate) fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type { unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, True) } } -} -impl<'ll, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { - fn type_i1(&self) -> &'ll Type { + pub(crate) fn type_i1(&self) -> &'ll Type { unsafe { llvm::LLVMInt1TypeInContext(self.llcx) } } + pub(crate) fn type_struct(&self, els: &[&'ll Type], packed: bool) -> &'ll Type { + unsafe { + llvm::LLVMStructTypeInContext( + self.llcx, + els.as_ptr(), + els.len() as c_uint, + packed as Bool, + ) + } + } +} + +impl<'ll, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn type_i8(&self) -> &'ll Type { unsafe { llvm::LLVMInt8TypeInContext(self.llcx) } } @@ -178,17 +189,6 @@ impl<'ll, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, False) } } - fn type_struct(&self, els: &[&'ll Type], packed: bool) -> &'ll Type { - unsafe { - llvm::LLVMStructTypeInContext( - self.llcx, - els.as_ptr(), - els.len() as c_uint, - packed as Bool, - ) - } - } - fn type_kind(&self, ty: &'ll Type) -> TypeKind { unsafe { llvm::LLVMRustGetTypeKind(ty).to_generic() } } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index fb71cdaa8ff..56a893738df 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,11 +1,13 @@ use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem}; use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr}; -use rustc_errors::{codes::*, struct_span_code_err}; +use rustc_errors::{codes::*, struct_span_code_err, DiagMessage, SubdiagMessage}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::{lang_items, weak_lang_items::WEAK_LANG_ITEMS, LangItem}; -use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; +use rustc_middle::middle::codegen_fn_attrs::{ + CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, +}; use rustc_middle::mir::mono::Linkage; use rustc_middle::query::Providers; use rustc_middle::ty::{self as ty, TyCtxt}; @@ -124,22 +126,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { .emit(); } } - sym::coverage => { - let inner = attr.meta_item_list(); - match inner.as_deref() { - Some([item]) if item.has_name(sym::off) => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE; - } - Some([item]) if item.has_name(sym::on) => { - // Allow #[coverage(on)] for being explicit, maybe also in future to enable - // coverage on a smaller scope within an excluded larger scope. - } - Some(_) | None => { - tcx.dcx() - .span_delayed_bug(attr.span, "unexpected value of coverage attribute"); - } - } - } sym::rustc_std_internal_symbol => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL } @@ -463,6 +449,80 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { None }; } + sym::patchable_function_entry => { + codegen_fn_attrs.patchable_function_entry = attr.meta_item_list().and_then(|l| { + let mut prefix = None; + let mut entry = None; + for item in l { + let Some(meta_item) = item.meta_item() else { + tcx.dcx().span_err(item.span(), "expected name value pair"); + continue; + }; + + let Some(name_value_lit) = meta_item.name_value_literal() else { + tcx.dcx().span_err(item.span(), "expected name value pair"); + continue; + }; + + fn emit_error_with_label( + tcx: TyCtxt<'_>, + span: Span, + error: impl Into<DiagMessage>, + label: impl Into<SubdiagMessage>, + ) { + let mut err: rustc_errors::Diag<'_, _> = + tcx.dcx().struct_span_err(span, error); + err.span_label(span, label); + err.emit(); + } + + let attrib_to_write = match meta_item.name_or_empty() { + sym::prefix_nops => &mut prefix, + sym::entry_nops => &mut entry, + _ => { + emit_error_with_label( + tcx, + item.span(), + "unexpected parameter name", + format!("expected {} or {}", sym::prefix_nops, sym::entry_nops), + ); + continue; + } + }; + + let rustc_ast::LitKind::Int(val, _) = name_value_lit.kind else { + emit_error_with_label( + tcx, + name_value_lit.span, + "invalid literal value", + "value must be an integer between `0` and `255`", + ); + continue; + }; + + let Ok(val) = val.get().try_into() else { + emit_error_with_label( + tcx, + name_value_lit.span, + "integer value out of range", + "value must be between `0` and `255`", + ); + continue; + }; + + *attrib_to_write = Some(val); + } + + if let (None, None) = (prefix, entry) { + tcx.dcx().span_err(attr.span, "must specify at least one parameter"); + } + + Some(PatchableFunctionEntry::from_prefix_and_entry( + prefix.unwrap_or(0), + entry.unwrap_or(0), + )) + }) + } _ => {} } } @@ -584,7 +644,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE; codegen_fn_attrs.inline = InlineAttr::Never; } diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index ddc6797388e..febc8ee2be2 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -133,6 +133,7 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( let align = cx.data_layout().pointer_align.abi; let vtable = cx.static_addr_of(vtable_const, align, Some("vtable")); + cx.apply_vcall_visibility_metadata(ty, trait_ref, vtable); cx.create_vtable_debuginfo(ty, trait_ref, vtable); cx.vtables().borrow_mut().insert((ty, trait_ref), vtable); vtable diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 57138d3b9db..b1c22faf1ae 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -658,7 +658,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // with #[rustc_inherit_overflow_checks] and inlined from // another crate (mostly core::num generic/#[inline] fns), // while the current crate doesn't use overflow checks. - if !bx.cx().check_overflow() && msg.is_optional_overflow_check() { + if !bx.sess().overflow_checks() && msg.is_optional_overflow_check() { const_cond = Some(expected); } @@ -751,7 +751,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &mut self, helper: &TerminatorCodegenHelper<'tcx>, bx: &mut Bx, - intrinsic: Option<ty::IntrinsicDef>, + intrinsic: ty::IntrinsicDef, instance: Option<Instance<'tcx>>, source_info: mir::SourceInfo, target: Option<mir::BasicBlock>, @@ -761,8 +761,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Emit a panic or a no-op for `assert_*` intrinsics. // These are intrinsics that compile to panics so that we can get a message // which mentions the offending type, even from a const context. - let panic_intrinsic = intrinsic.and_then(|i| ValidityRequirement::from_intrinsic(i.name)); - if let Some(requirement) = panic_intrinsic { + if let Some(requirement) = ValidityRequirement::from_intrinsic(intrinsic.name) { let ty = instance.unwrap().args.type_at(0); let do_panic = !bx @@ -869,12 +868,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let sig = callee.layout.ty.fn_sig(bx.tcx()); let abi = sig.abi(); - // Handle intrinsics old codegen wants Expr's for, ourselves. - let intrinsic = match def { - Some(ty::InstanceKind::Intrinsic(def_id)) => Some(bx.tcx().intrinsic(def_id).unwrap()), - _ => None, - }; - let extra_args = &args[sig.inputs().skip_binder().len()..]; let extra_args = bx.tcx().mk_type_list_from_iter(extra_args.iter().map(|op_arg| { let op_ty = op_arg.node.ty(self.mir, bx.tcx()); @@ -886,50 +879,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { None => bx.fn_abi_of_fn_ptr(sig, extra_args), }; - if let Some(merging_succ) = self.codegen_panic_intrinsic( - &helper, - bx, - intrinsic, - instance, - source_info, - target, - unwind, - mergeable_succ, - ) { - return merging_succ; - } - // The arguments we'll be passing. Plus one to account for outptr, if used. let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize; - if matches!(intrinsic, Some(ty::IntrinsicDef { name: sym::caller_location, .. })) { - return if let Some(target) = target { - let location = - self.get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info }); - - let mut llargs = Vec::with_capacity(arg_count); - let ret_dest = self.make_return_dest( + let instance = match def { + Some(ty::InstanceKind::Intrinsic(def_id)) => { + let intrinsic = bx.tcx().intrinsic(def_id).unwrap(); + if let Some(merging_succ) = self.codegen_panic_intrinsic( + &helper, bx, - destination, - &fn_abi.ret, - &mut llargs, intrinsic, - Some(target), - ); - assert_eq!(llargs, []); - if let ReturnDest::IndirectOperand(tmp, _) = ret_dest { - location.val.store(bx, tmp); + instance, + source_info, + target, + unwind, + mergeable_succ, + ) { + return merging_succ; } - self.store_return(bx, ret_dest, &fn_abi.ret, location.immediate()); - helper.funclet_br(self, bx, target, mergeable_succ) - } else { - MergingSucc::False - }; - } - let instance = match intrinsic { - None => instance, - Some(intrinsic) => { let mut llargs = Vec::with_capacity(1); let ret_dest = self.make_return_dest( bx, @@ -971,6 +939,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }) .collect(); + if matches!(intrinsic, ty::IntrinsicDef { name: sym::caller_location, .. }) { + let location = self + .get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info }); + + assert_eq!(llargs, []); + if let ReturnDest::IndirectOperand(tmp, _) = ret_dest { + location.val.store(bx, tmp); + } + self.store_return(bx, ret_dest, &fn_abi.ret, location.immediate()); + return helper.funclet_br(self, bx, target.unwrap(), mergeable_succ); + } + let instance = *instance.as_ref().unwrap(); match Self::codegen_intrinsic_call(bx, instance, fn_abi, &args, dest, span) { Ok(()) => { @@ -997,6 +977,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } + _ => instance, }; let mut llargs = Vec::with_capacity(arg_count); diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index e8b9490d401..3770bd11cf9 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -22,8 +22,6 @@ use rustc_session::{ use rustc_span::symbol::Symbol; use rustc_target::abi::call::FnAbi; -use std::fmt; - pub trait BackendTypes { type Value: CodegenObject; type Function: CodegenObject; @@ -62,7 +60,7 @@ pub trait CodegenBackend { fn locale_resource(&self) -> &'static str; fn init(&self, _sess: &Session) {} - fn print(&self, _req: &PrintRequest, _out: &mut dyn PrintBackendInfo, _sess: &Session) {} + fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {} fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec<Symbol> { vec![] } @@ -150,19 +148,3 @@ pub trait ExtraBackendMethods: std::thread::Builder::new().name(name).spawn(f) } } - -pub trait PrintBackendInfo { - fn infallible_write_fmt(&mut self, args: fmt::Arguments<'_>); -} - -impl PrintBackendInfo for String { - fn infallible_write_fmt(&mut self, args: fmt::Arguments<'_>) { - fmt::Write::write_fmt(self, args).unwrap(); - } -} - -impl dyn PrintBackendInfo + '_ { - pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) { - self.infallible_write_fmt(args); - } -} diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index 8cb17a5b37a..3da732602c5 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -37,6 +37,5 @@ pub trait ConstMethods<'tcx>: BackendTypes { fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value; - fn const_bitcast(&self, val: Self::Value, ty: Self::Type) -> Self::Value; fn const_ptr_byte_offset(&self, val: Self::Value, offset: abi::Size) -> Self::Value; } diff --git a/compiler/rustc_codegen_ssa/src/traits/misc.rs b/compiler/rustc_codegen_ssa/src/traits/misc.rs index 04e2b8796c4..0ace28ed3ba 100644 --- a/compiler/rustc_codegen_ssa/src/traits/misc.rs +++ b/compiler/rustc_codegen_ssa/src/traits/misc.rs @@ -9,7 +9,13 @@ pub trait MiscMethods<'tcx>: BackendTypes { fn vtables( &self, ) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), Self::Value>>; - fn check_overflow(&self) -> bool; + fn apply_vcall_visibility_metadata( + &self, + _ty: Ty<'tcx>, + _poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, + _vtable: Self::Value, + ) { + } fn get_fn(&self, instance: Instance<'tcx>) -> Self::Function; fn get_fn_addr(&self, instance: Instance<'tcx>) -> Self::Value; fn eh_personality(&self) -> Self::Value; diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index 728c2bc8c49..8cb58bd4c70 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -30,9 +30,7 @@ mod write; pub use self::abi::AbiBuilderMethods; pub use self::asm::{AsmBuilderMethods, AsmMethods, GlobalAsmOperandRef, InlineAsmOperandRef}; -pub use self::backend::{ - Backend, BackendTypes, CodegenBackend, ExtraBackendMethods, PrintBackendInfo, -}; +pub use self::backend::{Backend, BackendTypes, CodegenBackend, ExtraBackendMethods}; pub use self::builder::{BuilderMethods, OverflowOp}; pub use self::consts::ConstMethods; pub use self::coverageinfo::CoverageInfoBuilderMethods; diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index 403f6a73277..b1bad6cfa6f 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -12,7 +12,6 @@ use rustc_target::abi::{AddressSpace, Float, Integer}; // This depends on `Backend` and not `BackendTypes`, because consumers will probably want to use // `LayoutOf` or `HasTyCtxt`. This way, they don't have to add a constraint on it themselves. pub trait BaseTypeMethods<'tcx>: Backend<'tcx> { - fn type_i1(&self) -> Self::Type; fn type_i8(&self) -> Self::Type; fn type_i16(&self) -> Self::Type; fn type_i32(&self) -> Self::Type; @@ -27,7 +26,6 @@ pub trait BaseTypeMethods<'tcx>: Backend<'tcx> { fn type_array(&self, ty: Self::Type, len: u64) -> Self::Type; fn type_func(&self, args: &[Self::Type], ret: Self::Type) -> Self::Type; - fn type_struct(&self, els: &[Self::Type], packed: bool) -> Self::Type; fn type_kind(&self, ty: Self::Type) -> TypeKind; fn type_ptr(&self) -> Self::Type; fn type_ptr_ext(&self, address_space: AddressSpace) -> Self::Type; @@ -115,8 +113,8 @@ pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> { /// The backend type used for a rust type when it's in an SSA register. /// /// For nearly all types this is the same as the [`Self::backend_type`], however - /// `bool` (and other `0`-or-`1` values) are kept as [`BaseTypeMethods::type_i1`] - /// in registers but as [`BaseTypeMethods::type_i8`] in memory. + /// `bool` (and other `0`-or-`1` values) are kept as `i1` in registers but as + /// [`BaseTypeMethods::type_i8`] in memory. /// /// Converting values between the two different backend types is done using /// [`from_immediate`](super::BuilderMethods::from_immediate) and diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index 8c66888d100..7acd08e0cce 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -42,10 +42,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness { | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => { hir::Constness::Const } - hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => tcx - .generics_of(def_id) - .host_effect_index - .map_or(hir::Constness::NotConst, |_| hir::Constness::Const), + hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.constness, hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => { // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other // foreign items cannot be evaluated at compile-time. diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index a13630ce084..83b61ab1749 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -1,6 +1,6 @@ use std::assert_matches::assert_matches; -use rustc_apfloat::ieee::{Double, Single}; +use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_apfloat::{Float, FloatConvert}; use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; use rustc_middle::mir::CastKind; @@ -187,10 +187,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { bug!("FloatToFloat/FloatToInt cast: source type {} is not a float type", src.layout.ty) }; let val = match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => self.cast_from_float(src.to_scalar().to_f16()?, cast_to.ty), FloatTy::F32 => self.cast_from_float(src.to_scalar().to_f32()?, cast_to.ty), FloatTy::F64 => self.cast_from_float(src.to_scalar().to_f64()?, cast_to.ty), - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => self.cast_from_float(src.to_scalar().to_f128()?, cast_to.ty), }; Ok(ImmTy::from_scalar(val, cast_to)) } @@ -296,18 +296,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Float(fty) if signed => { let v = v as i128; match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => Scalar::from_f16(Half::from_i128(v).value), FloatTy::F32 => Scalar::from_f32(Single::from_i128(v).value), FloatTy::F64 => Scalar::from_f64(Double::from_i128(v).value), - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => Scalar::from_f128(Quad::from_i128(v).value), } } // unsigned int -> float Float(fty) => match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => Scalar::from_f16(Half::from_u128(v).value), FloatTy::F32 => Scalar::from_f32(Single::from_u128(v).value), FloatTy::F64 => Scalar::from_f64(Double::from_u128(v).value), - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => Scalar::from_f128(Quad::from_u128(v).value), }, // u8 -> char @@ -321,7 +321,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Low-level cast helper function. Converts an apfloat `f` into int or float types. fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::Provenance> where - F: Float + Into<Scalar<M::Provenance>> + FloatConvert<Single> + FloatConvert<Double>, + F: Float + + Into<Scalar<M::Provenance>> + + FloatConvert<Half> + + FloatConvert<Single> + + FloatConvert<Double> + + FloatConvert<Quad>, { use rustc_type_ir::TyKind::*; @@ -358,10 +363,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } // float -> float Float(fty) => match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => Scalar::from_f16(adjust_nan(self, f, f.convert(&mut false).value)), FloatTy::F32 => Scalar::from_f32(adjust_nan(self, f, f.convert(&mut false).value)), FloatTy::F64 => Scalar::from_f64(adjust_nan(self, f, f.convert(&mut false).value)), - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => { + Scalar::from_f128(adjust_nan(self, f, f.convert(&mut false).value)) + } }, // That's it. _ => span_bug!(self.cur_span(), "invalid float to {} cast", dest_ty), diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index ff0a94f8e9b..c4b2e067bbe 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -50,7 +50,7 @@ libc = "0.2" memmap2 = "0.2.1" # tidy-alphabetical-end -[target.'cfg(any(target_arch = "powerpc", target_arch = "mips"))'.dependencies] +[target.'cfg(not(target_has_atomic = "64"))'.dependencies] portable-atomic = "1.5.1" [features] diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index cddc67d1578..356ddf014be 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -10,6 +10,7 @@ #![allow(internal_features)] #![allow(rustc::default_hash_types)] #![allow(rustc::potential_query_instability)] +#![cfg_attr(bootstrap, feature(lint_reasons))] #![cfg_attr(not(parallel_compiler), feature(cell_leak))] #![deny(unsafe_op_in_unsafe_fn)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] @@ -24,7 +25,6 @@ #![feature(extend_one)] #![feature(hash_raw_entry)] #![feature(hasher_prefixfree_extras)] -#![feature(lint_reasons)] #![feature(macro_metavar_expr)] #![feature(map_try_insert)] #![feature(min_specialization)] diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index a9ccfbed411..83fdaff515b 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -147,14 +147,13 @@ cfg_match! { [crate::owned_slice::OwnedSlice] ); - // PowerPC and MIPS platforms with 32-bit pointers do not - // have AtomicU64 type. - #[cfg(not(any(target_arch = "powerpc", target_arch = "mips")))] + // Use portable AtomicU64 for targets without native 64-bit atomics + #[cfg(target_has_atomic = "64")] already_sync!( [std::sync::atomic::AtomicU64] ); - #[cfg(any(target_arch = "powerpc", target_arch = "mips"))] + #[cfg(not(target_has_atomic = "64"))] already_sync!( [portable_atomic::AtomicU64] ); diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index ecb85db33f7..79ceb28abb5 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -270,12 +270,11 @@ cfg_match! { pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32}; - // PowerPC and MIPS platforms with 32-bit pointers do not - // have AtomicU64 type. - #[cfg(not(any(target_arch = "powerpc", target_arch = "mips")))] + // Use portable AtomicU64 for targets without native 64-bit atomics + #[cfg(target_has_atomic = "64")] pub use std::sync::atomic::AtomicU64; - #[cfg(any(target_arch = "powerpc", target_arch = "mips"))] + #[cfg(not(target_has_atomic = "64"))] pub use portable_atomic::AtomicU64; pub use std::sync::Arc as Lrc; diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index af82d8092c2..764134d5335 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -135,7 +135,12 @@ impl Emitter for JsonEmitter { let data: Vec<FutureBreakageItem<'_>> = diags .into_iter() .map(|mut diag| { - if diag.level == crate::Level::Allow { + // Allowed or expected lints don't normally (by definition) emit a lint + // but future incompat lints are special and are emitted anyway. + // + // So to avoid ICEs and confused users we "upgrade" the lint level for + // those `FutureBreakageItem` to warn. + if matches!(diag.level, crate::Level::Allow | crate::Level::Expect(..)) { diag.level = crate::Level::Warning; } FutureBreakageItem { diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index badfa6d3aa3..56cbb54fcec 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -214,6 +214,12 @@ impl<'a> StripUnconfigured<'a> { ) => { panic!("Nonterminal should have been flattened: {:?}", tree); } + AttrTokenTree::Token( + Token { kind: TokenKind::OpenDelim(_) | TokenKind::CloseDelim(_), .. }, + _, + ) => { + panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tree); + } AttrTokenTree::Token(token, spacing) => { Some(AttrTokenTree::Token(token, spacing)).into_iter() } diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 9beaa6b8d95..f082cc2b569 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -232,6 +232,8 @@ declare_features! ( (accepted, label_break_value, "1.65.0", Some(48594)), /// Allows `let...else` statements. (accepted, let_else, "1.65.0", Some(87335)), + /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. + (accepted, lint_reasons, "CURRENT_RUSTC_VERSION", Some(54503)), /// Allows `break {expr}` with a value inside `loop`s. (accepted, loop_break_value, "1.19.0", Some(37339)), /// Allows use of `?` as the Kleene "at most one" operator in macros. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index c53bf965139..a4245f0908e 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -369,9 +369,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk, EncodeCrossCrate::No, ), - gated!( - expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk, - EncodeCrossCrate::No, lint_reasons, experimental!(expect) + ungated!( + expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + DuplicatesOk, EncodeCrossCrate::No, ), ungated!( forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), @@ -585,6 +585,13 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::No, derive_smart_pointer, experimental!(pointee) ), + // RFC 3543 + // `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` + gated!( + patchable_function_entry, Normal, template!(List: "prefix_nops = m, entry_nops = n"), ErrorPreceding, + EncodeCrossCrate::Yes, experimental!(patchable_function_entry) + ), + // ========================================================================== // Internal attributes: Stability, deprecation, and unsafe: // ========================================================================== @@ -826,6 +833,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_const_panic_str, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE ), + rustc_attr!( + rustc_runtime, Normal, template!(Word), WarnFollowing, + EncodeCrossCrate::No, INTERNAL_UNSTABLE + ), // ========================================================================== // Internal attributes, Layout related: diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 2dfaac8f6e7..ad6f7da8937 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -512,8 +512,6 @@ declare_features! ( /// Allows using `#[link(kind = "link-arg", name = "...")]` /// to pass custom arguments to the linker. (unstable, link_arg_attribute, "1.76.0", Some(99427)), - /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. - (unstable, lint_reasons, "1.31.0", Some(54503)), /// Give access to additional metadata about declarative macro meta-variables. (unstable, macro_metavar_expr, "1.61.0", Some(83527)), /// Provides a way to concatenate identifiers using metavariable expressions. @@ -565,6 +563,8 @@ declare_features! ( (unstable, offset_of_slice, "CURRENT_RUSTC_VERSION", Some(126151)), /// Allows using `#[optimize(X)]`. (unstable, optimize_attribute, "1.34.0", Some(54882)), + /// Allows specifying nop padding on functions for dynamic patching. + (unstable, patchable_function_entry, "CURRENT_RUSTC_VERSION", Some(123115)), /// Allows postfix match `expr.match { ... }` (unstable, postfix_match, "1.79.0", Some(121618)), /// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 22a6c06bba3..6cccdec94c0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -526,6 +526,7 @@ pub enum GenericParamKind<'hir> { /// Optional default value for the const generic param default: Option<&'hir AnonConst>, is_host_effect: bool, + synthetic: bool, }, } @@ -3364,6 +3365,7 @@ pub enum ItemKind<'hir> { /// Refer to [`ImplItem`] for an associated item within an impl block. #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Impl<'hir> { + pub constness: Constness, pub safety: Safety, pub polarity: ImplPolarity, pub defaultness: Defaultness, diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 065ecc5d7b7..9bb3245ae05 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -543,6 +543,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: try_visit!(visitor.visit_enum_def(enum_definition, item.hir_id())); } ItemKind::Impl(Impl { + constness: _, safety: _, defaultness: _, polarity: _, @@ -915,7 +916,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>( match param.kind { GenericParamKind::Lifetime { .. } => {} GenericParamKind::Type { ref default, .. } => visit_opt!(visitor, visit_ty, default), - GenericParamKind::Const { ref ty, ref default, is_host_effect: _ } => { + GenericParamKind::Const { ref ty, ref default, is_host_effect: _, synthetic: _ } => { try_visit!(visitor.visit_ty(ty)); if let Some(ref default) = default { try_visit!(visitor.visit_const_param_default(param.hir_id, default)); diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 69461957f80..3c44acb1657 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -393,6 +393,14 @@ language_item_table! { String, sym::String, string, Target::Struct, GenericRequirement::None; CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None; + + EffectsRuntime, sym::EffectsRuntime, effects_runtime, Target::Struct, GenericRequirement::None; + EffectsNoRuntime, sym::EffectsNoRuntime, effects_no_runtime, Target::Struct, GenericRequirement::None; + EffectsMaybe, sym::EffectsMaybe, effects_maybe, Target::Struct, GenericRequirement::None; + EffectsIntersection, sym::EffectsIntersection, effects_intersection, Target::Trait, GenericRequirement::None; + EffectsIntersectionOutput, sym::EffectsIntersectionOutput, effects_intersection_output, Target::AssocTy, GenericRequirement::None; + EffectsCompat, sym::EffectsCompat, effects_compat, Target::Trait, GenericRequirement::Exact(1); + EffectsTyCompat, sym::EffectsTyCompat, effects_ty_compat, Target::Trait, GenericRequirement::Exact(1); } pub enum GenericRequirement { diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index 7f0d72b3a8d..c7ee89e73c2 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -1,9 +1,13 @@ //! Bounds are restrictions applied to some types after they've been lowered from the HIR to the //! [`rustc_middle::ty`] form. +use rustc_data_structures::fx::FxIndexMap; +use rustc_hir::def::DefKind; use rustc_hir::LangItem; +use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; -use rustc_span::Span; +use rustc_span::def_id::DefId; +use rustc_span::{sym, Span}; /// Collects together a list of type bounds. These lists of bounds occur in many places /// in Rust's syntax: @@ -24,6 +28,7 @@ use rustc_span::Span; #[derive(Default, PartialEq, Eq, Clone, Debug)] pub struct Bounds<'tcx> { clauses: Vec<(ty::Clause<'tcx>, Span)>, + effects_min_tys: FxIndexMap<Ty<'tcx>, Span>, } impl<'tcx> Bounds<'tcx> { @@ -40,12 +45,14 @@ impl<'tcx> Bounds<'tcx> { pub fn push_trait_bound( &mut self, tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + defining_def_id: DefId, + bound_trait_ref: ty::PolyTraitRef<'tcx>, span: Span, polarity: ty::PredicatePolarity, + constness: ty::BoundConstness, ) { let clause = ( - trait_ref + bound_trait_ref .map_bound(|trait_ref| { ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity }) }) @@ -53,11 +60,98 @@ impl<'tcx> Bounds<'tcx> { span, ); // FIXME(-Znext-solver): We can likely remove this hack once the new trait solver lands. - if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) { + if tcx.is_lang_item(bound_trait_ref.def_id(), LangItem::Sized) { self.clauses.insert(0, clause); } else { self.clauses.push(clause); } + + if !tcx.features().effects { + return; + } + // For `T: ~const Tr` or `T: const Tr`, we need to add an additional bound on the + // associated type of `<T as Tr>` and make sure that the effect is compatible. + let compat_val = match (tcx.def_kind(defining_def_id), constness) { + // FIXME(effects): revisit the correctness of this + (_, ty::BoundConstness::Const) => tcx.consts.false_, + // body owners that can have trait bounds + (DefKind::Const | DefKind::Fn | DefKind::AssocFn, ty::BoundConstness::ConstIfConst) => { + tcx.expected_host_effect_param_for_body(defining_def_id) + } + + (_, ty::BoundConstness::NotConst) => { + if !tcx.has_attr(bound_trait_ref.def_id(), sym::const_trait) { + return; + } + tcx.consts.true_ + } + + ( + DefKind::Trait | DefKind::Impl { of_trait: true }, + ty::BoundConstness::ConstIfConst, + ) => { + // this is either a where clause on an impl/trait header or on a trait. + // push `<T as Tr>::Effects` into the set for the `Min` bound. + let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else { + tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc"); + return; + }; + + let ty = bound_trait_ref + .map_bound(|trait_ref| Ty::new_projection(tcx, assoc, trait_ref.args)); + + // When the user has written `for<'a, T> X<'a, T>: ~const Foo`, replace the + // binders to dummy ones i.e. `X<'static, ()>` so they can be referenced in + // the `Min` associated type properly (which doesn't allow using `for<>`) + // This should work for any bound variables as long as they don't have any + // bounds e.g. `for<T: Trait>`. + // FIXME(effects) reconsider this approach to allow compatibility with `for<T: Tr>` + let ty = tcx.replace_bound_vars_uncached( + ty, + FnMutDelegate { + regions: &mut |_| tcx.lifetimes.re_static, + types: &mut |_| tcx.types.unit, + consts: &mut |_| unimplemented!("`~const` does not support const binders"), + }, + ); + + self.effects_min_tys.insert(ty, span); + return; + } + // for + // ``` + // trait Foo { type Bar: ~const Trait } + // ``` + // ensure that `<Self::Bar as Trait>::Effects: TyCompat<Self::Effects>`. + // + // FIXME(effects) this is equality for now, which wouldn't be helpful for a non-const implementor + // that uses a `Bar` that implements `Trait` with `Maybe` effects. + (DefKind::AssocTy, ty::BoundConstness::ConstIfConst) => { + // FIXME(effects): implement this + return; + } + // probably illegal in this position. + (_, ty::BoundConstness::ConstIfConst) => { + tcx.dcx().span_delayed_bug(span, "invalid `~const` encountered"); + return; + } + }; + // create a new projection type `<T as Tr>::Effects` + let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else { + tcx.dcx().span_delayed_bug( + span, + "`~const` trait bound has no effect assoc yet no errors encountered?", + ); + return; + }; + let self_ty = Ty::new_projection(tcx, assoc, bound_trait_ref.skip_binder().args); + // make `<T as Tr>::Effects: Compat<runtime>` + let new_trait_ref = ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::EffectsCompat, Some(span)), + [ty::GenericArg::from(self_ty), compat_val.into()], + ); + self.clauses.push((bound_trait_ref.rebind(new_trait_ref).upcast(tcx), span)); } pub fn push_projection_bound( @@ -79,7 +173,15 @@ impl<'tcx> Bounds<'tcx> { self.clauses.insert(0, (trait_ref.upcast(tcx), span)); } - pub fn clauses(&self) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ { + pub fn clauses( + &self, + // FIXME(effects): remove tcx + _tcx: TyCtxt<'tcx>, + ) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ { self.clauses.iter().cloned() } + + pub fn effects_min_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_ { + self.effects_min_tys.keys().copied() + } } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index e13ea1a1935..f93777eda52 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -879,7 +879,8 @@ pub(super) fn check_specialization_validity<'tcx>( let result = opt_result.unwrap_or(Ok(())); if let Err(parent_impl) = result { - if !tcx.is_impl_trait_in_trait(impl_item) { + // FIXME(effects) the associated type from effects could be specialized + if !tcx.is_impl_trait_in_trait(impl_item) && !tcx.is_effects_desugared_assoc_ty(impl_item) { report_forbidden_specialization(tcx, impl_item, parent_impl); } else { tcx.dcx().delayed_bug(format!("parent item: {parent_impl:?} not marked as default")); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 7fa5c96bc9a..b5b68471b9d 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1985,10 +1985,10 @@ pub(super) fn check_type_bounds<'tcx>( let infcx = tcx.infer_ctxt().build(); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); - // A synthetic impl Trait for RPITIT desugaring has no HIR, which we currently use to get the - // span for an impl's associated type. Instead, for these, use the def_span for the synthesized - // associated type. - let impl_ty_span = if impl_ty.is_impl_trait_in_trait() { + // A synthetic impl Trait for RPITIT desugaring or assoc type for effects desugaring has no HIR, + // which we currently use to get the span for an impl's associated type. Instead, for these, + // use the def_span for the synthesized associated type. + let impl_ty_span = if impl_ty.is_impl_trait_in_trait() || impl_ty.is_effects_desugaring { tcx.def_span(impl_ty_def_id) } else { match tcx.hir_node_by_def_id(impl_ty_def_id) { diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index a188c1b12ae..2230528a5ae 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -913,7 +913,12 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => Ok(()), // Const parameters are well formed if their type is structural match. - hir::GenericParamKind::Const { ty: hir_ty, default: _, is_host_effect: _ } => { + hir::GenericParamKind::Const { + ty: hir_ty, + default: _, + is_host_effect: _, + synthetic: _, + } => { let ty = tcx.type_of(param.def_id).instantiate_identity(); if tcx.features().adt_const_params { diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index e7892f17660..41fbef48940 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -70,10 +70,10 @@ pub fn provide(providers: &mut Providers) { predicates_of: predicates_of::predicates_of, predicates_defined_on, explicit_predicates_of: predicates_of::explicit_predicates_of, - super_predicates_of: predicates_of::super_predicates_of, - implied_predicates_of: predicates_of::implied_predicates_of, - super_predicates_that_define_assoc_item: - predicates_of::super_predicates_that_define_assoc_item, + explicit_super_predicates_of: predicates_of::explicit_super_predicates_of, + explicit_implied_predicates_of: predicates_of::explicit_implied_predicates_of, + explicit_supertraits_containing_assoc_item: + predicates_of::explicit_supertraits_containing_assoc_item, trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds, type_param_predicates: predicates_of::type_param_predicates, trait_def, @@ -691,14 +691,14 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { hir::ItemKind::Trait(..) => { tcx.ensure().generics_of(def_id); tcx.ensure().trait_def(def_id); - tcx.at(it.span).super_predicates_of(def_id); + tcx.at(it.span).explicit_super_predicates_of(def_id); tcx.ensure().predicates_of(def_id); tcx.ensure().associated_items(def_id); } hir::ItemKind::TraitAlias(..) => { tcx.ensure().generics_of(def_id); - tcx.at(it.span).implied_predicates_of(def_id); - tcx.at(it.span).super_predicates_of(def_id); + tcx.at(it.span).explicit_implied_predicates_of(def_id); + tcx.at(it.span).explicit_super_predicates_of(def_id); tcx.ensure().predicates_of(def_id); } hir::ItemKind::Struct(struct_def, _) | hir::ItemKind::Union(struct_def, _) => { @@ -1459,8 +1459,25 @@ fn infer_return_ty_for_fn_sig<'tcx>( Some(ty) => { let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id]; // Typeck doesn't expect erased regions to be returned from `type_of`. + // This is a heuristic approach. If the scope has region paramters, + // we should change fn_sig's lifetime from `ReErased` to `ReError`, + // otherwise to `ReStatic`. + let has_region_params = generics.params.iter().any(|param| match param.kind { + GenericParamKind::Lifetime { .. } => true, + _ => false, + }); let fn_sig = tcx.fold_regions(fn_sig, |r, _| match *r { - ty::ReErased => tcx.lifetimes.re_static, + ty::ReErased => { + if has_region_params { + ty::Region::new_error_with_message( + tcx, + DUMMY_SP, + "erased region is not allowed here in return type", + ) + } else { + tcx.lifetimes.re_static + } + } _ => r, }); @@ -1638,44 +1655,19 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai let icx = ItemCtxt::new(tcx, def_id); let item = tcx.hir().expect_item(def_id); let impl_ = item.expect_impl(); - impl_ - .of_trait - .as_ref() - .map(|hir_trait_ref| { - let self_ty = tcx.type_of(def_id).instantiate_identity(); + impl_.of_trait.as_ref().map(|ast_trait_ref| { + let selfty = tcx.type_of(def_id).instantiate_identity(); - let trait_ref = if let Some(ErrorGuaranteed { .. }) = check_impl_constness( - tcx, - tcx.is_const_trait_impl_raw(def_id.to_def_id()), - hir_trait_ref, - ) { - // we have a const impl, but for a trait without `#[const_trait]`, so - // without the host param. If we continue with the HIR trait ref, we get - // ICEs for generic arg count mismatch. We do a little HIR editing to - // make HIR ty lowering happy. - let mut path_segments = hir_trait_ref.path.segments.to_vec(); - let last_segment = path_segments.len() - 1; - let mut args = *path_segments[last_segment].args(); - let last_arg = args.args.len() - 1; - assert!(matches!(args.args[last_arg], hir::GenericArg::Const(anon_const) if anon_const.is_desugared_from_effects)); - args.args = &args.args[..args.args.len() - 1]; - path_segments[last_segment].args = Some(tcx.hir_arena.alloc(args)); - let path = hir::Path { - span: hir_trait_ref.path.span, - res: hir_trait_ref.path.res, - segments: tcx.hir_arena.alloc_slice(&path_segments), - }; - let trait_ref = tcx.hir_arena.alloc(hir::TraitRef { path: tcx.hir_arena.alloc(path), hir_ref_id: hir_trait_ref.hir_ref_id }); - icx.lowerer().lower_impl_trait_ref(trait_ref, self_ty) - } else { - icx.lowerer().lower_impl_trait_ref(hir_trait_ref, self_ty) - }; - ty::ImplTraitHeader { - trait_ref: ty::EarlyBinder::bind(trait_ref), - safety: impl_.safety, - polarity: polarity_of_impl(tcx, def_id, impl_, item.span) - } - }) + check_impl_constness(tcx, tcx.is_const_trait_impl_raw(def_id.to_def_id()), ast_trait_ref); + + let trait_ref = icx.lowerer().lower_impl_trait_ref(ast_trait_ref, selfty); + + ty::ImplTraitHeader { + trait_ref: ty::EarlyBinder::bind(trait_ref), + safety: impl_.safety, + polarity: polarity_of_impl(tcx, def_id, impl_, item.span), + } + }) } fn check_impl_constness( diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 303fa23dbc1..9b02c1a61fa 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -354,7 +354,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { kind, }) } - GenericParamKind::Const { ty: _, default, is_host_effect } => { + GenericParamKind::Const { ty: _, default, is_host_effect, synthetic } => { if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() // `host` effect params are allowed to have defaults. @@ -388,6 +388,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { kind: ty::GenericParamDefKind::Const { has_default: default.is_some(), is_host_effect, + synthetic, }, }) } @@ -541,7 +542,8 @@ struct AnonConstInParamTyDetector { impl<'v> Visitor<'v> for AnonConstInParamTyDetector { fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) { - if let GenericParamKind::Const { ty, default: _, is_host_effect: _ } = p.kind { + if let GenericParamKind::Const { ty, default: _, is_host_effect: _, synthetic: _ } = p.kind + { let prev = self.in_param_ty; self.in_param_ty = true; self.visit_ty(ty); diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index d084d3aefeb..c03e074c80b 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -8,6 +8,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFold use rustc_middle::{bug, span_bug}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; +use rustc_type_ir::Upcast; /// For associated types we include both bounds written on the type /// (`type X: Trait`) and predicates from the trait: `where Self::X: Trait`. @@ -46,7 +47,7 @@ fn associated_type_bounds<'tcx>( } }); - let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent)); + let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(bounds_from_parent)); debug!( "associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id.to_def_id()), @@ -75,7 +76,7 @@ fn opaque_type_bounds<'tcx>( icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span); debug!(?bounds); - tcx.arena.alloc_from_iter(bounds.clauses()) + tcx.arena.alloc_from_iter(bounds.clauses(tcx)) }) } @@ -124,6 +125,32 @@ pub(super) fn explicit_item_bounds_with_filter( None => {} } + if tcx.is_effects_desugared_assoc_ty(def_id.to_def_id()) { + let mut predicates = Vec::new(); + + let parent = tcx.local_parent(def_id); + + let preds = tcx.explicit_predicates_of(parent); + + if let ty::AssocItemContainer::TraitContainer = tcx.associated_item(def_id).container { + // for traits, emit `type Effects: TyCompat<<(T1::Effects, ..) as Min>::Output>` + let tup = Ty::new(tcx, ty::Tuple(preds.effects_min_tys)); + // FIXME(effects) span + let span = tcx.def_span(def_id); + let assoc = tcx.require_lang_item(hir::LangItem::EffectsIntersectionOutput, Some(span)); + let proj = Ty::new_projection(tcx, assoc, [tup]); + let self_proj = Ty::new_projection( + tcx, + def_id.to_def_id(), + ty::GenericArgs::identity_for_item(tcx, def_id), + ); + let trait_ = tcx.require_lang_item(hir::LangItem::EffectsTyCompat, Some(span)); + let trait_ref = ty::TraitRef::new(tcx, trait_, [self_proj, proj]); + predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span)); + } + return ty::EarlyBinder::bind(tcx.arena.alloc_from_iter(predicates)); + } + let bounds = match tcx.hir_node_by_def_id(def_id) { hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(bounds, _), diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 3421c8da4e9..b89d034fc2e 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -57,6 +57,7 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic #[instrument(level = "trace", skip(tcx), ret)] fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericPredicates<'_> { use rustc_hir::*; + use rustc_middle::ty::Ty; match tcx.opt_rpitit_info(def_id.to_def_id()) { Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) => { @@ -84,6 +85,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen return ty::GenericPredicates { parent: Some(tcx.parent(def_id.to_def_id())), predicates: tcx.arena.alloc_from_iter(predicates), + effects_min_tys: ty::List::empty(), }; } @@ -105,6 +107,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen return ty::GenericPredicates { parent: Some(impl_def_id), predicates: tcx.arena.alloc_from_iter(impl_predicates), + effects_min_tys: ty::List::empty(), }; } @@ -124,6 +127,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // We use an `IndexSet` to preserve order of insertion. // Preserving the order of insertion is important here so as not to break UI tests. let mut predicates: FxIndexSet<(ty::Clause<'_>, Span)> = FxIndexSet::default(); + let mut effects_min_tys = Vec::new(); let hir_generics = node.generics().unwrap_or(NO_GENERICS); if let Node::Item(item) = node { @@ -150,11 +154,13 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // on a trait we must also consider the bounds that follow the trait's name, // like `trait Foo: A + B + C`. if let Some(self_bounds) = is_trait { - predicates.extend( - icx.lowerer() - .lower_mono_bounds(tcx.types.self_param, self_bounds, PredicateFilter::All) - .clauses(), + let bounds = icx.lowerer().lower_mono_bounds( + tcx.types.self_param, + self_bounds, + PredicateFilter::All, ); + predicates.extend(bounds.clauses(tcx)); + effects_min_tys.extend(bounds.effects_min_tys()); } // In default impls, we can assume that the self type implements @@ -187,7 +193,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen param.span, ); trace!(?bounds); - predicates.extend(bounds.clauses()); + predicates.extend(bounds.clauses(tcx)); trace!(?predicates); } hir::GenericParamKind::Const { .. } => { @@ -238,7 +244,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen bound_vars, OnlySelfBounds(false), ); - predicates.extend(bounds.clauses()); + predicates.extend(bounds.clauses(tcx)); + effects_min_tys.extend(bounds.effects_min_tys()); } hir::WherePredicate::RegionPredicate(region_pred) => { @@ -297,7 +304,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // and the duplicated parameter, to ensure that they do not get out of sync. if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node { let opaque_ty_node = tcx.parent_hir_node(hir_id); - let Node::Ty(&Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node else { + let Node::Ty(&hir::Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node + else { bug!("unexpected {opaque_ty_node:?}") }; debug!(?lifetimes); @@ -306,9 +314,30 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen debug!(?predicates); } + // add `Self::Effects: Compat<HOST>` to ensure non-const impls don't get called + // in const contexts. + if let Node::TraitItem(&TraitItem { kind: TraitItemKind::Fn(..), .. }) = node + && let Some(host_effect_index) = generics.host_effect_index + { + let parent = generics.parent.unwrap(); + let Some(assoc_def_id) = tcx.associated_type_for_effects(parent) else { + bug!("associated_type_for_effects returned None when there is host effect in generics"); + }; + let effects = + Ty::new_projection(tcx, assoc_def_id, ty::GenericArgs::identity_for_item(tcx, parent)); + let param = generics.param_at(host_effect_index, tcx); + let span = tcx.def_span(param.def_id); + let host = ty::Const::new_param(tcx, ty::ParamConst::for_def(param)); + let compat = tcx.require_lang_item(LangItem::EffectsCompat, Some(span)); + let trait_ref = + ty::TraitRef::new(tcx, compat, [ty::GenericArg::from(effects), host.into()]); + predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span)); + } + ty::GenericPredicates { parent: generics.parent, predicates: tcx.arena.alloc_from_iter(predicates), + effects_min_tys: tcx.mk_type_list(&effects_min_tys), } } @@ -459,6 +488,7 @@ pub(super) fn explicit_predicates_of<'tcx>( ty::GenericPredicates { parent: predicates_and_bounds.parent, predicates: tcx.arena.alloc_slice(&predicates), + effects_min_tys: predicates_and_bounds.effects_min_tys, } } } else { @@ -510,6 +540,7 @@ pub(super) fn explicit_predicates_of<'tcx>( return GenericPredicates { parent: parent_preds.parent, predicates: { tcx.arena.alloc_from_iter(filtered_predicates) }, + effects_min_tys: parent_preds.effects_min_tys, }; } gather_explicit_predicates_of(tcx, def_id) @@ -519,21 +550,21 @@ pub(super) fn explicit_predicates_of<'tcx>( /// Ensures that the super-predicates of the trait with a `DefId` /// of `trait_def_id` are lowered and stored. This also ensures that /// the transitive super-predicates are lowered. -pub(super) fn super_predicates_of( +pub(super) fn explicit_super_predicates_of( tcx: TyCtxt<'_>, trait_def_id: LocalDefId, ) -> ty::GenericPredicates<'_> { implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::SelfOnly) } -pub(super) fn super_predicates_that_define_assoc_item( +pub(super) fn explicit_supertraits_containing_assoc_item( tcx: TyCtxt<'_>, (trait_def_id, assoc_name): (DefId, Ident), ) -> ty::GenericPredicates<'_> { implied_predicates_with_filter(tcx, trait_def_id, PredicateFilter::SelfThatDefines(assoc_name)) } -pub(super) fn implied_predicates_of( +pub(super) fn explicit_implied_predicates_of( tcx: TyCtxt<'_>, trait_def_id: LocalDefId, ) -> ty::GenericPredicates<'_> { @@ -560,7 +591,7 @@ pub(super) fn implied_predicates_with_filter( // if `assoc_name` is None, then the query should've been redirected to an // external provider assert!(matches!(filter, PredicateFilter::SelfThatDefines(_))); - return tcx.super_predicates_of(trait_def_id); + return tcx.explicit_super_predicates_of(trait_def_id); }; let Node::Item(item) = tcx.hir_node_by_def_id(trait_def_id) else { @@ -587,7 +618,7 @@ pub(super) fn implied_predicates_with_filter( // Combine the two lists to form the complete set of superbounds: let implied_bounds = - &*tcx.arena.alloc_from_iter(superbounds.clauses().chain(where_bounds_that_match)); + &*tcx.arena.alloc_from_iter(superbounds.clauses(tcx).chain(where_bounds_that_match)); debug!(?implied_bounds); // Now require that immediate supertraits are lowered, which will, in @@ -601,7 +632,7 @@ pub(super) fn implied_predicates_with_filter( if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder() && bound.polarity == ty::PredicatePolarity::Positive { - tcx.at(span).super_predicates_of(bound.def_id()); + tcx.at(span).explicit_super_predicates_of(bound.def_id()); } } } @@ -611,14 +642,18 @@ pub(super) fn implied_predicates_with_filter( if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder() && bound.polarity == ty::PredicatePolarity::Positive { - tcx.at(span).implied_predicates_of(bound.def_id()); + tcx.at(span).explicit_implied_predicates_of(bound.def_id()); } } } _ => {} } - ty::GenericPredicates { parent: None, predicates: implied_bounds } + ty::GenericPredicates { + parent: None, + predicates: implied_bounds, + effects_min_tys: ty::List::empty(), + } } /// Returns the predicates defined on `item_def_id` of the form @@ -744,7 +779,7 @@ impl<'tcx> ItemCtxt<'tcx> { ); } - bounds.clauses().collect() + bounds.clauses(self.tcx).collect() } #[instrument(level = "trace", skip(self))] diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index abc3bb838db..cad7870a0a1 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -951,7 +951,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { self.visit_ty(ty); } } - GenericParamKind::Const { ty, default, is_host_effect: _ } => { + GenericParamKind::Const { ty, default, .. } => { self.visit_ty(ty); if let Some(default) = default { self.visit_body(self.tcx.hir().body(default.body)); @@ -1760,7 +1760,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { if let Some(assoc_item) = trait_defines_associated_item_named(def_id) { break Some((bound_vars.into_iter().collect(), assoc_item)); } - let predicates = tcx.super_predicates_that_define_assoc_item((def_id, assoc_name)); + let predicates = tcx.explicit_supertraits_containing_assoc_item((def_id, assoc_name)); let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| { let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index 3f888c4e272..e92c377f0ce 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -256,6 +256,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( | GenericParamDefKind::Lifetime, _, ) => { + // FIXME(effects): this should be removed // SPECIAL CASE FOR DESUGARED EFFECT PARAMS // This comes from the following example: // @@ -445,7 +446,7 @@ pub(crate) fn check_generic_arg_count( .own_params .iter() .filter(|param| { - matches!(param.kind, ty::GenericParamDefKind::Const { is_host_effect: true, .. }) + matches!(param.kind, ty::GenericParamDefKind::Const { synthetic: true, .. }) }) .count(); let named_const_param_count = param_counts.consts - synth_const_param_count; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 24ea328889c..2a68d3915bb 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -698,7 +698,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); debug!(?poly_trait_ref); - bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity); + bounds.push_trait_bound( + tcx, + self.item_def_id().to_def_id(), + poly_trait_ref, + span, + polarity, + constness, + ); let mut dup_constraints = FxIndexMap::default(); for constraint in trait_segment.args().constraints { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs index 34924f09d09..df69c1938dd 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs @@ -59,7 +59,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut trait_bounds = vec![]; let mut projection_bounds = vec![]; - for (pred, span) in bounds.clauses() { + for (pred, span) in bounds.clauses(tcx) { let bound_pred = pred.kind(); match bound_pred.skip_binder() { ty::ClauseKind::Trait(trait_pred) => { @@ -133,7 +133,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { tcx.associated_items(pred.def_id()) .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Type) - .filter(|item| !item.is_impl_trait_in_trait()) + .filter(|item| { + !item.is_impl_trait_in_trait() && !item.is_effects_desugaring + }) .map(|item| item.def_id), ); } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 25b0cbdc026..5105d60ae18 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -585,6 +585,7 @@ impl<'a> State<'a> { self.print_struct(struct_def, generics, item.ident.name, item.span, true); } hir::ItemKind::Impl(&hir::Impl { + constness, safety, polarity, defaultness, @@ -599,6 +600,10 @@ impl<'a> State<'a> { self.print_safety(safety); self.word_nbsp("impl"); + if let hir::Constness::Const = constness { + self.word_nbsp("const"); + } + if !generics.params.is_empty() { self.print_generic_params(generics.params); self.space(); @@ -2144,7 +2149,7 @@ impl<'a> State<'a> { self.print_type(default); } } - GenericParamKind::Const { ty, ref default, is_host_effect: _ } => { + GenericParamKind::Const { ty, ref default, is_host_effect: _, synthetic: _ } => { self.word_space(":"); self.print_type(ty); if let Some(default) = default { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 061afd03062..f6e21262b6a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1304,7 +1304,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.fcx.ty_infer(Some(param), inf.span).into() } ( - &GenericParamDefKind::Const { has_default, is_host_effect }, + &GenericParamDefKind::Const { has_default, is_host_effect, .. }, GenericArg::Infer(inf), ) => { if has_default && is_host_effect { @@ -1346,7 +1346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.fcx.var_for_def(self.span, param) } } - GenericParamDefKind::Const { has_default, is_host_effect } => { + GenericParamDefKind::Const { has_default, is_host_effect, .. } => { if has_default { // N.B. this is a bit of a hack. `infer_args` is passed depending on // whether the user has provided generic args. E.g. for `Vec::new` diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index c0d60477967..ed3cbb0663e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -274,6 +274,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { } }), ), + effects_min_tys: ty::List::empty(), } } diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index e1223307b53..ff8899ae036 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -21,7 +21,7 @@ use rustc_middle::ty::{self, GenericParamDefKind, Ty, TypeVisitableExt}; use rustc_middle::ty::{GenericArgs, GenericArgsRef}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::Ident; -use rustc_span::Span; +use rustc_span::{sym, Span}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{self, NormalizeExt}; @@ -356,6 +356,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { let (obligation, args) = self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types); + // FIXME(effects) find a better way to do this + // Operators don't have generic methods, but making them `#[const_trait]` gives them + // `const host: bool`. + let args = if self.tcx.has_attr(trait_def_id, sym::const_trait) { + self.tcx.mk_args_from_iter( + args.iter() + .chain([self.tcx.expected_host_effect_param_for_body(self.body_id).into()]), + ) + } else { + args + }; self.construct_obligation_for_trait(m_name, trait_def_id, obligation, args) } @@ -393,6 +404,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("lookup_in_trait_adjusted: method_item={:?}", method_item); let mut obligations = vec![]; + // FIXME(effects): revisit when binops get `#[const_trait]` + // Instantiate late-bound regions and instantiate the trait // parameters into the method type to get the actual method type. // diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 9747a91ccbf..63b30d79aba 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1279,6 +1279,7 @@ impl<'tcx> Pick<'tcx> { trait_item_def_id: _, fn_has_self_parameter: _, opt_rpitit_info: _, + is_effects_desugaring: _, }, kind: _, import_ids: _, diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index ab4148faaab..24cf9f03fcd 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -275,10 +275,10 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { } // Get predicates implied by the trait, or only super predicates if we only care about self predicates. let predicates = match self.mode { - Filter::All => tcx.implied_predicates_of(data.def_id()), - Filter::OnlySelf => tcx.super_predicates_of(data.def_id()), + Filter::All => tcx.explicit_implied_predicates_of(data.def_id()), + Filter::OnlySelf => tcx.explicit_super_predicates_of(data.def_id()), Filter::OnlySelfThatDefines(ident) => { - tcx.super_predicates_that_define_assoc_item((data.def_id(), ident)) + tcx.explicit_supertraits_containing_assoc_item((data.def_id(), ident)) } }; @@ -420,7 +420,7 @@ pub fn transitive_bounds<'tcx>( /// A specialized variant of `elaborate` that only elaborates trait references that may /// define the given associated item with the name `assoc_name`. It uses the -/// `super_predicates_that_define_assoc_item` query to avoid enumerating super-predicates that +/// `explicit_supertraits_containing_assoc_item` query to avoid enumerating super-predicates that /// aren't related to `assoc_item`. This is used when resolving types like `Self::Item` or /// `T::Item` and helps to avoid cycle errors (see e.g. #35237). pub fn transitive_bounds_that_define_assoc_item<'tcx>( diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 6ffc518097e..02322c9b282 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -8,8 +8,8 @@ use rustc_session::config::{ ErrorOutputType, ExternEntry, ExternLocation, Externs, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, - PacRet, Passes, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, - SymbolManglingVersion, WasiExecModel, + PacRet, Passes, PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, + SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, }; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; @@ -813,6 +813,11 @@ fn test_unstable_options_tracking_hash() { tracked!(packed_bundled_libs, true); tracked!(panic_abort_tests, true); tracked!(panic_in_drop, PanicStrategy::Abort); + tracked!( + patchable_function_entry, + PatchableFunctionEntry::from_total_and_prefix_nops(10, 5) + .expect("total must be greater than or equal to prefix") + ); tracked!(plt, Some(true)); tracked!(polonius, Polonius::Legacy); tracked!(precise_enum_drop_elaboration, false); diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index 40db765da53..04c2ebf189f 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -3,7 +3,6 @@ use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::UNFULFILLED_LINT_EXPECTATIONS; use rustc_session::lint::LintExpectationId; -use rustc_span::symbol::sym; use rustc_span::Symbol; pub(crate) fn provide(providers: &mut Providers) { @@ -11,10 +10,6 @@ pub(crate) fn provide(providers: &mut Providers) { } fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) { - if !tcx.features().active(sym::lint_reasons) { - return; - } - let lint_expectations = tcx.lint_expectations(()); let fulfilled_expectations = tcx.dcx().steal_fulfilled_expectation_ids(); diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 1317af50a4a..0df34c32e38 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -37,7 +37,6 @@ use rustc_session::lint::{ }, Level, Lint, LintExpectationId, LintId, }; -use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -788,15 +787,6 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { ast::MetaItemKind::NameValue(ref name_value) => { if item.path == sym::reason { if let ast::LitKind::Str(rationale, _) = name_value.kind { - if !self.features.lint_reasons { - feature_err( - &self.sess, - sym::lint_reasons, - item.span, - "lint reasons are experimental", - ) - .emit(); - } reason = Some(rationale); } else { sess.dcx().emit_err(MalformedAttribute { diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index aa1d94228ea..445dcd41e5d 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { { let direct_super_traits_iter = cx .tcx - .super_predicates_of(def_id) + .explicit_super_predicates_of(def_id) .predicates .into_iter() .filter_map(|(pred, _)| pred.as_trait_clause()); diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 300dac442d5..17429ed061f 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -50,7 +50,7 @@ declare_lint! { /// All nested bodies (functions, enum discriminant, array length, consts) (expect for /// `const _: Ty = { ... }` in top-level module, which is still undecided) are checked. pub NON_LOCAL_DEFINITIONS, - Warn, + Allow, "checks for non-local definitions", report_in_external_macro } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index a023d6161df..472e93d202d 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -608,13 +608,13 @@ declare_lint! { } declare_lint! { - /// The `unfulfilled_lint_expectations` lint detects lint trigger expectations - /// that have not been fulfilled. + /// The `unfulfilled_lint_expectations` lint detects when a lint expectation is + /// unfulfilled. /// /// ### Example /// /// ```rust - /// #![feature(lint_reasons)] + /// #![cfg_attr(bootstrap, feature(lint_reasons))] /// /// #[expect(unused_variables)] /// let x = 10; @@ -625,24 +625,14 @@ declare_lint! { /// /// ### Explanation /// - /// It was expected that the marked code would emit a lint. This expectation - /// has not been fulfilled. + /// The `#[expect]` attribute can be used to create a lint expectation. The + /// expectation is fulfilled, if a `#[warn]` attribute at the same location + /// would result in a lint emission. If the expectation is unfulfilled, + /// because no lint was emitted, this lint will be emitted on the attribute. /// - /// The `expect` attribute can be removed if this is intended behavior otherwise - /// it should be investigated why the expected lint is no longer issued. - /// - /// In rare cases, the expectation might be emitted at a different location than - /// shown in the shown code snippet. In most cases, the `#[expect]` attribute - /// works when added to the outer scope. A few lints can only be expected - /// on a crate level. - /// - /// Part of RFC 2383. The progress is being tracked in [#54503] - /// - /// [#54503]: https://github.com/rust-lang/rust/issues/54503 pub UNFULFILLED_LINT_EXPECTATIONS, Warn, - "unfulfilled lint expectation", - @feature_gate = rustc_span::sym::lint_reasons; + "unfulfilled lint expectation" } declare_lint! { diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index cdaabb036c2..3aa852c8304 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -235,6 +235,7 @@ fn main() { || target.starts_with("mips-") || target.starts_with("mipsel-") || target.starts_with("powerpc-") + || target.starts_with("sparc-") { // 32-bit targets need to link libatomic. println!("cargo:rustc-link-lib=atomic"); diff --git a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp index 8871f410e36..a8c278741a7 100644 --- a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp @@ -13,10 +13,7 @@ struct RustArchiveMember { Archive::Child Child; RustArchiveMember() - : Filename(nullptr), Name(nullptr), - Child(nullptr, nullptr, nullptr) - { - } + : Filename(nullptr), Name(nullptr), Child(nullptr, nullptr, nullptr) {} ~RustArchiveMember() {} }; @@ -27,11 +24,8 @@ struct RustArchiveIterator { std::unique_ptr<Error> Err; RustArchiveIterator(Archive::child_iterator Cur, Archive::child_iterator End, - std::unique_ptr<Error> Err) - : First(true), - Cur(Cur), - End(End), - Err(std::move(Err)) {} + std::unique_ptr<Error> Err) + : First(true), Cur(Cur), End(End), Err(std::move(Err)) {} }; enum class LLVMRustArchiveKind { @@ -66,8 +60,8 @@ typedef Archive::Child const *LLVMRustArchiveChildConstRef; typedef RustArchiveIterator *LLVMRustArchiveIteratorRef; extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *Path) { - ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr = - MemoryBuffer::getFile(Path, /*IsText*/false, /*RequiresNullTerminator=*/false); + ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr = MemoryBuffer::getFile( + Path, /*IsText*/ false, /*RequiresNullTerminator=*/false); if (!BufOr) { LLVMRustSetLastError(BufOr.getError().message().c_str()); return nullptr; @@ -146,8 +140,8 @@ extern "C" const char * LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) { Expected<StringRef> NameOrErr = Child->getName(); if (!NameOrErr) { - // rustc_codegen_llvm currently doesn't use this error string, but it might be - // useful in the future, and in the meantime this tells LLVM that the + // rustc_codegen_llvm currently doesn't use this error string, but it might + // be useful in the future, and in the meantime this tells LLVM that the // error was not ignored and that it shouldn't abort the process. LLVMRustSetLastError(toString(NameOrErr.takeError()).c_str()); return nullptr; @@ -172,10 +166,9 @@ extern "C" void LLVMRustArchiveMemberFree(LLVMRustArchiveMemberRef Member) { delete Member; } -extern "C" LLVMRustResult -LLVMRustWriteArchive(char *Dst, size_t NumMembers, - const LLVMRustArchiveMemberRef *NewMembers, - bool WriteSymbtab, LLVMRustArchiveKind RustKind, bool isEC) { +extern "C" LLVMRustResult LLVMRustWriteArchive( + char *Dst, size_t NumMembers, const LLVMRustArchiveMemberRef *NewMembers, + bool WriteSymbtab, LLVMRustArchiveKind RustKind, bool isEC) { std::vector<NewArchiveMember> Members; auto Kind = fromRust(RustKind); @@ -206,8 +199,10 @@ LLVMRustWriteArchive(char *Dst, size_t NumMembers, #if LLVM_VERSION_LT(18, 0) auto Result = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false); #else - auto SymtabMode = WriteSymbtab ? SymtabWritingMode::NormalSymtab : SymtabWritingMode::NoSymtab; - auto Result = writeArchive(Dst, Members, SymtabMode, Kind, true, false, nullptr, isEC); + auto SymtabMode = WriteSymbtab ? SymtabWritingMode::NormalSymtab + : SymtabWritingMode::NoSymtab; + auto Result = + writeArchive(Dst, Members, SymtabMode, Kind, true, false, nullptr, isEC); #endif if (!Result) return LLVMRustResult::Success; diff --git a/compiler/rustc_llvm/llvm-wrapper/Linker.cpp b/compiler/rustc_llvm/llvm-wrapper/Linker.cpp index 533df0f75f8..f43128ed550 100644 --- a/compiler/rustc_llvm/llvm-wrapper/Linker.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/Linker.cpp @@ -1,5 +1,5 @@ -#include "SuppressLLVMWarnings.h" #include "llvm/Linker/Linker.h" +#include "SuppressLLVMWarnings.h" #include "LLVMWrapper.h" @@ -9,26 +9,18 @@ struct RustLinker { Linker L; LLVMContext &Ctx; - RustLinker(Module &M) : - L(M), - Ctx(M.getContext()) - {} + RustLinker(Module &M) : L(M), Ctx(M.getContext()) {} }; -extern "C" RustLinker* -LLVMRustLinkerNew(LLVMModuleRef DstRef) { +extern "C" RustLinker *LLVMRustLinkerNew(LLVMModuleRef DstRef) { Module *Dst = unwrap(DstRef); return new RustLinker(*Dst); } -extern "C" void -LLVMRustLinkerFree(RustLinker *L) { - delete L; -} +extern "C" void LLVMRustLinkerFree(RustLinker *L) { delete L; } -extern "C" bool -LLVMRustLinkerAdd(RustLinker *L, char *BC, size_t Len) { +extern "C" bool LLVMRustLinkerAdd(RustLinker *L, char *BC, size_t Len) { std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBufferCopy(StringRef(BC, Len)); diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index a027ddcc150..c4cfc0b6dc6 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -2,23 +2,25 @@ #include <cstddef> #include <iomanip> -#include <vector> #include <set> +#include <vector> #include "LLVMWrapper.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/CodeGen/CommandFlags.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" -#include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/AssemblyAnnotationWriter.h" +#include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Verifier.h" +#include "llvm/LTO/LTO.h" #include "llvm/MC/TargetRegistry.h" -#include "llvm/Object/ObjectFile.h" #include "llvm/Object/IRObjectFile.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Passes/PassBuilder.h" #include "llvm/Passes/PassPlugin.h" #include "llvm/Passes/StandardInstrumentations.h" @@ -33,26 +35,24 @@ #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h" #include "llvm/Transforms/Utils/AddDiscriminators.h" #include "llvm/Transforms/Utils/FunctionImportUtils.h" -#include "llvm/LTO/LTO.h" -#include "llvm/Bitcode/BitcodeWriter.h" #if LLVM_VERSION_GE(18, 0) #include "llvm/TargetParser/Host.h" #endif +#include "llvm/Support/TimeProfiler.h" #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Instrumentation/AddressSanitizer.h" #include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h" -#include "llvm/Support/TimeProfiler.h" #if LLVM_VERSION_GE(19, 0) #include "llvm/Support/PGOOptions.h" #endif #include "llvm/Transforms/Instrumentation/GCOVProfiler.h" +#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h" #include "llvm/Transforms/Instrumentation/InstrProfiling.h" -#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" #include "llvm/Transforms/Instrumentation/MemorySanitizer.h" -#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h" +#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" +#include "llvm/Transforms/Utils.h" #include "llvm/Transforms/Utils/CanonicalizeAliases.h" #include "llvm/Transforms/Utils/NameAnonGlobals.h" -#include "llvm/Transforms/Utils.h" using namespace llvm; @@ -74,7 +74,7 @@ extern "C" void LLVMRustTimeTraceProfilerFinishThread() { timeTraceProfilerFinishThread(); } -extern "C" void LLVMRustTimeTraceProfilerFinish(const char* FileName) { +extern "C" void LLVMRustTimeTraceProfilerFinish(const char *FileName) { auto FN = StringRef(FileName); std::error_code EC; auto OS = raw_fd_ostream(FN, EC, sys::fs::CD_CreateAlways); @@ -188,7 +188,7 @@ extern "C" void LLVMRustTimeTraceProfilerFinish(const char* FileName) { SUBTARGET_HEXAGON \ SUBTARGET_XTENSA \ SUBTARGET_RISCV \ - SUBTARGET_LOONGARCH \ + SUBTARGET_LOONGARCH #define SUBTARGET(x) \ namespace llvm { \ @@ -215,8 +215,7 @@ enum class LLVMRustCodeModel { None, }; -static std::optional<CodeModel::Model> -fromRust(LLVMRustCodeModel Model) { +static std::optional<CodeModel::Model> fromRust(LLVMRustCodeModel Model) { switch (Model) { case LLVMRustCodeModel::Tiny: return CodeModel::Tiny; @@ -243,9 +242,9 @@ enum class LLVMRustCodeGenOptLevel { }; #if LLVM_VERSION_GE(18, 0) - using CodeGenOptLevelEnum = llvm::CodeGenOptLevel; +using CodeGenOptLevelEnum = llvm::CodeGenOptLevel; #else - using CodeGenOptLevelEnum = llvm::CodeGenOpt::Level; +using CodeGenOptLevelEnum = llvm::CodeGenOpt::Level; #endif static CodeGenOptLevelEnum fromRust(LLVMRustCodeGenOptLevel Level) { @@ -319,48 +318,49 @@ static Reloc::Model fromRust(LLVMRustRelocModel RustReloc) { } /// getLongestEntryLength - Return the length of the longest entry in the table. -template<typename KV> -static size_t getLongestEntryLength(ArrayRef<KV> Table) { +template <typename KV> static size_t getLongestEntryLength(ArrayRef<KV> Table) { size_t MaxLen = 0; for (auto &I : Table) MaxLen = std::max(MaxLen, std::strlen(I.Key)); return MaxLen; } -using PrintBackendInfo = void(void*, const char* Data, size_t Len); +using PrintBackendInfo = void(void *, const char *Data, size_t Len); extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM, - const char* TargetCPU, - PrintBackendInfo Print, - void* Out) { + const char *TargetCPU, + PrintBackendInfo Print, void *Out) { const TargetMachine *Target = unwrap(TM); - const Triple::ArchType HostArch = Triple(sys::getDefaultTargetTriple()).getArch(); + const Triple::ArchType HostArch = + Triple(sys::getDefaultTargetTriple()).getArch(); const Triple::ArchType TargetArch = Target->getTargetTriple().getArch(); std::ostringstream Buf; const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); - const ArrayRef<SubtargetSubTypeKV> CPUTable = MCInfo->getAllProcessorDescriptions(); + const ArrayRef<SubtargetSubTypeKV> CPUTable = + MCInfo->getAllProcessorDescriptions(); unsigned MaxCPULen = getLongestEntryLength(CPUTable); Buf << "Available CPUs for this target:\n"; // Don't print the "native" entry when the user specifies --target with a // different arch since that could be wrong or misleading. if (HostArch == TargetArch) { - MaxCPULen = std::max(MaxCPULen, (unsigned) std::strlen("native")); + MaxCPULen = std::max(MaxCPULen, (unsigned)std::strlen("native")); const StringRef HostCPU = sys::getHostCPUName(); Buf << " " << std::left << std::setw(MaxCPULen) << "native" << " - Select the CPU of the current host " - "(currently " << HostCPU.str() << ").\n"; + "(currently " + << HostCPU.str() << ").\n"; } for (auto &CPU : CPUTable) { // Compare cpu against current target to label the default if (strcmp(CPU.Key, TargetCPU) == 0) { Buf << " " << std::left << std::setw(MaxCPULen) << CPU.Key << " - This is the default target CPU for the current build target " - "(currently " << Target->getTargetTriple().str() << ")."; - } - else { + "(currently " + << Target->getTargetTriple().str() << ")."; + } else { Buf << " " << CPU.Key; } Buf << "\n"; @@ -374,7 +374,8 @@ extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef TM) { #if LLVM_VERSION_GE(18, 0) const TargetMachine *Target = unwrap(TM); const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); - const ArrayRef<SubtargetFeatureKV> FeatTable = MCInfo->getAllProcessorFeatures(); + const ArrayRef<SubtargetFeatureKV> FeatTable = + MCInfo->getAllProcessorFeatures(); return FeatTable.size(); #else return 0; @@ -382,18 +383,20 @@ extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef TM) { } extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef TM, size_t Index, - const char** Feature, const char** Desc) { + const char **Feature, + const char **Desc) { #if LLVM_VERSION_GE(18, 0) const TargetMachine *Target = unwrap(TM); const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); - const ArrayRef<SubtargetFeatureKV> FeatTable = MCInfo->getAllProcessorFeatures(); + const ArrayRef<SubtargetFeatureKV> FeatTable = + MCInfo->getAllProcessorFeatures(); const SubtargetFeatureKV Feat = FeatTable[Index]; *Feature = Feat.Key; *Desc = Feat.Desc; #endif } -extern "C" const char* LLVMRustGetHostCPUName(size_t *len) { +extern "C" const char *LLVMRustGetHostCPUName(size_t *len) { StringRef Name = sys::getHostCPUName(); *len = Name.size(); return Name.data(); @@ -403,19 +406,11 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( const char *TripleStr, const char *CPU, const char *Feature, const char *ABIStr, LLVMRustCodeModel RustCM, LLVMRustRelocModel RustReloc, LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat, - bool FunctionSections, - bool DataSections, - bool UniqueSectionNames, - bool TrapUnreachable, - bool Singlethread, - bool AsmComments, - bool EmitStackSizeSection, - bool RelaxELFRelocations, - bool UseInitArray, - const char *SplitDwarfFile, - const char *OutputObjFile, - const char *DebugInfoCompression, - bool UseEmulatedTls, + bool FunctionSections, bool DataSections, bool UniqueSectionNames, + bool TrapUnreachable, bool Singlethread, bool AsmComments, + bool EmitStackSizeSection, bool RelaxELFRelocations, bool UseInitArray, + const char *SplitDwarfFile, const char *OutputObjFile, + const char *DebugInfoCompression, bool UseEmulatedTls, const char *ArgsCstrBuff, size_t ArgsCstrBuffLen) { auto OptLevel = fromRust(RustOptLevel); @@ -444,18 +439,20 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.MCOptions.PreserveAsmComments = AsmComments; Options.MCOptions.ABIName = ABIStr; if (SplitDwarfFile) { - Options.MCOptions.SplitDwarfFile = SplitDwarfFile; + Options.MCOptions.SplitDwarfFile = SplitDwarfFile; } if (OutputObjFile) { - Options.ObjectFilenameForDebug = OutputObjFile; + Options.ObjectFilenameForDebug = OutputObjFile; } - if (!strcmp("zlib", DebugInfoCompression) && llvm::compression::zlib::isAvailable()) { + if (!strcmp("zlib", DebugInfoCompression) && + llvm::compression::zlib::isAvailable()) { #if LLVM_VERSION_GE(19, 0) Options.MCOptions.CompressDebugSections = DebugCompressionType::Zlib; #else Options.CompressDebugSections = DebugCompressionType::Zlib; #endif - } else if (!strcmp("zstd", DebugInfoCompression) && llvm::compression::zstd::isAvailable()) { + } else if (!strcmp("zstd", DebugInfoCompression) && + llvm::compression::zstd::isAvailable()) { #if LLVM_VERSION_GE(19, 0) Options.MCOptions.CompressDebugSections = DebugCompressionType::Zstd; #else @@ -499,24 +496,21 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.EmitStackSizeSection = EmitStackSizeSection; - - if (ArgsCstrBuff != nullptr) - { + if (ArgsCstrBuff != nullptr) { int buffer_offset = 0; assert(ArgsCstrBuff[ArgsCstrBuffLen - 1] == '\0'); const size_t arg0_len = std::strlen(ArgsCstrBuff); - char* arg0 = new char[arg0_len + 1]; + char *arg0 = new char[arg0_len + 1]; memcpy(arg0, ArgsCstrBuff, arg0_len); arg0[arg0_len] = '\0'; buffer_offset += arg0_len + 1; - const int num_cmd_arg_strings = - std::count(&ArgsCstrBuff[buffer_offset], &ArgsCstrBuff[ArgsCstrBuffLen], '\0'); + const int num_cmd_arg_strings = std::count( + &ArgsCstrBuff[buffer_offset], &ArgsCstrBuff[ArgsCstrBuffLen], '\0'); - std::string* cmd_arg_strings = new std::string[num_cmd_arg_strings]; - for (int i = 0; i < num_cmd_arg_strings; ++i) - { + std::string *cmd_arg_strings = new std::string[num_cmd_arg_strings]; + for (int i = 0; i < num_cmd_arg_strings; ++i) { assert(buffer_offset < ArgsCstrBuffLen); const int len = std::strlen(ArgsCstrBuff + buffer_offset); cmd_arg_strings[i] = std::string(&ArgsCstrBuff[buffer_offset], len); @@ -527,7 +521,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.MCOptions.Argv0 = arg0; Options.MCOptions.CommandLineArgs = - llvm::ArrayRef<std::string>(cmd_arg_strings, num_cmd_arg_strings); + llvm::ArrayRef<std::string>(cmd_arg_strings, num_cmd_arg_strings); } TargetMachine *TM = TheTarget->createTargetMachine( @@ -537,7 +531,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) { - MCTargetOptions& MCOptions = unwrap(TM)->Options.MCOptions; + MCTargetOptions &MCOptions = unwrap(TM)->Options.MCOptions; delete[] MCOptions.Argv0; delete[] MCOptions.CommandLineArgs.data(); @@ -613,7 +607,7 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR, auto DOS = raw_fd_ostream(DwoPath, EC, sys::fs::OF_None); EC.clear(); if (EC) - ErrorInfo = EC.message(); + ErrorInfo = EC.message(); if (ErrorInfo != "") { LLVMRustSetLastError(ErrorInfo.c_str()); return LLVMRustResult::Failure; @@ -633,10 +627,12 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR, return LLVMRustResult::Success; } -extern "C" typedef void (*LLVMRustSelfProfileBeforePassCallback)(void*, // LlvmSelfProfiler - const char*, // pass name - const char*); // IR name -extern "C" typedef void (*LLVMRustSelfProfileAfterPassCallback)(void*); // LlvmSelfProfiler +extern "C" typedef void (*LLVMRustSelfProfileBeforePassCallback)( + void *, // LlvmSelfProfiler + const char *, // pass name + const char *); // IR name +extern "C" typedef void (*LLVMRustSelfProfileAfterPassCallback)( + void *); // LlvmSelfProfiler std::string LLVMRustwrappedIrGetName(const llvm::Any &WrappedIr) { if (const auto *Cast = any_cast<const Module *>(&WrappedIr)) @@ -650,35 +646,35 @@ std::string LLVMRustwrappedIrGetName(const llvm::Any &WrappedIr) { return "<UNKNOWN>"; } - void LLVMSelfProfileInitializeCallbacks( - PassInstrumentationCallbacks& PIC, void* LlvmSelfProfiler, + PassInstrumentationCallbacks &PIC, void *LlvmSelfProfiler, LLVMRustSelfProfileBeforePassCallback BeforePassCallback, LLVMRustSelfProfileAfterPassCallback AfterPassCallback) { - PIC.registerBeforeNonSkippedPassCallback([LlvmSelfProfiler, BeforePassCallback]( - StringRef Pass, llvm::Any Ir) { - std::string PassName = Pass.str(); - std::string IrName = LLVMRustwrappedIrGetName(Ir); - BeforePassCallback(LlvmSelfProfiler, PassName.c_str(), IrName.c_str()); - }); + PIC.registerBeforeNonSkippedPassCallback( + [LlvmSelfProfiler, BeforePassCallback](StringRef Pass, llvm::Any Ir) { + std::string PassName = Pass.str(); + std::string IrName = LLVMRustwrappedIrGetName(Ir); + BeforePassCallback(LlvmSelfProfiler, PassName.c_str(), IrName.c_str()); + }); PIC.registerAfterPassCallback( - [LlvmSelfProfiler, AfterPassCallback](StringRef Pass, llvm::Any IR, - const PreservedAnalyses &Preserved) { + [LlvmSelfProfiler, AfterPassCallback]( + StringRef Pass, llvm::Any IR, const PreservedAnalyses &Preserved) { AfterPassCallback(LlvmSelfProfiler); }); PIC.registerAfterPassInvalidatedCallback( - [LlvmSelfProfiler, AfterPassCallback](StringRef Pass, const PreservedAnalyses &Preserved) { + [LlvmSelfProfiler, + AfterPassCallback](StringRef Pass, const PreservedAnalyses &Preserved) { AfterPassCallback(LlvmSelfProfiler); }); - PIC.registerBeforeAnalysisCallback([LlvmSelfProfiler, BeforePassCallback]( - StringRef Pass, llvm::Any Ir) { - std::string PassName = Pass.str(); - std::string IrName = LLVMRustwrappedIrGetName(Ir); - BeforePassCallback(LlvmSelfProfiler, PassName.c_str(), IrName.c_str()); - }); + PIC.registerBeforeAnalysisCallback( + [LlvmSelfProfiler, BeforePassCallback](StringRef Pass, llvm::Any Ir) { + std::string PassName = Pass.str(); + std::string IrName = LLVMRustwrappedIrGetName(Ir); + BeforePassCallback(LlvmSelfProfiler, PassName.c_str(), IrName.c_str()); + }); PIC.registerAfterAnalysisCallback( [LlvmSelfProfiler, AfterPassCallback](StringRef Pass, llvm::Any Ir) { @@ -704,7 +700,7 @@ struct LLVMRustSanitizerOptions { bool SanitizeKCFI; bool SanitizeMemory; bool SanitizeMemoryRecover; - int SanitizeMemoryTrackOrigins; + int SanitizeMemoryTrackOrigins; bool SanitizeThread; bool SanitizeHWAddress; bool SanitizeHWAddressRecover; @@ -712,31 +708,25 @@ struct LLVMRustSanitizerOptions { bool SanitizeKernelAddressRecover; }; -extern "C" LLVMRustResult -LLVMRustOptimize( - LLVMModuleRef ModuleRef, - LLVMTargetMachineRef TMRef, - LLVMRustPassBuilderOptLevel OptLevelRust, - LLVMRustOptStage OptStage, - bool IsLinkerPluginLTO, - bool NoPrepopulatePasses, bool VerifyIR, bool UseThinLTOBuffers, - bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize, - bool DisableSimplifyLibCalls, bool EmitLifetimeMarkers, - LLVMRustSanitizerOptions *SanitizerOptions, - const char *PGOGenPath, const char *PGOUsePath, - bool InstrumentCoverage, const char *InstrProfileOutput, - bool InstrumentGCOV, +extern "C" LLVMRustResult LLVMRustOptimize( + LLVMModuleRef ModuleRef, LLVMTargetMachineRef TMRef, + LLVMRustPassBuilderOptLevel OptLevelRust, LLVMRustOptStage OptStage, + bool IsLinkerPluginLTO, bool NoPrepopulatePasses, bool VerifyIR, + bool UseThinLTOBuffers, bool MergeFunctions, bool UnrollLoops, + bool SLPVectorize, bool LoopVectorize, bool DisableSimplifyLibCalls, + bool EmitLifetimeMarkers, LLVMRustSanitizerOptions *SanitizerOptions, + const char *PGOGenPath, const char *PGOUsePath, bool InstrumentCoverage, + const char *InstrProfileOutput, bool InstrumentGCOV, const char *PGOSampleUsePath, bool DebugInfoForProfiling, - void* LlvmSelfProfiler, + void *LlvmSelfProfiler, LLVMRustSelfProfileBeforePassCallback BeforePassCallback, LLVMRustSelfProfileAfterPassCallback AfterPassCallback, - const char *ExtraPasses, size_t ExtraPassesLen, - const char *LLVMPlugins, size_t LLVMPluginsLen) { + const char *ExtraPasses, size_t ExtraPassesLen, const char *LLVMPlugins, + size_t LLVMPluginsLen) { Module *TheModule = unwrap(ModuleRef); TargetMachine *TM = unwrap(TMRef); OptimizationLevel OptLevel = fromRust(OptLevelRust); - PipelineTuningOptions PTO; PTO.LoopUnrolling = UnrollLoops; PTO.LoopInterleaving = UnrollLoops; @@ -751,38 +741,39 @@ LLVMRustOptimize( StandardInstrumentations SI(TheModule->getContext(), DebugPassManager); SI.registerCallbacks(PIC); - if (LlvmSelfProfiler){ - LLVMSelfProfileInitializeCallbacks(PIC,LlvmSelfProfiler,BeforePassCallback,AfterPassCallback); + if (LlvmSelfProfiler) { + LLVMSelfProfileInitializeCallbacks(PIC, LlvmSelfProfiler, + BeforePassCallback, AfterPassCallback); } std::optional<PGOOptions> PGOOpt; auto FS = vfs::getRealFileSystem(); if (PGOGenPath) { assert(!PGOUsePath && !PGOSampleUsePath); - PGOOpt = PGOOptions(PGOGenPath, "", "", "", FS, - PGOOptions::IRInstr, PGOOptions::NoCSAction, + PGOOpt = PGOOptions(PGOGenPath, "", "", "", FS, PGOOptions::IRInstr, + PGOOptions::NoCSAction, #if LLVM_VERSION_GE(19, 0) PGOOptions::ColdFuncOpt::Default, #endif DebugInfoForProfiling); } else if (PGOUsePath) { assert(!PGOSampleUsePath); - PGOOpt = PGOOptions(PGOUsePath, "", "", "", FS, - PGOOptions::IRUse, PGOOptions::NoCSAction, + PGOOpt = PGOOptions(PGOUsePath, "", "", "", FS, PGOOptions::IRUse, + PGOOptions::NoCSAction, #if LLVM_VERSION_GE(19, 0) PGOOptions::ColdFuncOpt::Default, #endif DebugInfoForProfiling); } else if (PGOSampleUsePath) { - PGOOpt = PGOOptions(PGOSampleUsePath, "", "", "", FS, - PGOOptions::SampleUse, PGOOptions::NoCSAction, + PGOOpt = PGOOptions(PGOSampleUsePath, "", "", "", FS, PGOOptions::SampleUse, + PGOOptions::NoCSAction, #if LLVM_VERSION_GE(19, 0) PGOOptions::ColdFuncOpt::Default, #endif DebugInfoForProfiling); } else if (DebugInfoForProfiling) { - PGOOpt = PGOOptions("", "", "", "", FS, - PGOOptions::NoAction, PGOOptions::NoCSAction, + PGOOpt = PGOOptions("", "", "", "", FS, PGOOptions::NoAction, + PGOOptions::NoCSAction, #if LLVM_VERSION_GE(19, 0) PGOOptions::ColdFuncOpt::Default, #endif @@ -799,7 +790,7 @@ LLVMRustOptimize( auto PluginsStr = StringRef(LLVMPlugins, LLVMPluginsLen); SmallVector<StringRef> Plugins; PluginsStr.split(Plugins, ',', -1, false); - for (auto PluginPath: Plugins) { + for (auto PluginPath : Plugins) { auto Plugin = PassPlugin::Load(PluginPath.str()); if (!Plugin) { auto Err = Plugin.takeError(); @@ -814,7 +805,8 @@ LLVMRustOptimize( FAM.registerPass([&] { return PB.buildDefaultAAPipeline(); }); Triple TargetTriple(TheModule->getTargetTriple()); - std::unique_ptr<TargetLibraryInfoImpl> TLII(new TargetLibraryInfoImpl(TargetTriple)); + std::unique_ptr<TargetLibraryInfoImpl> TLII( + new TargetLibraryInfoImpl(TargetTriple)); if (DisableSimplifyLibCalls) TLII->disableAllFunctions(); FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); }); @@ -825,58 +817,53 @@ LLVMRustOptimize( PB.registerLoopAnalyses(LAM); PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); - // We manually collect pipeline callbacks so we can apply them at O0, where the - // PassBuilder does not create a pipeline. + // We manually collect pipeline callbacks so we can apply them at O0, where + // the PassBuilder does not create a pipeline. std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>> PipelineStartEPCallbacks; std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>> OptimizerLastEPCallbacks; - if (!IsLinkerPluginLTO - && SanitizerOptions && SanitizerOptions->SanitizeCFI - && !NoPrepopulatePasses) { + if (!IsLinkerPluginLTO && SanitizerOptions && SanitizerOptions->SanitizeCFI && + !NoPrepopulatePasses) { PipelineStartEPCallbacks.push_back( - [](ModulePassManager &MPM, OptimizationLevel Level) { - MPM.addPass(LowerTypeTestsPass(/*ExportSummary=*/nullptr, - /*ImportSummary=*/nullptr, - /*DropTypeTests=*/false)); - } - ); + [](ModulePassManager &MPM, OptimizationLevel Level) { + MPM.addPass(LowerTypeTestsPass(/*ExportSummary=*/nullptr, + /*ImportSummary=*/nullptr, + /*DropTypeTests=*/false)); + }); } if (VerifyIR) { PipelineStartEPCallbacks.push_back( - [VerifyIR](ModulePassManager &MPM, OptimizationLevel Level) { - MPM.addPass(VerifierPass()); - } - ); + [VerifyIR](ModulePassManager &MPM, OptimizationLevel Level) { + MPM.addPass(VerifierPass()); + }); } if (InstrumentGCOV) { PipelineStartEPCallbacks.push_back( - [](ModulePassManager &MPM, OptimizationLevel Level) { - MPM.addPass(GCOVProfilerPass(GCOVOptions::getDefault())); - } - ); + [](ModulePassManager &MPM, OptimizationLevel Level) { + MPM.addPass(GCOVProfilerPass(GCOVOptions::getDefault())); + }); } if (InstrumentCoverage) { PipelineStartEPCallbacks.push_back( - [InstrProfileOutput](ModulePassManager &MPM, OptimizationLevel Level) { - InstrProfOptions Options; - if (InstrProfileOutput) { - Options.InstrProfileOutput = InstrProfileOutput; - } - // cargo run tests in multhreading mode by default - // so use atomics for coverage counters - Options.Atomic = true; + [InstrProfileOutput](ModulePassManager &MPM, OptimizationLevel Level) { + InstrProfOptions Options; + if (InstrProfileOutput) { + Options.InstrProfileOutput = InstrProfileOutput; + } + // cargo run tests in multhreading mode by default + // so use atomics for coverage counters + Options.Atomic = true; #if LLVM_VERSION_GE(18, 0) - MPM.addPass(InstrProfilingLoweringPass(Options, false)); + MPM.addPass(InstrProfilingLoweringPass(Options, false)); #else - MPM.addPass(InstrProfiling(Options, false)); + MPM.addPass(InstrProfiling(Options, false)); #endif - } - ); + }); } if (SanitizerOptions) { @@ -886,10 +873,9 @@ LLVMRustOptimize( SanitizerOptions->SanitizeDataFlowABIList + SanitizerOptions->SanitizeDataFlowABIListLen); OptimizerLastEPCallbacks.push_back( - [ABIListFiles](ModulePassManager &MPM, OptimizationLevel Level) { - MPM.addPass(DataFlowSanitizerPass(ABIListFiles)); - } - ); + [ABIListFiles](ModulePassManager &MPM, OptimizationLevel Level) { + MPM.addPass(DataFlowSanitizerPass(ABIListFiles)); + }); } if (SanitizerOptions->SanitizeMemory) { @@ -899,54 +885,54 @@ LLVMRustOptimize( /*CompileKernel=*/false, /*EagerChecks=*/true); OptimizerLastEPCallbacks.push_back( - [Options](ModulePassManager &MPM, OptimizationLevel Level) { - MPM.addPass(MemorySanitizerPass(Options)); - } - ); + [Options](ModulePassManager &MPM, OptimizationLevel Level) { + MPM.addPass(MemorySanitizerPass(Options)); + }); } if (SanitizerOptions->SanitizeThread) { - OptimizerLastEPCallbacks.push_back( - [](ModulePassManager &MPM, OptimizationLevel Level) { - MPM.addPass(ModuleThreadSanitizerPass()); - MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass())); - } - ); + OptimizerLastEPCallbacks.push_back([](ModulePassManager &MPM, + OptimizationLevel Level) { + MPM.addPass(ModuleThreadSanitizerPass()); + MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass())); + }); } - if (SanitizerOptions->SanitizeAddress || SanitizerOptions->SanitizeKernelAddress) { + if (SanitizerOptions->SanitizeAddress || + SanitizerOptions->SanitizeKernelAddress) { OptimizerLastEPCallbacks.push_back( - [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) { - auto CompileKernel = SanitizerOptions->SanitizeKernelAddress; - AddressSanitizerOptions opts = AddressSanitizerOptions{ - CompileKernel, - SanitizerOptions->SanitizeAddressRecover - || SanitizerOptions->SanitizeKernelAddressRecover, - /*UseAfterScope=*/true, - AsanDetectStackUseAfterReturnMode::Runtime, - }; - MPM.addPass(AddressSanitizerPass(opts)); - } - ); + [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) { + auto CompileKernel = SanitizerOptions->SanitizeKernelAddress; + AddressSanitizerOptions opts = AddressSanitizerOptions{ + CompileKernel, + SanitizerOptions->SanitizeAddressRecover || + SanitizerOptions->SanitizeKernelAddressRecover, + /*UseAfterScope=*/true, + AsanDetectStackUseAfterReturnMode::Runtime, + }; + MPM.addPass(AddressSanitizerPass(opts)); + }); } if (SanitizerOptions->SanitizeHWAddress) { OptimizerLastEPCallbacks.push_back( - [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) { - HWAddressSanitizerOptions opts( - /*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover, - /*DisableOptimization=*/false); - MPM.addPass(HWAddressSanitizerPass(opts)); - } - ); + [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) { + HWAddressSanitizerOptions opts( + /*CompileKernel=*/false, + SanitizerOptions->SanitizeHWAddressRecover, + /*DisableOptimization=*/false); + MPM.addPass(HWAddressSanitizerPass(opts)); + }); } } ModulePassManager MPM; bool NeedThinLTOBufferPasses = UseThinLTOBuffers; if (!NoPrepopulatePasses) { - // The pre-link pipelines don't support O0 and require using buildO0DefaultPipeline() instead. - // At the same time, the LTO pipelines do support O0 and using them is required. - bool IsLTO = OptStage == LLVMRustOptStage::ThinLTO || OptStage == LLVMRustOptStage::FatLTO; + // The pre-link pipelines don't support O0 and require using + // buildO0DefaultPipeline() instead. At the same time, the LTO pipelines do + // support O0 and using them is required. + bool IsLTO = OptStage == LLVMRustOptStage::ThinLTO || + OptStage == LLVMRustOptStage::FatLTO; if (OptLevel == OptimizationLevel::O0 && !IsLTO) { for (const auto &C : PipelineStartEPCallbacks) PB.registerPipelineStartEPCallback(C); @@ -993,7 +979,8 @@ LLVMRustOptimize( } if (ExtraPassesLen) { - if (auto Err = PB.parsePassPipeline(MPM, StringRef(ExtraPasses, ExtraPassesLen))) { + if (auto Err = + PB.parsePassPipeline(MPM, StringRef(ExtraPasses, ExtraPassesLen))) { std::string ErrMsg = toString(std::move(Err)); LLVMRustSetLastError(ErrMsg.c_str()); return LLVMRustResult::Failure; @@ -1020,8 +1007,7 @@ LLVMRustOptimize( // * output buffer // * output buffer len // Returns len of demangled string, or 0 if demangle failed. -typedef size_t (*DemangleFn)(const char*, size_t, char*, size_t); - +typedef size_t (*DemangleFn)(const char *, size_t, char *, size_t); namespace { @@ -1064,7 +1050,7 @@ public: formatted_raw_ostream &OS) override { StringRef Demangled = CallDemangle(F->getName()); if (Demangled.empty()) { - return; + return; } OS << "; " << Demangled << "\n"; @@ -1077,7 +1063,7 @@ public: if (const CallInst *CI = dyn_cast<CallInst>(I)) { Name = "call"; Value = CI->getCalledOperand(); - } else if (const InvokeInst* II = dyn_cast<InvokeInst>(I)) { + } else if (const InvokeInst *II = dyn_cast<InvokeInst>(I)) { Name = "invoke"; Value = II->getCalledOperand(); } else { @@ -1101,8 +1087,8 @@ public: } // namespace -extern "C" LLVMRustResult -LLVMRustPrintModule(LLVMModuleRef M, const char *Path, DemangleFn Demangle) { +extern "C" LLVMRustResult LLVMRustPrintModule(LLVMModuleRef M, const char *Path, + DemangleFn Demangle) { std::string ErrorInfo; std::error_code EC; auto OS = raw_fd_ostream(Path, EC, sys::fs::OF_None); @@ -1264,11 +1250,9 @@ getFirstDefinitionForLinker(const GlobalValueSummaryList &GVSummaryList) { // The main entry point for creating the global ThinLTO analysis. The structure // here is basically the same as before threads are spawned in the `run` // function of `lib/LTO/ThinLTOCodeGenerator.cpp`. -extern "C" LLVMRustThinLTOData* -LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, - int num_modules, - const char **preserved_symbols, - int num_symbols) { +extern "C" LLVMRustThinLTOData * +LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, int num_modules, + const char **preserved_symbols, int num_symbols) { auto Ret = std::make_unique<LLVMRustThinLTOData>(); // Load each module's summary and merge it into one combined index @@ -1290,7 +1274,8 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, } // Collect for each module the list of function it defines (GUID -> Summary) - Ret->Index.collectDefinedGVSummariesPerModule(Ret->ModuleToDefinedGVSummaries); + Ret->Index.collectDefinedGVSummariesPerModule( + Ret->ModuleToDefinedGVSummaries); // Convert the preserved symbols set from string to GUID, this is then needed // for internalization. @@ -1310,7 +1295,8 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, // crate, so we need `ImportEnabled = false` to limit internalization. // Otherwise, we sometimes lose `static` values -- see #60184. computeDeadSymbolsWithConstProp(Ret->Index, Ret->GUIDPreservedSymbols, - deadIsPrevailing, /* ImportEnabled = */ false); + deadIsPrevailing, + /* ImportEnabled = */ false); // Resolve LinkOnce/Weak symbols, this has to be computed early be cause it // impacts the caching. // @@ -1319,7 +1305,8 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy; for (auto &I : Ret->Index) { if (I.second.SummaryList.size() > 1) - PrevailingCopy[I.first] = getFirstDefinitionForLinker(I.second.SummaryList); + PrevailingCopy[I.first] = + getFirstDefinitionForLinker(I.second.SummaryList); } auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) { const auto &Prevailing = PrevailingCopy.find(GUID); @@ -1327,13 +1314,8 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, return true; return Prevailing->second == S; }; - ComputeCrossModuleImport( - Ret->Index, - Ret->ModuleToDefinedGVSummaries, - isPrevailing, - Ret->ImportLists, - Ret->ExportLists - ); + ComputeCrossModuleImport(Ret->Index, Ret->ModuleToDefinedGVSummaries, + isPrevailing, Ret->ImportLists, Ret->ExportLists); auto recordNewLinkage = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID, @@ -1345,8 +1327,8 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, // formats. We probably could and should use ELF visibility scheme for many of // our targets, however. lto::Config conf; - thinLTOResolvePrevailingInIndex(conf, Ret->Index, isPrevailing, recordNewLinkage, - Ret->GUIDPreservedSymbols); + thinLTOResolvePrevailingInIndex(conf, Ret->Index, isPrevailing, + recordNewLinkage, Ret->GUIDPreservedSymbols); // Here we calculate an `ExportedGUIDs` set for use in the `isExported` // callback below. This callback below will dictate the linkage for all @@ -1355,7 +1337,7 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, // linkage will stay as external, and internal will stay as internal. std::set<GlobalValue::GUID> ExportedGUIDs; for (auto &List : Ret->Index) { - for (auto &GVS: List.second.SummaryList) { + for (auto &GVS : List.second.SummaryList) { if (GlobalValue::isLocalLinkage(GVS->linkage())) continue; auto GUID = GVS->getOriginalName(); @@ -1366,16 +1348,15 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, auto isExported = [&](StringRef ModuleIdentifier, ValueInfo VI) { const auto &ExportList = Ret->ExportLists.find(ModuleIdentifier); return (ExportList != Ret->ExportLists.end() && - ExportList->second.count(VI)) || - ExportedGUIDs.count(VI.getGUID()); + ExportList->second.count(VI)) || + ExportedGUIDs.count(VI.getGUID()); }; thinLTOInternalizeAndPromoteInIndex(Ret->Index, isExported, isPrevailing); return Ret.release(); } -extern "C" void -LLVMRustFreeThinLTOData(LLVMRustThinLTOData *Data) { +extern "C" void LLVMRustFreeThinLTOData(LLVMRustThinLTOData *Data) { delete Data; } @@ -1387,20 +1368,18 @@ LLVMRustFreeThinLTOData(LLVMRustThinLTOData *Data) { // `ProcessThinLTOModule` function. Here they're split up into separate steps // so rustc can save off the intermediate bytecode between each step. -static bool -clearDSOLocalOnDeclarations(Module &Mod, TargetMachine &TM) { +static bool clearDSOLocalOnDeclarations(Module &Mod, TargetMachine &TM) { // When linking an ELF shared object, dso_local should be dropped. We // conservatively do this for -fpic. - bool ClearDSOLocalOnDeclarations = - TM.getTargetTriple().isOSBinFormatELF() && - TM.getRelocationModel() != Reloc::Static && - Mod.getPIELevel() == PIELevel::Default; + bool ClearDSOLocalOnDeclarations = TM.getTargetTriple().isOSBinFormatELF() && + TM.getRelocationModel() != Reloc::Static && + Mod.getPIELevel() == PIELevel::Default; return ClearDSOLocalOnDeclarations; } -extern "C" bool -LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M, - LLVMTargetMachineRef TM) { +extern "C" bool LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, + LLVMModuleRef M, + LLVMTargetMachineRef TM) { Module &Mod = *unwrap(M); TargetMachine &Target = *unwrap(TM); @@ -1415,24 +1394,28 @@ LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M, } extern "C" bool -LLVMRustPrepareThinLTOResolveWeak(const LLVMRustThinLTOData *Data, LLVMModuleRef M) { +LLVMRustPrepareThinLTOResolveWeak(const LLVMRustThinLTOData *Data, + LLVMModuleRef M) { Module &Mod = *unwrap(M); - const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(Mod.getModuleIdentifier()); + const auto &DefinedGlobals = + Data->ModuleToDefinedGVSummaries.lookup(Mod.getModuleIdentifier()); thinLTOFinalizeInModule(Mod, DefinedGlobals, /*PropagateAttrs=*/true); return true; } extern "C" bool -LLVMRustPrepareThinLTOInternalize(const LLVMRustThinLTOData *Data, LLVMModuleRef M) { +LLVMRustPrepareThinLTOInternalize(const LLVMRustThinLTOData *Data, + LLVMModuleRef M) { Module &Mod = *unwrap(M); - const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(Mod.getModuleIdentifier()); + const auto &DefinedGlobals = + Data->ModuleToDefinedGVSummaries.lookup(Mod.getModuleIdentifier()); thinLTOInternalizeModule(Mod, DefinedGlobals); return true; } -extern "C" bool -LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M, - LLVMTargetMachineRef TM) { +extern "C" bool LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, + LLVMModuleRef M, + LLVMTargetMachineRef TM) { Module &Mod = *unwrap(M); TargetMachine &Target = *unwrap(TM); @@ -1464,7 +1447,8 @@ LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M, return Ret; } - auto *WasmCustomSections = (*MOrErr)->getNamedMetadata("wasm.custom_sections"); + auto *WasmCustomSections = + (*MOrErr)->getNamedMetadata("wasm.custom_sections"); if (WasmCustomSections) WasmCustomSections->eraseFromParent(); @@ -1498,7 +1482,7 @@ struct LLVMRustThinLTOBuffer { std::string thin_link_data; }; -extern "C" LLVMRustThinLTOBuffer* +extern "C" LLVMRustThinLTOBuffer * LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin, bool emit_summary) { auto Ret = std::make_unique<LLVMRustThinLTOBuffer>(); { @@ -1520,7 +1504,8 @@ LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin, bool emit_summary) { // We only pass ThinLinkOS to be filled in if we want the summary, // because otherwise LLVM does extra work and may double-emit some // errors or warnings. - MPM.addPass(ThinLTOBitcodeWriterPass(OS, emit_summary ? &ThinLinkOS : nullptr)); + MPM.addPass( + ThinLTOBitcodeWriterPass(OS, emit_summary ? &ThinLinkOS : nullptr)); MPM.run(*unwrap(M), MAM); } else { WriteBitcodeToFile(*unwrap(M), OS); @@ -1530,12 +1515,11 @@ LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin, bool emit_summary) { return Ret.release(); } -extern "C" void -LLVMRustThinLTOBufferFree(LLVMRustThinLTOBuffer *Buffer) { +extern "C" void LLVMRustThinLTOBufferFree(LLVMRustThinLTOBuffer *Buffer) { delete Buffer; } -extern "C" const void* +extern "C" const void * LLVMRustThinLTOBufferPtr(const LLVMRustThinLTOBuffer *Buffer) { return Buffer->data.data(); } @@ -1545,7 +1529,7 @@ LLVMRustThinLTOBufferLen(const LLVMRustThinLTOBuffer *Buffer) { return Buffer->data.length(); } -extern "C" const void* +extern "C" const void * LLVMRustThinLTOBufferThinLinkDataPtr(const LLVMRustThinLTOBuffer *Buffer) { return Buffer->thin_link_data.data(); } @@ -1558,11 +1542,10 @@ LLVMRustThinLTOBufferThinLinkDataLen(const LLVMRustThinLTOBuffer *Buffer) { // This is what we used to parse upstream bitcode for actual ThinLTO // processing. We'll call this once per module optimized through ThinLTO, and // it'll be called concurrently on many threads. -extern "C" LLVMModuleRef -LLVMRustParseBitcodeForLTO(LLVMContextRef Context, - const char *data, - size_t len, - const char *identifier) { +extern "C" LLVMModuleRef LLVMRustParseBitcodeForLTO(LLVMContextRef Context, + const char *data, + size_t len, + const char *identifier) { auto Data = StringRef(data, len); auto Buffer = MemoryBufferRef(Data, identifier); unwrap(Context)->enableDebugTypeODRUniquing(); @@ -1614,8 +1597,9 @@ extern "C" const char *LLVMRustGetSliceFromObjectDataByName(const char *data, // of access globals, etc). // The precise details are determined by LLVM in `computeLTOCacheKey`, which is // used during the normal linker-plugin incremental thin-LTO process. -extern "C" void -LLVMRustComputeLTOCacheKey(RustStringRef KeyOut, const char *ModId, LLVMRustThinLTOData *Data) { +extern "C" void LLVMRustComputeLTOCacheKey(RustStringRef KeyOut, + const char *ModId, + LLVMRustThinLTOData *Data) { SmallString<40> Key; llvm::lto::Config conf; const auto &ImportList = Data->ImportLists.lookup(ModId); @@ -1633,9 +1617,9 @@ LLVMRustComputeLTOCacheKey(RustStringRef KeyOut, const char *ModId, LLVMRustThin CfiFunctionDecls.insert( GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name))); - llvm::computeLTOCacheKey(Key, conf, Data->Index, ModId, - ImportList, ExportList, ResolvedODR, DefinedGlobals, CfiFunctionDefs, CfiFunctionDecls - ); + llvm::computeLTOCacheKey(Key, conf, Data->Index, ModId, ImportList, + ExportList, ResolvedODR, DefinedGlobals, + CfiFunctionDefs, CfiFunctionDecls); LLVMRustStringWriteImpl(KeyOut, Key.c_str(), Key.size()); } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 20167a4b45e..b6790b7df50 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1,5 +1,6 @@ #include "LLVMWrapper.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DiagnosticHandler.h" #include "llvm/IR/DiagnosticInfo.h" @@ -11,17 +12,16 @@ #include "llvm/IR/LLVMRemarkStreamer.h" #include "llvm/IR/Mangler.h" #include "llvm/IR/Value.h" -#include "llvm/Remarks/RemarkStreamer.h" -#include "llvm/Remarks/RemarkSerializer.h" -#include "llvm/Remarks/RemarkFormat.h" -#include "llvm/Support/ToolOutputFile.h" -#include "llvm/Support/ModRef.h" #include "llvm/Object/Archive.h" #include "llvm/Object/COFFImportFile.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Pass.h" -#include "llvm/Bitcode/BitcodeWriter.h" +#include "llvm/Remarks/RemarkFormat.h" +#include "llvm/Remarks/RemarkSerializer.h" +#include "llvm/Remarks/RemarkStreamer.h" +#include "llvm/Support/ModRef.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/ToolOutputFile.h" #include <iostream> @@ -71,12 +71,12 @@ static LLVM_THREAD_LOCAL char *LastError; // Custom error handler for fatal LLVM errors. // // Notably it exits the process with code 101, unlike LLVM's default of 1. -static void FatalErrorHandler(void *UserData, - const char* Reason, +static void FatalErrorHandler(void *UserData, const char *Reason, bool GenCrashDiag) { // Once upon a time we emitted "LLVM ERROR:" specifically to mimic LLVM. Then, - // we developed crater and other tools which only expose logs, not error codes. - // Use a more greppable prefix that will still match the "LLVM ERROR:" prefix. + // we developed crater and other tools which only expose logs, not error + // codes. Use a more greppable prefix that will still match the "LLVM ERROR:" + // prefix. std::cerr << "rustc-LLVM ERROR: " << Reason << std::endl; // Since this error handler exits the process, we have to run any cleanup that @@ -99,8 +99,7 @@ static void FatalErrorHandler(void *UserData, // // It aborts the process without any further allocations, similar to LLVM's // default except that may be configured to `throw std::bad_alloc()` instead. -static void BadAllocErrorHandler(void *UserData, - const char* Reason, +static void BadAllocErrorHandler(void *UserData, const char *Reason, bool GenCrashDiag) { const char *OOM = "rustc-LLVM ERROR: out of memory\n"; (void)!::write(2, OOM, strlen(OOM)); @@ -190,7 +189,8 @@ static CallInst::TailCallKind fromRust(LLVMRustTailCallKind Kind) { } } -extern "C" void LLVMRustSetTailCallKind(LLVMValueRef Call, LLVMRustTailCallKind TCK) { +extern "C" void LLVMRustSetTailCallKind(LLVMValueRef Call, + LLVMRustTailCallKind TCK) { unwrap<CallInst>(Call)->setTailCallKind(fromRust(TCK)); } @@ -201,12 +201,13 @@ extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M, return wrap(unwrap(M) ->getOrInsertFunction(StringRef(Name, NameLen), unwrap<FunctionType>(FunctionTy)) - .getCallee() - ); + .getCallee()); } -extern "C" LLVMValueRef -LLVMRustGetOrInsertGlobal(LLVMModuleRef M, const char *Name, size_t NameLen, LLVMTypeRef Ty) { +extern "C" LLVMValueRef LLVMRustGetOrInsertGlobal(LLVMModuleRef M, + const char *Name, + size_t NameLen, + LLVMTypeRef Ty) { Module *Mod = unwrap(M); auto NameRef = StringRef(Name, NameLen); @@ -221,13 +222,10 @@ LLVMRustGetOrInsertGlobal(LLVMModuleRef M, const char *Name, size_t NameLen, LLV return wrap(GV); } -extern "C" LLVMValueRef -LLVMRustInsertPrivateGlobal(LLVMModuleRef M, LLVMTypeRef Ty) { - return wrap(new GlobalVariable(*unwrap(M), - unwrap(Ty), - false, - GlobalValue::PrivateLinkage, - nullptr)); +extern "C" LLVMValueRef LLVMRustInsertPrivateGlobal(LLVMModuleRef M, + LLVMTypeRef Ty) { + return wrap(new GlobalVariable(*unwrap(M), unwrap(Ty), false, + GlobalValue::PrivateLinkage, nullptr)); } static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { @@ -326,8 +324,9 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { report_fatal_error("bad AttributeKind"); } -template<typename T> static inline void AddAttributes(T *t, unsigned Index, - LLVMAttributeRef *Attrs, size_t AttrsLen) { +template <typename T> +static inline void AddAttributes(T *t, unsigned Index, LLVMAttributeRef *Attrs, + size_t AttrsLen) { AttributeList PAL = t->getAttributes(); auto B = AttrBuilder(t->getContext()); for (LLVMAttributeRef Attr : ArrayRef<LLVMAttributeRef>(Attrs, AttrsLen)) @@ -337,19 +336,22 @@ template<typename T> static inline void AddAttributes(T *t, unsigned Index, } extern "C" void LLVMRustAddFunctionAttributes(LLVMValueRef Fn, unsigned Index, - LLVMAttributeRef *Attrs, size_t AttrsLen) { + LLVMAttributeRef *Attrs, + size_t AttrsLen) { Function *F = unwrap<Function>(Fn); AddAttributes(F, Index, Attrs, AttrsLen); } -extern "C" void LLVMRustAddCallSiteAttributes(LLVMValueRef Instr, unsigned Index, - LLVMAttributeRef *Attrs, size_t AttrsLen) { +extern "C" void LLVMRustAddCallSiteAttributes(LLVMValueRef Instr, + unsigned Index, + LLVMAttributeRef *Attrs, + size_t AttrsLen) { CallBase *Call = unwrap<CallBase>(Instr); AddAttributes(Call, Index, Attrs, AttrsLen); } -extern "C" LLVMAttributeRef LLVMRustCreateAttrNoValue(LLVMContextRef C, - LLVMRustAttribute RustAttr) { +extern "C" LLVMAttributeRef +LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttribute RustAttr) { return wrap(Attribute::get(*unwrap(C), fromRust(RustAttr))); } @@ -363,30 +365,36 @@ extern "C" LLVMAttributeRef LLVMRustCreateDereferenceableAttr(LLVMContextRef C, return wrap(Attribute::getWithDereferenceableBytes(*unwrap(C), Bytes)); } -extern "C" LLVMAttributeRef LLVMRustCreateDereferenceableOrNullAttr(LLVMContextRef C, - uint64_t Bytes) { +extern "C" LLVMAttributeRef +LLVMRustCreateDereferenceableOrNullAttr(LLVMContextRef C, uint64_t Bytes) { return wrap(Attribute::getWithDereferenceableOrNullBytes(*unwrap(C), Bytes)); } -extern "C" LLVMAttributeRef LLVMRustCreateByValAttr(LLVMContextRef C, LLVMTypeRef Ty) { +extern "C" LLVMAttributeRef LLVMRustCreateByValAttr(LLVMContextRef C, + LLVMTypeRef Ty) { return wrap(Attribute::getWithByValType(*unwrap(C), unwrap(Ty))); } -extern "C" LLVMAttributeRef LLVMRustCreateStructRetAttr(LLVMContextRef C, LLVMTypeRef Ty) { +extern "C" LLVMAttributeRef LLVMRustCreateStructRetAttr(LLVMContextRef C, + LLVMTypeRef Ty) { return wrap(Attribute::getWithStructRetType(*unwrap(C), unwrap(Ty))); } -extern "C" LLVMAttributeRef LLVMRustCreateElementTypeAttr(LLVMContextRef C, LLVMTypeRef Ty) { +extern "C" LLVMAttributeRef LLVMRustCreateElementTypeAttr(LLVMContextRef C, + LLVMTypeRef Ty) { return wrap(Attribute::get(*unwrap(C), Attribute::ElementType, unwrap(Ty))); } -extern "C" LLVMAttributeRef LLVMRustCreateUWTableAttr(LLVMContextRef C, bool Async) { +extern "C" LLVMAttributeRef LLVMRustCreateUWTableAttr(LLVMContextRef C, + bool Async) { return wrap(Attribute::getWithUWTableKind( *unwrap(C), Async ? UWTableKind::Async : UWTableKind::Sync)); } -extern "C" LLVMAttributeRef LLVMRustCreateAllocSizeAttr(LLVMContextRef C, uint32_t ElementSizeArg) { - return wrap(Attribute::getWithAllocSizeArgs(*unwrap(C), ElementSizeArg, std::nullopt)); +extern "C" LLVMAttributeRef +LLVMRustCreateAllocSizeAttr(LLVMContextRef C, uint32_t ElementSizeArg) { + return wrap(Attribute::getWithAllocSizeArgs(*unwrap(C), ElementSizeArg, + std::nullopt)); } // These values **must** match ffi::AllocKindFlags. @@ -403,12 +411,15 @@ enum class LLVMRustAllocKindFlags : uint64_t { Aligned = 1 << 5, }; -static LLVMRustAllocKindFlags operator&(LLVMRustAllocKindFlags A, LLVMRustAllocKindFlags B) { +static LLVMRustAllocKindFlags operator&(LLVMRustAllocKindFlags A, + LLVMRustAllocKindFlags B) { return static_cast<LLVMRustAllocKindFlags>(static_cast<uint64_t>(A) & - static_cast<uint64_t>(B)); + static_cast<uint64_t>(B)); } -static bool isSet(LLVMRustAllocKindFlags F) { return F != LLVMRustAllocKindFlags::Unknown; } +static bool isSet(LLVMRustAllocKindFlags F) { + return F != LLVMRustAllocKindFlags::Unknown; +} static llvm::AllocFnKind allocKindFromRust(LLVMRustAllocKindFlags F) { llvm::AllocFnKind AFK = llvm::AllocFnKind::Unknown; @@ -433,40 +444,47 @@ static llvm::AllocFnKind allocKindFromRust(LLVMRustAllocKindFlags F) { return AFK; } -extern "C" LLVMAttributeRef LLVMRustCreateAllocKindAttr(LLVMContextRef C, uint64_t AllocKindArg) { - return wrap(Attribute::get(*unwrap(C), Attribute::AllocKind, - static_cast<uint64_t>(allocKindFromRust(static_cast<LLVMRustAllocKindFlags>(AllocKindArg))))); +extern "C" LLVMAttributeRef LLVMRustCreateAllocKindAttr(LLVMContextRef C, + uint64_t AllocKindArg) { + return wrap( + Attribute::get(*unwrap(C), Attribute::AllocKind, + static_cast<uint64_t>(allocKindFromRust( + static_cast<LLVMRustAllocKindFlags>(AllocKindArg))))); } // Simplified representation of `MemoryEffects` across the FFI boundary. // -// Each variant corresponds to one of the static factory methods on `MemoryEffects`. +// Each variant corresponds to one of the static factory methods on +// `MemoryEffects`. enum class LLVMRustMemoryEffects { None, ReadOnly, InaccessibleMemOnly, }; -extern "C" LLVMAttributeRef LLVMRustCreateMemoryEffectsAttr(LLVMContextRef C, - LLVMRustMemoryEffects Effects) { +extern "C" LLVMAttributeRef +LLVMRustCreateMemoryEffectsAttr(LLVMContextRef C, + LLVMRustMemoryEffects Effects) { switch (Effects) { - case LLVMRustMemoryEffects::None: - return wrap(Attribute::getWithMemoryEffects(*unwrap(C), MemoryEffects::none())); - case LLVMRustMemoryEffects::ReadOnly: - return wrap(Attribute::getWithMemoryEffects(*unwrap(C), MemoryEffects::readOnly())); - case LLVMRustMemoryEffects::InaccessibleMemOnly: - return wrap(Attribute::getWithMemoryEffects(*unwrap(C), - MemoryEffects::inaccessibleMemOnly())); - default: - report_fatal_error("bad MemoryEffects."); - } -} - -// Enable all fast-math flags, including those which will cause floating-point operations -// to return poison for some well-defined inputs. This function can only be used to build -// unsafe Rust intrinsics. That unsafety does permit additional optimizations, but at the -// time of writing, their value is not well-understood relative to those enabled by -// LLVMRustSetAlgebraicMath. + case LLVMRustMemoryEffects::None: + return wrap( + Attribute::getWithMemoryEffects(*unwrap(C), MemoryEffects::none())); + case LLVMRustMemoryEffects::ReadOnly: + return wrap( + Attribute::getWithMemoryEffects(*unwrap(C), MemoryEffects::readOnly())); + case LLVMRustMemoryEffects::InaccessibleMemOnly: + return wrap(Attribute::getWithMemoryEffects( + *unwrap(C), MemoryEffects::inaccessibleMemOnly())); + default: + report_fatal_error("bad MemoryEffects."); + } +} + +// Enable all fast-math flags, including those which will cause floating-point +// operations to return poison for some well-defined inputs. This function can +// only be used to build unsafe Rust intrinsics. That unsafety does permit +// additional optimizations, but at the time of writing, their value is not +// well-understood relative to those enabled by LLVMRustSetAlgebraicMath. // // https://llvm.org/docs/LangRef.html#fast-math-flags extern "C" void LLVMRustSetFastMath(LLVMValueRef V) { @@ -475,14 +493,12 @@ extern "C" void LLVMRustSetFastMath(LLVMValueRef V) { } } -// Enable fast-math flags which permit algebraic transformations that are not allowed by -// IEEE floating point. For example: -// a + (b + c) = (a + b) + c -// and -// a / b = a * (1 / b) -// Note that this does NOT enable any flags which can cause a floating-point operation on -// well-defined inputs to return poison, and therefore this function can be used to build -// safe Rust intrinsics (such as fadd_algebraic). +// Enable fast-math flags which permit algebraic transformations that are not +// allowed by IEEE floating point. For example: a + (b + c) = (a + b) + c and a +// / b = a * (1 / b) Note that this does NOT enable any flags which can cause a +// floating-point operation on well-defined inputs to return poison, and +// therefore this function can be used to build safe Rust intrinsics (such as +// fadd_algebraic). // // https://llvm.org/docs/LangRef.html#fast-math-flags extern "C" void LLVMRustSetAlgebraicMath(LLVMValueRef V) { @@ -497,9 +513,9 @@ extern "C" void LLVMRustSetAlgebraicMath(LLVMValueRef V) { // Enable the reassoc fast-math flag, allowing transformations that pretend // floating-point addition and multiplication are associative. // -// Note that this does NOT enable any flags which can cause a floating-point operation on -// well-defined inputs to return poison, and therefore this function can be used to build -// safe Rust intrinsics (such as fadd_algebraic). +// Note that this does NOT enable any flags which can cause a floating-point +// operation on well-defined inputs to return poison, and therefore this +// function can be used to build safe Rust intrinsics (such as fadd_algebraic). // // https://llvm.org/docs/LangRef.html#fast-math-flags extern "C" void LLVMRustSetAllowReassoc(LLVMValueRef V) { @@ -547,11 +563,10 @@ LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, size_t AsmStringLen, char *Constraints, size_t ConstraintsLen, LLVMBool HasSideEffects, LLVMBool IsAlignStack, LLVMRustAsmDialect Dialect, LLVMBool CanThrow) { - return wrap(InlineAsm::get(unwrap<FunctionType>(Ty), - StringRef(AsmString, AsmStringLen), - StringRef(Constraints, ConstraintsLen), - HasSideEffects, IsAlignStack, - fromRust(Dialect), CanThrow)); + return wrap(InlineAsm::get( + unwrap<FunctionType>(Ty), StringRef(AsmString, AsmStringLen), + StringRef(Constraints, ConstraintsLen), HasSideEffects, IsAlignStack, + fromRust(Dialect), CanThrow)); } extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints, @@ -705,19 +720,22 @@ enum class LLVMRustDISPFlags : uint32_t { inline LLVMRustDISPFlags operator&(LLVMRustDISPFlags A, LLVMRustDISPFlags B) { return static_cast<LLVMRustDISPFlags>(static_cast<uint32_t>(A) & - static_cast<uint32_t>(B)); + static_cast<uint32_t>(B)); } inline LLVMRustDISPFlags operator|(LLVMRustDISPFlags A, LLVMRustDISPFlags B) { return static_cast<LLVMRustDISPFlags>(static_cast<uint32_t>(A) | - static_cast<uint32_t>(B)); + static_cast<uint32_t>(B)); } -inline LLVMRustDISPFlags &operator|=(LLVMRustDISPFlags &A, LLVMRustDISPFlags B) { +inline LLVMRustDISPFlags &operator|=(LLVMRustDISPFlags &A, + LLVMRustDISPFlags B) { return A = A | B; } -inline bool isSet(LLVMRustDISPFlags F) { return F != LLVMRustDISPFlags::SPFlagZero; } +inline bool isSet(LLVMRustDISPFlags F) { + return F != LLVMRustDISPFlags::SPFlagZero; +} inline LLVMRustDISPFlags virtuality(LLVMRustDISPFlags F) { return static_cast<LLVMRustDISPFlags>(static_cast<uint32_t>(F) & 0x3); @@ -761,7 +779,8 @@ enum class LLVMRustDebugEmissionKind { DebugDirectivesOnly, }; -static DICompileUnit::DebugEmissionKind fromRust(LLVMRustDebugEmissionKind Kind) { +static DICompileUnit::DebugEmissionKind +fromRust(LLVMRustDebugEmissionKind Kind) { switch (Kind) { case LLVMRustDebugEmissionKind::NoDebug: return DICompileUnit::DebugEmissionKind::NoDebug; @@ -777,12 +796,13 @@ static DICompileUnit::DebugEmissionKind fromRust(LLVMRustDebugEmissionKind Kind) } enum class LLVMRustDebugNameTableKind { - Default, - GNU, - None, + Default, + GNU, + None, }; -static DICompileUnit::DebugNameTableKind fromRust(LLVMRustDebugNameTableKind Kind) { +static DICompileUnit::DebugNameTableKind +fromRust(LLVMRustDebugNameTableKind Kind) { switch (Kind) { case LLVMRustDebugNameTableKind::Default: return DICompileUnit::DebugNameTableKind::Default; @@ -827,22 +847,18 @@ extern "C" uint32_t LLVMRustVersionMinor() { return LLVM_VERSION_MINOR; } extern "C" uint32_t LLVMRustVersionMajor() { return LLVM_VERSION_MAJOR; } -extern "C" void LLVMRustAddModuleFlagU32( - LLVMModuleRef M, - Module::ModFlagBehavior MergeBehavior, - const char *Name, - uint32_t Value) { +extern "C" void LLVMRustAddModuleFlagU32(LLVMModuleRef M, + Module::ModFlagBehavior MergeBehavior, + const char *Name, uint32_t Value) { unwrap(M)->addModuleFlag(MergeBehavior, Name, Value); } extern "C" void LLVMRustAddModuleFlagString( - LLVMModuleRef M, - Module::ModFlagBehavior MergeBehavior, - const char *Name, - const char *Value, - size_t ValueLen) { - unwrap(M)->addModuleFlag(MergeBehavior, Name, - MDString::get(unwrap(M)->getContext(), StringRef(Value, ValueLen))); + LLVMModuleRef M, Module::ModFlagBehavior MergeBehavior, const char *Name, + const char *Value, size_t ValueLen) { + unwrap(M)->addModuleFlag( + MergeBehavior, Name, + MDString::get(unwrap(M)->getContext(), StringRef(Value, ValueLen))); } extern "C" bool LLVMRustHasModuleFlag(LLVMModuleRef M, const char *Name, @@ -850,8 +866,8 @@ extern "C" bool LLVMRustHasModuleFlag(LLVMModuleRef M, const char *Name, return unwrap(M)->getModuleFlag(StringRef(Name, Len)) != nullptr; } -extern "C" void LLVMRustGlobalAddMetadata( - LLVMValueRef Global, unsigned Kind, LLVMMetadataRef MD) { +extern "C" void LLVMRustGlobalAddMetadata(LLVMValueRef Global, unsigned Kind, + LLVMMetadataRef MD) { unwrap<GlobalObject>(Global)->addMetadata(Kind, *unwrap<MDNode>(MD)); } @@ -870,33 +886,29 @@ extern "C" void LLVMRustDIBuilderFinalize(LLVMRustDIBuilderRef Builder) { extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateCompileUnit( LLVMRustDIBuilderRef Builder, unsigned Lang, LLVMMetadataRef FileRef, const char *Producer, size_t ProducerLen, bool isOptimized, - const char *Flags, unsigned RuntimeVer, - const char *SplitName, size_t SplitNameLen, - LLVMRustDebugEmissionKind Kind, - uint64_t DWOId, bool SplitDebugInlining, - LLVMRustDebugNameTableKind TableKind) { + const char *Flags, unsigned RuntimeVer, const char *SplitName, + size_t SplitNameLen, LLVMRustDebugEmissionKind Kind, uint64_t DWOId, + bool SplitDebugInlining, LLVMRustDebugNameTableKind TableKind) { auto *File = unwrapDI<DIFile>(FileRef); - return wrap(Builder->createCompileUnit(Lang, File, StringRef(Producer, ProducerLen), - isOptimized, Flags, RuntimeVer, - StringRef(SplitName, SplitNameLen), - fromRust(Kind), DWOId, SplitDebugInlining, - false, fromRust(TableKind))); + return wrap(Builder->createCompileUnit( + Lang, File, StringRef(Producer, ProducerLen), isOptimized, Flags, + RuntimeVer, StringRef(SplitName, SplitNameLen), fromRust(Kind), DWOId, + SplitDebugInlining, false, fromRust(TableKind))); } -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFile( - LLVMRustDIBuilderRef Builder, - const char *Filename, size_t FilenameLen, - const char *Directory, size_t DirectoryLen, LLVMRustChecksumKind CSKind, - const char *Checksum, size_t ChecksumLen) { +extern "C" LLVMMetadataRef +LLVMRustDIBuilderCreateFile(LLVMRustDIBuilderRef Builder, const char *Filename, + size_t FilenameLen, const char *Directory, + size_t DirectoryLen, LLVMRustChecksumKind CSKind, + const char *Checksum, size_t ChecksumLen) { std::optional<DIFile::ChecksumKind> llvmCSKind = fromRust(CSKind); std::optional<DIFile::ChecksumInfo<StringRef>> CSInfo{}; if (llvmCSKind) CSInfo.emplace(*llvmCSKind, StringRef{Checksum, ChecksumLen}); return wrap(Builder->createFile(StringRef(Filename, FilenameLen), - StringRef(Directory, DirectoryLen), - CSInfo)); + StringRef(Directory, DirectoryLen), CSInfo)); } extern "C" LLVMMetadataRef @@ -907,63 +919,59 @@ LLVMRustDIBuilderCreateSubroutineType(LLVMRustDIBuilderRef Builder, } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, - const char *LinkageName, size_t LinkageNameLen, - LLVMMetadataRef File, unsigned LineNo, - LLVMMetadataRef Ty, unsigned ScopeLine, LLVMRustDIFlags Flags, - LLVMRustDISPFlags SPFlags, LLVMValueRef MaybeFn, LLVMMetadataRef TParam, - LLVMMetadataRef Decl) { + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, const char *LinkageName, size_t LinkageNameLen, + LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, + unsigned ScopeLine, LLVMRustDIFlags Flags, LLVMRustDISPFlags SPFlags, + LLVMValueRef MaybeFn, LLVMMetadataRef TParam, LLVMMetadataRef Decl) { DITemplateParameterArray TParams = DITemplateParameterArray(unwrap<MDTuple>(TParam)); DISubprogram::DISPFlags llvmSPFlags = fromRust(SPFlags); DINode::DIFlags llvmFlags = fromRust(Flags); DISubprogram *Sub = Builder->createFunction( - unwrapDI<DIScope>(Scope), - StringRef(Name, NameLen), - StringRef(LinkageName, LinkageNameLen), - unwrapDI<DIFile>(File), LineNo, - unwrapDI<DISubroutineType>(Ty), ScopeLine, llvmFlags, - llvmSPFlags, TParams, unwrapDIPtr<DISubprogram>(Decl)); + unwrapDI<DIScope>(Scope), StringRef(Name, NameLen), + StringRef(LinkageName, LinkageNameLen), unwrapDI<DIFile>(File), LineNo, + unwrapDI<DISubroutineType>(Ty), ScopeLine, llvmFlags, llvmSPFlags, + TParams, unwrapDIPtr<DISubprogram>(Decl)); if (MaybeFn) unwrap<Function>(MaybeFn)->setSubprogram(Sub); return wrap(Sub); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMethod( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, - const char *LinkageName, size_t LinkageNameLen, - LLVMMetadataRef File, unsigned LineNo, - LLVMMetadataRef Ty, LLVMRustDIFlags Flags, - LLVMRustDISPFlags SPFlags, LLVMMetadataRef TParam) { + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, const char *LinkageName, size_t LinkageNameLen, + LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, + LLVMRustDIFlags Flags, LLVMRustDISPFlags SPFlags, LLVMMetadataRef TParam) { DITemplateParameterArray TParams = DITemplateParameterArray(unwrap<MDTuple>(TParam)); DISubprogram::DISPFlags llvmSPFlags = fromRust(SPFlags); DINode::DIFlags llvmFlags = fromRust(Flags); DISubprogram *Sub = Builder->createMethod( - unwrapDI<DIScope>(Scope), - StringRef(Name, NameLen), - StringRef(LinkageName, LinkageNameLen), - unwrapDI<DIFile>(File), LineNo, - unwrapDI<DISubroutineType>(Ty), - 0, 0, nullptr, // VTable params aren't used + unwrapDI<DIScope>(Scope), StringRef(Name, NameLen), + StringRef(LinkageName, LinkageNameLen), unwrapDI<DIFile>(File), LineNo, + unwrapDI<DISubroutineType>(Ty), 0, 0, + nullptr, // VTable params aren't used llvmFlags, llvmSPFlags, TParams); return wrap(Sub); } -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateBasicType( - LLVMRustDIBuilderRef Builder, const char *Name, size_t NameLen, - uint64_t SizeInBits, unsigned Encoding) { - return wrap(Builder->createBasicType(StringRef(Name, NameLen), SizeInBits, Encoding)); +extern "C" LLVMMetadataRef +LLVMRustDIBuilderCreateBasicType(LLVMRustDIBuilderRef Builder, const char *Name, + size_t NameLen, uint64_t SizeInBits, + unsigned Encoding) { + return wrap( + Builder->createBasicType(StringRef(Name, NameLen), SizeInBits, Encoding)); } -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTypedef( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Type, const char *Name, size_t NameLen, - LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Scope) { +extern "C" LLVMMetadataRef +LLVMRustDIBuilderCreateTypedef(LLVMRustDIBuilderRef Builder, + LLVMMetadataRef Type, const char *Name, + size_t NameLen, LLVMMetadataRef File, + unsigned LineNo, LLVMMetadataRef Scope) { return wrap(Builder->createTypedef( - unwrap<DIType>(Type), StringRef(Name, NameLen), unwrap<DIFile>(File), - LineNo, unwrapDIPtr<DIScope>(Scope))); + unwrap<DIType>(Type), StringRef(Name, NameLen), unwrap<DIFile>(File), + LineNo, unwrapDIPtr<DIScope>(Scope))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreatePointerType( @@ -971,118 +979,98 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreatePointerType( uint64_t SizeInBits, uint32_t AlignInBits, unsigned AddressSpace, const char *Name, size_t NameLen) { return wrap(Builder->createPointerType(unwrapDI<DIType>(PointeeTy), - SizeInBits, AlignInBits, - AddressSpace, + SizeInBits, AlignInBits, AddressSpace, StringRef(Name, NameLen))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStructType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, - LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, - uint32_t AlignInBits, LLVMRustDIFlags Flags, - LLVMMetadataRef DerivedFrom, LLVMMetadataRef Elements, - unsigned RunTimeLang, LLVMMetadataRef VTableHolder, - const char *UniqueId, size_t UniqueIdLen) { + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, + uint64_t SizeInBits, uint32_t AlignInBits, LLVMRustDIFlags Flags, + LLVMMetadataRef DerivedFrom, LLVMMetadataRef Elements, unsigned RunTimeLang, + LLVMMetadataRef VTableHolder, const char *UniqueId, size_t UniqueIdLen) { return wrap(Builder->createStructType( unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), - unwrapDI<DIFile>(File), LineNumber, - SizeInBits, AlignInBits, fromRust(Flags), unwrapDI<DIType>(DerivedFrom), + unwrapDI<DIFile>(File), LineNumber, SizeInBits, AlignInBits, + fromRust(Flags), unwrapDI<DIType>(DerivedFrom), DINodeArray(unwrapDI<MDTuple>(Elements)), RunTimeLang, unwrapDI<DIType>(VTableHolder), StringRef(UniqueId, UniqueIdLen))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantPart( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, - LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, - uint32_t AlignInBits, LLVMRustDIFlags Flags, LLVMMetadataRef Discriminator, - LLVMMetadataRef Elements, const char *UniqueId, size_t UniqueIdLen) { + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, + uint64_t SizeInBits, uint32_t AlignInBits, LLVMRustDIFlags Flags, + LLVMMetadataRef Discriminator, LLVMMetadataRef Elements, + const char *UniqueId, size_t UniqueIdLen) { return wrap(Builder->createVariantPart( unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), - unwrapDI<DIFile>(File), LineNumber, - SizeInBits, AlignInBits, fromRust(Flags), unwrapDI<DIDerivedType>(Discriminator), - DINodeArray(unwrapDI<MDTuple>(Elements)), StringRef(UniqueId, UniqueIdLen))); + unwrapDI<DIFile>(File), LineNumber, SizeInBits, AlignInBits, + fromRust(Flags), unwrapDI<DIDerivedType>(Discriminator), + DINodeArray(unwrapDI<MDTuple>(Elements)), + StringRef(UniqueId, UniqueIdLen))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMemberType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, - LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits, + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, LLVMRustDIFlags Flags, LLVMMetadataRef Ty) { - return wrap(Builder->createMemberType(unwrapDI<DIDescriptor>(Scope), - StringRef(Name, NameLen), - unwrapDI<DIFile>(File), LineNo, - SizeInBits, AlignInBits, OffsetInBits, - fromRust(Flags), unwrapDI<DIType>(Ty))); + return wrap(Builder->createMemberType( + unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), + unwrapDI<DIFile>(File), LineNo, SizeInBits, AlignInBits, OffsetInBits, + fromRust(Flags), unwrapDI<DIType>(Ty))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo, - uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, LLVMValueRef Discriminant, + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits, + uint32_t AlignInBits, uint64_t OffsetInBits, LLVMValueRef Discriminant, LLVMRustDIFlags Flags, LLVMMetadataRef Ty) { - llvm::ConstantInt* D = nullptr; + llvm::ConstantInt *D = nullptr; if (Discriminant) { D = unwrap<llvm::ConstantInt>(Discriminant); } - return wrap(Builder->createVariantMemberType(unwrapDI<DIDescriptor>(Scope), - StringRef(Name, NameLen), - unwrapDI<DIFile>(File), LineNo, - SizeInBits, AlignInBits, OffsetInBits, D, - fromRust(Flags), unwrapDI<DIType>(Ty))); + return wrap(Builder->createVariantMemberType( + unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), + unwrapDI<DIFile>(File), LineNo, SizeInBits, AlignInBits, OffsetInBits, D, + fromRust(Flags), unwrapDI<DIType>(Ty))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticMemberType( - LLVMRustDIBuilderRef Builder, - LLVMMetadataRef Scope, - const char *Name, - size_t NameLen, - LLVMMetadataRef File, - unsigned LineNo, - LLVMMetadataRef Ty, - LLVMRustDIFlags Flags, - LLVMValueRef val, - uint32_t AlignInBits -) { + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, + LLVMRustDIFlags Flags, LLVMValueRef val, uint32_t AlignInBits) { return wrap(Builder->createStaticMemberType( - unwrapDI<DIDescriptor>(Scope), - StringRef(Name, NameLen), - unwrapDI<DIFile>(File), - LineNo, - unwrapDI<DIType>(Ty), - fromRust(Flags), - unwrap<llvm::ConstantInt>(val), + unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), + unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), fromRust(Flags), + unwrap<llvm::ConstantInt>(val), #if LLVM_VERSION_GE(18, 0) - llvm::dwarf::DW_TAG_member, + llvm::dwarf::DW_TAG_member, #endif - AlignInBits - )); + AlignInBits)); } -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateLexicalBlock( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - LLVMMetadataRef File, unsigned Line, unsigned Col) { +extern "C" LLVMMetadataRef +LLVMRustDIBuilderCreateLexicalBlock(LLVMRustDIBuilderRef Builder, + LLVMMetadataRef Scope, LLVMMetadataRef File, + unsigned Line, unsigned Col) { return wrap(Builder->createLexicalBlock(unwrapDI<DIDescriptor>(Scope), unwrapDI<DIFile>(File), Line, Col)); } -extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateLexicalBlockFile(LLVMRustDIBuilderRef Builder, - LLVMMetadataRef Scope, - LLVMMetadataRef File) { +extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateLexicalBlockFile( + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, LLVMMetadataRef File) { return wrap(Builder->createLexicalBlockFile(unwrapDI<DIDescriptor>(Scope), unwrapDI<DIFile>(File))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Context, - const char *Name, size_t NameLen, - const char *LinkageName, size_t LinkageNameLen, - LLVMMetadataRef File, unsigned LineNo, - LLVMMetadataRef Ty, bool IsLocalToUnit, LLVMValueRef V, - LLVMMetadataRef Decl = nullptr, uint32_t AlignInBits = 0) { + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Context, const char *Name, + size_t NameLen, const char *LinkageName, size_t LinkageNameLen, + LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, + bool IsLocalToUnit, LLVMValueRef V, LLVMMetadataRef Decl = nullptr, + uint32_t AlignInBits = 0) { llvm::GlobalVariable *InitVal = cast<llvm::GlobalVariable>(unwrap(V)); llvm::DIExpression *InitExpr = nullptr; @@ -1095,14 +1083,13 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable( FPVal->getValueAPF().bitcastToAPInt().getZExtValue()); } - llvm::DIGlobalVariableExpression *VarExpr = Builder->createGlobalVariableExpression( - unwrapDI<DIDescriptor>(Context), StringRef(Name, NameLen), - StringRef(LinkageName, LinkageNameLen), - unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), IsLocalToUnit, - /* isDefined */ true, - InitExpr, unwrapDIPtr<MDNode>(Decl), - /* templateParams */ nullptr, - AlignInBits); + llvm::DIGlobalVariableExpression *VarExpr = + Builder->createGlobalVariableExpression( + unwrapDI<DIDescriptor>(Context), StringRef(Name, NameLen), + StringRef(LinkageName, LinkageNameLen), unwrapDI<DIFile>(File), + LineNo, unwrapDI<DIType>(Ty), IsLocalToUnit, + /* isDefined */ true, InitExpr, unwrapDIPtr<MDNode>(Decl), + /* templateParams */ nullptr, AlignInBits); InitVal->setMetadata("dbg", VarExpr); @@ -1111,20 +1098,19 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable( extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable( LLVMRustDIBuilderRef Builder, unsigned Tag, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, - LLVMMetadataRef File, unsigned LineNo, + const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, bool AlwaysPreserve, LLVMRustDIFlags Flags, unsigned ArgNo, uint32_t AlignInBits) { if (Tag == 0x100) { // DW_TAG_auto_variable return wrap(Builder->createAutoVariable( unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), - unwrapDI<DIFile>(File), LineNo, - unwrapDI<DIType>(Ty), AlwaysPreserve, fromRust(Flags), AlignInBits)); + unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), AlwaysPreserve, + fromRust(Flags), AlignInBits)); } else { return wrap(Builder->createParameterVariable( unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), ArgNo, - unwrapDI<DIFile>(File), LineNo, - unwrapDI<DIType>(Ty), AlwaysPreserve, fromRust(Flags))); + unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), AlwaysPreserve, + fromRust(Flags))); } } @@ -1157,9 +1143,9 @@ extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd( LLVMBasicBlockRef InsertAtEnd) { auto Result = Builder->insertDeclare( unwrap(V), unwrap<DILocalVariable>(VarInfo), - Builder->createExpression(llvm::ArrayRef<uint64_t>(AddrOps, AddrOpsCount)), - DebugLoc(cast<MDNode>(unwrap(DL))), - unwrap(InsertAtEnd)); + Builder->createExpression( + llvm::ArrayRef<uint64_t>(AddrOps, AddrOpsCount)), + DebugLoc(cast<MDNode>(unwrap(DL))), unwrap(InsertAtEnd)); #if LLVM_VERSION_GE(19, 0) return wrap(Result.get<llvm::Instruction *>()); #else @@ -1170,21 +1156,20 @@ extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd( extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerator( LLVMRustDIBuilderRef Builder, const char *Name, size_t NameLen, const uint64_t Value[2], unsigned SizeInBits, bool IsUnsigned) { - return wrap(Builder->createEnumerator(StringRef(Name, NameLen), + return wrap(Builder->createEnumerator( + StringRef(Name, NameLen), APSInt(APInt(SizeInBits, ArrayRef<uint64_t>(Value, 2)), IsUnsigned))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerationType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, - LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, - uint32_t AlignInBits, LLVMMetadataRef Elements, + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, + uint64_t SizeInBits, uint32_t AlignInBits, LLVMMetadataRef Elements, LLVMMetadataRef ClassTy, bool IsScoped) { return wrap(Builder->createEnumerationType( unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), - unwrapDI<DIFile>(File), LineNumber, - SizeInBits, AlignInBits, DINodeArray(unwrapDI<MDTuple>(Elements)), - unwrapDI<DIType>(ClassTy), + unwrapDI<DIFile>(File), LineNumber, SizeInBits, AlignInBits, + DINodeArray(unwrapDI<MDTuple>(Elements)), unwrapDI<DIType>(ClassTy), #if LLVM_VERSION_GE(18, 0) /* RunTimeLang */ 0, #endif @@ -1192,39 +1177,38 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerationType( } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, - LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, - uint32_t AlignInBits, LLVMRustDIFlags Flags, LLVMMetadataRef Elements, - unsigned RunTimeLang, const char *UniqueId, size_t UniqueIdLen) { + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, + uint64_t SizeInBits, uint32_t AlignInBits, LLVMRustDIFlags Flags, + LLVMMetadataRef Elements, unsigned RunTimeLang, const char *UniqueId, + size_t UniqueIdLen) { return wrap(Builder->createUnionType( - unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIFile>(File), - LineNumber, SizeInBits, AlignInBits, fromRust(Flags), - DINodeArray(unwrapDI<MDTuple>(Elements)), RunTimeLang, + unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), + unwrapDI<DIFile>(File), LineNumber, SizeInBits, AlignInBits, + fromRust(Flags), DINodeArray(unwrapDI<MDTuple>(Elements)), RunTimeLang, StringRef(UniqueId, UniqueIdLen))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, LLVMMetadataRef Ty) { + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, LLVMMetadataRef Ty) { bool IsDefault = false; // FIXME: should we ever set this true? return wrap(Builder->createTemplateTypeParameter( - unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty), IsDefault)); + unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), + unwrapDI<DIType>(Ty), IsDefault)); } -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateNameSpace( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, bool ExportSymbols) { +extern "C" LLVMMetadataRef +LLVMRustDIBuilderCreateNameSpace(LLVMRustDIBuilderRef Builder, + LLVMMetadataRef Scope, const char *Name, + size_t NameLen, bool ExportSymbols) { return wrap(Builder->createNameSpace( - unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), ExportSymbols - )); + unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), ExportSymbols)); } -extern "C" void -LLVMRustDICompositeTypeReplaceArrays(LLVMRustDIBuilderRef Builder, - LLVMMetadataRef CompositeTy, - LLVMMetadataRef Elements, - LLVMMetadataRef Params) { +extern "C" void LLVMRustDICompositeTypeReplaceArrays( + LLVMRustDIBuilderRef Builder, LLVMMetadataRef CompositeTy, + LLVMMetadataRef Elements, LLVMMetadataRef Params) { DICompositeType *Tmp = unwrapDI<DICompositeType>(CompositeTy); Builder->replaceArrays(Tmp, DINodeArray(unwrap<MDTuple>(Elements)), DINodeArray(unwrap<MDTuple>(Params))); @@ -1235,9 +1219,8 @@ LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column, LLVMMetadataRef ScopeRef, LLVMMetadataRef InlinedAt) { MDNode *Scope = unwrapDIPtr<MDNode>(ScopeRef); - DILocation *Loc = DILocation::get( - Scope->getContext(), Line, Column, Scope, - unwrapDIPtr<MDNode>(InlinedAt)); + DILocation *Loc = DILocation::get(Scope->getContext(), Line, Column, Scope, + unwrapDIPtr<MDNode>(InlinedAt)); return wrap(Loc); } @@ -1258,8 +1241,7 @@ extern "C" void LLVMRustWriteTypeToString(LLVMTypeRef Ty, RustStringRef Str) { unwrap<llvm::Type>(Ty)->print(OS); } -extern "C" void LLVMRustWriteValueToString(LLVMValueRef V, - RustStringRef Str) { +extern "C" void LLVMRustWriteValueToString(LLVMValueRef V, RustStringRef Str) { auto OS = RawRustStringOstream(Str); if (!V) { OS << "(null)"; @@ -1281,7 +1263,7 @@ extern "C" void LLVMRustWriteTwineToString(LLVMTwineRef T, RustStringRef Str) { extern "C" void LLVMRustUnpackOptimizationDiagnostic( LLVMDiagnosticInfoRef DI, RustStringRef PassNameOut, - LLVMValueRef *FunctionOut, unsigned* Line, unsigned* Column, + LLVMValueRef *FunctionOut, unsigned *Line, unsigned *Column, RustStringRef FilenameOut, RustStringRef MessageOut) { // Undefined to call this not on an optimization diagnostic! llvm::DiagnosticInfoOptimizationBase *Opt = @@ -1304,17 +1286,15 @@ extern "C" void LLVMRustUnpackOptimizationDiagnostic( } enum class LLVMRustDiagnosticLevel { - Error, - Warning, - Note, - Remark, + Error, + Warning, + Note, + Remark, }; -extern "C" void -LLVMRustUnpackInlineAsmDiagnostic(LLVMDiagnosticInfoRef DI, - LLVMRustDiagnosticLevel *LevelOut, - uint64_t *CookieOut, - LLVMTwineRef *MessageOut) { +extern "C" void LLVMRustUnpackInlineAsmDiagnostic( + LLVMDiagnosticInfoRef DI, LLVMRustDiagnosticLevel *LevelOut, + uint64_t *CookieOut, LLVMTwineRef *MessageOut) { // Undefined to call this not on an inline assembly diagnostic! llvm::DiagnosticInfoInlineAsm *IA = static_cast<llvm::DiagnosticInfoInlineAsm *>(unwrap(DI)); @@ -1323,20 +1303,20 @@ LLVMRustUnpackInlineAsmDiagnostic(LLVMDiagnosticInfoRef DI, *MessageOut = wrap(&IA->getMsgStr()); switch (IA->getSeverity()) { - case DS_Error: - *LevelOut = LLVMRustDiagnosticLevel::Error; - break; - case DS_Warning: - *LevelOut = LLVMRustDiagnosticLevel::Warning; - break; - case DS_Note: - *LevelOut = LLVMRustDiagnosticLevel::Note; - break; - case DS_Remark: - *LevelOut = LLVMRustDiagnosticLevel::Remark; - break; - default: - report_fatal_error("Invalid LLVMRustDiagnosticLevel value!"); + case DS_Error: + *LevelOut = LLVMRustDiagnosticLevel::Error; + break; + case DS_Warning: + *LevelOut = LLVMRustDiagnosticLevel::Warning; + break; + case DS_Note: + *LevelOut = LLVMRustDiagnosticLevel::Note; + break; + case DS_Remark: + *LevelOut = LLVMRustDiagnosticLevel::Remark; + break; + default: + report_fatal_error("Invalid LLVMRustDiagnosticLevel value!"); } } @@ -1454,61 +1434,61 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) { return LLVMBFloatTypeKind; case Type::X86_AMXTyID: return LLVMX86_AMXTypeKind; - default: - { - std::string error; - auto stream = llvm::raw_string_ostream(error); - stream << "Rust does not support the TypeID: " << unwrap(Ty)->getTypeID() - << " for the type: " << *unwrap(Ty); - stream.flush(); - report_fatal_error(error.c_str()); - } + default: { + std::string error; + auto stream = llvm::raw_string_ostream(error); + stream << "Rust does not support the TypeID: " << unwrap(Ty)->getTypeID() + << " for the type: " << *unwrap(Ty); + stream.flush(); + report_fatal_error(error.c_str()); + } } } DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef) -extern "C" LLVMSMDiagnosticRef LLVMRustGetSMDiagnostic( - LLVMDiagnosticInfoRef DI, unsigned *Cookie) { - llvm::DiagnosticInfoSrcMgr *SM = static_cast<llvm::DiagnosticInfoSrcMgr *>(unwrap(DI)); +extern "C" LLVMSMDiagnosticRef LLVMRustGetSMDiagnostic(LLVMDiagnosticInfoRef DI, + unsigned *Cookie) { + llvm::DiagnosticInfoSrcMgr *SM = + static_cast<llvm::DiagnosticInfoSrcMgr *>(unwrap(DI)); *Cookie = SM->getLocCookie(); return wrap(&SM->getSMDiag()); } -extern "C" bool LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef, - RustStringRef MessageOut, - RustStringRef BufferOut, - LLVMRustDiagnosticLevel* LevelOut, - unsigned* LocOut, - unsigned* RangesOut, - size_t* NumRanges) { - SMDiagnostic& D = *unwrap(DRef); +extern "C" bool +LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef, RustStringRef MessageOut, + RustStringRef BufferOut, + LLVMRustDiagnosticLevel *LevelOut, unsigned *LocOut, + unsigned *RangesOut, size_t *NumRanges) { + SMDiagnostic &D = *unwrap(DRef); auto MessageOS = RawRustStringOstream(MessageOut); MessageOS << D.getMessage(); switch (D.getKind()) { - case SourceMgr::DK_Error: - *LevelOut = LLVMRustDiagnosticLevel::Error; - break; - case SourceMgr::DK_Warning: - *LevelOut = LLVMRustDiagnosticLevel::Warning; - break; - case SourceMgr::DK_Note: - *LevelOut = LLVMRustDiagnosticLevel::Note; - break; - case SourceMgr::DK_Remark: - *LevelOut = LLVMRustDiagnosticLevel::Remark; - break; - default: - report_fatal_error("Invalid LLVMRustDiagnosticLevel value!"); + case SourceMgr::DK_Error: + *LevelOut = LLVMRustDiagnosticLevel::Error; + break; + case SourceMgr::DK_Warning: + *LevelOut = LLVMRustDiagnosticLevel::Warning; + break; + case SourceMgr::DK_Note: + *LevelOut = LLVMRustDiagnosticLevel::Note; + break; + case SourceMgr::DK_Remark: + *LevelOut = LLVMRustDiagnosticLevel::Remark; + break; + default: + report_fatal_error("Invalid LLVMRustDiagnosticLevel value!"); } if (D.getLoc() == SMLoc()) return false; const SourceMgr &LSM = *D.getSourceMgr(); - const MemoryBuffer *LBuf = LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc())); - LLVMRustStringWriteImpl(BufferOut, LBuf->getBufferStart(), LBuf->getBufferSize()); + const MemoryBuffer *LBuf = + LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc())); + LLVMRustStringWriteImpl(BufferOut, LBuf->getBufferStart(), + LBuf->getBufferSize()); *LocOut = D.getLoc().getPointer() - LBuf->getBufferStart(); @@ -1525,7 +1505,8 @@ extern "C" bool LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef, extern "C" OperandBundleDef *LLVMRustBuildOperandBundleDef(const char *Name, LLVMValueRef *Inputs, unsigned NumInputs) { - return new OperandBundleDef(Name, ArrayRef<Value*>(unwrap(Inputs), NumInputs)); + return new OperandBundleDef(Name, + ArrayRef<Value *>(unwrap(Inputs), NumInputs)); } extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) { @@ -1533,8 +1514,9 @@ extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) { } // OpBundlesIndirect is an array of pointers (*not* a pointer to an array). -extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, - LLVMValueRef *Args, unsigned NumArgs, +extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, + LLVMValueRef Fn, LLVMValueRef *Args, + unsigned NumArgs, OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles) { Value *Callee = unwrap(Fn); @@ -1547,17 +1529,19 @@ extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVM OpBundles.push_back(*OpBundlesIndirect[i]); } - return wrap(unwrap(B)->CreateCall( - FTy, Callee, ArrayRef<Value*>(unwrap(Args), NumArgs), - ArrayRef<OperandBundleDef>(OpBundles))); + return wrap(unwrap(B)->CreateCall(FTy, Callee, + ArrayRef<Value *>(unwrap(Args), NumArgs), + ArrayRef<OperandBundleDef>(OpBundles))); } -extern "C" LLVMValueRef LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) { +extern "C" LLVMValueRef +LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) { return wrap(llvm::Intrinsic::getDeclaration( unwrap(M), llvm::Intrinsic::instrprof_increment)); } -extern "C" LLVMValueRef LLVMRustGetInstrProfMCDCParametersIntrinsic(LLVMModuleRef M) { +extern "C" LLVMValueRef +LLVMRustGetInstrProfMCDCParametersIntrinsic(LLVMModuleRef M) { #if LLVM_VERSION_GE(18, 0) return wrap(llvm::Intrinsic::getDeclaration( unwrap(M), llvm::Intrinsic::instrprof_mcdc_parameters)); @@ -1566,7 +1550,8 @@ extern "C" LLVMValueRef LLVMRustGetInstrProfMCDCParametersIntrinsic(LLVMModuleRe #endif } -extern "C" LLVMValueRef LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(LLVMModuleRef M) { +extern "C" LLVMValueRef +LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(LLVMModuleRef M) { #if LLVM_VERSION_GE(18, 0) return wrap(llvm::Intrinsic::getDeclaration( unwrap(M), llvm::Intrinsic::instrprof_mcdc_tvbitmap_update)); @@ -1575,7 +1560,8 @@ extern "C" LLVMValueRef LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(LLVMModu #endif } -extern "C" LLVMValueRef LLVMRustGetInstrProfMCDCCondBitmapIntrinsic(LLVMModuleRef M) { +extern "C" LLVMValueRef +LLVMRustGetInstrProfMCDCCondBitmapIntrinsic(LLVMModuleRef M) { #if LLVM_VERSION_GE(18, 0) return wrap(llvm::Intrinsic::getDeclaration( unwrap(M), llvm::Intrinsic::instrprof_mcdc_condbitmap_update)); @@ -1584,32 +1570,31 @@ extern "C" LLVMValueRef LLVMRustGetInstrProfMCDCCondBitmapIntrinsic(LLVMModuleRe #endif } -extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B, - LLVMValueRef Dst, unsigned DstAlign, - LLVMValueRef Src, unsigned SrcAlign, - LLVMValueRef Size, bool IsVolatile) { - return wrap(unwrap(B)->CreateMemCpy( - unwrap(Dst), MaybeAlign(DstAlign), - unwrap(Src), MaybeAlign(SrcAlign), - unwrap(Size), IsVolatile)); +extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, + unsigned DstAlign, LLVMValueRef Src, + unsigned SrcAlign, + LLVMValueRef Size, + bool IsVolatile) { + return wrap(unwrap(B)->CreateMemCpy(unwrap(Dst), MaybeAlign(DstAlign), + unwrap(Src), MaybeAlign(SrcAlign), + unwrap(Size), IsVolatile)); } -extern "C" LLVMValueRef LLVMRustBuildMemMove(LLVMBuilderRef B, - LLVMValueRef Dst, unsigned DstAlign, - LLVMValueRef Src, unsigned SrcAlign, - LLVMValueRef Size, bool IsVolatile) { - return wrap(unwrap(B)->CreateMemMove( - unwrap(Dst), MaybeAlign(DstAlign), - unwrap(Src), MaybeAlign(SrcAlign), - unwrap(Size), IsVolatile)); +extern "C" LLVMValueRef +LLVMRustBuildMemMove(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign, + LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, + bool IsVolatile) { + return wrap(unwrap(B)->CreateMemMove(unwrap(Dst), MaybeAlign(DstAlign), + unwrap(Src), MaybeAlign(SrcAlign), + unwrap(Size), IsVolatile)); } -extern "C" LLVMValueRef LLVMRustBuildMemSet(LLVMBuilderRef B, - LLVMValueRef Dst, unsigned DstAlign, - LLVMValueRef Val, - LLVMValueRef Size, bool IsVolatile) { - return wrap(unwrap(B)->CreateMemSet( - unwrap(Dst), unwrap(Val), unwrap(Size), MaybeAlign(DstAlign), IsVolatile)); +extern "C" LLVMValueRef LLVMRustBuildMemSet(LLVMBuilderRef B, LLVMValueRef Dst, + unsigned DstAlign, LLVMValueRef Val, + LLVMValueRef Size, + bool IsVolatile) { + return wrap(unwrap(B)->CreateMemSet(unwrap(Dst), unwrap(Val), unwrap(Size), + MaybeAlign(DstAlign), IsVolatile)); } // OpBundlesIndirect is an array of pointers (*not* a pointer to an array). @@ -1630,7 +1615,7 @@ LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, } return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch), - ArrayRef<Value*>(unwrap(Args), NumArgs), + ArrayRef<Value *>(unwrap(Args), NumArgs), ArrayRef<OperandBundleDef>(OpBundles), Name)); } @@ -1647,7 +1632,7 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, FunctionType *FTy = unwrap<FunctionType>(Ty); // FIXME: Is there a way around this? - std::vector<BasicBlock*> IndirectDestsUnwrapped; + std::vector<BasicBlock *> IndirectDestsUnwrapped; IndirectDestsUnwrapped.reserve(NumIndirectDests); for (unsigned i = 0; i < NumIndirectDests; ++i) { IndirectDestsUnwrapped.push_back(unwrap(IndirectDests[i])); @@ -1660,12 +1645,11 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, OpBundles.push_back(*OpBundlesIndirect[i]); } - return wrap(unwrap(B)->CreateCallBr( - FTy, Callee, unwrap(DefaultDest), - ArrayRef<BasicBlock*>(IndirectDestsUnwrapped), - ArrayRef<Value*>(unwrap(Args), NumArgs), - ArrayRef<OperandBundleDef>(OpBundles), - Name)); + return wrap( + unwrap(B)->CreateCallBr(FTy, Callee, unwrap(DefaultDest), + ArrayRef<BasicBlock *>(IndirectDestsUnwrapped), + ArrayRef<Value *>(unwrap(Args), NumArgs), + ArrayRef<OperandBundleDef>(OpBundles), Name)); } extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B, @@ -1765,28 +1749,30 @@ extern "C" void LLVMRustSetLinkage(LLVMValueRef V, } extern "C" bool LLVMRustConstIntGetZExtValue(LLVMValueRef CV, uint64_t *value) { - auto C = unwrap<llvm::ConstantInt>(CV); - if (C->getBitWidth() > 64) - return false; - *value = C->getZExtValue(); - return true; + auto C = unwrap<llvm::ConstantInt>(CV); + if (C->getBitWidth() > 64) + return false; + *value = C->getZExtValue(); + return true; } -// Returns true if both high and low were successfully set. Fails in case constant wasn’t any of -// the common sizes (1, 8, 16, 32, 64, 128 bits) -extern "C" bool LLVMRustConstInt128Get(LLVMValueRef CV, bool sext, uint64_t *high, uint64_t *low) -{ - auto C = unwrap<llvm::ConstantInt>(CV); - if (C->getBitWidth() > 128) { return false; } - APInt AP; - if (sext) { - AP = C->getValue().sext(128); - } else { - AP = C->getValue().zext(128); - } - *low = AP.getLoBits(64).getZExtValue(); - *high = AP.getHiBits(64).getZExtValue(); - return true; +// Returns true if both high and low were successfully set. Fails in case +// constant wasn’t any of the common sizes (1, 8, 16, 32, 64, 128 bits) +extern "C" bool LLVMRustConstInt128Get(LLVMValueRef CV, bool sext, + uint64_t *high, uint64_t *low) { + auto C = unwrap<llvm::ConstantInt>(CV); + if (C->getBitWidth() > 128) { + return false; + } + APInt AP; + if (sext) { + AP = C->getValue().sext(128); + } else { + AP = C->getValue().zext(128); + } + *low = AP.getLoBits(64).getZExtValue(); + *high = AP.getHiBits(64).getZExtValue(); + return true; } enum class LLVMRustVisibility { @@ -1836,8 +1822,7 @@ struct LLVMRustModuleBuffer { std::string data; }; -extern "C" LLVMRustModuleBuffer* -LLVMRustModuleBufferCreate(LLVMModuleRef M) { +extern "C" LLVMRustModuleBuffer *LLVMRustModuleBufferCreate(LLVMModuleRef M) { auto Ret = std::make_unique<LLVMRustModuleBuffer>(); { auto OS = raw_string_ostream(Ret->data); @@ -1846,30 +1831,26 @@ LLVMRustModuleBufferCreate(LLVMModuleRef M) { return Ret.release(); } -extern "C" void -LLVMRustModuleBufferFree(LLVMRustModuleBuffer *Buffer) { +extern "C" void LLVMRustModuleBufferFree(LLVMRustModuleBuffer *Buffer) { delete Buffer; } -extern "C" const void* +extern "C" const void * LLVMRustModuleBufferPtr(const LLVMRustModuleBuffer *Buffer) { return Buffer->data.data(); } -extern "C" size_t -LLVMRustModuleBufferLen(const LLVMRustModuleBuffer *Buffer) { +extern "C" size_t LLVMRustModuleBufferLen(const LLVMRustModuleBuffer *Buffer) { return Buffer->data.length(); } -extern "C" uint64_t -LLVMRustModuleCost(LLVMModuleRef M) { +extern "C" uint64_t LLVMRustModuleCost(LLVMModuleRef M) { auto f = unwrap(M)->functions(); return std::distance(std::begin(f), std::end(f)); } -extern "C" void -LLVMRustModuleInstructionStats(LLVMModuleRef M, RustStringRef Str) -{ +extern "C" void LLVMRustModuleInstructionStats(LLVMModuleRef M, + RustStringRef Str) { auto OS = RawRustStringOstream(Str); auto JOS = llvm::json::OStream(OS); auto Module = unwrap(M); @@ -1881,41 +1862,45 @@ LLVMRustModuleInstructionStats(LLVMModuleRef M, RustStringRef Str) } // Vector reductions: -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceFAdd(LLVMBuilderRef B, LLVMValueRef Acc, LLVMValueRef Src) { - return wrap(unwrap(B)->CreateFAddReduce(unwrap(Acc),unwrap(Src))); -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceFMul(LLVMBuilderRef B, LLVMValueRef Acc, LLVMValueRef Src) { - return wrap(unwrap(B)->CreateFMulReduce(unwrap(Acc),unwrap(Src))); -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceAdd(LLVMBuilderRef B, LLVMValueRef Src) { - return wrap(unwrap(B)->CreateAddReduce(unwrap(Src))); -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceMul(LLVMBuilderRef B, LLVMValueRef Src) { - return wrap(unwrap(B)->CreateMulReduce(unwrap(Src))); -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceAnd(LLVMBuilderRef B, LLVMValueRef Src) { - return wrap(unwrap(B)->CreateAndReduce(unwrap(Src))); -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceOr(LLVMBuilderRef B, LLVMValueRef Src) { - return wrap(unwrap(B)->CreateOrReduce(unwrap(Src))); -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceXor(LLVMBuilderRef B, LLVMValueRef Src) { - return wrap(unwrap(B)->CreateXorReduce(unwrap(Src))); -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceMin(LLVMBuilderRef B, LLVMValueRef Src, bool IsSigned) { - return wrap(unwrap(B)->CreateIntMinReduce(unwrap(Src), IsSigned)); -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceMax(LLVMBuilderRef B, LLVMValueRef Src, bool IsSigned) { - return wrap(unwrap(B)->CreateIntMaxReduce(unwrap(Src), IsSigned)); +extern "C" LLVMValueRef LLVMRustBuildVectorReduceFAdd(LLVMBuilderRef B, + LLVMValueRef Acc, + LLVMValueRef Src) { + return wrap(unwrap(B)->CreateFAddReduce(unwrap(Acc), unwrap(Src))); +} +extern "C" LLVMValueRef LLVMRustBuildVectorReduceFMul(LLVMBuilderRef B, + LLVMValueRef Acc, + LLVMValueRef Src) { + return wrap(unwrap(B)->CreateFMulReduce(unwrap(Acc), unwrap(Src))); +} +extern "C" LLVMValueRef LLVMRustBuildVectorReduceAdd(LLVMBuilderRef B, + LLVMValueRef Src) { + return wrap(unwrap(B)->CreateAddReduce(unwrap(Src))); +} +extern "C" LLVMValueRef LLVMRustBuildVectorReduceMul(LLVMBuilderRef B, + LLVMValueRef Src) { + return wrap(unwrap(B)->CreateMulReduce(unwrap(Src))); +} +extern "C" LLVMValueRef LLVMRustBuildVectorReduceAnd(LLVMBuilderRef B, + LLVMValueRef Src) { + return wrap(unwrap(B)->CreateAndReduce(unwrap(Src))); +} +extern "C" LLVMValueRef LLVMRustBuildVectorReduceOr(LLVMBuilderRef B, + LLVMValueRef Src) { + return wrap(unwrap(B)->CreateOrReduce(unwrap(Src))); +} +extern "C" LLVMValueRef LLVMRustBuildVectorReduceXor(LLVMBuilderRef B, + LLVMValueRef Src) { + return wrap(unwrap(B)->CreateXorReduce(unwrap(Src))); +} +extern "C" LLVMValueRef LLVMRustBuildVectorReduceMin(LLVMBuilderRef B, + LLVMValueRef Src, + bool IsSigned) { + return wrap(unwrap(B)->CreateIntMinReduce(unwrap(Src), IsSigned)); +} +extern "C" LLVMValueRef LLVMRustBuildVectorReduceMax(LLVMBuilderRef B, + LLVMValueRef Src, + bool IsSigned) { + return wrap(unwrap(B)->CreateIntMaxReduce(unwrap(Src), IsSigned)); } extern "C" LLVMValueRef LLVMRustBuildVectorReduceFMin(LLVMBuilderRef B, LLVMValueRef Src, bool NoNaN) { @@ -1930,32 +1915,28 @@ LLVMRustBuildVectorReduceFMax(LLVMBuilderRef B, LLVMValueRef Src, bool NoNaN) { return wrap(I); } -extern "C" LLVMValueRef -LLVMRustBuildMinNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS) { - return wrap(unwrap(B)->CreateMinNum(unwrap(LHS),unwrap(RHS))); +extern "C" LLVMValueRef LLVMRustBuildMinNum(LLVMBuilderRef B, LLVMValueRef LHS, + LLVMValueRef RHS) { + return wrap(unwrap(B)->CreateMinNum(unwrap(LHS), unwrap(RHS))); } -extern "C" LLVMValueRef -LLVMRustBuildMaxNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS) { - return wrap(unwrap(B)->CreateMaxNum(unwrap(LHS),unwrap(RHS))); +extern "C" LLVMValueRef LLVMRustBuildMaxNum(LLVMBuilderRef B, LLVMValueRef LHS, + LLVMValueRef RHS) { + return wrap(unwrap(B)->CreateMaxNum(unwrap(LHS), unwrap(RHS))); } // This struct contains all necessary info about a symbol exported from a DLL. struct LLVMRustCOFFShortExport { - const char* name; + const char *name; bool ordinal_present; // The value of `ordinal` is only meaningful if `ordinal_present` is true. uint16_t ordinal; }; // Machine must be a COFF machine type, as defined in PE specs. -extern "C" LLVMRustResult LLVMRustWriteImportLibrary( - const char* ImportName, - const char* Path, - const LLVMRustCOFFShortExport* Exports, - size_t NumExports, - uint16_t Machine, - bool MinGW) -{ +extern "C" LLVMRustResult +LLVMRustWriteImportLibrary(const char *ImportName, const char *Path, + const LLVMRustCOFFShortExport *Exports, + size_t NumExports, uint16_t Machine, bool MinGW) { std::vector<llvm::object::COFFShortExport> ConvertedExports; ConvertedExports.reserve(NumExports); @@ -1963,27 +1944,24 @@ extern "C" LLVMRustResult LLVMRustWriteImportLibrary( bool ordinal_present = Exports[i].ordinal_present; uint16_t ordinal = ordinal_present ? Exports[i].ordinal : 0; ConvertedExports.push_back(llvm::object::COFFShortExport{ - Exports[i].name, // Name - std::string{}, // ExtName - std::string{}, // SymbolName - std::string{}, // AliasTarget + Exports[i].name, // Name + std::string{}, // ExtName + std::string{}, // SymbolName + std::string{}, // AliasTarget #if LLVM_VERSION_GE(19, 0) - std::string{}, // ExportAs + std::string{}, // ExportAs #endif - ordinal, // Ordinal - ordinal_present, // Noname - false, // Data - false, // Private - false // Constant + ordinal, // Ordinal + ordinal_present, // Noname + false, // Data + false, // Private + false // Constant }); } auto Error = llvm::object::writeImportLibrary( - ImportName, - Path, - ConvertedExports, - static_cast<llvm::COFF::MachineTypes>(Machine), - MinGW); + ImportName, Path, ConvertedExports, + static_cast<llvm::COFF::MachineTypes>(Machine), MinGW); if (Error) { std::string errorString; auto stream = llvm::raw_string_ostream(errorString); @@ -2019,27 +1997,23 @@ using LLVMDiagnosticHandlerTy = DiagnosticHandler::DiagnosticHandlerTy; // the RemarkPasses array specifies individual passes for which remarks will be // enabled. // -// If RemarkFilePath is not NULL, optimization remarks will be streamed directly into this file, -// bypassing the diagnostics handler. +// If RemarkFilePath is not NULL, optimization remarks will be streamed directly +// into this file, bypassing the diagnostics handler. extern "C" void LLVMRustContextConfigureDiagnosticHandler( LLVMContextRef C, LLVMDiagnosticHandlerTy DiagnosticHandlerCallback, void *DiagnosticHandlerContext, bool RemarkAllPasses, - const char * const * RemarkPasses, size_t RemarkPassesLen, - const char * RemarkFilePath, - bool PGOAvailable -) { + const char *const *RemarkPasses, size_t RemarkPassesLen, + const char *RemarkFilePath, bool PGOAvailable) { class RustDiagnosticHandler final : public DiagnosticHandler { public: RustDiagnosticHandler( - LLVMDiagnosticHandlerTy DiagnosticHandlerCallback, - void *DiagnosticHandlerContext, - bool RemarkAllPasses, - std::vector<std::string> RemarkPasses, - std::unique_ptr<ToolOutputFile> RemarksFile, - std::unique_ptr<llvm::remarks::RemarkStreamer> RemarkStreamer, - std::unique_ptr<LLVMRemarkStreamer> LlvmRemarkStreamer - ) + LLVMDiagnosticHandlerTy DiagnosticHandlerCallback, + void *DiagnosticHandlerContext, bool RemarkAllPasses, + std::vector<std::string> RemarkPasses, + std::unique_ptr<ToolOutputFile> RemarksFile, + std::unique_ptr<llvm::remarks::RemarkStreamer> RemarkStreamer, + std::unique_ptr<LLVMRemarkStreamer> LlvmRemarkStreamer) : DiagnosticHandlerCallback(DiagnosticHandlerCallback), DiagnosticHandlerContext(DiagnosticHandlerContext), RemarkAllPasses(RemarkAllPasses), @@ -2049,11 +2023,13 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler( LlvmRemarkStreamer(std::move(LlvmRemarkStreamer)) {} virtual bool handleDiagnostics(const DiagnosticInfo &DI) override { - // If this diagnostic is one of the optimization remark kinds, we can check if it's enabled - // before emitting it. This can avoid many short-lived allocations when unpacking the - // diagnostic and converting its various C++ strings into rust strings. - // FIXME: some diagnostic infos still allocate before we get here, and avoiding that would be - // good in the future. That will require changing a few call sites in LLVM. + // If this diagnostic is one of the optimization remark kinds, we can + // check if it's enabled before emitting it. This can avoid many + // short-lived allocations when unpacking the diagnostic and converting + // its various C++ strings into rust strings. + // FIXME: some diagnostic infos still allocate before we get here, and + // avoiding that would be good in the future. That will require changing a + // few call sites in LLVM. if (auto *OptDiagBase = dyn_cast<DiagnosticInfoOptimizationBase>(&DI)) { if (OptDiagBase->isEnabled()) { if (this->LlvmRemarkStreamer) { @@ -2109,16 +2085,15 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler( bool RemarkAllPasses = false; std::vector<std::string> RemarkPasses; - // Since LlvmRemarkStreamer contains a pointer to RemarkStreamer, the ordering of the three - // members below is important. + // Since LlvmRemarkStreamer contains a pointer to RemarkStreamer, the + // ordering of the three members below is important. std::unique_ptr<ToolOutputFile> RemarksFile; std::unique_ptr<llvm::remarks::RemarkStreamer> RemarkStreamer; std::unique_ptr<LLVMRemarkStreamer> LlvmRemarkStreamer; }; std::vector<std::string> Passes; - for (size_t I = 0; I != RemarkPassesLen; ++I) - { + for (size_t I = 0; I != RemarkPassesLen; ++I) { Passes.push_back(RemarkPasses[I]); } @@ -2135,13 +2110,10 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler( std::error_code EC; RemarkFile = std::make_unique<ToolOutputFile>( - RemarkFilePath, - EC, - llvm::sys::fs::OF_TextWithCRLF - ); + RemarkFilePath, EC, llvm::sys::fs::OF_TextWithCRLF); if (EC) { std::string Error = std::string("Cannot create remark file: ") + - toString(errorCodeToError(EC)); + toString(errorCodeToError(EC)); report_fatal_error(Twine(Error)); } @@ -2149,28 +2121,22 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler( RemarkFile->keep(); auto RemarkSerializer = remarks::createRemarkSerializer( - llvm::remarks::Format::YAML, - remarks::SerializerMode::Separate, - RemarkFile->os() - ); - if (Error E = RemarkSerializer.takeError()) - { - std::string Error = std::string("Cannot create remark serializer: ") + toString(std::move(E)); + llvm::remarks::Format::YAML, remarks::SerializerMode::Separate, + RemarkFile->os()); + if (Error E = RemarkSerializer.takeError()) { + std::string Error = std::string("Cannot create remark serializer: ") + + toString(std::move(E)); report_fatal_error(Twine(Error)); } - RemarkStreamer = std::make_unique<llvm::remarks::RemarkStreamer>(std::move(*RemarkSerializer)); + RemarkStreamer = std::make_unique<llvm::remarks::RemarkStreamer>( + std::move(*RemarkSerializer)); LlvmRemarkStreamer = std::make_unique<LLVMRemarkStreamer>(*RemarkStreamer); } unwrap(C)->setDiagnosticHandler(std::make_unique<RustDiagnosticHandler>( - DiagnosticHandlerCallback, - DiagnosticHandlerContext, - RemarkAllPasses, - Passes, - std::move(RemarkFile), - std::move(RemarkStreamer), - std::move(LlvmRemarkStreamer) - )); + DiagnosticHandlerCallback, DiagnosticHandlerContext, RemarkAllPasses, + Passes, std::move(RemarkFile), std::move(RemarkStreamer), + std::move(LlvmRemarkStreamer))); } extern "C" void LLVMRustGetMangledName(LLVMValueRef V, RustStringRef Str) { @@ -2180,14 +2146,14 @@ extern "C" void LLVMRustGetMangledName(LLVMValueRef V, RustStringRef Str) { } extern "C" int32_t LLVMRustGetElementTypeArgIndex(LLVMValueRef CallSite) { - auto *CB = unwrap<CallBase>(CallSite); - switch (CB->getIntrinsicID()) { - case Intrinsic::arm_ldrex: - return 0; - case Intrinsic::arm_strex: - return 1; - } - return -1; + auto *CB = unwrap<CallBase>(CallSite); + switch (CB->getIntrinsicID()) { + case Intrinsic::arm_ldrex: + return 0; + case Intrinsic::arm_strex: + return 1; + } + return -1; } extern "C" bool LLVMRustIsBitcode(char *ptr, size_t len) { @@ -2214,10 +2180,10 @@ extern "C" bool LLVMRustLLVMHasZstdCompressionForDebugSymbols() { } // Operations on composite constants. -// These are clones of LLVM api functions that will become available in future releases. -// They can be removed once Rust's minimum supported LLVM version supports them. -// See https://github.com/rust-lang/rust/issues/121868 -// See https://llvm.org/doxygen/group__LLVMCCoreValueConstantComposite.html +// These are clones of LLVM api functions that will become available in future +// releases. They can be removed once Rust's minimum supported LLVM version +// supports them. See https://github.com/rust-lang/rust/issues/121868 See +// https://llvm.org/doxygen/group__LLVMCCoreValueConstantComposite.html // FIXME: Remove when Rust's minimum supported LLVM version reaches 19. // https://github.com/llvm/llvm-project/commit/e1405e4f71c899420ebf8262d5e9745598419df8 @@ -2226,6 +2192,7 @@ extern "C" LLVMValueRef LLVMConstStringInContext2(LLVMContextRef C, const char *Str, size_t Length, bool DontNullTerminate) { - return wrap(ConstantDataArray::getString(*unwrap(C), StringRef(Str, Length), !DontNullTerminate)); + return wrap(ConstantDataArray::getString(*unwrap(C), StringRef(Str, Length), + !DontNullTerminate)); } #endif diff --git a/compiler/rustc_llvm/llvm-wrapper/SuppressLLVMWarnings.h b/compiler/rustc_llvm/llvm-wrapper/SuppressLLVMWarnings.h index 56964e4eaa7..09ecfd54cd8 100644 --- a/compiler/rustc_llvm/llvm-wrapper/SuppressLLVMWarnings.h +++ b/compiler/rustc_llvm/llvm-wrapper/SuppressLLVMWarnings.h @@ -1,13 +1,17 @@ #ifndef _rustc_llvm_SuppressLLVMWarnings_h #define _rustc_llvm_SuppressLLVMWarnings_h -// LLVM currently generates many warnings when compiled using MSVC. These warnings make it difficult -// to diagnose real problems when working on C++ code, so we suppress them. +// LLVM currently generates many warnings when compiled using MSVC. These +// warnings make it difficult to diagnose real problems when working on C++ +// code, so we suppress them. #ifdef _MSC_VER -#pragma warning(disable:4530) // C++ exception handler used, but unwind semantics are not enabled. -#pragma warning(disable:4624) // 'xxx': destructor was implicitly defined as deleted -#pragma warning(disable:4244) // conversion from 'xxx' to 'yyy', possible loss of data +#pragma warning(disable : 4530) // C++ exception handler used, but unwind + // semantics are not enabled. +#pragma warning( \ + disable : 4624) // 'xxx': destructor was implicitly defined as deleted +#pragma warning( \ + disable : 4244) // conversion from 'xxx' to 'yyy', possible loss of data #endif #endif // _rustc_llvm_SuppressLLVMWarnings_h diff --git a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp index ee8239ef8e7..a9d1362a338 100644 --- a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp @@ -34,14 +34,15 @@ static bool isArchiveSymbol(const object::BasicSymbolRef &S) { 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<MemoryBuffer> Buf = - MemoryBuffer::getMemBuffer(StringRef(BufPtr, BufLen), StringRef("LLVMRustGetSymbolsObject"), - false); +// 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<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer( + StringRef(BufPtr, BufLen), StringRef("LLVMRustGetSymbolsObject"), false); SmallString<0> SymNameBuf; auto SymName = raw_svector_ostream(SymNameBuf); @@ -57,7 +58,7 @@ extern "C" void *LLVMRustGetSymbols( if (Type == file_magic::bitcode) { auto ObjOrErr = object::SymbolicFile::createSymbolicFile( - Buf->getMemBufferRef(), file_magic::bitcode, &Context); + Buf->getMemBufferRef(), file_magic::bitcode, &Context); if (!ObjOrErr) { Error E = ObjOrErr.takeError(); SmallString<0> ErrorBuf; @@ -67,7 +68,8 @@ extern "C" void *LLVMRustGetSymbols( } Obj = std::move(*ObjOrErr); } else { - auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf->getMemBufferRef()); + auto ObjOrErr = + object::SymbolicFile::createSymbolicFile(Buf->getMemBufferRef()); if (!ObjOrErr) { Error E = ObjOrErr.takeError(); SmallString<0> ErrorBuf; @@ -78,7 +80,6 @@ extern "C" void *LLVMRustGetSymbols( Obj = std::move(*ObjOrErr); } - for (const object::BasicSymbolRef &S : Obj->symbols()) { if (!isArchiveSymbol(S)) continue; diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index ea7037740f1..83b41e0540e 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1348,7 +1348,9 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem { - let name = if self.root.tables.opt_rpitit_info.get(self, id).is_some() { + let name = if self.root.tables.opt_rpitit_info.get(self, id).is_some() + || self.root.tables.is_effects_desugaring.get(self, id) + { kw::Empty } else { self.item_name(id) @@ -1371,6 +1373,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { container, fn_has_self_parameter: has_self, opt_rpitit_info, + is_effects_desugaring: self.root.tables.is_effects_desugaring.get(self, id), } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index c9450142cd3..6b240f0f0b3 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -211,8 +211,8 @@ provide! { tcx, def_id, other, cdata, explicit_predicates_of => { table } generics_of => { table } inferred_outlives_of => { table_defaulted_array } - super_predicates_of => { table } - implied_predicates_of => { table } + explicit_super_predicates_of => { table } + explicit_implied_predicates_of => { table } type_of => { table } type_alias_is_lazy => { cdata.root.tables.type_alias_is_lazy.get(cdata, def_id.index) } variances_of => { table } @@ -279,6 +279,9 @@ provide! { tcx, def_id, other, cdata, .process_decoded(tcx, || panic!("{def_id:?} does not have trait_impl_trait_tys"))) } + associated_type_for_effects => { + table + } associated_types_for_impl_traits_in_associated_fn => { table_defaulted_array } visibility => { cdata.get_visibility(def_id.index) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 4bd2ec09a6e..209316ca20f 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1431,8 +1431,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if let DefKind::Trait = def_kind { record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); - record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); - record!(self.tables.implied_predicates_of[def_id] <- self.tcx.implied_predicates_of(def_id)); + record!(self.tables.explicit_super_predicates_of[def_id] <- self.tcx.explicit_super_predicates_of(def_id)); + record!(self.tables.explicit_implied_predicates_of[def_id] <- self.tcx.explicit_implied_predicates_of(def_id)); let module_children = self.tcx.module_children_local(local_id); record_array!(self.tables.module_children_non_reexports[def_id] <- @@ -1440,8 +1440,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if let DefKind::TraitAlias = def_kind { record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); - record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); - record!(self.tables.implied_predicates_of[def_id] <- self.tcx.implied_predicates_of(def_id)); + record!(self.tables.explicit_super_predicates_of[def_id] <- self.tcx.explicit_super_predicates_of(def_id)); + record!(self.tables.explicit_implied_predicates_of[def_id] <- self.tcx.explicit_implied_predicates_of(def_id)); } if let DefKind::Trait | DefKind::Impl { .. } = def_kind { let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id); @@ -1454,6 +1454,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { for &def_id in associated_item_def_ids { self.encode_info_for_assoc_item(def_id); } + if let Some(assoc_def_id) = self.tcx.associated_type_for_effects(def_id) { + record!(self.tables.associated_type_for_effects[def_id] <- assoc_def_id); + } } if def_kind == DefKind::Closure && let Some(coroutine_kind) = self.tcx.coroutine_kind(def_id) @@ -1634,6 +1637,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ); } } + if item.is_effects_desugaring { + self.tables.is_effects_desugaring.set(def_id.index, true); + } } fn encode_mir(&mut self) { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 87900c23d8d..2a44b3423ae 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -391,7 +391,9 @@ define_tables! { inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>, inherent_impls: Table<DefIndex, LazyArray<DefIndex>>, associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>, + associated_type_for_effects: Table<DefIndex, Option<LazyValue<DefId>>>, opt_rpitit_info: Table<DefIndex, Option<LazyValue<ty::ImplTraitInTraitData>>>, + is_effects_desugaring: Table<DefIndex, bool>, unused_generic_params: Table<DefIndex, UnusedGenericParams>, // Reexported names are not associated with individual `DefId`s, // e.g. a glob import can introduce a lot of names, all with the same `DefId`. @@ -416,10 +418,10 @@ define_tables! { lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>, explicit_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>, generics_of: Table<DefIndex, LazyValue<ty::Generics>>, - super_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>, + explicit_super_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>, // As an optimization, we only store this for trait aliases, - // since it's identical to super_predicates_of for traits. - implied_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>, + // since it's identical to explicit_super_predicates_of for traits. + explicit_implied_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>, type_of: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, Ty<'static>>>>, variances_of: Table<DefIndex, LazyArray<ty::Variance>>, fn_sig: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, ty::PolyFnSig<'static>>>>, diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 3fa5054baed..3ddf889b63a 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -45,6 +45,32 @@ pub struct CodegenFnAttrs { /// The `#[repr(align(...))]` attribute. Indicates the value of which the function should be /// aligned to. pub alignment: Option<Align>, + /// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around + /// the function entry. + pub patchable_function_entry: Option<PatchableFunctionEntry>, +} + +#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] +pub struct PatchableFunctionEntry { + /// Nops to prepend to the function + prefix: u8, + /// Nops after entry, but before body + entry: u8, +} + +impl PatchableFunctionEntry { + pub fn from_config(config: rustc_session::config::PatchableFunctionEntry) -> Self { + Self { prefix: config.prefix(), entry: config.entry() } + } + pub fn from_prefix_and_entry(prefix: u8, entry: u8) -> Self { + Self { prefix, entry } + } + pub fn prefix(&self) -> u8 { + self.prefix + } + pub fn entry(&self) -> u8 { + self.entry + } } #[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] @@ -87,10 +113,7 @@ bitflags::bitflags! { /// #[cmse_nonsecure_entry]: with a TrustZone-M extension, declare a /// function as an entry function from Non-Secure code. const CMSE_NONSECURE_ENTRY = 1 << 13; - /// `#[coverage(off)]`: indicates that the function should be ignored by - /// the MIR `InstrumentCoverage` pass and not added to the coverage map - /// during codegen. - const NO_COVERAGE = 1 << 14; + // (Bit 14 was used for `#[coverage(off)]`, but is now unused.) /// `#[used(linker)]`: /// indicates that neither LLVM nor the linker will eliminate this function. const USED_LINKER = 1 << 15; @@ -124,6 +147,7 @@ impl CodegenFnAttrs { no_sanitize: SanitizerSet::empty(), instruction_set: None, alignment: None, + patchable_function_entry: None, } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index c5afecffb07..d40a7833589 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -368,6 +368,7 @@ rustc_queries! { desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern + feedable } /// The set of item bounds (see [`TyCtxt::explicit_item_bounds`]) that @@ -378,6 +379,7 @@ rustc_queries! { desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern + feedable } /// Elaborated version of the predicates from `explicit_item_bounds`. @@ -572,6 +574,15 @@ rustc_queries! { separate_provide_extern } + /// Checks for the nearest `#[coverage(off)]` or `#[coverage(on)]` on + /// this def and any enclosing defs, up to the crate root. + /// + /// Returns `false` if `#[coverage(off)]` was found, or `true` if + /// either `#[coverage(on)]` or no coverage attribute was found. + query coverage_attr_on(key: LocalDefId) -> bool { + desc { |tcx| "checking for `#[coverage(..)]` on `{}`", tcx.def_path_str(key) } + } + /// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass /// (for compiler option `-Cinstrument-coverage`), after MIR optimizations /// have had a chance to potentially remove some of them. @@ -637,6 +648,9 @@ rustc_queries! { } /// Returns the predicates written explicitly by the user. + /// + /// You should probably use `predicates_of` unless you're looking for + /// predicates with explicit spans for diagnostics purposes. query explicit_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } @@ -653,29 +667,32 @@ rustc_queries! { feedable } - /// Maps from the `DefId` of a trait to the list of - /// super-predicates. This is a subset of the full list of - /// predicates. We store these in a separate map because we must - /// evaluate them even during type conversion, often before the - /// full predicates are available (note that supertraits have - /// additional acyclicity requirements). - query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { + /// Maps from the `DefId` of a trait to the list of super-predicates of the trait, + /// *before* elaboration (so it doesn't contain transitive super-predicates). This + /// is a subset of the full list of predicates. We store these in a separate map + /// because we must evaluate them even during type conversion, often before the full + /// predicates are available (note that super-predicates must not be cyclic). + query explicit_super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing the super predicates of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern } - query implied_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { + /// The predicates of the trait that are implied during elaboration. This is a + /// superset of the super-predicates of the trait, but a subset of the predicates + /// of the trait. For regular traits, this includes all super-predicates and their + /// associated type bounds. For trait aliases, currently, this includes all of the + /// predicates of the trait alias. + query explicit_implied_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing the implied predicates of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern } - /// The `Option<Ident>` is the name of an associated type. If it is `None`, then this query - /// returns the full set of predicates. If `Some<Ident>`, then the query returns only the - /// subset of super-predicates that reference traits that define the given associated type. - /// This is used to avoid cycles in resolving types like `T::Item`. - query super_predicates_that_define_assoc_item(key: (DefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { + /// The Ident is the name of an associated type.The query returns only the subset + /// of supertraits that define the given associated type. This is used to avoid + /// cycles in resolving type-dependent associated item paths like `T::Item`. + query explicit_supertraits_containing_assoc_item(key: (DefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing the super traits of `{}` with associated type name `{}`", tcx.def_path_str(key.0), key.1 @@ -838,6 +855,12 @@ rustc_queries! { separate_provide_extern } + query associated_type_for_effects(def_id: DefId) -> Option<DefId> { + desc { |tcx| "creating associated items for effects in `{}`", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } + separate_provide_extern + } + /// Given an impl trait in trait `opaque_ty_def_id`, create and return the corresponding /// associated item. query associated_type_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId { diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs index adbb6cf2ddc..7437be7a74c 100644 --- a/compiler/rustc_middle/src/traits/util.rs +++ b/compiler/rustc_middle/src/traits/util.rs @@ -35,7 +35,7 @@ struct Elaborator<'tcx> { impl<'tcx> Elaborator<'tcx> { fn elaborate(&mut self, trait_ref: PolyTraitRef<'tcx>) { let super_predicates = - self.tcx.super_predicates_of(trait_ref.def_id()).predicates.iter().filter_map( + self.tcx.explicit_super_predicates_of(trait_ref.def_id()).predicates.iter().filter_map( |&(pred, _)| { let clause = pred.instantiate_supertrait(self.tcx, trait_ref); self.visited.insert(clause).then_some(clause) diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 1cdde3f057c..820f5e950a9 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -34,6 +34,8 @@ pub struct AssocItem { /// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData` /// provides additional information about its source. pub opt_rpitit_info: Option<ty::ImplTraitInTraitData>, + + pub is_effects_desugaring: bool, } impl AssocItem { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 4bac9396e59..9225ae6300f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -342,12 +342,15 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) } - fn super_predicates_of( + fn explicit_super_predicates_of( self, def_id: DefId, ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> { ty::EarlyBinder::bind( - self.super_predicates_of(def_id).instantiate_identity(self).predicates.into_iter(), + self.explicit_super_predicates_of(def_id) + .instantiate_identity(self) + .predicates + .into_iter(), ) } @@ -598,6 +601,11 @@ fn trait_lang_item_to_lang_item(lang_item: TraitSolverLangItem) -> LangItem { TraitSolverLangItem::Destruct => LangItem::Destruct, TraitSolverLangItem::DiscriminantKind => LangItem::DiscriminantKind, TraitSolverLangItem::DynMetadata => LangItem::DynMetadata, + TraitSolverLangItem::EffectsMaybe => LangItem::EffectsMaybe, + TraitSolverLangItem::EffectsIntersection => LangItem::EffectsIntersection, + TraitSolverLangItem::EffectsIntersectionOutput => LangItem::EffectsIntersectionOutput, + TraitSolverLangItem::EffectsNoRuntime => LangItem::EffectsNoRuntime, + TraitSolverLangItem::EffectsRuntime => LangItem::EffectsRuntime, TraitSolverLangItem::FnPtrTrait => LangItem::FnPtrTrait, TraitSolverLangItem::FusedIterator => LangItem::FusedIterator, TraitSolverLangItem::Future => LangItem::Future, @@ -2440,7 +2448,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name` /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`. pub fn trait_may_define_assoc_item(self, trait_def_id: DefId, assoc_name: Ident) -> bool { - self.super_traits_of(trait_def_id).any(|trait_did| { + self.supertrait_def_ids(trait_def_id).any(|trait_did| { self.associated_items(trait_did) .filter_by_name_unhygienic(assoc_name.name) .any(|item| self.hygienic_eq(assoc_name, item.ident(self), trait_did)) @@ -2463,9 +2471,9 @@ impl<'tcx> TyCtxt<'tcx> { /// Computes the def-ids of the transitive supertraits of `trait_def_id`. This (intentionally) /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used - /// to identify which traits may define a given associated type to help avoid cycle errors. - /// Returns a `DefId` iterator. - fn super_traits_of(self, trait_def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx { + /// to identify which traits may define a given associated type to help avoid cycle errors, + /// and to make size estimates for vtable layout computation. + pub fn supertrait_def_ids(self, trait_def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx { let mut set = FxHashSet::default(); let mut stack = vec![trait_def_id]; @@ -2473,7 +2481,7 @@ impl<'tcx> TyCtxt<'tcx> { iter::from_fn(move || -> Option<DefId> { let trait_did = stack.pop()?; - let generic_predicates = self.super_predicates_of(trait_did); + let generic_predicates = self.explicit_super_predicates_of(trait_did); for (predicate, _) in generic_predicates.predicates { if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder() { @@ -3095,9 +3103,9 @@ impl<'tcx> TyCtxt<'tcx> { matches!( node, hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { generics, .. }), + kind: hir::ItemKind::Impl(hir::Impl { constness, .. }), .. - }) if generics.params.iter().any(|p| matches!(p.kind, hir::GenericParamKind::Const { is_host_effect: true, .. })) + }) if matches!(constness, hir::Constness::Const) ) } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 6467689a8aa..844023df1e3 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -14,7 +14,7 @@ use super::{Clause, InstantiatedPredicates, ParamConst, ParamTy, Ty, TyCtxt}; pub enum GenericParamDefKind { Lifetime, Type { has_default: bool, synthetic: bool }, - Const { has_default: bool, is_host_effect: bool }, + Const { has_default: bool, is_host_effect: bool, synthetic: bool }, } impl GenericParamDefKind { @@ -371,6 +371,7 @@ impl<'tcx> Generics { pub struct GenericPredicates<'tcx> { pub parent: Option<DefId>, pub predicates: &'tcx [(Clause<'tcx>, Span)], + pub effects_min_tys: &'tcx ty::List<Ty<'tcx>>, } impl<'tcx> GenericPredicates<'tcx> { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 9c2bfc12a18..7d57d88f40f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1608,7 +1608,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// If the def-id is an associated type that was desugared from a + /// If the `def_id` is an associated type that was desugared from a /// return-position `impl Trait` from a trait, then provide the source info /// about where that RPITIT came from. pub fn opt_rpitit_info(self, def_id: DefId) -> Option<ImplTraitInTraitData> { @@ -1619,6 +1619,16 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Whether the `def_id` is an associated type that was desugared from a + /// `#[const_trait]` or `impl_const`. + pub fn is_effects_desugared_assoc_ty(self, def_id: DefId) -> bool { + if let DefKind::AssocTy = self.def_kind(def_id) { + self.associated_item(def_id).is_effects_desugaring + } else { + false + } + } + pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option<FieldIdx> { variant.fields.iter_enumerated().find_map(|(i, field)| { self.hygienic_eq(ident, field.ident(self), variant.def_id).then_some(i) diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index dc3c84f9e43..466c3b93f8e 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -3,8 +3,6 @@ use std::fmt; use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar}; use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt}; use rustc_ast::Mutability; -use rustc_data_structures::fx::FxHashSet; -use rustc_hir::def_id::DefId; use rustc_macros::HashStable; #[derive(Clone, Copy, PartialEq, HashStable)] @@ -42,45 +40,12 @@ impl<'tcx> fmt::Debug for VtblEntry<'tcx> { impl<'tcx> TyCtxt<'tcx> { pub const COMMON_VTABLE_ENTRIES: &'tcx [VtblEntry<'tcx>] = &[VtblEntry::MetadataDropInPlace, VtblEntry::MetadataSize, VtblEntry::MetadataAlign]; - - pub fn supertrait_def_ids(self, trait_def_id: DefId) -> SupertraitDefIds<'tcx> { - SupertraitDefIds { - tcx: self, - stack: vec![trait_def_id], - visited: Some(trait_def_id).into_iter().collect(), - } - } } pub const COMMON_VTABLE_ENTRIES_DROPINPLACE: usize = 0; pub const COMMON_VTABLE_ENTRIES_SIZE: usize = 1; pub const COMMON_VTABLE_ENTRIES_ALIGN: usize = 2; -pub struct SupertraitDefIds<'tcx> { - tcx: TyCtxt<'tcx>, - stack: Vec<DefId>, - visited: FxHashSet<DefId>, -} - -impl Iterator for SupertraitDefIds<'_> { - type Item = DefId; - - fn next(&mut self) -> Option<DefId> { - let def_id = self.stack.pop()?; - let predicates = self.tcx.super_predicates_of(def_id); - let visited = &mut self.visited; - self.stack.extend( - predicates - .predicates - .iter() - .filter_map(|(pred, _)| pred.as_trait_clause()) - .map(|trait_ref| trait_ref.def_id()) - .filter(|&super_def_id| visited.insert(super_def_id)), - ); - Some(def_id) - } -} - // Note that we don't have access to a self type here, this has to be purely based on the trait (and // supertrait) definitions. That means we can't call into the same vtable_entries code since that // returns a specific instantiation (e.g., with Vacant slots when bounds aren't satisfied). The goal diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index c1d645aa42c..476969a1bd7 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -189,38 +189,37 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let initializer_span = this.thir[*initializer].span; let scope = (*init_scope, source_info); - let failure = unpack!( - block = this.in_scope(scope, *lint_level, |this| { - this.declare_bindings( - visibility_scope, - remainder_span, - pattern, - None, - Some((Some(&destination), initializer_span)), - ); - this.visit_primary_bindings( - pattern, - UserTypeProjections::none(), - &mut |this, _, _, node, span, _, _| { - this.storage_live_binding( - block, - node, - span, - OutsideGuard, - true, - ); - }, - ); - this.ast_let_else( - block, - *initializer, - initializer_span, - *else_block, - &last_remainder_scope, - pattern, - ) - }) - ); + let failure_and_block = this.in_scope(scope, *lint_level, |this| { + this.declare_bindings( + visibility_scope, + remainder_span, + pattern, + None, + Some((Some(&destination), initializer_span)), + ); + this.visit_primary_bindings( + pattern, + UserTypeProjections::none(), + &mut |this, _, _, node, span, _, _| { + this.storage_live_binding(block, node, span, OutsideGuard, true); + }, + ); + let else_block_span = this.thir[*else_block].span; + let (matching, failure) = + this.in_if_then_scope(last_remainder_scope, else_block_span, |this| { + this.lower_let_expr( + block, + *initializer, + pattern, + None, + initializer_span, + false, + true, + ) + }); + matching.and(failure) + }); + let failure = unpack!(block = failure_and_block); this.cfg.goto(failure, source_info, failure_entry); if let Some(source_scope) = visibility_scope { diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 932406fd1aa..6d52c308237 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -21,6 +21,7 @@ use rustc_span::symbol::Symbol; use rustc_span::{BytePos, Pos, Span}; use rustc_target::abi::VariantIdx; use tracing::{debug, instrument}; +use util::visit_bindings; // helper functions, broken out by category: mod simplify; @@ -146,6 +147,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some(args.variable_source_info.scope), args.variable_source_info.span, args.declare_let_bindings, + false, ), _ => { let mut block = block; @@ -314,13 +316,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let match_start_span = span.shrink_to_lo().to(scrutinee_span); - let fake_borrow_temps = self.lower_match_tree( + // The set of places that we are creating fake borrows of. If there are no match guards then + // we don't need any fake borrows, so don't track them. + let fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)> = if match_has_guard { + util::collect_fake_borrows(self, &candidates, scrutinee_span, scrutinee_place.base()) + } else { + Vec::new() + }; + + self.lower_match_tree( block, scrutinee_span, &scrutinee_place, match_start_span, - match_has_guard, &mut candidates, + false, ); self.lower_match_arms( @@ -375,89 +385,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .collect() } - /// Create the decision tree for the match expression, starting from `block`. - /// - /// Modifies `candidates` to store the bindings and type ascriptions for - /// that candidate. - /// - /// Returns the places that need fake borrows because we bind or test them. - fn lower_match_tree<'pat>( - &mut self, - block: BasicBlock, - scrutinee_span: Span, - scrutinee_place_builder: &PlaceBuilder<'tcx>, - match_start_span: Span, - match_has_guard: bool, - candidates: &mut [&mut Candidate<'pat, 'tcx>], - ) -> Vec<(Place<'tcx>, Local, FakeBorrowKind)> { - // The set of places that we are creating fake borrows of. If there are no match guards then - // we don't need any fake borrows, so don't track them. - let fake_borrows: Vec<(Place<'tcx>, Local, FakeBorrowKind)> = if match_has_guard { - util::collect_fake_borrows( - self, - candidates, - scrutinee_span, - scrutinee_place_builder.base(), - ) - } else { - Vec::new() - }; - - // See the doc comment on `match_candidates` for why we have an - // otherwise block. Match checking will ensure this is actually - // unreachable. - let otherwise_block = self.cfg.start_new_block(); - - // This will generate code to test scrutinee_place and - // branch to the appropriate arm block - self.match_candidates(match_start_span, scrutinee_span, block, otherwise_block, candidates); - - let source_info = self.source_info(scrutinee_span); - - // Matching on a `scrutinee_place` with an uninhabited type doesn't - // generate any memory reads by itself, and so if the place "expression" - // contains unsafe operations like raw pointer dereferences or union - // field projections, we wouldn't know to require an `unsafe` block - // around a `match` equivalent to `std::intrinsics::unreachable()`. - // See issue #47412 for this hole being discovered in the wild. - // - // HACK(eddyb) Work around the above issue by adding a dummy inspection - // of `scrutinee_place`, specifically by applying `ReadForMatch`. - // - // NOTE: ReadForMatch also checks that the scrutinee is initialized. - // This is currently needed to not allow matching on an uninitialized, - // uninhabited value. If we get never patterns, those will check that - // the place is initialized, and so this read would only be used to - // check safety. - let cause_matched_place = FakeReadCause::ForMatchedPlace(None); - - if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) { - self.cfg.push_fake_read( - otherwise_block, - source_info, - cause_matched_place, - scrutinee_place, - ); - } - - self.cfg.terminate(otherwise_block, source_info, TerminatorKind::Unreachable); - - // Link each leaf candidate to the `pre_binding_block` of the next one. - let mut previous_candidate: Option<&mut Candidate<'_, '_>> = None; - - for candidate in candidates { - candidate.visit_leaves(|leaf_candidate| { - if let Some(ref mut prev) = previous_candidate { - assert!(leaf_candidate.false_edge_start_block.is_some()); - prev.next_candidate_start_block = leaf_candidate.false_edge_start_block; - } - previous_candidate = Some(leaf_candidate); - }); - } - - fake_borrows - } - /// Lower the bindings, guards and arm bodies of a `match` expression. /// /// The decision tree should have already been created @@ -728,59 +655,53 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { set_match_place: bool, ) -> BlockAnd<()> { let mut candidate = Candidate::new(initializer.clone(), irrefutable_pat, false, self); - let fake_borrow_temps = self.lower_match_tree( - block, - irrefutable_pat.span, - &initializer, - irrefutable_pat.span, - false, - &mut [&mut candidate], - ); // For matches and function arguments, the place that is being matched // can be set when creating the variables. But the place for // let PATTERN = ... might not even exist until we do the assignment. // so we set it here instead. if set_match_place { - let mut next = Some(&candidate); - while let Some(candidate_ref) = next.take() { - for binding in &candidate_ref.extra_data.bindings { + // `try_to_place` may fail if it is unable to resolve the given `PlaceBuilder` inside a + // closure. In this case, we don't want to include a scrutinee place. + // `scrutinee_place_builder` will fail for destructured assignments. This is because a + // closure only captures the precise places that it will read and as a result a closure + // may not capture the entire tuple/struct and rather have individual places that will + // be read in the final MIR. + // Example: + // ``` + // let foo = (0, 1); + // let c = || { + // let (v1, v2) = foo; + // }; + // ``` + if let Some(place) = initializer.try_to_place(self) { + visit_bindings(&[&mut candidate], |binding: &Binding<'_>| { let local = self.var_local_id(binding.var_id, OutsideGuard); - // `try_to_place` may fail if it is unable to resolve the given - // `PlaceBuilder` inside a closure. In this case, we don't want to include - // a scrutinee place. `scrutinee_place_builder` will fail for destructured - // assignments. This is because a closure only captures the precise places - // that it will read and as a result a closure may not capture the entire - // tuple/struct and rather have individual places that will be read in the - // final MIR. - // Example: - // ``` - // let foo = (0, 1); - // let c = || { - // let (v1, v2) = foo; - // }; - // ``` - if let Some(place) = initializer.try_to_place(self) { - let LocalInfo::User(BindingForm::Var(VarBindingForm { - opt_match_place: Some((ref mut match_place, _)), - .. - })) = **self.local_decls[local].local_info.as_mut().assert_crate_local() - else { - bug!("Let binding to non-user variable.") - }; + if let LocalInfo::User(BindingForm::Var(VarBindingForm { + opt_match_place: Some((ref mut match_place, _)), + .. + })) = **self.local_decls[local].local_info.as_mut().assert_crate_local() + { *match_place = Some(place); - } - } - // All of the subcandidates should bind the same locals, so we - // only visit the first one. - next = candidate_ref.subcandidates.get(0) + } else { + bug!("Let binding to non-user variable.") + }; + }); } } + self.lower_match_tree( + block, + irrefutable_pat.span, + &initializer, + irrefutable_pat.span, + &mut [&mut candidate], + false, + ); self.bind_pattern( self.source_info(irrefutable_pat.span), candidate, - fake_borrow_temps.as_slice(), + &[], irrefutable_pat.span, None, false, @@ -1306,6 +1227,79 @@ pub(crate) struct ArmHasGuard(pub(crate) bool); // Main matching algorithm impl<'a, 'tcx> Builder<'a, 'tcx> { + /// The entrypoint of the matching algorithm. Create the decision tree for the match expression, + /// starting from `block`. + /// + /// Modifies `candidates` to store the bindings and type ascriptions for + /// that candidate. + /// + /// `refutable` indicates whether the candidate list is refutable (for `if let` and `let else`) + /// or not (for `let` and `match`). In the refutable case we return the block to which we branch + /// on failure. + fn lower_match_tree<'pat>( + &mut self, + block: BasicBlock, + scrutinee_span: Span, + scrutinee_place_builder: &PlaceBuilder<'tcx>, + match_start_span: Span, + candidates: &mut [&mut Candidate<'pat, 'tcx>], + refutable: bool, + ) -> BasicBlock { + // See the doc comment on `match_candidates` for why we have an otherwise block. + let otherwise_block = self.cfg.start_new_block(); + + // This will generate code to test scrutinee_place and branch to the appropriate arm block + self.match_candidates(match_start_span, scrutinee_span, block, otherwise_block, candidates); + + // Link each leaf candidate to the `false_edge_start_block` of the next one. + let mut previous_candidate: Option<&mut Candidate<'_, '_>> = None; + for candidate in candidates { + candidate.visit_leaves(|leaf_candidate| { + if let Some(ref mut prev) = previous_candidate { + assert!(leaf_candidate.false_edge_start_block.is_some()); + prev.next_candidate_start_block = leaf_candidate.false_edge_start_block; + } + previous_candidate = Some(leaf_candidate); + }); + } + + if refutable { + // In refutable cases there's always at least one candidate, and we want a false edge to + // the failure block. + previous_candidate.as_mut().unwrap().next_candidate_start_block = Some(otherwise_block) + } else { + // Match checking ensures `otherwise_block` is actually unreachable in irrefutable + // cases. + let source_info = self.source_info(scrutinee_span); + + // Matching on a scrutinee place of an uninhabited type doesn't generate any memory + // reads by itself, and so if the place is uninitialized we wouldn't know. In order to + // disallow the following: + // ```rust + // let x: !; + // match x {} + // ``` + // we add a dummy read on the place. + // + // NOTE: If we require never patterns for empty matches, those will check that the place + // is initialized, and so this read would no longer be needed. + let cause_matched_place = FakeReadCause::ForMatchedPlace(None); + + if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) { + self.cfg.push_fake_read( + otherwise_block, + source_info, + cause_matched_place, + scrutinee_place, + ); + } + + self.cfg.terminate(otherwise_block, source_info, TerminatorKind::Unreachable); + } + + otherwise_block + } + /// The main match algorithm. It begins with a set of candidates /// `candidates` and has the job of generating code to determine /// which of these candidates, if any, is the correct one. The @@ -1998,52 +1992,50 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { impl<'a, 'tcx> Builder<'a, 'tcx> { /// If the bindings have already been declared, set `declare_bindings` to - /// `false` to avoid duplicated bindings declaration. Used for if-let guards. + /// `false` to avoid duplicated bindings declaration; used for if-let guards. pub(crate) fn lower_let_expr( &mut self, mut block: BasicBlock, expr_id: ExprId, pat: &Pat<'tcx>, source_scope: Option<SourceScope>, - span: Span, + scope_span: Span, declare_bindings: bool, + storages_alive: bool, ) -> BlockAnd<()> { let expr_span = self.thir[expr_id].span; - let expr_place_builder = unpack!(block = self.lower_scrutinee(block, expr_id, expr_span)); - let wildcard = Pat::wildcard_from_ty(pat.ty); - let mut guard_candidate = Candidate::new(expr_place_builder.clone(), pat, false, self); - let mut otherwise_candidate = - Candidate::new(expr_place_builder.clone(), &wildcard, false, self); - let fake_borrow_temps = self.lower_match_tree( + let scrutinee = unpack!(block = self.lower_scrutinee(block, expr_id, expr_span)); + let mut candidate = Candidate::new(scrutinee.clone(), pat, false, self); + let otherwise_block = self.lower_match_tree( block, + expr_span, + &scrutinee, pat.span, - &expr_place_builder, - pat.span, - false, - &mut [&mut guard_candidate, &mut otherwise_candidate], + &mut [&mut candidate], + true, ); - let expr_place = expr_place_builder.try_to_place(self); - let opt_expr_place = expr_place.as_ref().map(|place| (Some(place), expr_span)); - let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap(); - self.break_for_else(otherwise_post_guard_block, self.source_info(expr_span)); + + self.break_for_else(otherwise_block, self.source_info(expr_span)); if declare_bindings { - self.declare_bindings(source_scope, pat.span.to(span), pat, None, opt_expr_place); + let expr_place = scrutinee.try_to_place(self); + let opt_expr_place = expr_place.as_ref().map(|place| (Some(place), expr_span)); + self.declare_bindings(source_scope, pat.span.to(scope_span), pat, None, opt_expr_place); } - let post_guard_block = self.bind_pattern( + let success = self.bind_pattern( self.source_info(pat.span), - guard_candidate, - fake_borrow_temps.as_slice(), + candidate, + &[], expr_span, None, - false, + storages_alive, ); // If branch coverage is enabled, record this branch. - self.visit_coverage_conditional_let(pat, post_guard_block, otherwise_post_guard_block); + self.visit_coverage_conditional_let(pat, success, otherwise_block); - post_guard_block.unit() + success.unit() } /// Initializes each of the bindings from the candidate by @@ -2091,14 +2083,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { return self.cfg.start_new_block(); } - self.ascribe_types( - block, - parent_data - .iter() - .flat_map(|d| &d.ascriptions) - .cloned() - .chain(candidate.extra_data.ascriptions), - ); + let ascriptions = parent_data + .iter() + .flat_map(|d| &d.ascriptions) + .cloned() + .chain(candidate.extra_data.ascriptions); + let bindings = + parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings); + + self.ascribe_types(block, ascriptions); // rust-lang/rust#27282: The `autoref` business deserves some // explanation here. @@ -2185,12 +2178,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { && let Some(guard) = arm.guard { let tcx = self.tcx; - let bindings = - parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings); self.bind_matched_candidate_for_guard(block, schedule_drops, bindings.clone()); - let guard_frame = - GuardFrame { locals: bindings.map(|b| GuardFrameLocal::new(b.var_id)).collect() }; + let guard_frame = GuardFrame { + locals: bindings.clone().map(|b| GuardFrameLocal::new(b.var_id)).collect(), + }; debug!("entering guard building context: {:?}", guard_frame); self.guard_context.push(guard_frame); @@ -2263,11 +2255,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // ``` // // and that is clearly not correct. - let by_value_bindings = parent_data - .iter() - .flat_map(|d| &d.bindings) - .chain(&candidate.extra_data.bindings) - .filter(|binding| matches!(binding.binding_mode.0, ByRef::No)); + let by_value_bindings = + bindings.filter(|binding| matches!(binding.binding_mode.0, ByRef::No)); // Read all of the by reference bindings to ensure that the // place they refer to can't be modified by the guard. for binding in by_value_bindings.clone() { @@ -2291,7 +2280,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.bind_matched_candidate_for_arm_body( block, schedule_drops, - parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings), + bindings, storages_alive, ); block @@ -2493,55 +2482,4 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug!(?locals); self.var_indices.insert(var_id, locals); } - - pub(crate) fn ast_let_else( - &mut self, - mut block: BasicBlock, - init_id: ExprId, - initializer_span: Span, - else_block: BlockId, - let_else_scope: ®ion::Scope, - pattern: &Pat<'tcx>, - ) -> BlockAnd<BasicBlock> { - let else_block_span = self.thir[else_block].span; - let (matching, failure) = self.in_if_then_scope(*let_else_scope, else_block_span, |this| { - let scrutinee = unpack!(block = this.lower_scrutinee(block, init_id, initializer_span)); - let pat = Pat { ty: pattern.ty, span: else_block_span, kind: PatKind::Wild }; - let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false, this); - let mut candidate = Candidate::new(scrutinee.clone(), pattern, false, this); - let fake_borrow_temps = this.lower_match_tree( - block, - initializer_span, - &scrutinee, - pattern.span, - false, - &mut [&mut candidate, &mut wildcard], - ); - // This block is for the matching case - let matching = this.bind_pattern( - this.source_info(pattern.span), - candidate, - fake_borrow_temps.as_slice(), - initializer_span, - None, - true, - ); - // This block is for the failure case - let failure = this.bind_pattern( - this.source_info(else_block_span), - wildcard, - fake_borrow_temps.as_slice(), - initializer_span, - None, - true, - ); - - // If branch coverage is enabled, record this branch. - this.visit_coverage_conditional_let(pattern, matching, failure); - - this.break_for_else(failure, this.source_info(initializer_span)); - matching.unit() - }); - matching.and(failure) - } } diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 630d0b9438d..3bec154e1df 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -1,3 +1,5 @@ +use std::marker::PhantomData; + use crate::build::expr::as_place::{PlaceBase, PlaceBuilder}; use crate::build::matches::{Binding, Candidate, FlatPat, MatchPair, TestCase}; use crate::build::Builder; @@ -269,18 +271,6 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { } } -pub(super) struct FakeBorrowCollector<'a, 'b, 'tcx> { - cx: &'a mut Builder<'b, 'tcx>, - /// Base of the scrutinee place. Used to distinguish bindings inside the scrutinee place from - /// bindings inside deref patterns. - scrutinee_base: PlaceBase, - /// Store for each place the kind of borrow to take. In case of conflicts, we take the strongest - /// borrow (i.e. Deep > Shallow). - /// Invariant: for any place in `fake_borrows`, all the prefixes of this place that are - /// dereferences are also borrowed with the same of stronger borrow kind. - fake_borrows: FxIndexMap<Place<'tcx>, FakeBorrowKind>, -} - /// Determine the set of places that have to be stable across match guards. /// /// Returns a list of places that need a fake borrow along with a local to store it. @@ -344,6 +334,18 @@ pub(super) fn collect_fake_borrows<'tcx>( .collect() } +pub(super) struct FakeBorrowCollector<'a, 'b, 'tcx> { + cx: &'a mut Builder<'b, 'tcx>, + /// Base of the scrutinee place. Used to distinguish bindings inside the scrutinee place from + /// bindings inside deref patterns. + scrutinee_base: PlaceBase, + /// Store for each place the kind of borrow to take. In case of conflicts, we take the strongest + /// borrow (i.e. Deep > Shallow). + /// Invariant: for any place in `fake_borrows`, all the prefixes of this place that are + /// dereferences are also borrowed with the same of stronger borrow kind. + fake_borrows: FxIndexMap<Place<'tcx>, FakeBorrowKind>, +} + impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { // Fake borrow this place and its dereference prefixes. fn fake_borrow(&mut self, place: Place<'tcx>, kind: FakeBorrowKind) { @@ -457,6 +459,57 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { } } +/// Visit all the bindings of these candidates. Because or-alternatives bind the same variables, we +/// only explore the first one of each or-pattern. +pub(super) fn visit_bindings<'tcx>( + candidates: &[&mut Candidate<'_, 'tcx>], + f: impl FnMut(&Binding<'tcx>), +) { + let mut visitor = BindingsVisitor { f, phantom: PhantomData }; + for candidate in candidates.iter() { + visitor.visit_candidate(candidate); + } +} + +pub(super) struct BindingsVisitor<'tcx, F> { + f: F, + phantom: PhantomData<&'tcx ()>, +} + +impl<'tcx, F> BindingsVisitor<'tcx, F> +where + F: FnMut(&Binding<'tcx>), +{ + fn visit_candidate(&mut self, candidate: &Candidate<'_, 'tcx>) { + for binding in &candidate.extra_data.bindings { + (self.f)(binding) + } + for match_pair in &candidate.match_pairs { + self.visit_match_pair(match_pair); + } + } + + fn visit_flat_pat(&mut self, flat_pat: &FlatPat<'_, 'tcx>) { + for binding in &flat_pat.extra_data.bindings { + (self.f)(binding) + } + for match_pair in &flat_pat.match_pairs { + self.visit_match_pair(match_pair); + } + } + + fn visit_match_pair(&mut self, match_pair: &MatchPair<'_, 'tcx>) { + if let TestCase::Or { pats, .. } = &match_pair.test_case { + // All the or-alternatives should bind the same locals, so we only visit the first one. + self.visit_flat_pat(&pats[0]) + } else { + for subpair in &match_pair.subpairs { + self.visit_match_pair(subpair); + } + } + } +} + #[must_use] pub(crate) fn ref_pat_borrow_kind(ref_mutability: Mutability) -> BorrowKind { match ref_mutability { diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index 25744009be8..1fce2abbbbf 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -6,11 +6,13 @@ use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::util::Providers; use rustc_span::def_id::LocalDefId; +use rustc_span::sym; /// Registers query/hook implementations related to coverage. pub(crate) fn provide(providers: &mut Providers) { providers.hooks.is_eligible_for_coverage = |TyCtxtAt { tcx, .. }, def_id| is_eligible_for_coverage(tcx, def_id); + providers.queries.coverage_attr_on = coverage_attr_on; providers.queries.coverage_ids_info = coverage_ids_info; } @@ -38,7 +40,12 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { return false; } - if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_COVERAGE) { + if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NAKED) { + trace!("InstrumentCoverage skipped for {def_id:?} (`#[naked]`)"); + return false; + } + + if !tcx.coverage_attr_on(def_id) { trace!("InstrumentCoverage skipped for {def_id:?} (`#[coverage(off)]`)"); return false; } @@ -46,6 +53,30 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { true } +/// Query implementation for `coverage_attr_on`. +fn coverage_attr_on(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + // Check for annotations directly on this def. + if let Some(attr) = tcx.get_attr(def_id, sym::coverage) { + match attr.meta_item_list().as_deref() { + Some([item]) if item.has_name(sym::off) => return false, + Some([item]) if item.has_name(sym::on) => return true, + Some(_) | None => { + // Other possibilities should have been rejected by `rustc_parse::validate_attr`. + tcx.dcx().span_bug(attr.span, "unexpected value of coverage attribute"); + } + } + } + + match tcx.opt_local_parent(def_id) { + // Check the parent def (and so on recursively) until we find an + // enclosing attribute or reach the crate root. + Some(parent) => tcx.coverage_attr_on(parent), + // We reached the crate root without seeing a coverage attribute, so + // allow coverage instrumentation by default. + None => true, + } +} + /// Query implementation for `coverage_ids_info`. fn coverage_ids_info<'tcx>( tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 0fd85eb345d..8b965f4d18e 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -181,11 +181,6 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { state.insert_value_idx(value_target, val, self.map()); } if let Some(overflow_target) = overflow_target { - let overflow = match overflow { - FlatSet::Top => FlatSet::Top, - FlatSet::Elem(overflow) => FlatSet::Elem(overflow), - FlatSet::Bottom => FlatSet::Bottom, - }; // We have flooded `target` earlier. state.insert_value_idx(overflow_target, overflow, self.map()); } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 0a5fc697d03..07482d0571a 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -11,7 +11,7 @@ use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs} use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::TypeVisitableExt; -use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt, TypeFlags}; use rustc_session::config::{DebugInfo, OptLevel}; use rustc_span::source_map::Spanned; use rustc_span::sym; @@ -306,6 +306,16 @@ impl<'tcx> Inliner<'tcx> { InstanceKind::Intrinsic(_) | InstanceKind::Virtual(..) => { return Err("instance without MIR (intrinsic / virtual)"); } + + // FIXME(#127030): `ConstParamHasTy` has bad interactions with + // the drop shim builder, which does not evaluate predicates in + // the correct param-env for types being dropped. Stall resolving + // the MIR for this instance until all of its const params are + // substituted. + InstanceKind::DropGlue(_, Some(ty)) if ty.has_type_flags(TypeFlags::HAS_CT_PARAM) => { + return Err("still needs substitution"); + } + // This cannot result in an immediate cycle since the callee MIR is a shim, which does // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we // do not need to catch this here, we can wait until the inliner decides to continue diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 21439530c08..6ee684605ac 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -269,6 +269,11 @@ where ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Vec<Candidate<I>>; + + fn consider_builtin_effects_intersection_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution>; } impl<D, I> EvalCtxt<'_, D> @@ -420,6 +425,8 @@ where G::consider_builtin_destruct_candidate(self, goal) } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::TransmuteTrait) { G::consider_builtin_transmute_candidate(self, goal) + } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::EffectsIntersection) { + G::consider_builtin_effects_intersection_candidate(self, goal) } else { Err(NoSolution) }; diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 0cef8d9f4bc..3447b39fa5b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -668,8 +668,9 @@ where { let cx = ecx.cx(); let mut requirements = vec![]; - requirements - .extend(cx.super_predicates_of(trait_ref.def_id).iter_instantiated(cx, trait_ref.args)); + requirements.extend( + cx.explicit_super_predicates_of(trait_ref.def_id).iter_instantiated(cx, trait_ref.args), + ); // FIXME(associated_const_equality): Also add associated consts to // the requirements here. diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 4e8cb4384f4..9275bcc8e97 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -864,6 +864,68 @@ where ) -> Result<Candidate<I>, NoSolution> { panic!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal) } + + fn consider_builtin_effects_intersection_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + let ty::Tuple(types) = goal.predicate.self_ty().kind() else { + return Err(NoSolution); + }; + + let cx = ecx.cx(); + + let mut first_non_maybe = None; + let mut non_maybe_count = 0; + for ty in types.iter() { + if !matches!(ty::EffectKind::try_from_ty(cx, ty), Some(ty::EffectKind::Maybe)) { + first_non_maybe.get_or_insert(ty); + non_maybe_count += 1; + } + } + + match non_maybe_count { + 0 => { + let ty = ty::EffectKind::Maybe.to_ty(cx); + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + ecx.instantiate_normalizes_to_term(goal, ty.into()); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) + } + 1 => { + let ty = first_non_maybe.unwrap(); + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + ecx.instantiate_normalizes_to_term(goal, ty.into()); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) + } + _ => { + let mut min = ty::EffectKind::Maybe; + + for ty in types.iter() { + // We can't find the intersection if the types used are generic. + // + // FIXME(effects) do we want to look at where clauses to get some + // clue for the case where generic types are being used? + let Some(kind) = ty::EffectKind::try_from_ty(cx, ty) else { + return Err(NoSolution); + }; + + let Some(result) = ty::EffectKind::intersection(min, kind) else { + return Err(NoSolution); + }; + + min = result; + } + + let ty = min.to_ty(cx); + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + ecx.instantiate_normalizes_to_term(goal, ty.into()); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) + } + } + } } impl<D, I> EvalCtxt<'_, D> diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 2bc9d35c2b0..f5832f7e5b4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -702,6 +702,47 @@ where } }) } + + fn consider_builtin_effects_intersection_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + if goal.predicate.polarity != ty::PredicatePolarity::Positive { + return Err(NoSolution); + } + + let ty::Tuple(types) = goal.predicate.self_ty().kind() else { + return Err(NoSolution); + }; + + let cx = ecx.cx(); + let maybe_count = types + .iter() + .filter_map(|ty| ty::EffectKind::try_from_ty(cx, ty)) + .filter(|&ty| ty == ty::EffectKind::Maybe) + .count(); + + // Don't do concrete type check unless there are more than one type that will influence the result. + // This would allow `(Maybe, T): Min` pass even if we know nothing about `T`. + if types.len() - maybe_count > 1 { + let mut min = ty::EffectKind::Maybe; + + for ty in types.iter() { + let Some(kind) = ty::EffectKind::try_from_ty(ecx.cx(), ty) else { + return Err(NoSolution); + }; + + let Some(result) = ty::EffectKind::intersection(min, kind) else { + return Err(NoSolution); + }; + + min = result; + } + } + + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) + .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) + } } impl<D, I> EvalCtxt<'_, D> diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 9fad954adda..b2df9a14eb0 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -39,36 +39,6 @@ use rustc_span::{BytePos, ErrorGuaranteed, Pos, Span}; use thin_vec::{thin_vec, ThinVec}; use tracing::instrument; -/// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression -/// dropped into the token stream, which happens while parsing the result of -/// macro expansion). Placement of these is not as complex as I feared it would -/// be. The important thing is to make sure that lookahead doesn't balk at -/// `token::Interpolated` tokens. -macro_rules! maybe_whole_expr { - ($p:expr) => { - if let token::Interpolated(nt) = &$p.token.kind { - match &**nt { - token::NtExpr(e) | token::NtLiteral(e) => { - let e = e.clone(); - $p.bump(); - return Ok(e); - } - token::NtPath(path) => { - let path = (**path).clone(); - $p.bump(); - return Ok($p.mk_expr($p.prev_token.span, ExprKind::Path(None, path))); - } - token::NtBlock(block) => { - let block = block.clone(); - $p.bump(); - return Ok($p.mk_expr($p.prev_token.span, ExprKind::Block(block, None))); - } - _ => {} - }; - } - }; -} - #[derive(Debug)] pub(super) enum LhsExpr { // Already parsed just the outer attributes. @@ -1421,7 +1391,27 @@ impl<'a> Parser<'a> { /// correctly if called from `parse_dot_or_call_expr()`. fn parse_expr_bottom(&mut self) -> PResult<'a, P<Expr>> { maybe_recover_from_interpolated_ty_qpath!(self, true); - maybe_whole_expr!(self); + + if let token::Interpolated(nt) = &self.token.kind { + match &**nt { + token::NtExpr(e) | token::NtLiteral(e) => { + let e = e.clone(); + self.bump(); + return Ok(e); + } + token::NtPath(path) => { + let path = (**path).clone(); + self.bump(); + return Ok(self.mk_expr(self.prev_token.span, ExprKind::Path(None, path))); + } + token::NtBlock(block) => { + let block = block.clone(); + self.bump(); + return Ok(self.mk_expr(self.prev_token.span, ExprKind::Block(block, None))); + } + _ => {} + }; + } // Outer attributes are already parsed and will be // added to the return value after the fact. @@ -2190,7 +2180,26 @@ impl<'a> Parser<'a> { /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`). /// Keep this in sync with `Token::can_begin_literal_maybe_minus`. pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> { - maybe_whole_expr!(self); + if let token::Interpolated(nt) = &self.token.kind { + match &**nt { + // FIXME(nnethercote) The `NtExpr` case should only match if + // `e` is an `ExprKind::Lit` or an `ExprKind::Unary` containing + // an `UnOp::Neg` and an `ExprKind::Lit`, like how + // `can_begin_literal_maybe_minus` works. But this method has + // been over-accepting for a long time, and to make that change + // here requires also changing some `parse_literal_maybe_minus` + // call sites to accept additional expression kinds. E.g. + // `ExprKind::Path` must be accepted when parsing range + // patterns. That requires some care. So for now, we continue + // being less strict here than we should be. + token::NtExpr(e) | token::NtLiteral(e) => { + let e = e.clone(); + self.bump(); + return Ok(e); + } + _ => {} + }; + } let lo = self.token.span; let minus_present = self.eat(&token::BinOp(token::Minus)); @@ -2318,7 +2327,7 @@ impl<'a> Parser<'a> { let before = self.prev_token.clone(); let binder = if self.check_keyword(kw::For) { let lo = self.token.span; - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?; let span = lo.to(self.prev_token.span); self.psess.gated_spans.gate(sym::closure_lifetime_binder, span); @@ -3423,8 +3432,9 @@ impl<'a> Parser<'a> { } } let capture_clause = self.parse_capture_clause()?; + let decl_span = lo.to(self.prev_token.span); let (attrs, body) = self.parse_inner_attrs_and_block()?; - let kind = ExprKind::Gen(capture_clause, body, kind); + let kind = ExprKind::Gen(capture_clause, body, kind, decl_span); Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs)) } @@ -4013,7 +4023,7 @@ impl MutVisitor for CondChecker<'_> { | ExprKind::Match(_, _, _) | ExprKind::Closure(_) | ExprKind::Block(_, _) - | ExprKind::Gen(_, _, _) + | ExprKind::Gen(_, _, _, _) | ExprKind::TryBlock(_) | ExprKind::Underscore | ExprKind::Path(_, _) diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index fde16ac957d..10c7715c7dc 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -457,7 +457,7 @@ impl<'a> Parser<'a> { // * `for<'a> Trait1<'a>: Trait2<'a /* ok */>` // * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>` // * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>` - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?; // Parse type with mandatory colon and (possibly empty) bounds, // or with mandatory equality sign and the second type. diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index d2043c353fe..1e5b227aaa9 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -18,7 +18,7 @@ use rustc_ast::{ }; use rustc_errors::{Applicability, PResult}; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{Span, Symbol}; +use rustc_span::{ErrorGuaranteed, Span, Symbol}; use thin_vec::{thin_vec, ThinVec}; #[derive(Copy, Clone, PartialEq)] @@ -280,7 +280,7 @@ impl<'a> Parser<'a> { // Function pointer type or bound list (trait object type) starting with a poly-trait. // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` // `for<'lt> Trait1<'lt> + Trait2 + 'a` - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?; if self.check_fn_front_matter(false, Case::Sensitive) { self.parse_ty_bare_fn( lo, @@ -833,12 +833,9 @@ impl<'a> Parser<'a> { let lo = self.token.span; let leading_token = self.prev_token.clone(); let has_parens = self.eat(&token::OpenDelim(Delimiter::Parenthesis)); - let inner_lo = self.token.span; - let modifiers = self.parse_trait_bound_modifiers()?; let bound = if self.token.is_lifetime() { - self.error_lt_bound_with_modifiers(modifiers); - self.parse_generic_lt_bound(lo, inner_lo, has_parens)? + self.parse_generic_lt_bound(lo, has_parens)? } else if self.eat_keyword(kw::Use) { // parse precise captures, if any. This is `use<'lt, 'lt, P, P>`; a list of // lifetimes and ident params (including SelfUpper). These are validated later @@ -848,7 +845,7 @@ impl<'a> Parser<'a> { let (args, args_span) = self.parse_precise_capturing_args()?; GenericBound::Use(args, use_span.to(args_span)) } else { - self.parse_generic_ty_bound(lo, has_parens, modifiers, &leading_token)? + self.parse_generic_ty_bound(lo, has_parens, &leading_token)? }; Ok(bound) @@ -858,50 +855,64 @@ impl<'a> Parser<'a> { /// ```ebnf /// LT_BOUND = LIFETIME /// ``` - fn parse_generic_lt_bound( - &mut self, - lo: Span, - inner_lo: Span, - has_parens: bool, - ) -> PResult<'a, GenericBound> { - let bound = GenericBound::Outlives(self.expect_lifetime()); + fn parse_generic_lt_bound(&mut self, lo: Span, has_parens: bool) -> PResult<'a, GenericBound> { + let lt = self.expect_lifetime(); + let bound = GenericBound::Outlives(lt); if has_parens { // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead, // possibly introducing `GenericBound::Paren(P<GenericBound>)`? - self.recover_paren_lifetime(lo, inner_lo)?; + self.recover_paren_lifetime(lo, lt.ident.span)?; } Ok(bound) } /// Emits an error if any trait bound modifiers were present. - fn error_lt_bound_with_modifiers(&self, modifiers: TraitBoundModifiers) { - match modifiers.constness { + fn error_lt_bound_with_modifiers( + &self, + modifiers: TraitBoundModifiers, + binder_span: Option<Span>, + ) -> ErrorGuaranteed { + let TraitBoundModifiers { constness, asyncness, polarity } = modifiers; + + match constness { BoundConstness::Never => {} BoundConstness::Always(span) | BoundConstness::Maybe(span) => { - self.dcx().emit_err(errors::ModifierLifetime { - span, - modifier: modifiers.constness.as_str(), - }); + return self + .dcx() + .emit_err(errors::ModifierLifetime { span, modifier: constness.as_str() }); } } - match modifiers.polarity { + match polarity { BoundPolarity::Positive => {} BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => { - self.dcx().emit_err(errors::ModifierLifetime { - span, - modifier: modifiers.polarity.as_str(), - }); + return self + .dcx() + .emit_err(errors::ModifierLifetime { span, modifier: polarity.as_str() }); + } + } + + match asyncness { + BoundAsyncness::Normal => {} + BoundAsyncness::Async(span) => { + return self + .dcx() + .emit_err(errors::ModifierLifetime { span, modifier: asyncness.as_str() }); } } + + if let Some(span) = binder_span { + return self.dcx().emit_err(errors::ModifierLifetime { span, modifier: "for<...>" }); + } + + unreachable!("lifetime bound intercepted in `parse_generic_ty_bound` but no modifiers?") } /// Recover on `('lifetime)` with `(` already eaten. - fn recover_paren_lifetime(&mut self, lo: Span, inner_lo: Span) -> PResult<'a, ()> { - let inner_span = inner_lo.to(self.prev_token.span); + fn recover_paren_lifetime(&mut self, lo: Span, lt_span: Span) -> PResult<'a, ()> { self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; let span = lo.to(self.prev_token.span); - let (sugg, snippet) = if let Ok(snippet) = self.span_to_snippet(inner_span) { + let (sugg, snippet) = if let Ok(snippet) = self.span_to_snippet(lt_span) { (Some(span), snippet) } else { (None, String::new()) @@ -916,7 +927,7 @@ impl<'a> Parser<'a> { /// If no modifiers are present, this does not consume any tokens. /// /// ```ebnf - /// TRAIT_BOUND_MODIFIERS = [["~"] "const"] ["?" | "!"] + /// TRAIT_BOUND_MODIFIERS = [["~"] "const"] ["async"] ["?" | "!"] /// ``` fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> { let constness = if self.eat(&token::Tilde) { @@ -970,15 +981,23 @@ impl<'a> Parser<'a> { /// TY_BOUND_NOPAREN = [TRAIT_BOUND_MODIFIERS] [for<LT_PARAM_DEFS>] SIMPLE_PATH /// ``` /// - /// For example, this grammar accepts `~const ?for<'a: 'b> m::Trait<'a>`. + /// For example, this grammar accepts `for<'a: 'b> ~const ?m::Trait<'a>`. fn parse_generic_ty_bound( &mut self, lo: Span, has_parens: bool, - modifiers: TraitBoundModifiers, leading_token: &Token, ) -> PResult<'a, GenericBound> { - let mut lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let modifiers = self.parse_trait_bound_modifiers()?; + let (mut lifetime_defs, binder_span) = self.parse_late_bound_lifetime_defs()?; + + // Recover erroneous lifetime bound with modifiers or binder. + // e.g. `T: for<'a> 'a` or `T: ~const 'a`. + if self.token.is_lifetime() { + let _: ErrorGuaranteed = self.error_lt_bound_with_modifiers(modifiers, binder_span); + return self.parse_generic_lt_bound(lo, has_parens); + } + let mut path = if self.token.is_keyword(kw::Fn) && self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis)) && let Some(path) = self.recover_path_from_fn() @@ -1094,16 +1113,19 @@ impl<'a> Parser<'a> { } /// Optionally parses `for<$generic_params>`. - pub(super) fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, ThinVec<GenericParam>> { + pub(super) fn parse_late_bound_lifetime_defs( + &mut self, + ) -> PResult<'a, (ThinVec<GenericParam>, Option<Span>)> { if self.eat_keyword(kw::For) { + let lo = self.token.span; self.expect_lt()?; let params = self.parse_generic_params()?; self.expect_gt()?; - // We rely on AST validation to rule out invalid cases: There must not be type - // parameters, and the lifetime parameters must not have bounds. - Ok(params) + // We rely on AST validation to rule out invalid cases: There must not be + // type or const parameters, and parameters must not have bounds. + Ok((params, Some(lo.to(self.prev_token.span)))) } else { - Ok(ThinVec::new()) + Ok((ThinVec::new(), None)) } } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 5a560325ab9..d7513fbad63 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -782,6 +782,7 @@ passes_used_compiler_linker = passes_used_static = attribute must be applied to a `static` variable + .label = but this is a {$target} passes_useless_assignment = useless assignment of {$is_field_assign -> diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d33f12a973f..0eb9d1ce59f 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -274,7 +274,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } self.check_repr(attrs, span, target, item, hir_id); - self.check_used(attrs, target); + self.check_used(attrs, target, span); } fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) { @@ -369,13 +369,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks that `#[coverage(..)]` is applied to a function or closure. + /// Checks that `#[coverage(..)]` is applied to a function/closure/method, + /// or to an impl block or module. fn check_coverage(&self, attr: &Attribute, span: Span, target: Target) -> bool { match target { - // #[coverage(..)] on function is fine Target::Fn | Target::Closure - | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, + | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) + | Target::Impl + | Target::Mod => true, + _ => { self.dcx().emit_err(errors::CoverageNotFnOrClosure { attr_span: attr.span, @@ -1927,12 +1930,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_used(&self, attrs: &[Attribute], target: Target) { + fn check_used(&self, attrs: &[Attribute], target: Target, target_span: Span) { let mut used_linker_span = None; let mut used_compiler_span = None; for attr in attrs.iter().filter(|attr| attr.has_name(sym::used)) { if target != Target::Static { - self.dcx().emit_err(errors::UsedStatic { span: attr.span }); + self.dcx().emit_err(errors::UsedStatic { + attr_span: attr.span, + span: target_span, + target: target.name(), + }); } let inner = attr.meta_item_list(); match inner.as_deref() { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 7734dba3670..a026ff3b13b 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -551,7 +551,10 @@ pub struct ReprConflictingLint; #[diag(passes_used_static)] pub struct UsedStatic { #[primary_span] + pub attr_span: Span, + #[label] pub span: Span, + pub target: &'static str, } #[derive(Diagnostic)] diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index da4435ebebe..6dd8eaf7e67 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -30,7 +30,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Node; use rustc_middle::bug; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::middle::privacy::{self, Level}; use rustc_middle::mir::interpret::{ConstAllocation, ErrorHandled, GlobalAlloc}; use rustc_middle::query::Providers; @@ -178,7 +178,15 @@ impl<'tcx> ReachableContext<'tcx> { if !self.any_library { // If we are building an executable, only explicitly extern // types need to be exported. - if has_custom_linkage(self.tcx, search_item) { + let codegen_attrs = if self.tcx.def_kind(search_item).has_codegen_attrs() { + self.tcx.codegen_fn_attrs(search_item) + } else { + CodegenFnAttrs::EMPTY + }; + let is_extern = codegen_attrs.contains_extern_indicator(); + let std_internal = + codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL); + if is_extern || std_internal { self.reachable_symbols.insert(search_item); } } else { diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 1bca5602a4e..80619c59cc3 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -334,7 +334,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { None => closure_def, } } - ExprKind::Gen(_, _, _) => { + ExprKind::Gen(_, _, _, _) => { self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span) } ExprKind::ConstBlock(ref constant) => { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 2d38ad37133..41c99f7edee 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2965,8 +2965,9 @@ pub(crate) mod dep_tracking { CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FunctionReturn, InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, - Polonius, RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, - SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, + PatchableFunctionEntry, Polonius, RemapPathScopeComponents, ResolveDocLinks, + SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, + WasiExecModel, }; use crate::lint; use crate::utils::NativeLib; @@ -3073,6 +3074,7 @@ pub(crate) mod dep_tracking { OomStrategy, LanguageIdentifier, NextSolverConfig, + PatchableFunctionEntry, Polonius, InliningThreshold, FunctionReturn, @@ -3250,6 +3252,35 @@ impl DumpMonoStatsFormat { } } +/// `-Z patchable-function-entry` representation - how many nops to put before and after function +/// entry. +#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)] +pub struct PatchableFunctionEntry { + /// Nops before the entry + prefix: u8, + /// Nops after the entry + entry: u8, +} + +impl PatchableFunctionEntry { + pub fn from_total_and_prefix_nops( + total_nops: u8, + prefix_nops: u8, + ) -> Option<PatchableFunctionEntry> { + if total_nops < prefix_nops { + None + } else { + Some(Self { prefix: prefix_nops, entry: total_nops - prefix_nops }) + } + } + pub fn prefix(&self) -> u8 { + self.prefix + } + pub fn entry(&self) -> u8 { + self.entry + } +} + /// `-Zpolonius` values, enabling the borrow checker polonius analysis, and which version: legacy, /// or future prototype. #[derive(Clone, Copy, PartialEq, Hash, Debug, Default)] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 9a10adeb6d1..80f7ca544f3 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -379,6 +379,7 @@ mod desc { pub const parse_passes: &str = "a space-separated list of passes, or `all`"; pub const parse_panic_strategy: &str = "either `unwind` or `abort`"; pub const parse_on_broken_pipe: &str = "either `kill`, `error`, or `inherit`"; + pub const parse_patchable_function_entry: &str = "either two comma separated integers (total_nops,prefix_nops), with prefix_nops <= total_nops, or one integer (total_nops)"; pub const parse_opt_panic_strategy: &str = parse_panic_strategy; pub const parse_oom_strategy: &str = "either `panic` or `abort`"; pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`"; @@ -734,6 +735,32 @@ mod parse { true } + pub(crate) fn parse_patchable_function_entry( + slot: &mut PatchableFunctionEntry, + v: Option<&str>, + ) -> bool { + let mut total_nops = 0; + let mut prefix_nops = 0; + + if !parse_number(&mut total_nops, v) { + let parts = v.and_then(|v| v.split_once(',')).unzip(); + if !parse_number(&mut total_nops, parts.0) { + return false; + } + if !parse_number(&mut prefix_nops, parts.1) { + return false; + } + } + + if let Some(pfe) = + PatchableFunctionEntry::from_total_and_prefix_nops(total_nops, prefix_nops) + { + *slot = pfe; + return true; + } + false + } + pub(crate) fn parse_oom_strategy(slot: &mut OomStrategy, v: Option<&str>) -> bool { match v { Some("panic") => *slot = OomStrategy::Panic, @@ -1859,6 +1886,8 @@ options! { "panic strategy for panics in drops"), parse_only: bool = (false, parse_bool, [UNTRACKED], "parse only; do not compile, assemble, or link (default: no)"), + patchable_function_entry: PatchableFunctionEntry = (PatchableFunctionEntry::default(), parse_patchable_function_entry, [TRACKED], + "nop padding at function entry"), plt: Option<bool> = (None, parse_opt_bool, [TRACKED], "whether to use the PLT when calling into shared libraries; only has effect for PIC code on systems with ELF binaries diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml index 1e0a60bc371..1230667ee91 100644 --- a/compiler/rustc_smir/Cargo.toml +++ b/compiler/rustc_smir/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" [dependencies] # tidy-alphabetical-start rustc_abi = { path = "../rustc_abi" } +rustc_ast = { path = "../rustc_ast" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir" } rustc_middle = { path = "../rustc_middle" } diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index c9c1570a29a..7b5abcf4513 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -188,8 +188,10 @@ impl RustcInternal for FloatTy { fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { match self { + FloatTy::F16 => rustc_ty::FloatTy::F16, FloatTy::F32 => rustc_ty::FloatTy::F32, FloatTy::F64 => rustc_ty::FloatTy::F64, + FloatTy::F128 => rustc_ty::FloatTy::F128, } } } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index dde5e30c3d0..4eefd0eb17c 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -160,7 +160,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates { let mut tables = self.0.borrow_mut(); let def_id = tables[def_id]; - let GenericPredicates { parent, predicates } = tables.tcx.predicates_of(def_id); + let GenericPredicates { parent, predicates, effects_min_tys: _ } = + tables.tcx.predicates_of(def_id); stable_mir::ty::GenericPredicates { parent: parent.map(|did| tables.trait_def(did)), predicates: predicates @@ -181,7 +182,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { ) -> stable_mir::ty::GenericPredicates { let mut tables = self.0.borrow_mut(); let def_id = tables[def_id]; - let GenericPredicates { parent, predicates } = tables.tcx.explicit_predicates_of(def_id); + let GenericPredicates { parent, predicates, effects_min_tys: _ } = + tables.tcx.explicit_predicates_of(def_id); stable_mir::ty::GenericPredicates { parent: parent.map(|did| tables.trait_def(did)), predicates: predicates @@ -228,6 +230,46 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } + fn get_attrs_by_path( + &self, + def_id: stable_mir::DefId, + attr: &[stable_mir::Symbol], + ) -> Vec<stable_mir::crate_def::Attribute> { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let did = tables[def_id]; + let attr_name: Vec<_> = + attr.iter().map(|seg| rustc_span::symbol::Symbol::intern(&seg)).collect(); + tcx.get_attrs_by_path(did, &attr_name) + .map(|attribute| { + let attr_str = rustc_ast_pretty::pprust::attribute_to_string(attribute); + let span = attribute.span; + stable_mir::crate_def::Attribute::new(attr_str, span.stable(&mut *tables)) + }) + .collect() + } + + fn get_all_attrs(&self, def_id: stable_mir::DefId) -> Vec<stable_mir::crate_def::Attribute> { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let did = tables[def_id]; + let filter_fn = move |a: &&rustc_ast::ast::Attribute| { + matches!(a.kind, rustc_ast::ast::AttrKind::Normal(_)) + }; + let attrs_iter = if let Some(did) = did.as_local() { + tcx.hir().attrs(tcx.local_def_id_to_hir_id(did)).iter().filter(filter_fn) + } else { + tcx.item_attrs(did).iter().filter(filter_fn) + }; + attrs_iter + .map(|attribute| { + let attr_str = rustc_ast_pretty::pprust::attribute_to_string(attribute); + let span = attribute.span; + stable_mir::crate_def::Attribute::new(attr_str, span.stable(&mut *tables)) + }) + .collect() + } + fn span_to_string(&self, span: stable_mir::ty::Span) -> String { let tables = self.0.borrow(); tables.tcx.sess.source_map().span_to_diagnostic_string(tables[span]) diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 9cd841bba10..9382460d6d4 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -304,10 +304,10 @@ impl<'tcx> Stable<'tcx> for ty::FloatTy { fn stable(&self, _: &mut Tables<'_>) -> Self::T { match self { - ty::FloatTy::F16 => unimplemented!("f16_f128"), + ty::FloatTy::F16 => FloatTy::F16, ty::FloatTy::F32 => FloatTy::F32, ty::FloatTy::F64 => FloatTy::F64, - ty::FloatTy::F128 => unimplemented!("f16_f128"), + ty::FloatTy::F128 => FloatTy::F128, } } } @@ -600,7 +600,7 @@ impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDefKind { ty::GenericParamDefKind::Type { has_default, synthetic } => { GenericParamDefKind::Type { has_default: *has_default, synthetic: *synthetic } } - ty::GenericParamDefKind::Const { has_default, is_host_effect: _ } => { + ty::GenericParamDefKind::Const { has_default, is_host_effect: _, synthetic: _ } => { GenericParamDefKind::Const { has_default: *has_default } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6d4a8c29bc9..8b7a63f5eb9 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -194,6 +194,14 @@ symbols! { Display, DoubleEndedIterator, Duration, + EffectsCompat, + EffectsIntersection, + EffectsIntersectionOutput, + EffectsMaybe, + EffectsNoRuntime, + EffectsRuntime, + EffectsTyCompat, + Effects__, Encodable, Encoder, Enumerate, @@ -768,6 +776,7 @@ symbols! { enable, encode, end, + entry_nops, enumerate_method, env, env_CFG_RELEASE: env!("CFG_RELEASE"), @@ -1383,6 +1392,7 @@ symbols! { passes, pat, pat_param, + patchable_function_entry, path, pattern_complexity, pattern_parentheses, @@ -1421,6 +1431,7 @@ symbols! { prefetch_read_instruction, prefetch_write_data, prefetch_write_instruction, + prefix_nops, preg, prelude, prelude_import, @@ -1655,6 +1666,7 @@ symbols! { rustc_reallocator, rustc_regions, rustc_reservation_impl, + rustc_runtime, rustc_safe_intrinsic, rustc_serialize, rustc_skip_during_method_dispatch, diff --git a/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs index c10f9d82d46..5cee06e4936 100644 --- a/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs @@ -1,13 +1,7 @@ use crate::abi::Endian; -use crate::spec::{base, Cc, LinkerFlavor, Lld, Target}; +use crate::spec::{base, Cc, LinkerFlavor, Lld, Target, TargetOptions}; pub fn target() -> Target { - let mut base = base::linux_gnu::opts(); - base.endian = Endian::Big; - base.cpu = "v9".into(); - base.max_atomic_width = Some(32); - base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-mv8plus"]); - Target { llvm_target: "sparc-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { @@ -19,6 +13,15 @@ pub fn target() -> Target { pointer_width: 32, data_layout: "E-m:e-p:32:32-i64:64-f128:64-n32-S64".into(), arch: "sparc".into(), - options: base, + options: TargetOptions { + cpu: "v9".into(), + endian: Endian::Big, + late_link_args: TargetOptions::link_args( + LinkerFlavor::Gnu(Cc::Yes, Lld::No), + &["-mcpu=v9", "-m32"], + ), + max_atomic_width: Some(32), + ..base::linux_gnu::opts() + }, } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index f4a026c0367..599a95f2300 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -4995,6 +4995,12 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>( let ty::ClauseKind::Projection(proj) = clause else { return; }; + // avoid ICEing since effects desugared associated types don't have names. + // this path should only be hit for `~const` on invalid places, so they + // will have an informative error already. + if tcx.is_effects_desugared_assoc_ty(proj.projection_term.def_id) { + return; + } let name = tcx.item_name(proj.projection_term.def_id); let mut predicates = generics.predicates.iter().peekable(); let mut prev: Option<&hir::WhereBoundPredicate<'_>> = None; diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 4d10d33fa6e..f1611bd049d 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -187,7 +187,7 @@ fn predicates_reference_self( ) -> SmallVec<[Span; 1]> { let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id)); let predicates = if supertraits_only { - tcx.super_predicates_of(trait_def_id) + tcx.explicit_super_predicates_of(trait_def_id) } else { tcx.predicates_of(trait_def_id) }; @@ -256,7 +256,7 @@ fn super_predicates_have_non_lifetime_binders( if !tcx.features().non_lifetime_binders { return SmallVec::new(); } - tcx.super_predicates_of(trait_def_id) + tcx.explicit_super_predicates_of(trait_def_id) .predicates .iter() .filter_map(|(pred, span)| pred.has_non_region_bound_vars().then_some(*span)) diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 8c5dc88184c..9508a3e8e15 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -574,7 +574,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Check supertraits hold. This is so that their associated type bounds // will be checked in the code below. for super_trait in tcx - .super_predicates_of(trait_predicate.def_id()) + .explicit_super_predicates_of(trait_predicate.def_id()) .instantiate(tcx, trait_predicate.trait_ref.args) .predicates .into_iter() diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index f132e36468a..951af4b0920 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -128,7 +128,7 @@ impl<'tcx> TraitAliasExpander<'tcx> { } // Get components of trait alias. - let predicates = tcx.super_predicates_of(trait_ref.def_id()); + let predicates = tcx.explicit_super_predicates_of(trait_ref.def_id()); debug!(?predicates); let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| { diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 017b0a45d1f..e54ced85dee 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -117,7 +117,7 @@ fn prepare_vtable_segments_inner<'tcx, T>( let &(inner_most_trait_ref, _, _) = stack.last().unwrap(); let mut direct_super_traits_iter = tcx - .super_predicates_of(inner_most_trait_ref.def_id()) + .explicit_super_predicates_of(inner_most_trait_ref.def_id()) .predicates .into_iter() .filter_map(move |(pred, _)| { diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 4395eb57cd6..6726db8bb54 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -4,8 +4,9 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt}; +use rustc_middle::ty::{self, ImplTraitInTraitData, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; +use rustc_span::sym; use rustc_span::symbol::kw; pub(crate) fn provide(providers: &mut Providers) { @@ -14,6 +15,7 @@ pub(crate) fn provide(providers: &mut Providers) { associated_item_def_ids, associated_items, associated_types_for_impl_traits_in_associated_fn, + associated_type_for_effects, associated_type_for_impl_trait_in_trait, impl_item_implementor_ids, ..*providers @@ -44,7 +46,8 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] { ) }) .copied(), - ), + ) + .chain(tcx.associated_type_for_effects(def_id)), ) } hir::ItemKind::Impl(impl_) => { @@ -70,7 +73,8 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] { ) }) .copied() - })), + })) + .chain(tcx.associated_type_for_effects(def_id)), ) } _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"), @@ -143,6 +147,7 @@ fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty container: ty::TraitContainer, fn_has_self_parameter: has_self, opt_rpitit_info: None, + is_effects_desugaring: false, } } @@ -162,9 +167,138 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A container: ty::ImplContainer, fn_has_self_parameter: has_self, opt_rpitit_info: None, + is_effects_desugaring: false, } } +/// Given an `def_id` of a trait or a trait impl: +/// +/// If `def_id` is a trait that has `#[const_trait]`, then it synthesizes +/// a new def id corresponding to a new associated type for the effects. +/// +/// If `def_id` is an impl, then synthesize the associated type according +/// to the constness of the impl. +fn associated_type_for_effects(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> { + // don't synthesize the associated type even if the user has written `const_trait` + // if the effects feature is disabled. + if !tcx.features().effects { + return None; + } + let (feed, parent_did) = match tcx.def_kind(def_id) { + DefKind::Trait => { + let trait_def_id = def_id; + let attr = tcx.get_attr(def_id, sym::const_trait)?; + + let span = attr.span; + let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, kw::Empty, DefKind::AssocTy); + + let local_def_id = trait_assoc_ty.def_id(); + let def_id = local_def_id.to_def_id(); + + // Copy span of the attribute. + trait_assoc_ty.def_ident_span(Some(span)); + + trait_assoc_ty.associated_item(ty::AssocItem { + name: kw::Empty, + kind: ty::AssocKind::Type, + def_id, + trait_item_def_id: None, + container: ty::TraitContainer, + fn_has_self_parameter: false, + opt_rpitit_info: None, + is_effects_desugaring: true, + }); + + // No default type + trait_assoc_ty.defaultness(hir::Defaultness::Default { has_value: false }); + + trait_assoc_ty.is_type_alias_impl_trait(false); + + (trait_assoc_ty, trait_def_id) + } + DefKind::Impl { .. } => { + let impl_def_id = def_id; + let trait_id = tcx.trait_id_of_impl(def_id.to_def_id())?; + + // first get the DefId of the assoc type on the trait, if there is not, + // then we don't need to generate it on the impl. + let trait_assoc_id = tcx.associated_type_for_effects(trait_id)?; + + // FIXME(effects): span + let span = tcx.def_ident_span(def_id).unwrap(); + + let impl_assoc_ty = tcx.at(span).create_def(def_id, kw::Empty, DefKind::AssocTy); + + let local_def_id = impl_assoc_ty.def_id(); + let def_id = local_def_id.to_def_id(); + + impl_assoc_ty.def_ident_span(Some(span)); + + impl_assoc_ty.associated_item(ty::AssocItem { + name: kw::Empty, + kind: ty::AssocKind::Type, + def_id, + trait_item_def_id: Some(trait_assoc_id), + container: ty::ImplContainer, + fn_has_self_parameter: false, + opt_rpitit_info: None, + is_effects_desugaring: true, + }); + + // no default value. + impl_assoc_ty.defaultness(hir::Defaultness::Final); + + // set the type of the associated type! If this is a const impl, + // we set to Maybe, otherwise we set to `Runtime`. + let type_def_id = if tcx.is_const_trait_impl_raw(impl_def_id.to_def_id()) { + tcx.require_lang_item(hir::LangItem::EffectsMaybe, Some(span)) + } else { + tcx.require_lang_item(hir::LangItem::EffectsRuntime, Some(span)) + }; + // FIXME(effects): make impls use `Min` for their effect types + impl_assoc_ty.type_of(ty::EarlyBinder::bind(Ty::new_adt( + tcx, + tcx.adt_def(type_def_id), + ty::GenericArgs::empty(), + ))); + + (impl_assoc_ty, impl_def_id) + } + def_kind => bug!( + "associated_type_for_effects: {:?} should be Trait or Impl but is {:?}", + def_id, + def_kind + ), + }; + + feed.feed_hir(); + + // visibility is public. + feed.visibility(ty::Visibility::Public); + + // Copy generics_of of the trait/impl, making the trait/impl as parent. + feed.generics_of({ + let parent_generics = tcx.generics_of(parent_did); + let parent_count = parent_generics.parent_count + parent_generics.own_params.len(); + + ty::Generics { + parent: Some(parent_did.to_def_id()), + parent_count, + own_params: vec![], + param_def_id_to_index: parent_generics.param_def_id_to_index.clone(), + has_self: false, + has_late_bound_regions: None, + host_effect_index: parent_generics.host_effect_index, + } + }); + feed.explicit_item_super_predicates(ty::EarlyBinder::bind(&[])); + + // There are no inferred outlives for the synthesized associated type. + feed.inferred_outlives_of(&[]); + + Some(feed.def_id().to_def_id()) +} + /// Given an `fn_def_id` of a trait or a trait implementation: /// /// if `fn_def_id` is a function defined inside a trait, then it synthesizes @@ -275,6 +409,7 @@ fn associated_type_for_impl_trait_in_trait( fn_def_id: fn_def_id.to_def_id(), opaque_def_id: opaque_ty_def_id.to_def_id(), }), + is_effects_desugaring: false, }); // Copy visility of the containing function. @@ -326,6 +461,7 @@ fn associated_type_for_impl_trait_in_impl( container: ty::ImplContainer, fn_has_self_parameter: false, opt_rpitit_info: Some(ImplTraitInTraitData::Impl { fn_def_id: impl_fn_def_id.to_def_id() }), + is_effects_desugaring: false, }); // Copy visility of the containing function. diff --git a/compiler/rustc_type_ir/src/effects.rs b/compiler/rustc_type_ir/src/effects.rs new file mode 100644 index 00000000000..f7942f2f982 --- /dev/null +++ b/compiler/rustc_type_ir/src/effects.rs @@ -0,0 +1,59 @@ +use crate::inherent::{AdtDef, IntoKind, Ty}; +use crate::lang_items::TraitSolverLangItem::{EffectsMaybe, EffectsNoRuntime, EffectsRuntime}; +use crate::Interner; + +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum EffectKind { + Maybe, + Runtime, + NoRuntime, +} + +impl EffectKind { + pub fn try_from_def_id<I: Interner>(tcx: I, def_id: I::DefId) -> Option<EffectKind> { + if tcx.is_lang_item(def_id, EffectsMaybe) { + Some(EffectKind::Maybe) + } else if tcx.is_lang_item(def_id, EffectsRuntime) { + Some(EffectKind::Runtime) + } else if tcx.is_lang_item(def_id, EffectsNoRuntime) { + Some(EffectKind::NoRuntime) + } else { + None + } + } + + pub fn to_def_id<I: Interner>(self, tcx: I) -> I::DefId { + let lang_item = match self { + EffectKind::Maybe => EffectsMaybe, + EffectKind::NoRuntime => EffectsNoRuntime, + EffectKind::Runtime => EffectsRuntime, + }; + + tcx.require_lang_item(lang_item) + } + + pub fn try_from_ty<I: Interner>(tcx: I, ty: I::Ty) -> Option<EffectKind> { + if let crate::Adt(def, _) = ty.kind() { + Self::try_from_def_id(tcx, def.def_id()) + } else { + None + } + } + + pub fn to_ty<I: Interner>(self, tcx: I) -> I::Ty { + I::Ty::new_adt(tcx, tcx.adt_def(self.to_def_id(tcx)), Default::default()) + } + + /// Returns an intersection between two effect kinds. If one effect kind + /// is more permissive than the other (e.g. `Maybe` vs `Runtime`), this + /// returns the less permissive effect kind (`Runtime`). + pub fn intersection(a: Self, b: Self) -> Option<Self> { + use EffectKind::*; + match (a, b) { + (Maybe, x) | (x, Maybe) => Some(x), + (Runtime, Runtime) => Some(Runtime), + (NoRuntime, NoRuntime) => Some(NoRuntime), + (Runtime, NoRuntime) | (NoRuntime, Runtime) => None, + } + } +} diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index b89ea30fc34..6665158c7cd 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -209,8 +209,7 @@ pub trait Interner: def_id: Self::DefId, ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>; - // FIXME: Rename this so it's obvious it's only *immediate* super predicates. - fn super_predicates_of( + fn explicit_super_predicates_of( self, def_id: Self::DefId, ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>; diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index cf5ec1ab3fe..cf00c37caa2 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -17,6 +17,11 @@ pub enum TraitSolverLangItem { Destruct, DiscriminantKind, DynMetadata, + EffectsIntersection, + EffectsIntersectionOutput, + EffectsMaybe, + EffectsNoRuntime, + EffectsRuntime, FnPtrTrait, FusedIterator, Future, diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 9b8ca5efdda..d7442e7c89c 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -35,6 +35,7 @@ mod macros; mod binder; mod canonical; mod const_kind; +mod effects; mod flags; mod generic_arg; mod interner; @@ -51,6 +52,7 @@ pub use canonical::*; #[cfg(feature = "nightly")] pub use codec::*; pub use const_kind::*; +pub use effects::*; pub use flags::*; pub use generic_arg::*; pub use interner::*; diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 44dbf549c1a..5f2d9b96c73 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -6,6 +6,7 @@ use std::cell::Cell; use crate::abi::{FnAbi, Layout, LayoutShape}; +use crate::crate_def::Attribute; use crate::mir::alloc::{AllocId, GlobalAlloc}; use crate::mir::mono::{Instance, InstanceDef, StaticDef}; use crate::mir::{BinOp, Body, Place, UnOp}; @@ -55,6 +56,15 @@ pub trait Context { /// Returns the name of given `DefId` fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol; + /// Return attributes with the given attribute name. + /// + /// Single segmented name like `#[inline]` is specified as `&["inline".to_string()]`. + /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`. + fn get_attrs_by_path(&self, def_id: DefId, attr: &[Symbol]) -> Vec<Attribute>; + + /// Get all attributes of a definition. + fn get_all_attrs(&self, def_id: DefId) -> Vec<Attribute>; + /// Returns printable, human readable form of `Span` fn span_to_string(&self, span: Span) -> String; diff --git a/compiler/stable_mir/src/crate_def.rs b/compiler/stable_mir/src/crate_def.rs index 67752a5e629..d9b987c28a2 100644 --- a/compiler/stable_mir/src/crate_def.rs +++ b/compiler/stable_mir/src/crate_def.rs @@ -50,6 +50,21 @@ pub trait CrateDef { let def_id = self.def_id(); with(|cx| cx.span_of_an_item(def_id)) } + + /// Return attributes with the given attribute name. + /// + /// Single segmented name like `#[inline]` is specified as `&["inline".to_string()]`. + /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`. + fn attrs_by_path(&self, attr: &[Symbol]) -> Vec<Attribute> { + let def_id = self.def_id(); + with(|cx| cx.get_attrs_by_path(def_id, attr)) + } + + /// Return all attributes of this definition. + fn all_attrs(&self) -> Vec<Attribute> { + let def_id = self.def_id(); + with(|cx| cx.get_all_attrs(def_id)) + } } /// A trait that can be used to retrieve a definition's type. @@ -69,6 +84,28 @@ pub trait CrateDefType: CrateDef { } } +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Attribute { + value: String, + span: Span, +} + +impl Attribute { + pub fn new(value: String, span: Span) -> Attribute { + Attribute { value, span } + } + + /// Get the span of this attribute. + pub fn span(&self) -> Span { + self.span + } + + /// Get the string representation of this attribute. + pub fn as_str(&self) -> &str { + &self.value + } +} + macro_rules! crate_def { ( $(#[$attr:meta])* $vis:vis $name:ident $(;)? diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 8c120a96e75..01e4f1d1f33 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -608,8 +608,10 @@ impl UintTy { #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum FloatTy { + F16, F32, F64, + F128, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index 0f767df6063..d5ca5c4ed27 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -41,18 +41,18 @@ #[allow_internal_unstable(rustc_attrs, liballoc_internals)] macro_rules! vec { () => ( - $crate::__rust_force_expr!($crate::vec::Vec::new()) + $crate::vec::Vec::new() ); ($elem:expr; $n:expr) => ( - $crate::__rust_force_expr!($crate::vec::from_elem($elem, $n)) + $crate::vec::from_elem($elem, $n) ); ($($x:expr),+ $(,)?) => ( - $crate::__rust_force_expr!(<[_]>::into_vec( + <[_]>::into_vec( // This rustc_box is not required, but it produces a dramatic improvement in compile // time when constructing arrays with many elements. #[rustc_box] $crate::boxed::Box::new([$($x),+]) - )) + ) ); } @@ -126,13 +126,3 @@ macro_rules! format { res }} } - -/// Force AST node to an expression to improve diagnostics in pattern position. -#[doc(hidden)] -#[macro_export] -#[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")] -macro_rules! __rust_force_expr { - ($e:expr) => { - $e - }; -} diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 3e23612d0c1..3bb808a6c73 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -206,15 +206,16 @@ impl BorrowMut<str> for String { #[stable(feature = "rust1", since = "1.0.0")] impl ToOwned for str { type Owned = String; + #[inline] fn to_owned(&self) -> String { unsafe { String::from_utf8_unchecked(self.as_bytes().to_owned()) } } + #[inline] fn clone_into(&self, target: &mut String) { - let mut b = mem::take(target).into_bytes(); - self.as_bytes().clone_into(&mut b); - *target = unsafe { String::from_utf8_unchecked(b) } + target.clear(); + target.push_str(self); } } diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index c25bc5a1b13..3bcd4be1834 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -459,6 +459,12 @@ impl<'a> Arguments<'a> { } } +// Manually implementing these results in better error messages. +#[stable(feature = "rust1", since = "1.0.0")] +impl !Send for Arguments<'_> {} +#[stable(feature = "rust1", since = "1.0.0")] +impl !Sync for Arguments<'_> {} + #[stable(feature = "rust1", since = "1.0.0")] impl Debug for Arguments<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index 92626feabf3..65a4d537cc7 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -5,6 +5,7 @@ use super::*; use crate::hint::unreachable_unchecked; +use crate::ptr::NonNull; #[lang = "format_placeholder"] #[derive(Copy, Clone)] @@ -66,7 +67,13 @@ pub(super) enum Flag { #[derive(Copy, Clone)] enum ArgumentType<'a> { - Placeholder { value: &'a Opaque, formatter: fn(&Opaque, &mut Formatter<'_>) -> Result }, + Placeholder { + // INVARIANT: `formatter` has type `fn(&T, _) -> _` for some `T`, and `value` + // was derived from a `&'a T`. + value: NonNull<()>, + formatter: unsafe fn(NonNull<()>, &mut Formatter<'_>) -> Result, + _lifetime: PhantomData<&'a ()>, + }, Count(usize), } @@ -90,21 +97,15 @@ pub struct Argument<'a> { impl<'a> Argument<'a> { #[inline(always)] fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'b> { - // SAFETY: `mem::transmute(x)` is safe because - // 1. `&'b T` keeps the lifetime it originated with `'b` - // (so as to not have an unbounded lifetime) - // 2. `&'b T` and `&'b Opaque` have the same memory layout - // (when `T` is `Sized`, as it is here) - // `mem::transmute(f)` is safe since `fn(&T, &mut Formatter<'_>) -> Result` - // and `fn(&Opaque, &mut Formatter<'_>) -> Result` have the same ABI - // (as long as `T` is `Sized`) - unsafe { - Argument { - ty: ArgumentType::Placeholder { - formatter: mem::transmute(f), - value: mem::transmute(x), - }, - } + Argument { + // INVARIANT: this creates an `ArgumentType<'b>` from a `&'b T` and + // a `fn(&T, ...)`, so the invariant is maintained. + ty: ArgumentType::Placeholder { + value: NonNull::from(x).cast(), + // SAFETY: function pointers always have the same layout. + formatter: unsafe { mem::transmute(f) }, + _lifetime: PhantomData, + }, } } @@ -162,7 +163,14 @@ impl<'a> Argument<'a> { #[inline(always)] pub(super) unsafe fn fmt(&self, f: &mut Formatter<'_>) -> Result { match self.ty { - ArgumentType::Placeholder { formatter, value } => formatter(value, f), + // SAFETY: + // Because of the invariant that if `formatter` had the type + // `fn(&T, _) -> _` then `value` has type `&'b T` where `'b` is + // the lifetime of the `ArgumentType`, and because references + // and `NonNull` are ABI-compatible, this is completely equivalent + // to calling the original function passed to `new` with the + // original reference, which is sound. + ArgumentType::Placeholder { formatter, value, .. } => unsafe { formatter(value, f) }, // SAFETY: the caller promised this. ArgumentType::Count(_) => unsafe { unreachable_unchecked() }, } @@ -208,7 +216,3 @@ impl UnsafeArg { Self { _private: () } } } - -extern "C" { - type Opaque; -} diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index 1c93a7b28fd..da734466263 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -334,6 +334,7 @@ pub trait Hasher { /// /// [`write`]: Hasher::write #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] fn finish(&self) -> u64; /// Writes some data into this `Hasher`. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index d1692729a31..cfadfb0233e 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -231,6 +231,7 @@ #![feature(let_chains)] #![feature(link_llvm_intrinsics)] #![feature(macro_metavar_expr)] +#![feature(marker_trait_attr)] #![feature(min_exhaustive_patterns)] #![feature(min_specialization)] #![feature(multiple_supertrait_upcastable)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 0fedb8835d1..21abd7c036b 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -996,15 +996,12 @@ marker_impls! { bool, char, str /* Technically requires `[u8]: ConstParamTy` */, + (), {T: ConstParamTy, const N: usize} [T; N], {T: ConstParamTy} [T], {T: ?Sized + ConstParamTy} &T, } -// FIXME(adt_const_params): Add to marker_impls call above once not in bootstrap -#[unstable(feature = "adt_const_params", issue = "95174")] -impl ConstParamTy for () {} - /// A common trait implemented by all function pointers. #[unstable( feature = "fn_ptr_trait", @@ -1027,3 +1024,49 @@ pub trait FnPtr: Copy + Clone { pub macro SmartPointer($item:item) { /* compiler built-in */ } + +// Support traits and types for the desugaring of const traits and +// `~const` bounds. Not supposed to be used by anything other than +// the compiler. +#[doc(hidden)] +#[unstable( + feature = "effect_types", + issue = "none", + reason = "internal module for implementing effects" +)] +#[allow(missing_debug_implementations)] // these unit structs don't need `Debug` impls. +#[cfg(not(bootstrap))] +pub mod effects { + #[lang = "EffectsNoRuntime"] + pub struct NoRuntime; + #[lang = "EffectsMaybe"] + pub struct Maybe; + #[lang = "EffectsRuntime"] + pub struct Runtime; + + #[lang = "EffectsCompat"] + pub trait Compat<#[rustc_runtime] const RUNTIME: bool> {} + + impl Compat<false> for NoRuntime {} + impl Compat<true> for Runtime {} + impl<#[rustc_runtime] const RUNTIME: bool> Compat<RUNTIME> for Maybe {} + + #[lang = "EffectsTyCompat"] + #[marker] + pub trait TyCompat<T: ?Sized> {} + + impl<T: ?Sized> TyCompat<T> for T {} + impl<T: ?Sized> TyCompat<T> for Maybe {} + impl<T: ?Sized> TyCompat<Maybe> for T {} + + #[lang = "EffectsIntersection"] + pub trait Intersection { + #[lang = "EffectsIntersectionOutput"] + type Output: ?Sized; + } + + // FIXME(effects): remove this after next trait solver lands + impl Intersection for () { + type Output = Maybe; + } +} diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index cd74cece0d1..ad72c29758b 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2726,7 +2726,7 @@ macro_rules! uint_impl { pub const fn div_ceil(self, rhs: Self) -> Self { let d = self / rhs; let r = self % rhs; - if r > 0 && rhs > 0 { + if r > 0 { d + 1 } else { d diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index b1f94caed35..5537d26669a 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -112,71 +112,6 @@ impl<T: ?Sized> *const T { self as _ } - /// Casts a pointer to its raw bits. - /// - /// This is equivalent to `as usize`, but is more specific to enhance readability. - /// The inverse method is [`from_bits`](#method.from_bits). - /// - /// In particular, `*p as usize` and `p as usize` will both compile for - /// pointers to numeric types but do very different things, so using this - /// helps emphasize that reading the bits was intentional. - /// - /// # Examples - /// - /// ``` - /// #![feature(ptr_to_from_bits)] - /// # #[cfg(not(miri))] { // doctest does not work with strict provenance - /// let array = [13, 42]; - /// let p0: *const i32 = &array[0]; - /// assert_eq!(<*const _>::from_bits(p0.to_bits()), p0); - /// let p1: *const i32 = &array[1]; - /// assert_eq!(p1.to_bits() - p0.to_bits(), 4); - /// # } - /// ``` - #[unstable(feature = "ptr_to_from_bits", issue = "91126")] - #[deprecated( - since = "1.67.0", - note = "replaced by the `expose_provenance` method, or update your code \ - to follow the strict provenance rules using its APIs" - )] - #[inline(always)] - pub fn to_bits(self) -> usize - where - T: Sized, - { - self as usize - } - - /// Creates a pointer from its raw bits. - /// - /// This is equivalent to `as *const T`, but is more specific to enhance readability. - /// The inverse method is [`to_bits`](#method.to_bits). - /// - /// # Examples - /// - /// ``` - /// #![feature(ptr_to_from_bits)] - /// # #[cfg(not(miri))] { // doctest does not work with strict provenance - /// use std::ptr::NonNull; - /// let dangling: *const u8 = NonNull::dangling().as_ptr(); - /// assert_eq!(<*const u8>::from_bits(1), dangling); - /// # } - /// ``` - #[unstable(feature = "ptr_to_from_bits", issue = "91126")] - #[deprecated( - since = "1.67.0", - note = "replaced by the `ptr::with_exposed_provenance` function, or update \ - your code to follow the strict provenance rules using its APIs" - )] - #[allow(fuzzy_provenance_casts)] // this is an unstable and semi-deprecated cast function - #[inline(always)] - pub fn from_bits(bits: usize) -> Self - where - T: Sized, - { - bits as Self - } - /// Gets the "address" portion of the pointer. /// /// This is similar to `self as usize`, which semantically discards *provenance* and diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 7c685156cbb..30d5b2cfc5a 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -117,72 +117,6 @@ impl<T: ?Sized> *mut T { self as _ } - /// Casts a pointer to its raw bits. - /// - /// This is equivalent to `as usize`, but is more specific to enhance readability. - /// The inverse method is [`from_bits`](pointer#method.from_bits-1). - /// - /// In particular, `*p as usize` and `p as usize` will both compile for - /// pointers to numeric types but do very different things, so using this - /// helps emphasize that reading the bits was intentional. - /// - /// # Examples - /// - /// ``` - /// #![feature(ptr_to_from_bits)] - /// # #[cfg(not(miri))] { // doctest does not work with strict provenance - /// let mut array = [13, 42]; - /// let mut it = array.iter_mut(); - /// let p0: *mut i32 = it.next().unwrap(); - /// assert_eq!(<*mut _>::from_bits(p0.to_bits()), p0); - /// let p1: *mut i32 = it.next().unwrap(); - /// assert_eq!(p1.to_bits() - p0.to_bits(), 4); - /// } - /// ``` - #[unstable(feature = "ptr_to_from_bits", issue = "91126")] - #[deprecated( - since = "1.67.0", - note = "replaced by the `expose_provenance` method, or update your code \ - to follow the strict provenance rules using its APIs" - )] - #[inline(always)] - pub fn to_bits(self) -> usize - where - T: Sized, - { - self as usize - } - - /// Creates a pointer from its raw bits. - /// - /// This is equivalent to `as *mut T`, but is more specific to enhance readability. - /// The inverse method is [`to_bits`](pointer#method.to_bits-1). - /// - /// # Examples - /// - /// ``` - /// #![feature(ptr_to_from_bits)] - /// # #[cfg(not(miri))] { // doctest does not work with strict provenance - /// use std::ptr::NonNull; - /// let dangling: *mut u8 = NonNull::dangling().as_ptr(); - /// assert_eq!(<*mut u8>::from_bits(1), dangling); - /// } - /// ``` - #[unstable(feature = "ptr_to_from_bits", issue = "91126")] - #[deprecated( - since = "1.67.0", - note = "replaced by the `ptr::with_exposed_provenance_mut` function, or \ - update your code to follow the strict provenance rules using its APIs" - )] - #[allow(fuzzy_provenance_casts)] // this is an unstable and semi-deprecated cast function - #[inline(always)] - pub fn from_bits(bits: usize) -> Self - where - T: Sized, - { - bits as Self - } - /// Gets the "address" portion of the pointer. /// /// This is similar to `self as usize`, which semantically discards *provenance* and diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 1d19c985f23..df108f5e0e4 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -3766,7 +3766,7 @@ impl<T> fmt::Debug for AtomicPtr<T> { #[stable(feature = "atomic_pointer", since = "1.24.0")] impl<T> fmt::Pointer for AtomicPtr<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&self.load(Ordering::SeqCst), f) + fmt::Pointer::fmt(&self.load(Ordering::Relaxed), f) } } diff --git a/library/core/src/time.rs b/library/core/src/time.rs index bc0fa3f0968..73c556249be 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -842,7 +842,7 @@ impl Duration { /// Returns the number of seconds contained by this `Duration` as `f64`. /// - /// The returned value does include the fractional (nanosecond) part of the duration. + /// The returned value includes the fractional (nanosecond) part of the duration. /// /// # Examples /// ``` @@ -861,7 +861,7 @@ impl Duration { /// Returns the number of seconds contained by this `Duration` as `f32`. /// - /// The returned value does include the fractional (nanosecond) part of the duration. + /// The returned value includes the fractional (nanosecond) part of the duration. /// /// # Examples /// ``` @@ -880,7 +880,7 @@ impl Duration { /// Returns the number of milliseconds contained by this `Duration` as `f64`. /// - /// The returned value does include the fractional (nanosecond) part of the duration. + /// The returned value includes the fractional (nanosecond) part of the duration. /// /// # Examples /// ``` @@ -901,7 +901,7 @@ impl Duration { /// Returns the number of milliseconds contained by this `Duration` as `f32`. /// - /// The returned value does include the fractional (nanosecond) part of the duration. + /// The returned value includes the fractional (nanosecond) part of the duration. /// /// # Examples /// ``` diff --git a/library/std/src/sys/thread_local/guard/key.rs b/library/std/src/sys/thread_local/guard/key.rs index ee9d55ddd5e..67c3ca88627 100644 --- a/library/std/src/sys/thread_local/guard/key.rs +++ b/library/std/src/sys/thread_local/guard/key.rs @@ -4,15 +4,15 @@ use crate::ptr; use crate::sys::thread_local::destructors; -use crate::sys::thread_local::key::StaticKey; +use crate::sys::thread_local::key::{set, LazyKey}; pub fn enable() { - static DTORS: StaticKey = StaticKey::new(Some(run)); + static DTORS: LazyKey = LazyKey::new(Some(run)); // Setting the key value to something other than NULL will result in the // destructor being run at thread exit. unsafe { - DTORS.set(ptr::without_provenance_mut(1)); + set(DTORS.force(), ptr::without_provenance_mut(1)); } unsafe extern "C" fn run(_: *mut u8) { diff --git a/library/std/src/sys/thread_local/key/racy.rs b/library/std/src/sys/thread_local/key/racy.rs index eda8b83bc7f..69f11458c32 100644 --- a/library/std/src/sys/thread_local/key/racy.rs +++ b/library/std/src/sys/thread_local/key/racy.rs @@ -1,4 +1,4 @@ -//! A `StaticKey` implementation using racy initialization. +//! A `LazyKey` implementation using racy initialization. //! //! Unfortunately, none of the platforms currently supported by `std` allows //! creating TLS keys at compile-time. Thus we need a way to lazily create keys. @@ -10,34 +10,12 @@ use crate::sync::atomic::{self, AtomicUsize, Ordering}; /// A type for TLS keys that are statically allocated. /// -/// This type is entirely `unsafe` to use as it does not protect against -/// use-after-deallocation or use-during-deallocation. -/// -/// The actual OS-TLS key is lazily allocated when this is used for the first -/// time. The key is also deallocated when the Rust runtime exits or `destroy` -/// is called, whichever comes first. -/// -/// # Examples -/// -/// ```ignore (cannot-doctest-private-modules) -/// use tls::os::{StaticKey, INIT}; -/// -/// // Use a regular global static to store the key. -/// static KEY: StaticKey = INIT; -/// -/// // The state provided via `get` and `set` is thread-local. -/// unsafe { -/// assert!(KEY.get().is_null()); -/// KEY.set(1 as *mut u8); -/// } -/// ``` -pub struct StaticKey { +/// This is basically a `LazyLock<Key>`, but avoids blocking and circular +/// dependencies with the rest of `std`. +pub struct LazyKey { /// Inner static TLS key (internals). key: AtomicUsize, /// Destructor for the TLS value. - /// - /// See `Key::new` for information about when the destructor runs and how - /// it runs. dtor: Option<unsafe extern "C" fn(*mut u8)>, } @@ -51,32 +29,14 @@ const KEY_SENTVAL: usize = 0; #[cfg(target_os = "nto")] const KEY_SENTVAL: usize = libc::PTHREAD_KEYS_MAX + 1; -impl StaticKey { +impl LazyKey { #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] - pub const fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> StaticKey { - StaticKey { key: atomic::AtomicUsize::new(KEY_SENTVAL), dtor } - } - - /// Gets the value associated with this TLS key - /// - /// This will lazily allocate a TLS key from the OS if one has not already - /// been allocated. - #[inline] - pub unsafe fn get(&self) -> *mut u8 { - unsafe { super::get(self.key()) } - } - - /// Sets this TLS key to a new value. - /// - /// This will lazily allocate a TLS key from the OS if one has not already - /// been allocated. - #[inline] - pub unsafe fn set(&self, val: *mut u8) { - unsafe { super::set(self.key(), val) } + pub const fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> LazyKey { + LazyKey { key: atomic::AtomicUsize::new(KEY_SENTVAL), dtor } } #[inline] - fn key(&self) -> super::Key { + pub fn force(&self) -> super::Key { match self.key.load(Ordering::Acquire) { KEY_SENTVAL => self.lazy_init() as super::Key, n => n as super::Key, diff --git a/library/std/src/sys/thread_local/key/tests.rs b/library/std/src/sys/thread_local/key/tests.rs index 24cad396da2..d82b34e71f0 100644 --- a/library/std/src/sys/thread_local/key/tests.rs +++ b/library/std/src/sys/thread_local/key/tests.rs @@ -1,18 +1,25 @@ -use super::StaticKey; +use super::{get, set, LazyKey}; use crate::ptr; #[test] fn smoke() { - static K1: StaticKey = StaticKey::new(None); - static K2: StaticKey = StaticKey::new(None); + static K1: LazyKey = LazyKey::new(None); + static K2: LazyKey = LazyKey::new(None); + + let k1 = K1.force(); + let k2 = K2.force(); + assert_ne!(k1, k2); + + assert_eq!(K1.force(), k1); + assert_eq!(K2.force(), k2); unsafe { - assert!(K1.get().is_null()); - assert!(K2.get().is_null()); - K1.set(ptr::without_provenance_mut(1)); - K2.set(ptr::without_provenance_mut(2)); - assert_eq!(K1.get() as usize, 1); - assert_eq!(K2.get() as usize, 2); + assert!(get(k1).is_null()); + assert!(get(k2).is_null()); + set(k1, ptr::without_provenance_mut(1)); + set(k2, ptr::without_provenance_mut(2)); + assert_eq!(get(k1) as usize, 1); + assert_eq!(get(k2) as usize, 2); } } @@ -26,25 +33,27 @@ fn destructors() { drop(unsafe { Arc::from_raw(ptr as *const ()) }); } - static KEY: StaticKey = StaticKey::new(Some(destruct)); + static KEY: LazyKey = LazyKey::new(Some(destruct)); let shared1 = Arc::new(()); let shared2 = Arc::clone(&shared1); + let key = KEY.force(); unsafe { - assert!(KEY.get().is_null()); - KEY.set(Arc::into_raw(shared1) as *mut u8); + assert!(get(key).is_null()); + set(key, Arc::into_raw(shared1) as *mut u8); } thread::spawn(move || unsafe { - assert!(KEY.get().is_null()); - KEY.set(Arc::into_raw(shared2) as *mut u8); + let key = KEY.force(); + assert!(get(key).is_null()); + set(key, Arc::into_raw(shared2) as *mut u8); }) .join() .unwrap(); // Leak the Arc, let the TLS destructor clean it up. - let shared1 = unsafe { ManuallyDrop::new(Arc::from_raw(KEY.get() as *const ())) }; + let shared1 = unsafe { ManuallyDrop::new(Arc::from_raw(get(key) as *const ())) }; assert_eq!( Arc::strong_count(&shared1), 1, diff --git a/library/std/src/sys/thread_local/key/unix.rs b/library/std/src/sys/thread_local/key/unix.rs index 13522d44b35..28e48a750b9 100644 --- a/library/std/src/sys/thread_local/key/unix.rs +++ b/library/std/src/sys/thread_local/key/unix.rs @@ -16,6 +16,7 @@ pub unsafe fn set(key: Key, value: *mut u8) { } #[inline] +#[cfg(any(not(target_thread_local), test))] pub unsafe fn get(key: Key) -> *mut u8 { unsafe { libc::pthread_getspecific(key) as *mut u8 } } diff --git a/library/std/src/sys/thread_local/key/windows.rs b/library/std/src/sys/thread_local/key/windows.rs index ad0e72c29ed..baf23979c7c 100644 --- a/library/std/src/sys/thread_local/key/windows.rs +++ b/library/std/src/sys/thread_local/key/windows.rs @@ -1,4 +1,4 @@ -//! Implementation of `StaticKey` for Windows. +//! Implementation of `LazyKey` for Windows. //! //! Windows has no native support for running destructors so we manage our own //! list of destructors to keep track of how to destroy keys. We then install a @@ -13,9 +13,9 @@ //! don't reach a fixed point after a short while then we just inevitably leak //! something. //! -//! The list is implemented as an atomic single-linked list of `StaticKey`s and +//! The list is implemented as an atomic single-linked list of `LazyKey`s and //! does not support unregistration. Unfortunately, this means that we cannot -//! use racy initialization for creating the keys in `StaticKey`, as that could +//! use racy initialization for creating the keys in `LazyKey`, as that could //! result in destructors being missed. Hence, we synchronize the creation of //! keys with destructors through [`INIT_ONCE`](c::INIT_ONCE) (`std`'s //! [`Once`](crate::sync::Once) cannot be used since it might use TLS itself). @@ -33,26 +33,26 @@ use crate::sync::atomic::{ use crate::sys::c; use crate::sys::thread_local::guard; -type Key = c::DWORD; +pub type Key = c::DWORD; type Dtor = unsafe extern "C" fn(*mut u8); -pub struct StaticKey { +pub struct LazyKey { /// The key value shifted up by one. Since TLS_OUT_OF_INDEXES == DWORD::MAX /// is not a valid key value, this allows us to use zero as sentinel value /// without risking overflow. key: AtomicU32, dtor: Option<Dtor>, - next: AtomicPtr<StaticKey>, + next: AtomicPtr<LazyKey>, /// Currently, destructors cannot be unregistered, so we cannot use racy /// initialization for keys. Instead, we need synchronize initialization. /// Use the Windows-provided `Once` since it does not require TLS. once: UnsafeCell<c::INIT_ONCE>, } -impl StaticKey { +impl LazyKey { #[inline] - pub const fn new(dtor: Option<Dtor>) -> StaticKey { - StaticKey { + pub const fn new(dtor: Option<Dtor>) -> LazyKey { + LazyKey { key: AtomicU32::new(0), dtor, next: AtomicPtr::new(ptr::null_mut()), @@ -61,18 +61,7 @@ impl StaticKey { } #[inline] - pub unsafe fn set(&'static self, val: *mut u8) { - let r = unsafe { c::TlsSetValue(self.key(), val.cast()) }; - debug_assert_eq!(r, c::TRUE); - } - - #[inline] - pub unsafe fn get(&'static self) -> *mut u8 { - unsafe { c::TlsGetValue(self.key()).cast() } - } - - #[inline] - fn key(&'static self) -> Key { + pub fn force(&'static self) -> Key { match self.key.load(Acquire) { 0 => unsafe { self.init() }, key => key - 1, @@ -141,17 +130,28 @@ impl StaticKey { } } -unsafe impl Send for StaticKey {} -unsafe impl Sync for StaticKey {} +unsafe impl Send for LazyKey {} +unsafe impl Sync for LazyKey {} + +#[inline] +pub unsafe fn set(key: Key, val: *mut u8) { + let r = unsafe { c::TlsSetValue(key, val.cast()) }; + debug_assert_eq!(r, c::TRUE); +} + +#[inline] +pub unsafe fn get(key: Key) -> *mut u8 { + unsafe { c::TlsGetValue(key).cast() } +} -static DTORS: AtomicPtr<StaticKey> = AtomicPtr::new(ptr::null_mut()); +static DTORS: AtomicPtr<LazyKey> = AtomicPtr::new(ptr::null_mut()); /// Should only be called once per key, otherwise loops or breaks may occur in /// the linked list. -unsafe fn register_dtor(key: &'static StaticKey) { +unsafe fn register_dtor(key: &'static LazyKey) { guard::enable(); - let this = <*const StaticKey>::cast_mut(key); + let this = <*const LazyKey>::cast_mut(key); // Use acquire ordering to pass along the changes done by the previously // registered keys when we store the new head with release ordering. let mut head = DTORS.load(Acquire); @@ -176,9 +176,9 @@ pub unsafe fn run_dtors() { let dtor = unsafe { (*cur).dtor.unwrap() }; cur = unsafe { (*cur).next.load(Relaxed) }; - // In StaticKey::init, we register the dtor before setting `key`. + // In LazyKey::init, we register the dtor before setting `key`. // So if one thread's `run_dtors` races with another thread executing `init` on the same - // `StaticKey`, we can encounter a key of 0 here. That means this key was never + // `LazyKey`, we can encounter a key of 0 here. That means this key was never // initialized in this thread so we can safely skip it. if pre_key == 0 { continue; diff --git a/library/std/src/sys/thread_local/key/xous.rs b/library/std/src/sys/thread_local/key/xous.rs index a23f6de95f7..5a837a33e19 100644 --- a/library/std/src/sys/thread_local/key/xous.rs +++ b/library/std/src/sys/thread_local/key/xous.rs @@ -30,7 +30,7 @@ //! really. //! //! Perhaps one day we can fold the `Box` here into a static allocation, -//! expanding the `StaticKey` structure to contain not only a slot for the TLS +//! expanding the `LazyKey` structure to contain not only a slot for the TLS //! key but also a slot for the destructor queue on windows. An optimization for //! another day! diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index f74fd828cbe..3d1b91a7ea0 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -36,7 +36,7 @@ cfg_if::cfg_if! { pub use native::{EagerStorage, LazyStorage, thread_local_inner}; } else { mod os; - pub use os::{Key, thread_local_inner}; + pub use os::{Storage, thread_local_inner}; } } @@ -126,28 +126,33 @@ pub(crate) mod key { mod unix; #[cfg(test)] mod tests; - pub(super) use racy::StaticKey; - use unix::{Key, create, destroy, get, set}; + pub(super) use racy::LazyKey; + pub(super) use unix::{Key, set}; + #[cfg(any(not(target_thread_local), test))] + pub(super) use unix::get; + use unix::{create, destroy}; } else if #[cfg(all(not(target_thread_local), target_os = "windows"))] { #[cfg(test)] mod tests; mod windows; - pub(super) use windows::{StaticKey, run_dtors}; + pub(super) use windows::{Key, LazyKey, get, run_dtors, set}; } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { mod racy; mod sgx; #[cfg(test)] mod tests; - pub(super) use racy::StaticKey; - use sgx::{Key, create, destroy, get, set}; + pub(super) use racy::LazyKey; + pub(super) use sgx::{Key, get, set}; + use sgx::{create, destroy}; } else if #[cfg(target_os = "xous")] { mod racy; #[cfg(test)] mod tests; mod xous; - pub(super) use racy::StaticKey; + pub(super) use racy::LazyKey; pub(crate) use xous::destroy_tls; - use xous::{Key, create, destroy, get, set}; + pub(super) use xous::{Key, get, set}; + use xous::{create, destroy}; } } } diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs index 6980c897fdb..e06185f0069 100644 --- a/library/std/src/sys/thread_local/os.rs +++ b/library/std/src/sys/thread_local/os.rs @@ -2,7 +2,7 @@ use super::abort_on_dtor_unwind; use crate::cell::Cell; use crate::marker::PhantomData; use crate::ptr; -use crate::sys::thread_local::key::StaticKey as OsKey; +use crate::sys::thread_local::key::{get, set, Key, LazyKey}; #[doc(hidden)] #[allow_internal_unstable(thread_local_internals)] @@ -22,12 +22,12 @@ pub macro thread_local_inner { unsafe { use $crate::thread::LocalKey; - use $crate::thread::local_impl::Key; + use $crate::thread::local_impl::Storage; // Inlining does not work on windows-gnu due to linking errors around // dllimports. See https://github.com/rust-lang/rust/issues/109797. LocalKey::new(#[cfg_attr(windows, inline(never))] |init| { - static VAL: Key<$t> = Key::new(); + static VAL: Storage<$t> = Storage::new(); VAL.get(init, __init) }) } @@ -41,22 +41,23 @@ pub macro thread_local_inner { /// Use a regular global static to store this key; the state provided will then be /// thread-local. #[allow(missing_debug_implementations)] -pub struct Key<T> { - os: OsKey, +pub struct Storage<T> { + key: LazyKey, marker: PhantomData<Cell<T>>, } -unsafe impl<T> Sync for Key<T> {} +unsafe impl<T> Sync for Storage<T> {} struct Value<T: 'static> { value: T, - key: &'static Key<T>, + // INVARIANT: if this value is stored under a TLS key, `key` must be that `key`. + key: Key, } -impl<T: 'static> Key<T> { +impl<T: 'static> Storage<T> { #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] - pub const fn new() -> Key<T> { - Key { os: OsKey::new(Some(destroy_value::<T>)), marker: PhantomData } + pub const fn new() -> Storage<T> { + Storage { key: LazyKey::new(Some(destroy_value::<T>)), marker: PhantomData } } /// Get a pointer to the TLS value, potentially initializing it with the @@ -66,19 +67,23 @@ impl<T: 'static> Key<T> { /// The resulting pointer may not be used after reentrant inialialization /// or thread destruction has occurred. pub fn get(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T { - // SAFETY: (FIXME: get should actually be safe) - let ptr = unsafe { self.os.get() as *mut Value<T> }; + let key = self.key.force(); + let ptr = unsafe { get(key) as *mut Value<T> }; if ptr.addr() > 1 { // SAFETY: the check ensured the pointer is safe (its destructor // is not running) + it is coming from a trusted source (self). unsafe { &(*ptr).value } } else { - self.try_initialize(ptr, i, f) + // SAFETY: trivially correct. + unsafe { Self::try_initialize(key, ptr, i, f) } } } - fn try_initialize( - &'static self, + /// # Safety + /// * `key` must be the result of calling `self.key.force()` + /// * `ptr` must be the current value associated with `key`. + unsafe fn try_initialize( + key: Key, ptr: *mut Value<T>, i: Option<&mut Option<T>>, f: impl FnOnce() -> T, @@ -88,14 +93,19 @@ impl<T: 'static> Key<T> { return ptr::null(); } - let value = i.and_then(Option::take).unwrap_or_else(f); - let ptr = Box::into_raw(Box::new(Value { value, key: self })); - // SAFETY: (FIXME: get should actually be safe) - let old = unsafe { self.os.get() as *mut Value<T> }; - // SAFETY: `ptr` is a correct pointer that can be destroyed by the key destructor. - unsafe { - self.os.set(ptr as *mut u8); - } + let value = Box::new(Value { value: i.and_then(Option::take).unwrap_or_else(f), key }); + let ptr = Box::into_raw(value); + + // SAFETY: + // * key came from a `LazyKey` and is thus correct. + // * `ptr` is a correct pointer that can be destroyed by the key destructor. + // * the value is stored under the key that it contains. + let old = unsafe { + let old = get(key) as *mut Value<T>; + set(key, ptr as *mut u8); + old + }; + if !old.is_null() { // If the variable was recursively initialized, drop the old value. // SAFETY: We cannot be inside a `LocalKey::with` scope, as the @@ -123,8 +133,10 @@ unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) { abort_on_dtor_unwind(|| { let ptr = unsafe { Box::from_raw(ptr as *mut Value<T>) }; let key = ptr.key; - unsafe { key.os.set(ptr::without_provenance_mut(1)) }; + // SAFETY: `key` is the TLS key `ptr` was stored under. + unsafe { set(key, ptr::without_provenance_mut(1)) }; drop(ptr); - unsafe { key.os.set(ptr::null_mut()) }; + // SAFETY: `key` is the TLS key `ptr` was stored under. + unsafe { set(key, ptr::null_mut()) }; }); } diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 708f62f476e..117a3e23044 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -480,7 +480,7 @@ impl Wtf8Buf { #[inline] pub(crate) fn extend_from_slice(&mut self, other: &[u8]) { self.bytes.extend_from_slice(other); - self.is_known_utf8 = self.is_known_utf8 || self.next_surrogate(0).is_none(); + self.is_known_utf8 = false; } } diff --git a/library/std/src/sys_common/wtf8/tests.rs b/library/std/src/sys_common/wtf8/tests.rs index 6a1cc41a8fb..b57c99a8452 100644 --- a/library/std/src/sys_common/wtf8/tests.rs +++ b/library/std/src/sys_common/wtf8/tests.rs @@ -725,3 +725,27 @@ fn wtf8_utf8_boundary_between_surrogates() { string.push(CodePoint::from_u32(0xD800).unwrap()); check_utf8_boundary(&string, 3); } + +#[test] +fn wobbled_wtf8_plus_bytes_isnt_utf8() { + let mut string: Wtf8Buf = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() }; + assert!(!string.is_known_utf8); + string.extend_from_slice(b"some utf-8"); + assert!(!string.is_known_utf8); +} + +#[test] +fn wobbled_wtf8_plus_str_isnt_utf8() { + let mut string: Wtf8Buf = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() }; + assert!(!string.is_known_utf8); + string.push_str("some utf-8"); + assert!(!string.is_known_utf8); +} + +#[test] +fn unwobbly_wtf8_plus_utf8_is_utf8() { + let mut string: Wtf8Buf = Wtf8Buf::from_str("hello world"); + assert!(string.is_known_utf8); + string.push_str("some utf-8"); + assert!(string.is_known_utf8); +} diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 9861121aac0..7e47b373ff9 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -617,6 +617,9 @@ class RustBuild(object): self.fix_bin_or_dylib("{}/bin/rustdoc".format(bin_root)) self.fix_bin_or_dylib("{}/libexec/rust-analyzer-proc-macro-srv".format(bin_root)) lib_dir = "{}/lib".format(bin_root) + rustlib_bin_dir = "{}/rustlib/{}/bin".format(lib_dir, self.build) + self.fix_bin_or_dylib("{}/rust-lld".format(rustlib_bin_dir)) + self.fix_bin_or_dylib("{}/gcc-ld/ld.lld".format(rustlib_bin_dir)) for lib in os.listdir(lib_dir): # .so is not necessarily the suffix, there can be version numbers afterwards. if ".so" in lib: @@ -731,12 +734,9 @@ class RustBuild(object): patchelf = "{}/bin/patchelf".format(nix_deps_dir) rpath_entries = [ - # Relative default, all binary and dynamic libraries we ship - # appear to have this (even when `../lib` is redundant). - "$ORIGIN/../lib", os.path.join(os.path.realpath(nix_deps_dir), "lib") ] - patchelf_args = ["--set-rpath", ":".join(rpath_entries)] + patchelf_args = ["--add-rpath", ":".join(rpath_entries)] if ".so" not in fname: # Finally, set the correct .interp for binaries with open("{}/nix-support/dynamic-linker".format(nix_deps_dir)) as dynamic_linker: diff --git a/src/bootstrap/defaults/config.dist.toml b/src/bootstrap/defaults/config.dist.toml index d06930f2b9d..d4feffe0227 100644 --- a/src/bootstrap/defaults/config.dist.toml +++ b/src/bootstrap/defaults/config.dist.toml @@ -16,6 +16,7 @@ download-ci-llvm = false # Make sure they don't get set when installing from source. channel = "nightly" download-rustc = false +lld = true # Build the llvm-bitcode-linker llvm-bitcode-linker = true diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index d2274199177..009e62469b4 100644 --- a/src/bootstrap/src/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -20,26 +20,24 @@ use std::path::{Path, PathBuf}; use std::process::{Child, Command}; use std::time::Instant; -use dylib_util::{dylib_path, dylib_path_var, exe}; +use shared_helpers::{ + dylib_path, dylib_path_var, exe, maybe_dump, parse_rustc_stage, parse_rustc_verbose, + parse_value_from_args, +}; -#[path = "../utils/bin_helpers.rs"] -mod bin_helpers; - -#[path = "../utils/dylib.rs"] -mod dylib_util; +#[path = "../utils/shared_helpers.rs"] +mod shared_helpers; fn main() { let orig_args = env::args_os().skip(1).collect::<Vec<_>>(); let mut args = orig_args.clone(); - let arg = - |name| orig_args.windows(2).find(|args| args[0] == name).and_then(|args| args[1].to_str()); - let stage = bin_helpers::parse_rustc_stage(); - let verbose = bin_helpers::parse_rustc_verbose(); + let stage = parse_rustc_stage(); + let verbose = parse_rustc_verbose(); // Detect whether or not we're a build script depending on whether --target // is passed (a bit janky...) - let target = arg("--target"); + let target = parse_value_from_args(&orig_args, "--target"); let version = args.iter().find(|w| &**w == "-vV"); // Use a different compiler for build scripts, since there may not yet be a @@ -102,7 +100,7 @@ fn main() { cmd.args(&args).env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); // Get the name of the crate we're compiling, if any. - let crate_name = arg("--crate-name"); + let crate_name = parse_value_from_args(&orig_args, "--crate-name"); if let Some(crate_name) = crate_name { if let Some(target) = env::var_os("RUSTC_TIME") { @@ -143,10 +141,11 @@ fn main() { cmd.arg("-C").arg("panic=abort"); } + let crate_type = parse_value_from_args(&orig_args, "--crate-type"); // `-Ztls-model=initial-exec` must not be applied to proc-macros, see // issue https://github.com/rust-lang/rust/issues/100530 if env::var("RUSTC_TLS_MODEL_INITIAL_EXEC").is_ok() - && arg("--crate-type") != Some("proc-macro") + && crate_type != Some("proc-macro") && !matches!(crate_name, Some("proc_macro2" | "quote" | "syn" | "synstructure")) { cmd.arg("-Ztls-model=initial-exec"); @@ -251,7 +250,7 @@ fn main() { eprintln!("{prefix} libdir: {libdir:?}"); } - bin_helpers::maybe_dump(format!("stage{stage}-rustc"), &cmd); + maybe_dump(format!("stage{stage}-rustc"), &cmd); let start = Instant::now(); let (child, status) = { diff --git a/src/bootstrap/src/bin/rustdoc.rs b/src/bootstrap/src/bin/rustdoc.rs index b4d1415189c..ba6b0c2dbda 100644 --- a/src/bootstrap/src/bin/rustdoc.rs +++ b/src/bootstrap/src/bin/rustdoc.rs @@ -6,19 +6,19 @@ use std::env; use std::path::PathBuf; use std::process::Command; -use dylib_util::{dylib_path, dylib_path_var}; +use shared_helpers::{ + dylib_path, dylib_path_var, maybe_dump, parse_rustc_stage, parse_rustc_verbose, + parse_value_from_args, +}; -#[path = "../utils/bin_helpers.rs"] -mod bin_helpers; - -#[path = "../utils/dylib.rs"] -mod dylib_util; +#[path = "../utils/shared_helpers.rs"] +mod shared_helpers; fn main() { let args = env::args_os().skip(1).collect::<Vec<_>>(); - let stage = bin_helpers::parse_rustc_stage(); - let verbose = bin_helpers::parse_rustc_verbose(); + let stage = parse_rustc_stage(); + let verbose = parse_rustc_verbose(); let rustdoc = env::var_os("RUSTDOC_REAL").expect("RUSTDOC_REAL was not set"); let libdir = env::var_os("RUSTDOC_LIBDIR").expect("RUSTDOC_LIBDIR was not set"); @@ -26,7 +26,7 @@ fn main() { // Detect whether or not we're a build script depending on whether --target // is passed (a bit janky...) - let target = args.windows(2).find(|w| &*w[0] == "--target").and_then(|w| w[1].to_str()); + let target = parse_value_from_args(&args, "--target"); let mut dylib_path = dylib_path(); dylib_path.insert(0, PathBuf::from(libdir.clone())); @@ -62,7 +62,7 @@ fn main() { cmd.arg("-Zunstable-options"); cmd.arg("--check-cfg=cfg(bootstrap)"); - bin_helpers::maybe_dump(format!("stage{stage}-rustdoc"), &cmd); + maybe_dump(format!("stage{stage}-rustdoc"), &cmd); if verbose > 1 { eprintln!( diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs index a81d6403013..479af4af666 100644 --- a/src/bootstrap/src/core/build_steps/clean.rs +++ b/src/bootstrap/src/core/build_steps/clean.rs @@ -85,7 +85,7 @@ macro_rules! clean_crate_tree { // NOTE: doesn't use `run_cargo` because we don't want to save a stamp file, // and doesn't use `stream_cargo` to avoid passing `--message-format` which `clean` doesn't accept. - builder.run(&mut cargo); + builder.run(cargo); } } )+ } diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 5b18cb3f7e1..a6172589dbb 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -27,6 +27,7 @@ use crate::core::builder::crate_description; use crate::core::builder::Cargo; use crate::core::builder::{Builder, Kind, PathSet, RunConfig, ShouldRun, Step, TaskPath}; use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection}; +use crate::utils::exec::BootstrapCommand; use crate::utils::helpers::{ exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, output, symlink_dir, t, up_to_date, }; @@ -771,7 +772,7 @@ impl Step for StartupObjects { let src_file = &src_dir.join(file.to_string() + ".rs"); let dst_file = &dst_dir.join(file.to_string() + ".o"); if !up_to_date(src_file, dst_file) { - let mut cmd = Command::new(&builder.initial_rustc); + let mut cmd = BootstrapCommand::new(&builder.initial_rustc); cmd.env("RUSTC_BOOTSTRAP", "1"); if !builder.local_rebuild { // a local_rebuild compiler already has stage1 features @@ -2076,7 +2077,7 @@ pub fn stream_cargo( tail_args: Vec<String>, cb: &mut dyn FnMut(CargoMessage<'_>), ) -> bool { - let mut cargo = Command::from(cargo); + let mut cargo = BootstrapCommand::from(cargo).command; // Instruct Cargo to give us json messages on stdout, critically leaving // stderr as piped so we can get those pretty colors. let mut message_format = if builder.config.json_output { diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 2dc7cd7de6a..08795efe5bb 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -26,6 +26,7 @@ use crate::core::build_steps::tool::{self, Tool}; use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; use crate::core::config::TargetSelection; use crate::utils::channel::{self, Info}; +use crate::utils::exec::BootstrapCommand; use crate::utils::helpers::{ exe, is_dylib, move_file, output, t, target_supports_cranelift_backend, timeit, }; @@ -1599,14 +1600,14 @@ impl Step for Extended { let _ = fs::remove_dir_all(&pkg); let pkgbuild = |component: &str| { - let mut cmd = Command::new("pkgbuild"); + let mut cmd = BootstrapCommand::new("pkgbuild"); cmd.arg("--identifier") .arg(format!("org.rust-lang.{}", component)) .arg("--scripts") .arg(pkg.join(component)) .arg("--nopayload") .arg(pkg.join(component).with_extension("pkg")); - builder.run(&mut cmd); + builder.run(cmd); }; let prepare = |name: &str| { @@ -1636,7 +1637,7 @@ impl Step for Extended { builder.create_dir(&pkg.join("res")); builder.create(&pkg.join("res/LICENSE.txt"), &license); builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644); - let mut cmd = Command::new("productbuild"); + let mut cmd = BootstrapCommand::new("productbuild"); cmd.arg("--distribution") .arg(xform(&etc.join("pkg/Distribution.xml"))) .arg("--resources") @@ -1649,7 +1650,7 @@ impl Step for Extended { .arg("--package-path") .arg(&pkg); let _time = timeit(builder); - builder.run(&mut cmd); + builder.run(cmd); } if target.is_windows() { @@ -1704,7 +1705,7 @@ impl Step for Extended { let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"]; builder.run( - Command::new(&heat) + BootstrapCommand::new(&heat) .current_dir(&exe) .arg("dir") .arg("rustc") @@ -1720,7 +1721,7 @@ impl Step for Extended { ); if built_tools.contains("rust-docs") { builder.run( - Command::new(&heat) + BootstrapCommand::new(&heat) .current_dir(&exe) .arg("dir") .arg("rust-docs") @@ -1738,7 +1739,7 @@ impl Step for Extended { ); } builder.run( - Command::new(&heat) + BootstrapCommand::new(&heat) .current_dir(&exe) .arg("dir") .arg("cargo") @@ -1755,7 +1756,7 @@ impl Step for Extended { .arg(etc.join("msi/remove-duplicates.xsl")), ); builder.run( - Command::new(&heat) + BootstrapCommand::new(&heat) .current_dir(&exe) .arg("dir") .arg("rust-std") @@ -1771,7 +1772,7 @@ impl Step for Extended { ); if built_tools.contains("rust-analyzer") { builder.run( - Command::new(&heat) + BootstrapCommand::new(&heat) .current_dir(&exe) .arg("dir") .arg("rust-analyzer") @@ -1790,7 +1791,7 @@ impl Step for Extended { } if built_tools.contains("clippy") { builder.run( - Command::new(&heat) + BootstrapCommand::new(&heat) .current_dir(&exe) .arg("dir") .arg("clippy") @@ -1809,7 +1810,7 @@ impl Step for Extended { } if built_tools.contains("miri") { builder.run( - Command::new(&heat) + BootstrapCommand::new(&heat) .current_dir(&exe) .arg("dir") .arg("miri") @@ -1827,7 +1828,7 @@ impl Step for Extended { ); } builder.run( - Command::new(&heat) + BootstrapCommand::new(&heat) .current_dir(&exe) .arg("dir") .arg("rust-analysis") @@ -1845,7 +1846,7 @@ impl Step for Extended { ); if target.ends_with("windows-gnu") { builder.run( - Command::new(&heat) + BootstrapCommand::new(&heat) .current_dir(&exe) .arg("dir") .arg("rust-mingw") @@ -1864,7 +1865,7 @@ impl Step for Extended { let candle = |input: &Path| { let output = exe.join(input.file_stem().unwrap()).with_extension("wixobj"); let arch = if target.contains("x86_64") { "x64" } else { "x86" }; - let mut cmd = Command::new(&candle); + let mut cmd = BootstrapCommand::new(&candle); cmd.current_dir(&exe) .arg("-nologo") .arg("-dRustcDir=rustc") @@ -1893,7 +1894,7 @@ impl Step for Extended { if target.ends_with("windows-gnu") { cmd.arg("-dGccDir=rust-mingw"); } - builder.run(&mut cmd); + builder.run(cmd); }; candle(&xform(&etc.join("msi/rust.wxs"))); candle(&etc.join("msi/ui.wxs")); @@ -1925,7 +1926,7 @@ impl Step for Extended { builder.info(&format!("building `msi` installer with {light:?}")); let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target.triple); - let mut cmd = Command::new(&light); + let mut cmd = BootstrapCommand::new(&light); cmd.arg("-nologo") .arg("-ext") .arg("WixUIExtension") @@ -1962,7 +1963,7 @@ impl Step for Extended { cmd.arg("-sice:ICE57"); let _time = timeit(builder); - builder.run(&mut cmd); + builder.run(cmd); if !builder.config.dry_run() { t!(move_file(exe.join(&filename), distdir(builder).join(&filename))); @@ -1971,7 +1972,7 @@ impl Step for Extended { } } -fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) { +fn add_env(builder: &Builder<'_>, cmd: &mut BootstrapCommand, target: TargetSelection) { let mut parts = builder.version.split('.'); cmd.env("CFG_RELEASE_INFO", builder.rust_version()) .env("CFG_RELEASE_NUM", &builder.version) @@ -2270,9 +2271,6 @@ impl Step for RustDev { builder.ensure(crate::core::build_steps::llvm::Llvm { target }); - // We want to package `lld` to use it with `download-ci-llvm`. - builder.ensure(crate::core::build_steps::llvm::Lld { target }); - let src_bindir = builder.llvm_out(target).join("bin"); // If updating this, you likely want to change // src/bootstrap/download-ci-llvm-stamp as well, otherwise local users @@ -2289,10 +2287,15 @@ impl Step for RustDev { } } - // We don't build LLD on some platforms, so only add it if it exists - let lld_path = builder.lld_out(target).join("bin").join(exe("lld", target)); - if lld_path.exists() { - tarball.add_file(lld_path, "bin", 0o755); + if builder.config.lld_enabled { + // We want to package `lld` to use it with `download-ci-llvm`. + let lld_out = builder.ensure(crate::core::build_steps::llvm::Lld { target }); + + // We don't build LLD on some platforms, so only add it if it exists + let lld_path = lld_out.join("bin").join(exe("lld", target)); + if lld_path.exists() { + tarball.add_file(lld_path, "bin", 0o755); + } } tarball.add_file(builder.llvm_filecheck(target), "bin", 0o755); diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 6748625f132..4a5af25b3b2 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -249,6 +249,7 @@ impl Step for TheBook { let shared_assets = builder.ensure(SharedAssets { target }); // build the command first so we don't nest GHA groups + // FIXME: this doesn't do anything! builder.rustdoc_cmd(compiler); // build the redirect pages @@ -300,7 +301,7 @@ fn invoke_rustdoc( cmd.arg("-Z").arg("unstable-options").arg("--disable-minification"); } - builder.run(&mut cmd); + builder.run(cmd); } #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -394,7 +395,7 @@ impl Step for Standalone { } else { cmd.arg("--markdown-css").arg("rust.css"); } - builder.run(&mut cmd); + builder.run(cmd); } // We open doc/index.html as the default if invoked as `x.py doc --open` @@ -493,7 +494,7 @@ impl Step for Releases { cmd.arg("--disable-minification"); } - builder.run(&mut cmd); + builder.run(cmd); } // We open doc/RELEASES.html as the default if invoked as `x.py doc --open RELEASES.md` @@ -737,7 +738,7 @@ fn doc_std( format!("library{} in {} format", crate_description(requested_crates), format.as_str()); let _guard = builder.msg_doc(compiler, description, target); - builder.run(&mut cargo.into()); + builder.run(cargo); builder.cp_link_r(&out_dir, out); } @@ -862,7 +863,7 @@ impl Step for Rustc { let proc_macro_out_dir = builder.stage_out(compiler, Mode::Rustc).join("doc"); symlink_dir_force(&builder.config, &out, &proc_macro_out_dir); - builder.run(&mut cargo.into()); + builder.run(cargo); if !builder.config.dry_run() { // Sanity check on linked compiler crates @@ -888,12 +889,11 @@ impl Step for Rustc { macro_rules! tool_doc { ( $tool: ident, - $should_run: literal, $path: literal, $(rustc_tool = $rustc_tool:literal, )? - $(in_tree = $in_tree:literal ,)? $(is_library = $is_library:expr,)? $(crates = $crates:expr)? + $(, submodule $(= $submodule:literal)? )? ) => { #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct $tool { @@ -907,7 +907,7 @@ macro_rules! tool_doc { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run.crate_or_deps($should_run).default_condition(builder.config.compiler_docs) + run.path($path).default_condition(builder.config.compiler_docs) } fn make_run(run: RunConfig<'_>) { @@ -921,6 +921,15 @@ macro_rules! tool_doc { /// we do not merge it with the other documentation from std, test and /// proc_macros. This is largely just a wrapper around `cargo doc`. fn run(self, builder: &Builder<'_>) { + let source_type = SourceType::InTree; + $( + let _ = source_type; // silence the "unused variable" warning + let source_type = SourceType::Submodule; + + let path = Path::new(submodule_helper!( $path, submodule $( = $submodule )? )); + builder.update_submodule(&path); + )? + let stage = builder.top_stage; let target = self.target; @@ -941,12 +950,6 @@ macro_rules! tool_doc { builder.ensure(compile::Rustc::new(compiler, target)); } - let source_type = if true $(&& $in_tree)? { - SourceType::InTree - } else { - SourceType::Submodule - }; - // Build cargo command. let mut cargo = prepare_tool_cargo( builder, @@ -993,7 +996,7 @@ macro_rules! tool_doc { symlink_dir_force(&builder.config, &out, &proc_macro_out_dir); let _guard = builder.msg_doc(compiler, stringify!($tool).to_lowercase(), target); - builder.run(&mut cargo.into()); + builder.run(cargo); if !builder.config.dry_run() { // Sanity check on linked doc directories @@ -1008,21 +1011,14 @@ macro_rules! tool_doc { } } -tool_doc!(Rustdoc, "rustdoc-tool", "src/tools/rustdoc", crates = ["rustdoc", "rustdoc-json-types"]); -tool_doc!( - Rustfmt, - "rustfmt-nightly", - "src/tools/rustfmt", - crates = ["rustfmt-nightly", "rustfmt-config_proc_macro"] -); -tool_doc!(Clippy, "clippy", "src/tools/clippy", crates = ["clippy_config", "clippy_utils"]); -tool_doc!(Miri, "miri", "src/tools/miri", crates = ["miri"]); +tool_doc!(Rustdoc, "src/tools/rustdoc", crates = ["rustdoc", "rustdoc-json-types"]); +tool_doc!(Rustfmt, "src/tools/rustfmt", crates = ["rustfmt-nightly", "rustfmt-config_proc_macro"]); +tool_doc!(Clippy, "src/tools/clippy", crates = ["clippy_config", "clippy_utils"]); +tool_doc!(Miri, "src/tools/miri", crates = ["miri"]); tool_doc!( Cargo, - "cargo", "src/tools/cargo", rustc_tool = false, - in_tree = false, crates = [ "cargo", "cargo-credential", @@ -1034,12 +1030,12 @@ tool_doc!( "crates-io", "mdman", "rustfix", - ] + ], + submodule = "src/tools/cargo" ); -tool_doc!(Tidy, "tidy", "src/tools/tidy", rustc_tool = false, crates = ["tidy"]); +tool_doc!(Tidy, "src/tools/tidy", rustc_tool = false, crates = ["tidy"]); tool_doc!( Bootstrap, - "bootstrap", "src/bootstrap", rustc_tool = false, is_library = true, @@ -1047,7 +1043,6 @@ tool_doc!( ); tool_doc!( RunMakeSupport, - "run_make_support", "src/tools/run-make-support", rustc_tool = false, is_library = true, @@ -1085,7 +1080,7 @@ impl Step for ErrorIndex { index.arg(out); index.arg(&builder.version); - builder.run(&mut index); + builder.run(index); } } @@ -1121,7 +1116,7 @@ impl Step for UnstableBookGen { cmd.arg(builder.src.join("src")); cmd.arg(out); - builder.run(&mut cmd); + builder.run(cmd); } } @@ -1216,7 +1211,7 @@ impl Step for RustcBook { self.compiler.host, self.target, ); - builder.run(&mut cmd); + builder.run(cmd); drop(doc_generator_guard); // Run rustbook/mdbook to generate the HTML pages. diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index c47233ca42a..7ee1aca2abc 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -6,11 +6,11 @@ use std::env; use std::fs; use std::path::{Component, Path, PathBuf}; -use std::process::Command; use crate::core::build_steps::dist; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::core::config::{Config, TargetSelection}; +use crate::utils::exec::BootstrapCommand; use crate::utils::helpers::t; use crate::utils::tarball::GeneratedTarball; use crate::{Compiler, Kind}; @@ -102,7 +102,7 @@ fn install_sh( let empty_dir = builder.out.join("tmp/empty_dir"); t!(fs::create_dir_all(&empty_dir)); - let mut cmd = Command::new(SHELL); + let mut cmd = BootstrapCommand::new(SHELL); cmd.current_dir(&empty_dir) .arg(sanitize_sh(&tarball.decompressed_output().join("install.sh"))) .arg(format!("--prefix={}", prepare_dir(&destdir_env, prefix))) @@ -113,7 +113,7 @@ fn install_sh( .arg(format!("--libdir={}", prepare_dir(&destdir_env, libdir))) .arg(format!("--mandir={}", prepare_dir(&destdir_env, mandir))) .arg("--disable-ldconfig"); - builder.run(&mut cmd); + builder.run(cmd); t!(fs::remove_dir_all(&empty_dir)); } diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 8b379d3be5c..8e6795b11bd 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -407,18 +407,21 @@ impl Step for Llvm { cfg.define("LLVM_LINK_LLVM_DYLIB", "ON"); } - if (target.starts_with("riscv") || target.starts_with("csky")) + if (target.starts_with("csky") + || target.starts_with("riscv") + || target.starts_with("sparc-")) && !target.contains("freebsd") && !target.contains("openbsd") && !target.contains("netbsd") { - // RISC-V and CSKY GCC erroneously requires linking against + // CSKY and RISC-V GCC erroneously requires linking against // `libatomic` when using 1-byte and 2-byte C++ // atomics but the LLVM build system check cannot // detect this. Therefore it is set manually here. // Some BSD uses Clang as its system compiler and // provides no libatomic in its base system so does - // not want this. + // not want this. 32-bit SPARC requires linking against + // libatomic as well. ldflags.exe.push(" -latomic"); ldflags.shared.push(" -latomic"); } diff --git a/src/bootstrap/src/core/build_steps/perf.rs b/src/bootstrap/src/core/build_steps/perf.rs index 9d70ca6bd71..f41b5fe10f1 100644 --- a/src/bootstrap/src/core/build_steps/perf.rs +++ b/src/bootstrap/src/core/build_steps/perf.rs @@ -1,7 +1,5 @@ -use std::process::Command; - use crate::core::build_steps::compile::{Std, Sysroot}; -use crate::core::build_steps::tool::RustcPerf; +use crate::core::build_steps::tool::{RustcPerf, Tool}; use crate::core::builder::Builder; use crate::core::config::DebuginfoLevel; @@ -22,24 +20,16 @@ Consider setting `rust.debuginfo-level = 1` in `config.toml`."#); let sysroot = builder.ensure(Sysroot::new(compiler)); let rustc = sysroot.join("bin/rustc"); - let results_dir = builder.build.tempdir().join("rustc-perf"); - - let mut cmd = Command::new(collector); - let cmd = cmd - .arg("profile_local") - .arg("eprintln") - .arg("--out-dir") - .arg(&results_dir) - .arg("--include") - .arg("helloworld") - .arg(&rustc); - - builder.info(&format!("Running `rustc-perf` using `{}`", rustc.display())); + let rustc_perf_dir = builder.build.tempdir().join("rustc-perf"); + let profile_results_dir = rustc_perf_dir.join("results"); - // We need to set the working directory to `src/tools/perf`, so that it can find the directory - // with compile-time benchmarks. - let cmd = cmd.current_dir(builder.src.join("src/tools/rustc-perf")); - builder.build.run(cmd); + // We need to take args passed after `--` and pass them to `rustc-perf-wrapper` + let args = std::env::args().skip_while(|a| a != "--").skip(1); - builder.info(&format!("You can find the results at `{}`", results_dir.display())); + let mut cmd = builder.tool_cmd(Tool::RustcPerfWrapper); + cmd.env("RUSTC_REAL", rustc) + .env("PERF_COLLECTOR", collector) + .env("PERF_RESULT_DIR", profile_results_dir) + .args(args); + builder.run(&mut cmd); } diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 9268b335db7..22d5efa5d95 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -50,7 +50,7 @@ impl Step for BuildManifest { cmd.arg(&builder.config.channel); builder.create_dir(&distdir(builder)); - builder.run(&mut cmd); + builder.run(cmd); } } @@ -72,7 +72,7 @@ impl Step for BumpStage0 { fn run(self, builder: &Builder<'_>) -> Self::Output { let mut cmd = builder.tool_cmd(Tool::BumpStage0); cmd.args(builder.config.args()); - builder.run(&mut cmd); + builder.run(cmd); } } @@ -94,7 +94,7 @@ impl Step for ReplaceVersionPlaceholder { fn run(self, builder: &Builder<'_>) -> Self::Output { let mut cmd = builder.tool_cmd(Tool::ReplaceVersionPlaceholder); cmd.arg(&builder.src); - builder.run(&mut cmd); + builder.run(cmd); } } @@ -158,8 +158,7 @@ impl Step for Miri { // after another --, so this must be at the end. miri.args(builder.config.args()); - let mut miri = Command::from(miri); - builder.run(&mut miri); + builder.run(miri); } } @@ -189,7 +188,7 @@ impl Step for CollectLicenseMetadata { let mut cmd = builder.tool_cmd(Tool::CollectLicenseMetadata); cmd.env("REUSE_EXE", reuse); cmd.env("DEST", &dest); - builder.run(&mut cmd); + builder.run(cmd); dest } @@ -219,7 +218,7 @@ impl Step for GenerateCopyright { let mut cmd = builder.tool_cmd(Tool::GenerateCopyright); cmd.env("LICENSE_METADATA", &license_metadata); cmd.env("DEST", &dest); - builder.run(&mut cmd); + builder.run(cmd); dest } @@ -243,7 +242,7 @@ impl Step for GenerateWindowsSys { fn run(self, builder: &Builder<'_>) { let mut cmd = builder.tool_cmd(Tool::GenerateWindowsSys); cmd.arg(&builder.src); - builder.run(&mut cmd); + builder.run(cmd); } } diff --git a/src/bootstrap/src/core/build_steps/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs index 754d1e61da8..7c5e0d4e13e 100644 --- a/src/bootstrap/src/core/build_steps/suggest.rs +++ b/src/bootstrap/src/core/build_steps/suggest.rs @@ -16,6 +16,7 @@ pub fn suggest(builder: &Builder<'_>, run: bool) { .tool_cmd(Tool::SuggestTests) .env("SUGGEST_TESTS_GIT_REPOSITORY", git_config.git_repository) .env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch) + .command .output() .expect("failed to run `suggest-tests` tool"); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index efc09c41bf4..1460a229019 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -156,7 +156,7 @@ You can skip linkcheck with --skip src/tools/linkchecker" let _guard = builder.msg(Kind::Test, compiler.stage, "Linkcheck", bootstrap_host, bootstrap_host); let _time = helpers::timeit(builder); - builder.run_tracked( + builder.run( BootstrapCommand::from(linkchecker.arg(builder.out.join(host.triple).join("doc"))) .delay_failure(), ); @@ -216,7 +216,7 @@ impl Step for HtmlCheck { builder, )); - builder.run_tracked( + builder.run( BootstrapCommand::from( builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target)), ) @@ -267,7 +267,7 @@ impl Step for Cargotest { .env("RUSTC", builder.rustc(compiler)) .env("RUSTDOC", builder.rustdoc(compiler)); add_rustdoc_cargo_linker_args(cmd, builder, compiler.host, LldThreads::No); - builder.run_tracked(BootstrapCommand::from(cmd).delay_failure()); + builder.run(BootstrapCommand::from(cmd).delay_failure()); } } @@ -465,7 +465,7 @@ impl Miri { // Tell it where to put the sysroot. cargo.env("MIRI_SYSROOT", &miri_sysroot); - let mut cargo = Command::from(cargo); + let mut cargo = BootstrapCommand::from(cargo); let _guard = builder.msg(Kind::Build, compiler.stage, "miri sysroot", compiler.host, target); builder.run(&mut cargo); @@ -482,8 +482,10 @@ impl Miri { String::new() } else { builder.verbose(|| println!("running: {cargo:?}")); - let out = - cargo.output().expect("We already ran `cargo miri setup` before and that worked"); + let out = cargo + .command + .output() + .expect("We already ran `cargo miri setup` before and that worked"); assert!(out.status.success(), "`cargo miri setup` returned with non-0 exit code"); // Output is "<sysroot>\n". let stdout = String::from_utf8(out.stdout) @@ -596,7 +598,7 @@ impl Step for Miri { target, ); let _time = helpers::timeit(builder); - builder.run(&mut cargo); + builder.run(cargo); } } } @@ -661,11 +663,11 @@ impl Step for CargoMiri { // Finally, pass test-args and run everything. cargo.arg("--").args(builder.config.test_args()); - let mut cargo = Command::from(cargo); + let cargo = BootstrapCommand::from(cargo); { let _guard = builder.msg_sysroot_tool(Kind::Test, stage, "cargo-miri", host, target); let _time = helpers::timeit(builder); - builder.run(&mut cargo); + builder.run(cargo); } } } @@ -766,7 +768,7 @@ impl Step for Clippy { let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "clippy", host, host); // Clippy reports errors if it blessed the outputs - if builder.run_cmd(BootstrapCommand::from(&mut cargo).allow_failure()) { + if builder.run(BootstrapCommand::from(&mut cargo).allow_failure()).is_success() { // The tests succeeded; nothing to do. return; } @@ -819,7 +821,7 @@ impl Step for RustdocTheme { .env("RUSTC_BOOTSTRAP", "1"); cmd.args(linker_args(builder, self.compiler.host, LldThreads::No)); - builder.run_tracked(BootstrapCommand::from(&mut cmd).delay_failure()); + builder.run(BootstrapCommand::from(&mut cmd).delay_failure()); } } @@ -845,7 +847,7 @@ impl Step for RustdocJSStd { fn run(self, builder: &Builder<'_>) { let nodejs = builder.config.nodejs.as_ref().expect("need nodejs to run rustdoc-js-std tests"); - let mut command = Command::new(nodejs); + let mut command = BootstrapCommand::new(nodejs); command .arg(builder.src.join("src/tools/rustdoc-js/tester.js")) .arg("--crate-name") @@ -879,7 +881,7 @@ impl Step for RustdocJSStd { builder.config.build, self.target, ); - builder.run(&mut command); + builder.run(command); } } @@ -1097,7 +1099,7 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to } builder.info("tidy check"); - builder.run_tracked(BootstrapCommand::from(&mut cmd).delay_failure()); + builder.run(BootstrapCommand::from(&mut cmd).delay_failure()); builder.info("x.py completions check"); let [bash, zsh, fish, powershell] = ["x.py.sh", "x.py.zsh", "x.py.fish", "x.py.ps1"] @@ -1304,8 +1306,7 @@ impl Step for RunMakeSupport { &[], ); - let mut cargo = Command::from(cargo); - builder.run(&mut cargo); + builder.run(cargo); let lib_name = "librun_make_support.rlib"; let lib = builder.tools_dir(self.compiler).join(lib_name); @@ -1816,23 +1817,25 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--gdb").arg(gdb); } - let run = |cmd: &mut Command| { - cmd.output().map(|output| { - String::from_utf8_lossy(&output.stdout) - .lines() - .next() - .unwrap_or_else(|| panic!("{:?} failed {:?}", cmd, output)) - .to_string() - }) - }; - let lldb_exe = builder.config.lldb.clone().unwrap_or_else(|| PathBuf::from("lldb")); let lldb_version = Command::new(&lldb_exe) .arg("--version") .output() - .map(|output| String::from_utf8_lossy(&output.stdout).to_string()) - .ok(); + .map(|output| { + (String::from_utf8_lossy(&output.stdout).to_string(), output.status.success()) + }) + .ok() + .and_then(|(output, success)| if success { Some(output) } else { None }); if let Some(ref vers) = lldb_version { + let run = |cmd: &mut Command| { + cmd.output().map(|output| { + String::from_utf8_lossy(&output.stdout) + .lines() + .next() + .unwrap_or_else(|| panic!("{:?} failed {:?}", cmd, output)) + .to_string() + }) + }; cmd.arg("--lldb-version").arg(vers); let lldb_python_dir = run(Command::new(&lldb_exe).arg("-P")).ok(); if let Some(ref dir) = lldb_python_dir { @@ -2066,7 +2069,8 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--git-repository").arg(git_config.git_repository); cmd.arg("--nightly-branch").arg(git_config.nightly_branch); - builder.ci_env.force_coloring_in_ci(&mut cmd); + // FIXME: Move CiEnv back to bootstrap, it is only used here anyway + builder.ci_env.force_coloring_in_ci(&mut cmd.command); #[cfg(feature = "build-metrics")] builder.metrics.begin_test_suite( @@ -2184,11 +2188,8 @@ impl BookTest { ); let _time = helpers::timeit(builder); let cmd = BootstrapCommand::from(&mut rustbook_cmd).delay_failure(); - let toolstate = if builder.run_tracked(cmd).is_success() { - ToolState::TestPass - } else { - ToolState::TestFail - }; + let toolstate = + if builder.run(cmd).is_success() { ToolState::TestPass } else { ToolState::TestFail }; builder.save_toolstate(self.name, toolstate); } @@ -2317,8 +2318,7 @@ impl Step for ErrorIndex { let guard = builder.msg(Kind::Test, compiler.stage, "error-index", compiler.host, compiler.host); let _time = helpers::timeit(builder); - builder - .run_tracked(BootstrapCommand::from(&mut tool).output_mode(OutputMode::OnlyOnFailure)); + builder.run(BootstrapCommand::from(&mut tool).output_mode(OutputMode::OnlyOnFailure)); drop(guard); // The tests themselves need to link to std, so make sure it is // available. @@ -2347,11 +2347,11 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> let test_args = builder.config.test_args().join(" "); cmd.arg("--test-args").arg(test_args); - let mut cmd = BootstrapCommand::from(&mut cmd).delay_failure(); + cmd = cmd.delay_failure(); if !builder.config.verbose_tests { cmd = cmd.quiet(); } - builder.run_tracked(cmd).is_success() + builder.run(cmd).is_success() } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -2377,11 +2377,8 @@ impl Step for RustcGuide { let src = builder.src.join(relative_path); let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook); let cmd = BootstrapCommand::from(rustbook_cmd.arg("linkcheck").arg(&src)).delay_failure(); - let toolstate = if builder.run_tracked(cmd).is_success() { - ToolState::TestPass - } else { - ToolState::TestFail - }; + let toolstate = + if builder.run(cmd).is_success() { ToolState::TestPass } else { ToolState::TestFail }; builder.save_toolstate("rustc-dev-guide", toolstate); } } @@ -2432,7 +2429,7 @@ impl Step for CrateLibrustc { /// Returns whether the test succeeded. #[allow(clippy::too_many_arguments)] // FIXME: reduce the number of args and remove this. fn run_cargo_test<'a>( - cargo: impl Into<Command>, + cargo: impl Into<BootstrapCommand>, libtest_args: &[&str], crates: &[String], primary_crate: &str, @@ -2463,14 +2460,14 @@ fn run_cargo_test<'a>( /// Given a `cargo test` subcommand, pass it the appropriate test flags given a `builder`. fn prepare_cargo_test( - cargo: impl Into<Command>, + cargo: impl Into<BootstrapCommand>, libtest_args: &[&str], crates: &[String], primary_crate: &str, compiler: Compiler, target: TargetSelection, builder: &Builder<'_>, -) -> Command { +) -> BootstrapCommand { let mut cargo = cargo.into(); // Propegate `--bless` if it has not already been set/unset @@ -2881,19 +2878,19 @@ impl Step for RemoteCopyLibs { // Spawn the emulator and wait for it to come online let tool = builder.tool_exe(Tool::RemoteTestClient); - let mut cmd = Command::new(&tool); + let mut cmd = BootstrapCommand::new(&tool); cmd.arg("spawn-emulator").arg(target.triple).arg(&server).arg(builder.tempdir()); if let Some(rootfs) = builder.qemu_rootfs(target) { cmd.arg(rootfs); } - builder.run(&mut cmd); + builder.run(cmd); // Push all our dylibs to the emulator for f in t!(builder.sysroot_libdir(compiler, target).read_dir()) { let f = t!(f); let name = f.file_name().into_string().unwrap(); if helpers::is_dylib(&name) { - builder.run(Command::new(&tool).arg("push").arg(f.path())); + builder.run(BootstrapCommand::new(&tool).arg("push").arg(f.path())); } } } @@ -2924,20 +2921,20 @@ impl Step for Distcheck { builder.ensure(dist::PlainSourceTarball); builder.ensure(dist::Src); - let mut cmd = Command::new("tar"); + let mut cmd = BootstrapCommand::new("tar"); cmd.arg("-xf") .arg(builder.ensure(dist::PlainSourceTarball).tarball()) .arg("--strip-components=1") .current_dir(&dir); - builder.run(&mut cmd); + builder.run(cmd); builder.run( - Command::new("./configure") + BootstrapCommand::new("./configure") .args(&builder.config.configure_args) .arg("--enable-vendor") .current_dir(&dir), ); builder.run( - Command::new(helpers::make(&builder.config.build.triple)) + BootstrapCommand::new(helpers::make(&builder.config.build.triple)) .arg("check") .current_dir(&dir), ); @@ -2948,16 +2945,16 @@ impl Step for Distcheck { let _ = fs::remove_dir_all(&dir); t!(fs::create_dir_all(&dir)); - let mut cmd = Command::new("tar"); + let mut cmd = BootstrapCommand::new("tar"); cmd.arg("-xf") .arg(builder.ensure(dist::Src).tarball()) .arg("--strip-components=1") .current_dir(&dir); - builder.run(&mut cmd); + builder.run(cmd); let toml = dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml"); builder.run( - Command::new(&builder.initial_cargo) + BootstrapCommand::new(&builder.initial_cargo) // Will read the libstd Cargo.toml // which uses the unstable `public-dependency` feature. .env("RUSTC_BOOTSTRAP", "1") @@ -2983,7 +2980,10 @@ impl Step for Bootstrap { let compiler = builder.compiler(0, host); let _guard = builder.msg(Kind::Test, 0, "bootstrap", host, host); - let mut check_bootstrap = Command::new(builder.python()); + // Some tests require cargo submodule to be present. + builder.build.update_submodule(Path::new("src/tools/cargo")); + + let mut check_bootstrap = BootstrapCommand::new(builder.python()); check_bootstrap .args(["-m", "unittest", "bootstrap_test.py"]) .env("BUILD_DIR", &builder.out) @@ -2991,9 +2991,9 @@ impl Step for Bootstrap { .current_dir(builder.src.join("src/bootstrap/")); // NOTE: we intentionally don't pass test_args here because the args for unittest and cargo test are mutually incompatible. // Use `python -m unittest` manually if you want to pass arguments. - builder.run_tracked(BootstrapCommand::from(&mut check_bootstrap).delay_failure()); + builder.run(check_bootstrap.delay_failure()); - let mut cmd = Command::new(&builder.initial_cargo); + let mut cmd = BootstrapCommand::new(&builder.initial_cargo); cmd.arg("test") .args(["--features", "bootstrap-self-test"]) .current_dir(builder.src.join("src/bootstrap")) @@ -3068,7 +3068,7 @@ impl Step for TierCheck { self.compiler.host, self.compiler.host, ); - builder.run_tracked(BootstrapCommand::from(&mut cargo.into()).delay_failure()); + builder.run(BootstrapCommand::from(cargo).delay_failure()); } } @@ -3144,8 +3144,7 @@ impl Step for RustInstaller { return; } - let mut cmd = - std::process::Command::new(builder.src.join("src/tools/rust-installer/test.sh")); + let mut cmd = BootstrapCommand::new(builder.src.join("src/tools/rust-installer/test.sh")); let tmpdir = testdir(builder, compiler.host).join("rust-installer"); let _ = std::fs::remove_dir_all(&tmpdir); let _ = std::fs::create_dir_all(&tmpdir); @@ -3154,7 +3153,7 @@ impl Step for RustInstaller { cmd.env("CARGO", &builder.initial_cargo); cmd.env("RUSTC", &builder.initial_rustc); cmd.env("TMP_DIR", &tmpdir); - builder.run_tracked(BootstrapCommand::from(&mut cmd).delay_failure()); + builder.run(cmd.delay_failure()); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -3348,8 +3347,7 @@ impl Step for CodegenCranelift { .arg("testsuite.extended_sysroot"); cargo.args(builder.config.test_args()); - let mut cmd: Command = cargo.into(); - builder.run_cmd(BootstrapCommand::from(&mut cmd).fail_fast()); + builder.run(cargo); } } @@ -3474,7 +3472,6 @@ impl Step for CodegenGCC { .arg("--std-tests"); cargo.args(builder.config.test_args()); - let mut cmd: Command = cargo.into(); - builder.run_cmd(BootstrapCommand::from(&mut cmd).fail_fast()); + builder.run(cargo); } } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 7411d0ba2be..b3464043912 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -9,6 +9,7 @@ use crate::core::builder; use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step}; use crate::core::config::TargetSelection; use crate::utils::channel::GitInfo; +use crate::utils::exec::BootstrapCommand; use crate::utils::helpers::output; use crate::utils::helpers::{add_dylib_path, exe, t}; use crate::Compiler; @@ -336,6 +337,7 @@ bootstrap_tool!( GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys"; RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = "test"; CoverageDump, "src/tools/coverage-dump", "coverage-dump"; + RustcPerfWrapper, "src/tools/rustc-perf-wrapper", "rustc-perf-wrapper"; ); #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -432,12 +434,12 @@ pub struct ErrorIndex { } impl ErrorIndex { - pub fn command(builder: &Builder<'_>) -> Command { + pub fn command(builder: &Builder<'_>) -> BootstrapCommand { // Error-index-generator links with the rustdoc library, so we need to add `rustc_lib_paths` // for rustc_private and libLLVM.so, and `sysroot_lib` for libstd, etc. let host = builder.config.build; let compiler = builder.compiler_for(builder.top_stage, host, host); - let mut cmd = Command::new(builder.ensure(ErrorIndex { compiler })); + let mut cmd = BootstrapCommand::new(builder.ensure(ErrorIndex { compiler })); let mut dylib_paths = builder.rustc_lib_paths(compiler); dylib_paths.push(PathBuf::from(&builder.sysroot_libdir(compiler, compiler.host))); add_dylib_path(dylib_paths, &mut cmd); @@ -551,24 +553,23 @@ impl Step for Rustdoc { return builder.initial_rustc.with_file_name(exe("rustdoc", target_compiler.host)); } let target = target_compiler.host; - // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise - // we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage - // compilers, which isn't what we want. Rustdoc should be linked in the same way as the - // rustc compiler it's paired with, so it must be built with the previous stage compiler. - let build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build); + + let build_compiler = if builder.download_rustc() && target_compiler.stage == 1 { + // We already have the stage 1 compiler, we don't need to cut the stage. + builder.compiler(target_compiler.stage, builder.config.build) + } else { + // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise + // we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage + // compilers, which isn't what we want. Rustdoc should be linked in the same way as the + // rustc compiler it's paired with, so it must be built with the previous stage compiler. + builder.compiler(target_compiler.stage - 1, builder.config.build) + }; // When using `download-rustc` and a stage0 build_compiler, copying rustc doesn't actually // build stage0 libstd (because the libstd in sysroot has the wrong ABI). Explicitly build // it. builder.ensure(compile::Std::new(build_compiler, target_compiler.host)); builder.ensure(compile::Rustc::new(build_compiler, target_compiler.host)); - // NOTE: this implies that `download-rustc` is pretty useless when compiling with the stage0 - // compiler, since you do just as much work. - if !builder.config.dry_run() && builder.download_rustc() && build_compiler.stage == 0 { - println!( - "WARNING: `download-rustc` does nothing when building stage1 tools; consider using `--stage 2` instead" - ); - } // The presence of `target_compiler` ensures that the necessary libraries (codegen backends, // compiler libraries, ...) are built. Rustdoc does not require the presence of any @@ -602,7 +603,7 @@ impl Step for Rustdoc { &self.compiler.host, &target, ); - builder.run(&mut cargo.into()); + builder.run(cargo); // Cargo adds a number of paths to the dylib search path on windows, which results in // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool" @@ -657,6 +658,8 @@ impl Step for Cargo { } fn run(self, builder: &Builder<'_>) -> PathBuf { + builder.build.update_submodule(Path::new("src/tools/cargo")); + builder.ensure(ToolBuild { compiler: self.compiler, target: self.target, @@ -855,7 +858,7 @@ impl Step for LlvmBitcodeLinker { &self.extra_features, ); - builder.run(&mut cargo.into()); + builder.run(cargo); let tool_out = builder .cargo_out(self.compiler, Mode::ToolRustc, self.target) @@ -910,13 +913,13 @@ impl Step for LibcxxVersionTool { } let compiler = builder.cxx(self.target).unwrap(); - let mut cmd = Command::new(compiler); + let mut cmd = BootstrapCommand::new(compiler); cmd.arg("-o") .arg(&executable) .arg(builder.src.join("src/tools/libcxx-version/main.cpp")); - builder.run_cmd(&mut cmd); + builder.run(cmd); if !executable.exists() { panic!("Something went wrong. {} is not present", executable.display()); @@ -1044,10 +1047,10 @@ tool_extended!((self, builder), ); impl<'a> Builder<'a> { - /// Gets a `Command` which is ready to run `tool` in `stage` built for + /// Gets a `BootstrapCommand` which is ready to run `tool` in `stage` built for /// `host`. - pub fn tool_cmd(&self, tool: Tool) -> Command { - let mut cmd = Command::new(self.tool_exe(tool)); + pub fn tool_cmd(&self, tool: Tool) -> BootstrapCommand { + let mut cmd = BootstrapCommand::new(self.tool_exe(tool)); let compiler = self.compiler(0, self.config.build); let host = &compiler.host; // Prepares the `cmd` provided to be able to run the `compiler` provided. diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs index 68f1b1bef3f..0b999a24a1f 100644 --- a/src/bootstrap/src/core/build_steps/vendor.rs +++ b/src/bootstrap/src/core/build_steps/vendor.rs @@ -1,6 +1,6 @@ use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; -use std::path::PathBuf; -use std::process::Command; +use crate::utils::exec::BootstrapCommand; +use std::path::{Path, PathBuf}; #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub(crate) struct Vendor { @@ -27,13 +27,16 @@ impl Step for Vendor { } fn run(self, builder: &Builder<'_>) -> Self::Output { - let mut cmd = Command::new(&builder.initial_cargo); + let mut cmd = BootstrapCommand::new(&builder.initial_cargo); cmd.arg("vendor"); if self.versioned_dirs { cmd.arg("--versioned-dirs"); } + // cargo submodule must be present for `x vendor` to work. + builder.build.update_submodule(Path::new("src/tools/cargo")); + // Sync these paths by default. for p in [ "src/tools/cargo/Cargo.toml", @@ -56,6 +59,6 @@ impl Step for Vendor { cmd.current_dir(self.root_dir); - builder.run(&mut cmd); + builder.run(cmd); } } diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 14ccbfe0267..58d6e7a58e3 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -24,6 +24,7 @@ use crate::utils::helpers::{check_cfg_arg, libdir, linker_flags, output, t, LldT use crate::EXTRA_CHECK_CFGS; use crate::{Build, CLang, Crate, DocTests, GitRepo, Mode}; +use crate::utils::exec::BootstrapCommand; pub use crate::Compiler; use clap::ValueEnum; @@ -1217,7 +1218,7 @@ impl<'a> Builder<'a> { /// Adds the compiler's directory of dynamic libraries to `cmd`'s dynamic /// library lookup path. - pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Command) { + pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut BootstrapCommand) { // Windows doesn't need dylib path munging because the dlls for the // compiler live next to the compiler and the system will find them // automatically. @@ -1250,11 +1251,11 @@ impl<'a> Builder<'a> { self.ensure(tool::Rustdoc { compiler }) } - pub fn cargo_clippy_cmd(&self, run_compiler: Compiler) -> Command { + pub fn cargo_clippy_cmd(&self, run_compiler: Compiler) -> BootstrapCommand { if run_compiler.stage == 0 { // `ensure(Clippy { stage: 0 })` *builds* clippy with stage0, it doesn't use the beta clippy. let cargo_clippy = self.build.config.download_clippy(); - let mut cmd = Command::new(cargo_clippy); + let mut cmd = BootstrapCommand::new(cargo_clippy); cmd.env("CARGO", &self.initial_cargo); return cmd; } @@ -1273,13 +1274,13 @@ impl<'a> Builder<'a> { let mut dylib_path = helpers::dylib_path(); dylib_path.insert(0, self.sysroot(run_compiler).join("lib")); - let mut cmd = Command::new(cargo_clippy); + let mut cmd = BootstrapCommand::new(cargo_clippy); cmd.env(helpers::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); cmd.env("CARGO", &self.initial_cargo); cmd } - pub fn cargo_miri_cmd(&self, run_compiler: Compiler) -> Command { + pub fn cargo_miri_cmd(&self, run_compiler: Compiler) -> BootstrapCommand { assert!(run_compiler.stage > 0, "miri can not be invoked at stage 0"); let build_compiler = self.compiler(run_compiler.stage - 1, self.build.build); @@ -1295,7 +1296,7 @@ impl<'a> Builder<'a> { extra_features: Vec::new(), }); // Invoke cargo-miri, make sure it can find miri and cargo. - let mut cmd = Command::new(cargo_miri); + let mut cmd = BootstrapCommand::new(cargo_miri); cmd.env("MIRI", &miri); cmd.env("CARGO", &self.initial_cargo); // Need to add the `run_compiler` libs. Those are the libs produces *by* `build_compiler`, @@ -1310,8 +1311,8 @@ impl<'a> Builder<'a> { cmd } - pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command { - let mut cmd = Command::new(self.bootstrap_out.join("rustdoc")); + pub fn rustdoc_cmd(&self, compiler: Compiler) -> BootstrapCommand { + let mut cmd = BootstrapCommand::new(self.bootstrap_out.join("rustdoc")); cmd.env("RUSTC_STAGE", compiler.stage.to_string()) .env("RUSTC_SYSROOT", self.sysroot(compiler)) // Note that this is *not* the sysroot_libdir because rustdoc must be linked @@ -1352,7 +1353,7 @@ impl<'a> Builder<'a> { mode: Mode, target: TargetSelection, cmd: &str, // FIXME make this properly typed - ) -> Command { + ) -> BootstrapCommand { let mut cargo; if cmd == "clippy" { cargo = self.cargo_clippy_cmd(compiler); @@ -1365,7 +1366,7 @@ impl<'a> Builder<'a> { cargo = self.cargo_miri_cmd(compiler); cargo.arg("miri").arg(subcmd); } else { - cargo = Command::new(&self.initial_cargo); + cargo = BootstrapCommand::new(&self.initial_cargo); cargo.arg(cmd); } @@ -2104,7 +2105,7 @@ impl<'a> Builder<'a> { // Try to use a sysroot-relative bindir, in case it was configured absolutely. cargo.env("RUSTC_INSTALL_BINDIR", self.config.bindir_relative()); - self.ci_env.force_coloring_in_ci(&mut cargo); + self.ci_env.force_coloring_in_ci(&mut cargo.command); // When we build Rust dylibs they're all intended for intermediate // usage, so make sure we pass the -Cprefer-dynamic flag instead of @@ -2373,7 +2374,7 @@ impl HostFlags { #[derive(Debug)] pub struct Cargo { - command: Command, + command: BootstrapCommand, compiler: Compiler, target: TargetSelection, rustflags: Rustflags, @@ -2598,8 +2599,8 @@ impl Cargo { } } -impl From<Cargo> for Command { - fn from(mut cargo: Cargo) -> Command { +impl From<Cargo> for BootstrapCommand { + fn from(mut cargo: Cargo) -> BootstrapCommand { let rustflags = &cargo.rustflags.0; if !rustflags.is_empty() { cargo.command.env("RUSTFLAGS", rustflags); @@ -2618,7 +2619,12 @@ impl From<Cargo> for Command { if !cargo.allow_features.is_empty() { cargo.command.env("RUSTC_ALLOW_FEATURES", cargo.allow_features); } - cargo.command } } + +impl From<Cargo> for Command { + fn from(cargo: Cargo) -> Command { + BootstrapCommand::from(cargo).command + } +} diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index eb5152a3831..aeb608a9ea2 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -470,7 +470,9 @@ Arguments: versioned_dirs: bool, }, /// Perform profiling and benchmarking of the compiler using the - /// `rustc-perf` benchmark suite. + /// `rustc-perf-wrapper` tool. + /// + /// You need to pass arguments after `--`, e.g.`x perf -- cachegrind`. Perf {}, } diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 2b11b8c3d4f..c35398e2eb7 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -11,6 +11,7 @@ use std::{ use build_helper::ci::CiEnv; use xz2::bufread::XzDecoder; +use crate::utils::exec::BootstrapCommand; use crate::utils::helpers::hex_encode; use crate::utils::helpers::{check_run, exe, move_file, program_out_of_date}; use crate::{t, Config}; @@ -56,7 +57,7 @@ impl Config { /// Runs a command, printing out nice contextual information if it fails. /// Returns false if do not execute at all, otherwise returns its /// `status.success()`. - pub(crate) fn check_run(&self, cmd: &mut Command) -> bool { + pub(crate) fn check_run(&self, cmd: &mut BootstrapCommand) -> bool { if self.dry_run() { return true; } @@ -173,15 +174,10 @@ impl Config { } let mut patchelf = Command::new(nix_deps_dir.join("bin/patchelf")); - let rpath_entries = { - // ORIGIN is a relative default, all binary and dynamic libraries we ship - // appear to have this (even when `../lib` is redundant). - // NOTE: there are only two paths here, delimited by a `:` - let mut entries = OsString::from("$ORIGIN/../lib:"); - entries.push(t!(fs::canonicalize(nix_deps_dir)).join("lib")); - entries - }; - patchelf.args(&[OsString::from("--set-rpath"), rpath_entries]); + patchelf.args(&[ + OsString::from("--add-rpath"), + OsString::from(t!(fs::canonicalize(nix_deps_dir)).join("lib")), + ]); if !path_is_dylib(fname) { // Finally, set the correct .interp for binaries let dynamic_linker_path = nix_deps_dir.join("nix-support/dynamic-linker"); @@ -216,7 +212,7 @@ impl Config { fn download_http_with_retries(&self, tempfile: &Path, url: &str, help_on_error: &str) { println!("downloading {url}"); // Try curl. If that fails and we are on windows, fallback to PowerShell. - let mut curl = Command::new("curl"); + let mut curl = BootstrapCommand::new("curl"); curl.args([ "-y", "30", diff --git a/src/bootstrap/src/core/metadata.rs b/src/bootstrap/src/core/metadata.rs index 08a96407a69..220eb5ba126 100644 --- a/src/bootstrap/src/core/metadata.rs +++ b/src/bootstrap/src/core/metadata.rs @@ -67,9 +67,9 @@ pub fn build(build: &mut Build) { /// Invokes `cargo metadata` to get package metadata of each workspace member. /// -/// Note that `src/tools/cargo` is no longer a workspace member but we still -/// treat it as one here, by invoking an additional `cargo metadata` command. -fn workspace_members(build: &Build) -> impl Iterator<Item = Package> { +/// This is used to resolve specific crate paths in `fn should_run` to compile +/// particular crate (e.g., `x build sysroot` to build library/sysroot). +fn workspace_members(build: &Build) -> Vec<Package> { let collect_metadata = |manifest_path| { let mut cargo = Command::new(&build.initial_cargo); cargo @@ -88,13 +88,5 @@ fn workspace_members(build: &Build) -> impl Iterator<Item = Package> { }; // Collects `metadata.packages` from all workspaces. - let packages = collect_metadata("Cargo.toml"); - let cargo_packages = collect_metadata("src/tools/cargo/Cargo.toml"); - let ra_packages = collect_metadata("src/tools/rust-analyzer/Cargo.toml"); - let bootstrap_packages = collect_metadata("src/bootstrap/Cargo.toml"); - - // We only care about the root package from `src/tool/cargo` workspace. - let cargo_package = cargo_packages.into_iter().find(|pkg| pkg.name == "cargo").into_iter(); - - packages.into_iter().chain(cargo_package).chain(ra_packages).chain(bootstrap_packages) + collect_metadata("Cargo.toml") } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index dfc30298c28..730d0ae5f3d 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -469,8 +469,7 @@ impl Build { // Make sure we update these before gathering metadata so we don't get an error about missing // Cargo.toml files. - let rust_submodules = - ["src/tools/cargo", "src/doc/book", "library/backtrace", "library/stdarch"]; + let rust_submodules = ["src/doc/book", "library/backtrace", "library/stdarch"]; for s in rust_submodules { build.update_submodule(Path::new(s)); } @@ -576,19 +575,17 @@ impl Build { }; // NOTE: doesn't use `try_run` because this shouldn't print an error if it fails. if !update(true).status().map_or(false, |status| status.success()) { - self.run(&mut update(false)); + self.run(update(false)); } // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error). // diff-index reports the modifications through the exit status - let has_local_modifications = !self.run_cmd( - BootstrapCommand::from(submodule_git().args(["diff-index", "--quiet", "HEAD"])) - .allow_failure() - .output_mode(match self.is_verbose() { - true => OutputMode::All, - false => OutputMode::OnlyOutput, - }), - ); + let has_local_modifications = self + .run( + BootstrapCommand::from(submodule_git().args(["diff-index", "--quiet", "HEAD"])) + .allow_failure(), + ) + .is_failure(); if has_local_modifications { self.run(submodule_git().args(["stash", "push"])); } @@ -940,7 +937,7 @@ impl Build { } /// Adds the `RUST_TEST_THREADS` env var if necessary - fn add_rust_test_threads(&self, cmd: &mut Command) { + fn add_rust_test_threads(&self, cmd: &mut BootstrapCommand) { if env::var_os("RUST_TEST_THREADS").is_none() { cmd.env("RUST_TEST_THREADS", self.jobs().to_string()); } @@ -962,11 +959,14 @@ impl Build { } /// Execute a command and return its output. - fn run_tracked(&self, command: BootstrapCommand<'_>) -> CommandOutput { + /// This method should be used for all command executions in bootstrap. + fn run<C: Into<BootstrapCommand>>(&self, command: C) -> CommandOutput { if self.config.dry_run() { return CommandOutput::default(); } + let mut command = command.into(); + self.verbose(|| println!("running: {command:?}")); let output_mode = command.output_mode.unwrap_or_else(|| match self.is_verbose() { @@ -1025,22 +1025,6 @@ impl Build { output } - /// Runs a command, printing out nice contextual information if it fails. - fn run(&self, cmd: &mut Command) { - self.run_cmd(BootstrapCommand::from(cmd).fail_fast().output_mode( - match self.is_verbose() { - true => OutputMode::All, - false => OutputMode::OnlyOutput, - }, - )); - } - - /// A centralized function for running commands that do not return output. - pub(crate) fn run_cmd<'a, C: Into<BootstrapCommand<'a>>>(&self, cmd: C) -> bool { - let command = cmd.into(); - self.run_tracked(command).is_success() - } - /// Check if verbosity is greater than the `level` pub fn is_verbose_than(&self, level: usize) -> bool { self.verbosity > level diff --git a/src/bootstrap/src/utils/bin_helpers.rs b/src/bootstrap/src/utils/bin_helpers.rs deleted file mode 100644 index 5fbbe0bde0e..00000000000 --- a/src/bootstrap/src/utils/bin_helpers.rs +++ /dev/null @@ -1,50 +0,0 @@ -//! This file is meant to be included directly from bootstrap shims to avoid a -//! dependency on the bootstrap library. This reduces the binary size and -//! improves compilation time by reducing the linking time. - -use std::env; -use std::fs::OpenOptions; -use std::io::Write; -use std::process::Command; -use std::str::FromStr; - -/// Parses the value of the "RUSTC_VERBOSE" environment variable and returns it as a `usize`. -/// If it was not defined, returns 0 by default. -/// -/// Panics if "RUSTC_VERBOSE" is defined with the value that is not an unsigned integer. -pub(crate) fn parse_rustc_verbose() -> usize { - match env::var("RUSTC_VERBOSE") { - Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"), - Err(_) => 0, - } -} - -/// Parses the value of the "RUSTC_STAGE" environment variable and returns it as a `String`. -/// -/// If "RUSTC_STAGE" was not set, the program will be terminated with 101. -pub(crate) fn parse_rustc_stage() -> String { - env::var("RUSTC_STAGE").unwrap_or_else(|_| { - // Don't panic here; it's reasonable to try and run these shims directly. Give a helpful error instead. - eprintln!("rustc shim: FATAL: RUSTC_STAGE was not set"); - eprintln!("rustc shim: NOTE: use `x.py build -vvv` to see all environment variables set by bootstrap"); - std::process::exit(101); - }) -} - -/// Writes the command invocation to a file if `DUMP_BOOTSTRAP_SHIMS` is set during bootstrap. -/// -/// Before writing it, replaces user-specific values to create generic dumps for cross-environment -/// comparisons. -pub(crate) fn maybe_dump(dump_name: String, cmd: &Command) { - if let Ok(dump_dir) = env::var("DUMP_BOOTSTRAP_SHIMS") { - let dump_file = format!("{dump_dir}/{dump_name}"); - - let mut file = OpenOptions::new().create(true).append(true).open(dump_file).unwrap(); - - let cmd_dump = format!("{:?}\n", cmd); - let cmd_dump = cmd_dump.replace(&env::var("BUILD_OUT").unwrap(), "${BUILD_OUT}"); - let cmd_dump = cmd_dump.replace(&env::var("CARGO_HOME").unwrap(), "${CARGO_HOME}"); - - file.write_all(cmd_dump.as_bytes()).expect("Unable to write file"); - } -} diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index bfe3622e40d..ccab25e55a9 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -195,4 +195,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "Removed `dist.missing-tools` configuration as it was deprecated long time ago.", }, + ChangeInfo { + change_id: 126701, + severity: ChangeSeverity::Warning, + summary: "`llvm.lld` is enabled by default for the dist profile. If set to false, `lld` will not be included in the dist build.", + }, ]; diff --git a/src/bootstrap/src/utils/dylib.rs b/src/bootstrap/src/utils/dylib.rs deleted file mode 100644 index 90bcff59a64..00000000000 --- a/src/bootstrap/src/utils/dylib.rs +++ /dev/null @@ -1,40 +0,0 @@ -//! Various utilities for working with dylib paths. - -/// Returns the environment variable which the dynamic library lookup path -/// resides in for this platform. -pub fn dylib_path_var() -> &'static str { - if cfg!(target_os = "windows") { - "PATH" - } else if cfg!(target_vendor = "apple") { - "DYLD_LIBRARY_PATH" - } else if cfg!(target_os = "haiku") { - "LIBRARY_PATH" - } else if cfg!(target_os = "aix") { - "LIBPATH" - } else { - "LD_LIBRARY_PATH" - } -} - -/// Parses the `dylib_path_var()` environment variable, returning a list of -/// paths that are members of this lookup path. -pub fn dylib_path() -> Vec<std::path::PathBuf> { - let var = match std::env::var_os(dylib_path_var()) { - Some(v) => v, - None => return vec![], - }; - std::env::split_paths(&var).collect() -} - -/// Given an executable called `name`, return the filename for the -/// executable for a particular target. -#[allow(dead_code)] -pub fn exe(name: &str, target: &str) -> String { - if target.contains("windows") { - format!("{name}.exe") - } else if target.contains("uefi") { - format!("{name}.efi") - } else { - name.to_string() - } -} diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index e8c588b75b3..8bcb2301f1a 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -1,4 +1,6 @@ -use std::process::{Command, ExitStatus, Output}; +use std::ffi::OsStr; +use std::path::Path; +use std::process::{Command, CommandArgs, CommandEnvs, ExitStatus, Output}; /// What should be done when the command fails. #[derive(Debug, Copy, Clone)] @@ -24,14 +26,71 @@ pub enum OutputMode { } /// Wrapper around `std::process::Command`. +/// +/// By default, the command will exit bootstrap if it fails. +/// If you want to allow failures, use [allow_failure]. +/// If you want to delay failures until the end of bootstrap, use [delay_failure]. +/// +/// By default, the command will print its stdout/stderr to stdout/stderr of bootstrap +/// ([OutputMode::OnlyOutput]). If bootstrap uses verbose mode, then it will also print the +/// command itself in case of failure ([OutputMode::All]). +/// If you want to handle the output programmatically, use `output_mode(OutputMode::OnlyOnFailure)`. +/// +/// [allow_failure]: BootstrapCommand::allow_failure +/// [delay_failure]: BootstrapCommand::delay_failure #[derive(Debug)] -pub struct BootstrapCommand<'a> { - pub command: &'a mut Command, +pub struct BootstrapCommand { + pub command: Command, pub failure_behavior: BehaviorOnFailure, pub output_mode: Option<OutputMode>, } -impl<'a> BootstrapCommand<'a> { +impl BootstrapCommand { + pub fn new<S: AsRef<OsStr>>(program: S) -> Self { + Command::new(program).into() + } + + pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self { + self.command.arg(arg.as_ref()); + self + } + + pub fn args<I, S>(&mut self, args: I) -> &mut Self + where + I: IntoIterator<Item = S>, + S: AsRef<OsStr>, + { + self.command.args(args); + self + } + + pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Self + where + K: AsRef<OsStr>, + V: AsRef<OsStr>, + { + self.command.env(key, val); + self + } + + pub fn get_envs(&self) -> CommandEnvs<'_> { + self.command.get_envs() + } + + pub fn get_args(&self) -> CommandArgs<'_> { + self.command.get_args() + } + + pub fn env_remove<K: AsRef<OsStr>>(&mut self, key: K) -> &mut Self { + self.command.env_remove(key); + self + } + + pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Self { + self.command.current_dir(dir); + self + } + pub fn delay_failure(self) -> Self { Self { failure_behavior: BehaviorOnFailure::DelayFail, ..self } } @@ -54,8 +113,41 @@ impl<'a> BootstrapCommand<'a> { } } -impl<'a> From<&'a mut Command> for BootstrapCommand<'a> { +/// This implementation is temporary, until all `Command` invocations are migrated to +/// `BootstrapCommand`. +impl<'a> From<&'a mut Command> for BootstrapCommand { fn from(command: &'a mut Command) -> Self { + // This is essentially a manual `Command::clone` + let mut cmd = Command::new(command.get_program()); + if let Some(dir) = command.get_current_dir() { + cmd.current_dir(dir); + } + cmd.args(command.get_args()); + for (key, value) in command.get_envs() { + match value { + Some(value) => { + cmd.env(key, value); + } + None => { + cmd.env_remove(key); + } + } + } + + cmd.into() + } +} + +/// This implementation is temporary, until all `Command` invocations are migrated to +/// `BootstrapCommand`. +impl<'a> From<&'a mut BootstrapCommand> for BootstrapCommand { + fn from(command: &'a mut BootstrapCommand) -> Self { + BootstrapCommand::from(&mut command.command) + } +} + +impl From<Command> for BootstrapCommand { + fn from(command: Command) -> Self { Self { command, failure_behavior: BehaviorOnFailure::Exit, output_mode: None } } } diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 59b29eedb79..adf18c0ace1 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -18,7 +18,7 @@ use crate::core::builder::Builder; use crate::core::config::{Config, TargetSelection}; use crate::LldMode; -pub use crate::utils::dylib::{dylib_path, dylib_path_var}; +pub use crate::utils::shared_helpers::{dylib_path, dylib_path_var}; #[cfg(test)] mod tests; @@ -47,10 +47,11 @@ macro_rules! t { } }; } +use crate::utils::exec::BootstrapCommand; pub use t; pub fn exe(name: &str, target: TargetSelection) -> String { - crate::utils::dylib::exe(name, &target.triple) + crate::utils::shared_helpers::exe(name, &target.triple) } /// Returns `true` if the file name given looks like a dynamic library. @@ -72,7 +73,7 @@ pub fn libdir(target: TargetSelection) -> &'static str { /// Adds a list of lookup paths to `cmd`'s dynamic library lookup path. /// If the dylib_path_var is already set for this cmd, the old value will be overwritten! -pub fn add_dylib_path(path: Vec<PathBuf>, cmd: &mut Command) { +pub fn add_dylib_path(path: Vec<PathBuf>, cmd: &mut BootstrapCommand) { let mut list = dylib_path(); for path in path { list.insert(0, path); @@ -81,7 +82,7 @@ pub fn add_dylib_path(path: Vec<PathBuf>, cmd: &mut Command) { } /// Adds a list of lookup paths to `cmd`'s link library lookup path. -pub fn add_link_lib_path(path: Vec<PathBuf>, cmd: &mut Command) { +pub fn add_link_lib_path(path: Vec<PathBuf>, cmd: &mut BootstrapCommand) { let mut list = link_lib_path(); for path in path { list.insert(0, path); @@ -241,8 +242,9 @@ pub fn is_valid_test_suite_arg<'a, P: AsRef<Path>>( } } -pub fn check_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { - let status = match cmd.status() { +// FIXME: get rid of this function +pub fn check_run(cmd: &mut BootstrapCommand, print_cmd_on_fail: bool) -> bool { + let status = match cmd.command.status() { Ok(status) => status, Err(e) => { println!("failed to execute command: {cmd:?}\nERROR: {e}"); @@ -437,7 +439,7 @@ pub fn linker_flags( } pub fn add_rustdoc_cargo_linker_args( - cmd: &mut Command, + cmd: &mut BootstrapCommand, builder: &Builder<'_>, target: TargetSelection, lld_threads: LldThreads, diff --git a/src/bootstrap/src/utils/mod.rs b/src/bootstrap/src/utils/mod.rs index cb535f0e163..53b41f15780 100644 --- a/src/bootstrap/src/utils/mod.rs +++ b/src/bootstrap/src/utils/mod.rs @@ -6,11 +6,11 @@ pub(crate) mod cache; pub(crate) mod cc_detect; pub(crate) mod change_tracker; pub(crate) mod channel; -pub(crate) mod dylib; pub(crate) mod exec; pub(crate) mod helpers; pub(crate) mod job; #[cfg(feature = "build-metrics")] pub(crate) mod metrics; pub(crate) mod render_tests; +pub(crate) mod shared_helpers; pub(crate) mod tarball; diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index 5c9918bce32..2e99bc68a8b 100644 --- a/src/bootstrap/src/utils/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -7,14 +7,18 @@ //! to reimplement all the rendering logic in this module because of that. use crate::core::builder::Builder; +use crate::utils::exec::BootstrapCommand; use std::io::{BufRead, BufReader, Read, Write}; -use std::process::{ChildStdout, Command, Stdio}; +use std::process::{ChildStdout, Stdio}; use std::time::Duration; use termcolor::{Color, ColorSpec, WriteColor}; const TERSE_TESTS_PER_LINE: usize = 88; -pub(crate) fn add_flags_and_try_run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { +pub(crate) fn add_flags_and_try_run_tests( + builder: &Builder<'_>, + cmd: &mut BootstrapCommand, +) -> bool { if !cmd.get_args().any(|arg| arg == "--") { cmd.arg("--"); } @@ -23,7 +27,11 @@ pub(crate) fn add_flags_and_try_run_tests(builder: &Builder<'_>, cmd: &mut Comma try_run_tests(builder, cmd, false) } -pub(crate) fn try_run_tests(builder: &Builder<'_>, cmd: &mut Command, stream: bool) -> bool { +pub(crate) fn try_run_tests( + builder: &Builder<'_>, + cmd: &mut BootstrapCommand, + stream: bool, +) -> bool { if builder.config.dry_run() { return true; } @@ -41,7 +49,8 @@ pub(crate) fn try_run_tests(builder: &Builder<'_>, cmd: &mut Command, stream: bo } } -fn run_tests(builder: &Builder<'_>, cmd: &mut Command, stream: bool) -> bool { +fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) -> bool { + let cmd = &mut cmd.command; cmd.stdout(Stdio::piped()); builder.verbose(|| println!("running: {cmd:?}")); diff --git a/src/bootstrap/src/utils/shared_helpers.rs b/src/bootstrap/src/utils/shared_helpers.rs new file mode 100644 index 00000000000..7150c84313c --- /dev/null +++ b/src/bootstrap/src/utils/shared_helpers.rs @@ -0,0 +1,112 @@ +//! This module serves two purposes: +//! 1. It is part of the `utils` module and used in other parts of bootstrap. +//! 2. It is embedded inside bootstrap shims to avoid a dependency on the bootstrap library. +//! Therefore, this module should never use any other bootstrap module. This reduces binary +//! size and improves compilation time by minimizing linking time. + +#![allow(dead_code)] + +use std::env; +use std::ffi::OsString; +use std::fs::OpenOptions; +use std::io::Write; +use std::process::Command; +use std::str::FromStr; + +#[cfg(test)] +mod tests; + +/// Returns the environment variable which the dynamic library lookup path +/// resides in for this platform. +pub fn dylib_path_var() -> &'static str { + if cfg!(target_os = "windows") { + "PATH" + } else if cfg!(target_vendor = "apple") { + "DYLD_LIBRARY_PATH" + } else if cfg!(target_os = "haiku") { + "LIBRARY_PATH" + } else if cfg!(target_os = "aix") { + "LIBPATH" + } else { + "LD_LIBRARY_PATH" + } +} + +/// Parses the `dylib_path_var()` environment variable, returning a list of +/// paths that are members of this lookup path. +pub fn dylib_path() -> Vec<std::path::PathBuf> { + let var = match std::env::var_os(dylib_path_var()) { + Some(v) => v, + None => return vec![], + }; + std::env::split_paths(&var).collect() +} + +/// Given an executable called `name`, return the filename for the +/// executable for a particular target. +pub fn exe(name: &str, target: &str) -> String { + if target.contains("windows") { + format!("{name}.exe") + } else if target.contains("uefi") { + format!("{name}.efi") + } else { + name.to_string() + } +} + +/// Parses the value of the "RUSTC_VERBOSE" environment variable and returns it as a `usize`. +/// If it was not defined, returns 0 by default. +/// +/// Panics if "RUSTC_VERBOSE" is defined with the value that is not an unsigned integer. +pub fn parse_rustc_verbose() -> usize { + match env::var("RUSTC_VERBOSE") { + Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"), + Err(_) => 0, + } +} + +/// Parses the value of the "RUSTC_STAGE" environment variable and returns it as a `String`. +/// +/// If "RUSTC_STAGE" was not set, the program will be terminated with 101. +pub fn parse_rustc_stage() -> String { + env::var("RUSTC_STAGE").unwrap_or_else(|_| { + // Don't panic here; it's reasonable to try and run these shims directly. Give a helpful error instead. + eprintln!("rustc shim: FATAL: RUSTC_STAGE was not set"); + eprintln!("rustc shim: NOTE: use `x.py build -vvv` to see all environment variables set by bootstrap"); + std::process::exit(101); + }) +} + +/// Writes the command invocation to a file if `DUMP_BOOTSTRAP_SHIMS` is set during bootstrap. +/// +/// Before writing it, replaces user-specific values to create generic dumps for cross-environment +/// comparisons. +pub fn maybe_dump(dump_name: String, cmd: &Command) { + if let Ok(dump_dir) = env::var("DUMP_BOOTSTRAP_SHIMS") { + let dump_file = format!("{dump_dir}/{dump_name}"); + + let mut file = OpenOptions::new().create(true).append(true).open(dump_file).unwrap(); + + let cmd_dump = format!("{:?}\n", cmd); + let cmd_dump = cmd_dump.replace(&env::var("BUILD_OUT").unwrap(), "${BUILD_OUT}"); + let cmd_dump = cmd_dump.replace(&env::var("CARGO_HOME").unwrap(), "${CARGO_HOME}"); + + file.write_all(cmd_dump.as_bytes()).expect("Unable to write file"); + } +} + +/// Finds `key` and returns its value from the given list of arguments `args`. +pub fn parse_value_from_args<'a>(args: &'a [OsString], key: &str) -> Option<&'a str> { + let mut args = args.iter(); + while let Some(arg) = args.next() { + let arg = arg.to_str().unwrap(); + + if let Some(value) = arg.strip_prefix(&format!("{key}=")) { + return Some(value); + } else if arg == key { + return args.next().map(|v| v.to_str().unwrap()); + } + } + + None +} diff --git a/src/bootstrap/src/utils/shared_helpers/tests.rs b/src/bootstrap/src/utils/shared_helpers/tests.rs new file mode 100644 index 00000000000..da7924276f7 --- /dev/null +++ b/src/bootstrap/src/utils/shared_helpers/tests.rs @@ -0,0 +1,28 @@ +use super::parse_value_from_args; + +#[test] +fn test_parse_value_from_args() { + let args = vec![ + "--stage".into(), + "1".into(), + "--version".into(), + "2".into(), + "--target".into(), + "x86_64-unknown-linux".into(), + ]; + + assert_eq!(parse_value_from_args(args.as_slice(), "--stage").unwrap(), "1"); + assert_eq!(parse_value_from_args(args.as_slice(), "--version").unwrap(), "2"); + assert_eq!(parse_value_from_args(args.as_slice(), "--target").unwrap(), "x86_64-unknown-linux"); + assert!(parse_value_from_args(args.as_slice(), "random-key").is_none()); + + let args = vec![ + "app-name".into(), + "--key".into(), + "value".into(), + "random-value".into(), + "--sysroot=/x/y/z".into(), + ]; + assert_eq!(parse_value_from_args(args.as_slice(), "--key").unwrap(), "value"); + assert_eq!(parse_value_from_args(args.as_slice(), "--sysroot").unwrap(), "/x/y/z"); +} diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index fd934f18de2..5cc319826db 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -5,14 +5,12 @@ //! In uplifting, a tarball from Stage N captures essential components //! to assemble Stage N + 1 compiler. -use std::{ - path::{Path, PathBuf}, - process::Command, -}; +use std::path::{Path, PathBuf}; use crate::core::builder::Builder; use crate::core::{build_steps::dist::distdir, builder::Kind}; use crate::utils::channel; +use crate::utils::exec::BootstrapCommand; use crate::utils::helpers::{move_file, t}; #[derive(Copy, Clone)] @@ -300,7 +298,7 @@ impl<'a> Tarball<'a> { } } - fn non_bare_args(&self, cmd: &mut Command) { + fn non_bare_args(&self, cmd: &mut BootstrapCommand) { cmd.arg("--rel-manifest-dir=rustlib") .arg("--legacy-manifest-dirs=rustlib,cargo") .arg(format!("--product-name={}", self.product_name)) @@ -312,7 +310,7 @@ impl<'a> Tarball<'a> { .arg(distdir(self.builder)); } - fn run(self, build_cli: impl FnOnce(&Tarball<'a>, &mut Command)) -> GeneratedTarball { + fn run(self, build_cli: impl FnOnce(&Tarball<'a>, &mut BootstrapCommand)) -> GeneratedTarball { t!(std::fs::create_dir_all(&self.overlay_dir)); self.builder.create(&self.overlay_dir.join("version"), &self.overlay.version(self.builder)); if let Some(info) = self.builder.rust_info().info() { @@ -353,7 +351,7 @@ impl<'a> Tarball<'a> { }; cmd.args(["--compression-profile", compression_profile]); - self.builder.run(&mut cmd); + self.builder.run(cmd); // Ensure there are no symbolic links in the tarball. In particular, // rustup-toolchain-install-master and most versions of Windows can't handle symbolic links. diff --git a/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile index 55c737bd0aa..7e35f781b6b 100644 --- a/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile @@ -25,5 +25,10 @@ ENV CC_loongarch64_unknown_linux_gnu=loongarch64-unknown-linux-gnu-gcc \ ENV HOSTS=loongarch64-unknown-linux-gnu -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs +ENV RUST_CONFIGURE_ARGS \ + --enable-extended \ + --enable-full-tools \ + --enable-profiler \ + --disable-docs + ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile index 560adf971ba..62dbfaaa673 100644 --- a/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile @@ -27,7 +27,8 @@ ENV HOSTS=loongarch64-unknown-linux-musl ENV RUST_CONFIGURE_ARGS \ --enable-extended \ - --enable-lld \ + --enable-full-tools \ + --enable-profiler \ --disable-docs \ --set target.loongarch64-unknown-linux-musl.crt-static=false \ --musl-root-loongarch64=/x-tools/loongarch64-unknown-linux-musl/loongarch64-unknown-linux-musl/sysroot/usr diff --git a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile index 0a49eab4d50..cb17592b201 100644 --- a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile @@ -35,4 +35,4 @@ COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/ # NOTE: intentionally uses python2 for x.py so we can test it still works. # validate-toolstate only runs in our CI, so it's ok for it to only support python3. ENV SCRIPT TIDY_PRINT_DIFF=1 python2.7 ../x.py test \ - --stage 0 src/tools/tidy tidyselftest --extra-checks=py:lint + --stage 0 src/tools/tidy tidyselftest --extra-checks=py:lint,cpp:fmt diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile b/src/ci/docker/host-x86_64/x86_64-fuchsia/Dockerfile index a944f370c6b..ba3e8bdb687 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-fuchsia/Dockerfile @@ -1,5 +1,6 @@ # This job builds a toolchain capable of building Fuchsia, and then builds -# Fuchsia. See the build-fuchsia.sh script in this directory for more details. +# Fuchsia as an integration test of the toolchain. See the build-fuchsia.sh +# script in this directory for more details. FROM ubuntu:22.04 @@ -24,7 +25,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && rm -rf /var/lib/apt/lists/* # Duplicated in dist-various-2 Dockerfile. -# FIXME: Move to canonical triple ENV \ AR_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-ar \ CC_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang \ @@ -48,10 +48,6 @@ ENV CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_RUSTFLAGS \ ENV TARGETS=x86_64-unknown-fuchsia ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnu -ENV TARGETS=$TARGETS,wasm32-unknown-unknown - -# Fuchsia clang does not have wasm target enabled, use system clang. -ENV CC_wasm32_unknown_unknown=clang-15 COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh @@ -76,4 +72,4 @@ ENV RUST_CONFIGURE_ARGS \ --set target.x86_64-unknown-fuchsia.linker=/usr/local/bin/ld.lld ENV SCRIPT \ python3 ../x.py install --target $TARGETS compiler/rustc library/std clippy && \ - bash ../src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh + bash ../src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh b/src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh index 2bb1d0a6338..c806b886dae 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh +++ b/src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh @@ -5,14 +5,14 @@ # # You may run this script locally using Docker with the following command: # -# $ src/ci/docker/run.sh x86_64-gnu-integration +# $ src/ci/docker/run.sh x86_64-fuchsia # # Alternatively, from within the container with --dev, assuming you have made it # as far as building the toolchain with the above command: # -# $ src/ci/docker/run.sh --dev x86_64-gnu-integration +# $ src/ci/docker/run.sh --dev x86_64-fuchsia # docker# git config --global --add safe.directory /checkout/obj/fuchsia -# docker# ../src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh +# docker# ../src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh # # Also see the docs in the rustc-dev-guide for more info: # https://github.com/rust-lang/rustc-dev-guide/pull/1989 @@ -21,7 +21,7 @@ set -euf -o pipefail # Set this variable to 1 to disable updating the Fuchsia checkout. This is # useful for making local changes. You can find the Fuchsia checkout in -# `obj/x86_64-gnu-integration/fuchsia` in your local checkout after running this +# `obj/x86_64-fuchsia/fuchsia` in your local checkout after running this # job for the first time. KEEP_CHECKOUT= @@ -35,7 +35,7 @@ PICK_REFS=() # commit hash of fuchsia.git and some other repos in the "monorepo" checkout, in # addition to versions of prebuilts. It should be bumped regularly by the # Fuchsia team – we aim for every 1-2 months. -INTEGRATION_SHA=737ebdd83afa47b742ca8325fad0176952fcefbd +INTEGRATION_SHA=d1d2f20efe46e22be179953dd6726c96eced54ab checkout=fuchsia jiri=.jiri_root/bin/jiri diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index 50c2e5e29f0..47d04a52883 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.17.2 \ No newline at end of file +0.18.0 \ No newline at end of file diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index e3903c3dd5a..cf750bbd0c5 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -208,6 +208,13 @@ auto: - image: test-various <<: *job-linux-4c + - image: x86_64-fuchsia + # Only run this job on the nightly channel. Fuchsia requires + # nightly features to compile, and this job would fail if + # executed on beta and stable. + only_on_channel: nightly + <<: *job-linux-8c + - image: x86_64-gnu <<: *job-linux-4c @@ -229,13 +236,6 @@ auto: - image: x86_64-gnu-aux <<: *job-linux-4c - - image: x86_64-gnu-integration - # Only run this job on the nightly channel. Fuchsia requires - # nightly features to compile, and this job would fail if - # executed on beta and stable. - only_on_channel: nightly - <<: *job-linux-8c - - image: x86_64-gnu-debug <<: *job-linux-4c diff --git a/src/ci/run.sh b/src/ci/run.sh index efaf70078c4..869f75e923d 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -85,6 +85,10 @@ fi # space required for CI artifacts. RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --dist-compression-formats=xz" +if [ "$EXTERNAL_LLVM" = "1" ]; then + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.lld=false" +fi + # Enable the `c` feature for compiler_builtins, but only when the `compiler-rt` source is available # (to avoid spending a lot of time cloning llvm) if [ "$EXTERNAL_LLVM" = "" ]; then diff --git a/src/doc/rustc/src/lints/levels.md b/src/doc/rustc/src/lints/levels.md index 93892d6ade6..18e827bd3c9 100644 --- a/src/doc/rustc/src/lints/levels.md +++ b/src/doc/rustc/src/lints/levels.md @@ -1,12 +1,13 @@ # Lint Levels -In `rustc`, lints are divided into five *levels*: +In `rustc`, lints are divided into six *levels*: 1. allow -2. warn -3. force-warn -4. deny -5. forbid +2. expect +3. warn +4. force-warn +5. deny +6. forbid Each lint has a default level (explained in the lint listing later in this chapter), and the compiler has a default warning level. First, let's explain @@ -33,6 +34,40 @@ But this code violates the `missing_docs` lint. These lints exist mostly to be manually turned on via configuration, as we'll talk about later in this section. +## expect + +Sometimes, it can be helpful to suppress lints, but at the same time ensure that +the code in question still emits them. The 'expect' level does exactly this. If +the lint in question is not emitted, the `unfulfilled_lint_expectation` lint +triggers on the `expect` attribute, notifying you that the expectation is no +longer fulfilled. + +```rust +fn main() { + #[expect(unused_variables)] + let unused = "Everyone ignores me"; + + #[expect(unused_variables)] // `unused_variables` lint is not emitted + let used = "I'm useful"; // the expectation is therefore unfulfilled + println!("The `used` value is equal to: {:?}", used); +} +``` + +This will produce the following warning: + +```txt +warning: this lint expectation is unfulfilled + --> src/main.rs:7:14 + | +7 | #[expect(unused_variables)] + | ^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unfulfilled_lint_expectations)]` on by default +``` + +This level can only be defined via the `#[expect]` attribute, there is no equivalent +flag. Lints with the special 'force-warn' level will still be emitted as usual. + ## warn The 'warn' lint level will produce a warning if you violate the lint. For example, @@ -240,6 +275,21 @@ And use multiple attributes together: pub fn foo() {} ``` +All lint attributes support an additional `reason` parameter, to give context why +a certain attribute was added. This reason will be displayed as part of the lint +message, if the lint is emitted at the defined level. + +```rust +use std::path::PathBuf; +pub fn get_path() -> PathBuf { + #[allow(unused_mut, reason = "this is only modified on some platforms")] + let mut file_name = PathBuf::from("git"); + #[cfg(target_os = "windows")] + file_name.set_extension("exe"); + file_name +} +``` + ### Capping lints `rustc` supports a flag, `--cap-lints LEVEL` that sets the "lint cap level." diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 71dc8c4ca0f..f5cd4bd217a 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -168,12 +168,12 @@ target | std | notes `i686-unknown-freebsd` | ✓ | 32-bit FreeBSD [^x86_32-floats-return-ABI] `i686-unknown-linux-musl` | ✓ | 32-bit Linux with musl 1.2.3 [^x86_32-floats-return-ABI] [`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 32-bit UEFI -[`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * | | LoongArch64 Bare-metal (LP64D ABI) -[`loongarch64-unknown-none-softfloat`](platform-support/loongarch-none.md) | * | | LoongArch64 Bare-metal (LP64S ABI) +[`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64D ABI) +[`loongarch64-unknown-none-softfloat`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64S ABI) [`nvptx64-nvidia-cuda`](platform-support/nvptx64-nvidia-cuda.md) | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs] [`riscv32imac-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMAC ISA) [`riscv32i-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32I ISA) -[`riscv32im-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | | Bare RISC-V (RV32IM ISA) +[`riscv32im-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IM ISA) [`riscv32imc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMC ISA) [`riscv32imafc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMAFC ISA) `riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA) @@ -193,7 +193,7 @@ target | std | notes `wasm32-unknown-unknown` | ✓ | WebAssembly `wasm32-wasi` | ✓ | WebAssembly with WASI (undergoing a [rename to `wasm32-wasip1`][wasi-rename]) [`wasm32-wasip1`](platform-support/wasm32-wasip1.md) | ✓ | WebAssembly with WASI -[`wasm32-wasip1-threads`](platform-support/wasm32-wasip1-threads.md) | ✓ | | WebAssembly with WASI Preview 1 and threads +[`wasm32-wasip1-threads`](platform-support/wasm32-wasip1-threads.md) | ✓ | WebAssembly with WASI Preview 1 and threads [`x86_64-apple-ios`](platform-support/apple-ios.md) | ✓ | 64-bit x86 iOS [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX `x86_64-fuchsia` | ✓ | Alias for `x86_64-unknown-fuchsia` diff --git a/src/doc/unstable-book/src/compiler-flags/patchable-function-entry.md b/src/doc/unstable-book/src/compiler-flags/patchable-function-entry.md new file mode 100644 index 00000000000..4a9bf47a290 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/patchable-function-entry.md @@ -0,0 +1,24 @@ +# `patchable-function-entry` + +-------------------- + +The `-Z patchable-function-entry=total_nops,prefix_nops` or `-Z patchable-function-entry=total_nops` +compiler flag enables nop padding of function entries with 'total_nops' nops, with +an offset for the entry of the function at 'prefix_nops' nops. In the second form, +'prefix_nops' defaults to 0. + +As an illustrative example, `-Z patchable-function-entry=3,2` would produce: + +```text +nop +nop +function_label: +nop +//Actual function code begins here +``` + +This flag is used for hotpatching, especially in the Linux kernel. The flag +arguments are modeled after the `-fpatchable-function-entry` flag as defined +for both [Clang](https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fpatchable-function-entry) +and [gcc](https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html#index-fpatchable-function-entry) +and is intended to provide the same effect. diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index 2072f76a481..805fc8aa8cc 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -48,7 +48,7 @@ complete -c x.py -n "__fish_use_subcommand" -f -a "run" -d 'Run tools contained complete -c x.py -n "__fish_use_subcommand" -f -a "setup" -d 'Set up the environment for development' complete -c x.py -n "__fish_use_subcommand" -f -a "suggest" -d 'Suggest a subset of tests to run, based on modified files' complete -c x.py -n "__fish_use_subcommand" -f -a "vendor" -d 'Vendor dependencies' -complete -c x.py -n "__fish_use_subcommand" -f -a "perf" -d 'Perform profiling and benchmarking of the compiler using the `rustc-perf` benchmark suite' +complete -c x.py -n "__fish_use_subcommand" -f -a "perf" -d 'Perform profiling and benchmarking of the compiler using the `rustc-perf-wrapper` tool' complete -c x.py -n "__fish_seen_subcommand_from build" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_seen_subcommand_from build" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_seen_subcommand_from build" -l build -d 'build target of the stage0 compiler' -r -f diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index 919382d441f..ce590d2fa48 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -75,7 +75,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('setup', 'setup', [CompletionResultType]::ParameterValue, 'Set up the environment for development') [CompletionResult]::new('suggest', 'suggest', [CompletionResultType]::ParameterValue, 'Suggest a subset of tests to run, based on modified files') [CompletionResult]::new('vendor', 'vendor', [CompletionResultType]::ParameterValue, 'Vendor dependencies') - [CompletionResult]::new('perf', 'perf', [CompletionResultType]::ParameterValue, 'Perform profiling and benchmarking of the compiler using the `rustc-perf` benchmark suite') + [CompletionResult]::new('perf', 'perf', [CompletionResultType]::ParameterValue, 'Perform profiling and benchmarking of the compiler using the `rustc-perf-wrapper` tool') break } 'x.py;build' { diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index bbebf8b892d..fc8be4f7881 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -856,7 +856,7 @@ _x.py_commands() { 'setup:Set up the environment for development' \ 'suggest:Suggest a subset of tests to run, based on modified files' \ 'vendor:Vendor dependencies' \ -'perf:Perform profiling and benchmarking of the compiler using the \`rustc-perf\` benchmark suite' \ +'perf:Perform profiling and benchmarking of the compiler using the \`rustc-perf-wrapper\` tool' \ ) _describe -t commands 'x.py commands' commands "$@" } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 22565ea4028..b5660cd8492 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -549,7 +549,7 @@ fn clean_generic_param_def<'tcx>( }, ) } - ty::GenericParamDefKind::Const { has_default, is_host_effect } => ( + ty::GenericParamDefKind::Const { has_default, synthetic, is_host_effect: _ } => ( def.name, GenericParamDefKind::Const { ty: Box::new(clean_middle_ty( @@ -572,7 +572,7 @@ fn clean_generic_param_def<'tcx>( } else { None }, - is_host_effect, + synthetic, }, ), }; @@ -628,13 +628,13 @@ fn clean_generic_param<'tcx>( }, ) } - hir::GenericParamKind::Const { ty, default, is_host_effect } => ( + hir::GenericParamKind::Const { ty, default, synthetic, is_host_effect: _ } => ( param.name.ident().name, GenericParamDefKind::Const { ty: Box::new(clean_ty(ty, cx)), default: default .map(|ct| Box::new(ty::Const::from_anon_const(cx.tcx, ct.def_id).to_string())), - is_host_effect, + synthetic, }, ), }; @@ -1411,7 +1411,11 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( let mut generics = clean_ty_generics( cx, tcx.generics_of(assoc_item.def_id), - ty::GenericPredicates { parent: None, predicates }, + ty::GenericPredicates { + parent: None, + predicates, + effects_min_tys: ty::List::empty(), + }, ); simplify::move_bounds_to_generic_parameters(&mut generics); diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index af61eb6ae8d..58eef36677b 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -113,7 +113,7 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId) if child == trait_ { return true; } - let predicates = cx.tcx.super_predicates_of(child); + let predicates = cx.tcx.explicit_super_predicates_of(child); debug_assert!(cx.tcx.generics_of(child).has_self); let self_ty = cx.tcx.types.self_param; predicates diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c4020f2a450..9050a1c1207 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1321,7 +1321,7 @@ pub(crate) enum GenericParamDefKind { Lifetime { outlives: ThinVec<Lifetime> }, Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool }, // Option<Box<String>> makes this type smaller than `Option<String>` would. - Const { ty: Box<Type>, default: Option<Box<String>>, is_host_effect: bool }, + Const { ty: Box<Type>, default: Option<Box<String>>, synthetic: bool }, } impl GenericParamDefKind { @@ -1345,7 +1345,7 @@ impl GenericParamDef { pub(crate) fn is_synthetic_param(&self) -> bool { match self.kind { GenericParamDefKind::Lifetime { .. } => false, - GenericParamDefKind::Const { is_host_effect, .. } => is_host_effect, + GenericParamDefKind::Const { synthetic: is_host_effect, .. } => is_host_effect, GenericParamDefKind::Type { synthetic, .. } => synthetic, } } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index d099a97f1cb..b965ab019cc 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -466,7 +466,7 @@ impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind { default: default.map(|x| (*x).into_tcx(tcx)), synthetic, }, - Const { ty, default, is_host_effect: _ } => GenericParamDefKind::Const { + Const { ty, default, synthetic: _ } => GenericParamDefKind::Const { type_: (*ty).into_tcx(tcx), default: default.map(|x| *x), }, @@ -501,14 +501,12 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate { synthetic, } } - clean::GenericParamDefKind::Const { - ty, - default, - is_host_effect: _, - } => GenericParamDefKind::Const { - type_: (*ty).into_tcx(tcx), - default: default.map(|d| *d), - }, + clean::GenericParamDefKind::Const { ty, default, synthetic: _ } => { + GenericParamDefKind::Const { + type_: (*ty).into_tcx(tcx), + default: default.map(|d| *d), + } + } }; GenericParamDef { name, kind } }) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 440b02a1fa7..37f7e7ed385 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1507,6 +1507,15 @@ impl Disambiguator { fn from_str(link: &str) -> Result<Option<(Self, &str, &str)>, (String, Range<usize>)> { use Disambiguator::{Kind, Namespace as NS, Primitive}; + let suffixes = [ + // If you update this list, please also update the relevant rustdoc book section! + ("!()", DefKind::Macro(MacroKind::Bang)), + ("!{}", DefKind::Macro(MacroKind::Bang)), + ("![]", DefKind::Macro(MacroKind::Bang)), + ("()", DefKind::Fn), + ("!", DefKind::Macro(MacroKind::Bang)), + ]; + if let Some(idx) = link.find('@') { let (prefix, rest) = link.split_at(idx); let d = match prefix { @@ -1530,16 +1539,23 @@ impl Disambiguator { "prim" | "primitive" => Primitive, _ => return Err((format!("unknown disambiguator `{prefix}`"), 0..idx)), }; + + for (suffix, kind) in suffixes { + if let Some(path_str) = rest.strip_suffix(suffix) { + if d.ns() != Kind(kind).ns() { + return Err(( + format!("unmatched disambiguator `{prefix}` and suffix `{suffix}`"), + 0..idx, + )); + } else if path_str.len() > 1 { + // path_str != "@" + return Ok(Some((d, &path_str[1..], &rest[1..]))); + } + } + } + Ok(Some((d, &rest[1..], &rest[1..]))) } else { - let suffixes = [ - // If you update this list, please also update the relevant rustdoc book section! - ("!()", DefKind::Macro(MacroKind::Bang)), - ("!{}", DefKind::Macro(MacroKind::Bang)), - ("![]", DefKind::Macro(MacroKind::Bang)), - ("()", DefKind::Fn), - ("!", DefKind::Macro(MacroKind::Bang)), - ]; for (suffix, kind) in suffixes { if let Some(path_str) = link.strip_suffix(suffix) { // Avoid turning `!` or `()` into an empty string diff --git a/src/tools/clippy/.github/workflows/lintcheck.yml b/src/tools/clippy/.github/workflows/lintcheck.yml new file mode 100644 index 00000000000..91c98b3a256 --- /dev/null +++ b/src/tools/clippy/.github/workflows/lintcheck.yml @@ -0,0 +1,118 @@ +name: Lintcheck + +on: pull_request + +env: + RUST_BACKTRACE: 1 + CARGO_INCREMENTAL: 0 + +concurrency: + # For a given workflow, if we push to the same PR, cancel all previous builds on that PR. + group: "${{ github.workflow }}-${{ github.event.pull_request.number}}" + cancel-in-progress: true + +jobs: + # Runs lintcheck on the PR's target branch and stores the results as an artifact + base: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + # HEAD is the generated merge commit `refs/pull/N/merge` between the PR and `master`, `HEAD^` + # being the commit from `master` that is the base of the merge + - name: Checkout base + run: git checkout HEAD^ + + # Use the lintcheck from the PR to generate the JSON in case the PR modifies lintcheck in some + # way + - name: Checkout current lintcheck + run: | + rm -rf lintcheck + git checkout ${{ github.sha }} -- lintcheck + + - name: Cache lintcheck bin + id: cache-lintcheck-bin + uses: actions/cache@v4 + with: + path: target/debug/lintcheck + key: lintcheck-bin-${{ hashfiles('lintcheck/**') }} + + - name: Build lintcheck + if: steps.cache-lintcheck-bin.outputs.cache-hit != 'true' + run: cargo build --manifest-path=lintcheck/Cargo.toml + + - name: Create cache key + id: key + run: echo "key=lintcheck-base-${{ hashfiles('lintcheck/**') }}-$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + + - name: Cache results JSON + id: cache-json + uses: actions/cache@v4 + with: + path: lintcheck-logs/lintcheck_crates_logs.json + key: ${{ steps.key.outputs.key }} + + - name: Run lintcheck + if: steps.cache-json.outputs.cache-hit != 'true' + run: ./target/debug/lintcheck --format json + + - name: Upload base JSON + uses: actions/upload-artifact@v4 + with: + name: base + path: lintcheck-logs/lintcheck_crates_logs.json + + # Runs lintcheck on the PR and stores the results as an artifact + head: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Cache lintcheck bin + id: cache-lintcheck-bin + uses: actions/cache@v4 + with: + path: target/debug/lintcheck + key: lintcheck-bin-${{ hashfiles('lintcheck/**') }} + + - name: Build lintcheck + if: steps.cache-lintcheck-bin.outputs.cache-hit != 'true' + run: cargo build --manifest-path=lintcheck/Cargo.toml + + - name: Run lintcheck + run: ./target/debug/lintcheck --format json + + - name: Upload head JSON + uses: actions/upload-artifact@v4 + with: + name: head + path: lintcheck-logs/lintcheck_crates_logs.json + + # Retrieves the head and base JSON results and prints the diff to the GH actions step summary + diff: + runs-on: ubuntu-latest + + needs: [base, head] + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Restore lintcheck bin + uses: actions/cache/restore@v4 + with: + path: target/debug/lintcheck + key: lintcheck-bin-${{ hashfiles('lintcheck/**') }} + fail-on-cache-miss: true + + - name: Download JSON + uses: actions/download-artifact@v4 + + - name: Diff results + run: ./target/debug/lintcheck diff {base,head}/lintcheck_crates_logs.json >> $GITHUB_STEP_SUMMARY diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index d7bcd7a1968..70ef2c79364 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -1943,7 +1943,7 @@ Released 2022-05-19 [#8218](https://github.com/rust-lang/rust-clippy/pull/8218) * [`needless_match`] [#8471](https://github.com/rust-lang/rust-clippy/pull/8471) -* [`allow_attributes_without_reason`] (Requires `#![feature(lint_reasons)]`) +* [`allow_attributes_without_reason`] [#8504](https://github.com/rust-lang/rust-clippy/pull/8504) * [`print_in_format_impl`] [#8253](https://github.com/rust-lang/rust-clippy/pull/8253) @@ -5362,6 +5362,7 @@ Released 2018-09-13 [`extra_unused_type_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_type_parameters [`fallible_impl_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#fallible_impl_from [`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default +[`field_scoped_visibility_modifiers`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_scoped_visibility_modifiers [`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file [`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map [`filter_map_bool_then`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_bool_then @@ -5520,6 +5521,7 @@ Released 2018-09-13 [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map [`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten [`manual_hash_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one +[`manual_inspect`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_inspect [`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check [`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite @@ -5915,6 +5917,7 @@ Released 2018-09-13 [`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations [`unnecessary_literal_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_unwrap [`unnecessary_map_on_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_map_on_constructor +[`unnecessary_min_or_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_min_or_max [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation [`unnecessary_owned_empty_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_owned_empty_strings diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index c8223007df7..cfd34c7d2a7 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -454,7 +454,7 @@ default configuration of Clippy. By default, any configuration will replace the * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. -**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` +**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DevOps", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` --- **Affected lints:** @@ -669,6 +669,8 @@ The minimum rust version that the project supports. Defaults to the `rust-versio --- **Affected lints:** +* [`allow_attributes`](https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes) +* [`allow_attributes_without_reason`](https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes_without_reason) * [`almost_complete_range`](https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range) * [`approx_constant`](https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant) * [`assigning_clones`](https://rust-lang.github.io/rust-clippy/master/index.html#assigning_clones) @@ -693,6 +695,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`manual_is_ascii_check`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check) * [`manual_let_else`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else) * [`manual_non_exhaustive`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive) +* [`manual_pattern_char_comparison`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_pattern_char_comparison) * [`manual_range_contains`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains) * [`manual_rem_euclid`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid) * [`manual_retain`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain) diff --git a/src/tools/clippy/book/src/usage.md b/src/tools/clippy/book/src/usage.md index 36448e4cccf..7a0be6994fe 100644 --- a/src/tools/clippy/book/src/usage.md +++ b/src/tools/clippy/book/src/usage.md @@ -36,7 +36,7 @@ You can configure lint levels on the command line by adding cargo clippy -- -Aclippy::style -Wclippy::double_neg -Dclippy::perf ``` -For [CI] all warnings can be elevated to errors which will inturn fail +For [CI] all warnings can be elevated to errors which will in turn fail the build and cause Clippy to exit with a code other than `0`. ``` diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs index cfdf620b7d0..dbab3b106a8 100644 --- a/src/tools/clippy/clippy_config/src/conf.rs +++ b/src/tools/clippy/clippy_config/src/conf.rs @@ -18,6 +18,7 @@ use std::{cmp, env, fmt, fs, io}; #[rustfmt::skip] const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", + "DevOps", "DirectX", "ECMAScript", "GPLv2", "GPLv3", @@ -265,7 +266,7 @@ define_Conf! { /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS, MANUAL_PATTERN_CHAR_COMPARISON, ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON. /// /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml` #[default_text = ""] diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs index a3e7d0c3fa5..a5761d3270c 100644 --- a/src/tools/clippy/clippy_config/src/msrvs.rs +++ b/src/tools/clippy/clippy_config/src/msrvs.rs @@ -17,8 +17,9 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { + 1,81,0 { LINT_REASONS_STABILIZATION } 1,77,0 { C_STR_LITERALS } - 1,76,0 { PTR_FROM_REF } + 1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT } 1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE } 1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN } 1,68,0 { PATH_MAIN_SEPARATOR_STR } diff --git a/src/tools/clippy/clippy_lints/src/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/allow_attributes.rs deleted file mode 100644 index 123d0e51eee..00000000000 --- a/src/tools/clippy/clippy_lints/src/allow_attributes.rs +++ /dev/null @@ -1,74 +0,0 @@ -use ast::{AttrStyle, Attribute}; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_from_proc_macro; -use rustc_ast as ast; -use rustc_errors::Applicability; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; -use rustc_session::declare_lint_pass; - -declare_clippy_lint! { - /// ### What it does - /// Checks for usage of the `#[allow]` attribute and suggests replacing it with - /// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html)) - /// - /// The expect attribute is still unstable and requires the `lint_reasons` - /// on nightly. It can be enabled by adding `#![feature(lint_reasons)]` to - /// the crate root. - /// - /// This lint only warns outer attributes (`#[allow]`), as inner attributes - /// (`#![allow]`) are usually used to enable or disable lints on a global scale. - /// - /// ### Why restrict this? - /// `#[allow]` attributes can linger after their reason for existence is gone. - /// `#[expect]` attributes suppress the lint emission, but emit a warning if - /// the expectation is unfulfilled. This can be useful to be notified when the - /// lint is no longer triggered, which may indicate the attribute can be removed. - /// - /// ### Example - /// ```rust,ignore - /// #[allow(unused_mut)] - /// fn foo() -> usize { - /// let mut a = Vec::new(); - /// a.len() - /// } - /// ``` - /// Use instead: - /// ```rust,ignore - /// #![feature(lint_reasons)] - /// #[expect(unused_mut)] - /// fn foo() -> usize { - /// let mut a = Vec::new(); - /// a.len() - /// } - /// ``` - #[clippy::version = "1.70.0"] - pub ALLOW_ATTRIBUTES, - restriction, - "`#[allow]` will not trigger if a warning isn't found. `#[expect]` triggers if there are no warnings." -} - -declare_lint_pass!(AllowAttribute => [ALLOW_ATTRIBUTES]); - -impl LateLintPass<'_> for AllowAttribute { - // Separate each crate's features. - fn check_attribute<'cx>(&mut self, cx: &LateContext<'cx>, attr: &'cx Attribute) { - if !in_external_macro(cx.sess(), attr.span) - && cx.tcx.features().lint_reasons - && let AttrStyle::Outer = attr.style - && let Some(ident) = attr.ident() - && ident.name == rustc_span::symbol::sym::allow - && !is_from_proc_macro(cx, &attr) - { - span_lint_and_sugg( - cx, - ALLOW_ATTRIBUTES, - ident.span, - "#[allow] attribute found", - "replace it with", - "expect".into(), - Applicability::MachineApplicable, - ); - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs index 38933897389..d57ab539fff 100644 --- a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs +++ b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// `Arc<T>` is a thread-safe `Rc<T>` and guarantees that updates to the reference counter /// use atomic operations. To send an `Arc<T>` across thread boundaries and /// share ownership between multiple threads, `T` must be [both `Send` and `Sync`](https://doc.rust-lang.org/std/sync/struct.Arc.html#thread-safety), - /// so either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc` + /// so either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc`. /// /// ### Example /// ```no_run diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs index e94a6f3e3fc..05ea74b0d53 100644 --- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs +++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs @@ -1,16 +1,18 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::HirNode; +use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap}; use clippy_utils::sugg::Sugg; use clippy_utils::{is_trait_method, local_is_initialized, path_to_local}; use rustc_errors::Applicability; use rustc_hir::{self as hir, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::mir; use rustc_middle::ty::{self, Instance, Mutability}; use rustc_session::impl_lint_pass; use rustc_span::def_id::DefId; use rustc_span::symbol::sym; -use rustc_span::{ExpnKind, SyntaxContext}; +use rustc_span::{ExpnKind, Span, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -144,6 +146,7 @@ fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option< }; Some(CallCandidate { + span: expr.span, target, kind, method_def_id: resolved_method.def_id(), @@ -215,6 +218,10 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC return false; }; + if clone_source_borrows_from_dest(cx, lhs, call.span) { + return false; + } + // Now take a look if the impl block defines an implementation for the method that we're interested // in. If not, then we're using a default implementation, which is not interesting, so we will // not suggest the lint. @@ -222,6 +229,74 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC implemented_fns.contains_key(&provided_fn.def_id) } +/// Checks if the data being cloned borrows from the place that is being assigned to: +/// +/// ``` +/// let mut s = String::new(); +/// let s2 = &s; +/// s = s2.to_owned(); +/// ``` +/// +/// This cannot be written `s2.clone_into(&mut s)` because it has conflicting borrows. +fn clone_source_borrows_from_dest(cx: &LateContext<'_>, lhs: &Expr<'_>, call_span: Span) -> bool { + /// If this basic block only exists to drop a local as part of an assignment, returns its + /// successor. Otherwise returns the basic block that was passed in. + fn skip_drop_block(mir: &mir::Body<'_>, bb: mir::BasicBlock) -> mir::BasicBlock { + if let mir::TerminatorKind::Drop { target, .. } = mir.basic_blocks[bb].terminator().kind { + target + } else { + bb + } + } + + let Some(mir) = enclosing_mir(cx.tcx, lhs.hir_id) else { + return false; + }; + let PossibleBorrowerMap { map: borrow_map, .. } = PossibleBorrowerMap::new(cx, mir); + + // The operation `dest = src.to_owned()` in MIR is split up across 3 blocks *if* the type has `Drop` + // code. For types that don't, the second basic block is simply skipped. + // For the doc example above that would be roughly: + // + // bb0: + // s2 = &s + // s_temp = ToOwned::to_owned(move s2) -> bb1 + // + // bb1: + // drop(s) -> bb2 // drop the old string + // + // bb2: + // s = s_temp + for bb in mir.basic_blocks.iter() { + let terminator = bb.terminator(); + + // Look for the to_owned/clone call. + if terminator.source_info.span != call_span { + continue; + } + + if let mir::TerminatorKind::Call { ref args, target: Some(assign_bb), .. } = terminator.kind + && let [source] = &**args + && let mir::Operand::Move(source) = &source.node + && let assign_bb = skip_drop_block(mir, assign_bb) + // Skip any storage statements as they are just noise + && let Some(assignment) = mir.basic_blocks[assign_bb].statements + .iter() + .find(|stmt| { + !matches!(stmt.kind, mir::StatementKind::StorageDead(_) | mir::StatementKind::StorageLive(_)) + }) + && let mir::StatementKind::Assign(box (borrowed, _)) = &assignment.kind + && let Some(borrowers) = borrow_map.get(&borrowed.local) + && borrowers.contains(source.local) + { + return true; + } + + return false; + } + false +} + fn suggest<'tcx>( cx: &LateContext<'tcx>, ctxt: SyntaxContext, @@ -255,6 +330,7 @@ enum TargetTrait { #[derive(Debug)] struct CallCandidate<'tcx> { + span: Span, target: TargetTrait, kind: CallKind<'tcx>, // DefId of the called method from an impl block that implements the target trait diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs new file mode 100644 index 00000000000..df9994086cd --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs @@ -0,0 +1,26 @@ +use super::ALLOW_ATTRIBUTES; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_from_proc_macro; +use rustc_ast::{AttrStyle, Attribute}; +use rustc_errors::Applicability; +use rustc_lint::{LateContext, LintContext}; +use rustc_middle::lint::in_external_macro; + +// Separate each crate's features. +pub fn check<'cx>(cx: &LateContext<'cx>, attr: &'cx Attribute) { + if !in_external_macro(cx.sess(), attr.span) + && let AttrStyle::Outer = attr.style + && let Some(ident) = attr.ident() + && !is_from_proc_macro(cx, attr) + { + span_lint_and_sugg( + cx, + ALLOW_ATTRIBUTES, + ident.span, + "#[allow] attribute found", + "replace it with", + "expect".into(), + Applicability::MachineApplicable, + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs index 4a22e17463f..4b42616a636 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs @@ -8,11 +8,6 @@ use rustc_span::sym; use rustc_span::symbol::Symbol; pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMetaItem], attr: &'cx Attribute) { - // Check for the feature - if !cx.tcx.features().lint_reasons { - return; - } - // Check if the reason is present if let Some(item) = items.last().and_then(NestedMetaItem::meta_item) && let MetaItemKind::NameValue(_) = &item.kind @@ -22,7 +17,7 @@ pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMet } // Check if the attribute is in an external macro and therefore out of the developer's control - if in_external_macro(cx.sess(), attr.span) || is_from_proc_macro(cx, &attr) { + if in_external_macro(cx.sess(), attr.span) || is_from_proc_macro(cx, attr) { return; } diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs index e4c98a32fd6..8ec60314cc9 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs @@ -1,5 +1,6 @@ //! checks for attributes +mod allow_attributes; mod allow_attributes_without_reason; mod blanket_clippy_restriction_lints; mod deprecated_cfg_attr; @@ -14,11 +15,11 @@ mod unnecessary_clippy_cfg; mod useless_attribute; mod utils; -use clippy_config::msrvs::Msrv; +use clippy_config::msrvs::{self, Msrv}; use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; use utils::{is_lint_level, is_relevant_impl, is_relevant_item, is_relevant_trait}; @@ -272,23 +273,17 @@ declare_clippy_lint! { /// ### What it does /// Checks for attributes that allow lints without a reason. /// - /// (This requires the `lint_reasons` feature) - /// /// ### Why restrict this? /// Justifying each `allow` helps readers understand the reasoning, /// and may allow removing `allow` attributes if their purpose is obsolete. /// /// ### Example /// ```no_run - /// #![feature(lint_reasons)] - /// /// #![allow(clippy::some_lint)] /// ``` /// /// Use instead: /// ```no_run - /// #![feature(lint_reasons)] - /// /// #![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")] /// ``` #[clippy::version = "1.61.0"] @@ -299,6 +294,41 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does + /// Checks for usage of the `#[allow]` attribute and suggests replacing it with + /// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html)) + /// + /// This lint only warns outer attributes (`#[allow]`), as inner attributes + /// (`#![allow]`) are usually used to enable or disable lints on a global scale. + /// + /// ### Why is this bad? + /// `#[expect]` attributes suppress the lint emission, but emit a warning, if + /// the expectation is unfulfilled. This can be useful to be notified when the + /// lint is no longer triggered. + /// + /// ### Example + /// ```rust,ignore + /// #[allow(unused_mut)] + /// fn foo() -> usize { + /// let mut a = Vec::new(); + /// a.len() + /// } + /// ``` + /// Use instead: + /// ```rust,ignore + /// #[expect(unused_mut)] + /// fn foo() -> usize { + /// let mut a = Vec::new(); + /// a.len() + /// } + /// ``` + #[clippy::version = "1.70.0"] + pub ALLOW_ATTRIBUTES, + restriction, + "`#[allow]` will not trigger if a warning isn't found. `#[expect]` triggers if there are no warnings." +} + +declare_clippy_lint! { + /// ### What it does /// Checks for `#[should_panic]` attributes without specifying the expected panic message. /// /// ### Why is this bad? @@ -469,7 +499,13 @@ declare_clippy_lint! { "duplicated attribute" } -declare_lint_pass!(Attributes => [ +#[derive(Clone)] +pub struct Attributes { + msrv: Msrv, +} + +impl_lint_pass!(Attributes => [ + ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON, INLINE_ALWAYS, DEPRECATED_SEMVER, @@ -480,6 +516,13 @@ declare_lint_pass!(Attributes => [ DUPLICATED_ATTRIBUTES, ]); +impl Attributes { + #[must_use] + pub fn new(msrv: Msrv) -> Self { + Self { msrv } + } +} + impl<'tcx> LateLintPass<'tcx> for Attributes { fn check_crate(&mut self, cx: &LateContext<'tcx>) { blanket_clippy_restriction_lints::check_command_line(cx); @@ -492,7 +535,11 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { if is_lint_level(ident.name, attr.id) { blanket_clippy_restriction_lints::check(cx, ident.name, items); } - if matches!(ident.name, sym::allow | sym::expect) { + if matches!(ident.name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { + allow_attributes::check(cx, attr); + } + if matches!(ident.name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) + { allow_attributes_without_reason::check(cx, ident.name, items, attr); } if items.is_empty() || !attr.has_name(sym::deprecated) { @@ -537,6 +584,8 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { inline_always::check(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id())); } } + + extract_msrv_attr!(LateContext); } pub struct EarlyAttributes { diff --git a/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs index f42bafce4dd..5f48b8bd206 100644 --- a/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs @@ -22,9 +22,9 @@ pub(super) fn check<'tcx>( if matches!(cast_from.kind(), ty::Ref(..)) && let ty::RawPtr(_, to_mutbl) = cast_to.kind() - && let Some(use_cx) = expr_use_ctxt(cx, expr) + && let use_cx = expr_use_ctxt(cx, expr) // TODO: only block the lint if `cast_expr` is a temporary - && !matches!(use_cx.node, ExprUseNode::LetStmt(_) | ExprUseNode::ConstStatic(_)) + && !matches!(use_cx.use_node(cx), ExprUseNode::LetStmt(_) | ExprUseNode::ConstStatic(_)) { let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" }; let fn_name = match to_mutbl { diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index e41abf42234..60815f4f2af 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -1,7 +1,7 @@ //! calculate cognitive complexity and warn about overly complex functions use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{get_async_fn_body, is_async_fn, LimitStack}; @@ -12,7 +12,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -50,7 +50,6 @@ impl CognitiveComplexity { impl_lint_pass!(CognitiveComplexity => [COGNITIVE_COMPLEXITY]); impl CognitiveComplexity { - #[expect(clippy::cast_possible_truncation)] fn check<'tcx>( &mut self, cx: &LateContext<'tcx>, @@ -100,17 +99,12 @@ impl CognitiveComplexity { FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span, FnKind::Closure => { let header_span = body_span.with_hi(decl.output.span().lo()); - let pos = snippet_opt(cx, header_span).and_then(|snip| { - let low_offset = snip.find('|')?; - let high_offset = 1 + snip.get(low_offset + 1..)?.find('|')?; - let low = header_span.lo() + BytePos(low_offset as u32); - let high = low + BytePos(high_offset as u32 + 1); - - Some((low, high)) - }); - - if let Some((low, high)) = pos { - Span::new(low, high, header_span.ctxt(), header_span.parent()) + #[expect(clippy::range_plus_one)] + if let Some(range) = header_span.map_range(cx, |src, range| { + let mut idxs = src.get(range.clone())?.match_indices('|'); + Some(range.start + idxs.next()?.0..range.start + idxs.next()?.0 + 1) + }) { + range.with_ctxt(header_span.ctxt()) } else { return; } diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index 480df675d75..d896452be92 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; -use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt}; +use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, IntoSpan, SpanRangeExt}; use clippy_utils::ty::{needs_ordered_drop, InteriorMut}; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{ @@ -14,7 +14,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::hygiene::walk_chain; use rustc_span::source_map::SourceMap; -use rustc_span::{BytePos, Span, Symbol}; +use rustc_span::{Span, Symbol}; use std::borrow::Cow; declare_clippy_lint! { @@ -266,12 +266,12 @@ fn lint_branches_sharing_code<'tcx>( let span = span.with_hi(last_block.span.hi()); // Improve formatting if the inner block has indention (i.e. normal Rust formatting) - let test_span = Span::new(span.lo() - BytePos(4), span.lo(), span.ctxt(), span.parent()); - let span = if snippet_opt(cx, test_span).map_or(false, |snip| snip == " ") { - span.with_lo(test_span.lo()) - } else { - span - }; + let span = span + .map_range(cx, |src, range| { + (range.start > 4 && src.get(range.start - 4..range.start)? == " ") + .then_some(range.start - 4..range.end) + }) + .map_or(span, |range| range.with_ctxt(span.ctxt())); (span, suggestion.to_string()) }); diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 7e43a99e9f2..638de5e818c 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -38,7 +38,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ #[cfg(feature = "internal")] crate::utils::internal_lints::unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS_INFO, crate::absolute_paths::ABSOLUTE_PATHS_INFO, - crate::allow_attributes::ALLOW_ATTRIBUTES_INFO, crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO, crate::approx_const::APPROX_CONSTANT_INFO, crate::arc_with_non_send_sync::ARC_WITH_NON_SEND_SYNC_INFO, @@ -49,6 +48,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES_INFO, crate::assigning_clones::ASSIGNING_CLONES_INFO, crate::async_yields_async::ASYNC_YIELDS_ASYNC_INFO, + crate::attrs::ALLOW_ATTRIBUTES_INFO, crate::attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON_INFO, crate::attrs::BLANKET_CLIPPY_RESTRICTION_LINTS_INFO, crate::attrs::DEPRECATED_CFG_ATTR_INFO, @@ -178,6 +178,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::explicit_write::EXPLICIT_WRITE_INFO, crate::extra_unused_type_parameters::EXTRA_UNUSED_TYPE_PARAMETERS_INFO, crate::fallible_impl_from::FALLIBLE_IMPL_FROM_INFO, + crate::field_scoped_visibility_modifiers::FIELD_SCOPED_VISIBILITY_MODIFIERS_INFO, crate::float_literal::EXCESSIVE_PRECISION_INFO, crate::float_literal::LOSSY_FLOAT_LITERAL_INFO, crate::floating_point_arithmetic::IMPRECISE_FLOPS_INFO, @@ -402,6 +403,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::MANUAL_C_STR_LITERALS_INFO, crate::methods::MANUAL_FILTER_MAP_INFO, crate::methods::MANUAL_FIND_MAP_INFO, + crate::methods::MANUAL_INSPECT_INFO, crate::methods::MANUAL_IS_VARIANT_AND_INFO, crate::methods::MANUAL_NEXT_BACK_INFO, crate::methods::MANUAL_OK_OR_INFO, @@ -469,6 +471,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::UNNECESSARY_JOIN_INFO, crate::methods::UNNECESSARY_LAZY_EVALUATIONS_INFO, crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO, + crate::methods::UNNECESSARY_MIN_OR_MAX_INFO, crate::methods::UNNECESSARY_RESULT_MAP_OR_ELSE_INFO, crate::methods::UNNECESSARY_SORT_BY_INFO, crate::methods::UNNECESSARY_TO_OWNED_INFO, diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index f451758c335..a115f8d0631 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -6,7 +6,7 @@ use clippy_utils::{ expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode, }; use core::mem; -use rustc_ast::util::parser::{PREC_UNAMBIGUOUS, PREC_PREFIX}; +use rustc_ast::util::parser::{PREC_PREFIX, PREC_UNAMBIGUOUS}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_ty, Visitor}; @@ -260,18 +260,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { (None, kind) => { let expr_ty = typeck.expr_ty(expr); let use_cx = expr_use_ctxt(cx, expr); - let adjusted_ty = match &use_cx { - Some(use_cx) => match use_cx.adjustments { - [.., a] => a.target, - _ => expr_ty, - }, - _ => typeck.expr_ty_adjusted(expr), - }; + let adjusted_ty = use_cx.adjustments.last().map_or(expr_ty, |a| a.target); - match (use_cx, kind) { - (Some(use_cx), RefOp::Deref) => { + match kind { + RefOp::Deref if use_cx.same_ctxt => { + let use_node = use_cx.use_node(cx); let sub_ty = typeck.expr_ty(sub_expr); - if let ExprUseNode::FieldAccess(name) = use_cx.node + if let ExprUseNode::FieldAccess(name) = use_node && !use_cx.moved_before_use && !ty_contains_field(sub_ty, name.name) { @@ -288,9 +283,9 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { } else if sub_ty.is_ref() // Linting method receivers would require verifying that name lookup // would resolve the same way. This is complicated by trait methods. - && !use_cx.node.is_recv() - && let Some(ty) = use_cx.node.defined_ty(cx) - && TyCoercionStability::for_defined_ty(cx, ty, use_cx.node.is_return()).is_deref_stable() + && !use_node.is_recv() + && let Some(ty) = use_node.defined_ty(cx) + && TyCoercionStability::for_defined_ty(cx, ty, use_node.is_return()).is_deref_stable() { self.state = Some(( State::ExplicitDeref { mutability: None }, @@ -301,7 +296,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { )); } }, - (_, RefOp::Method { mutbl, is_ufcs }) + RefOp::Method { mutbl, is_ufcs } if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id) // Allow explicit deref in method chains. e.g. `foo.deref().bar()` && (is_ufcs || !in_postfix_position(cx, expr)) => @@ -319,7 +314,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { }, )); }, - (Some(use_cx), RefOp::AddrOf(mutability)) => { + RefOp::AddrOf(mutability) if use_cx.same_ctxt => { // Find the number of times the borrow is auto-derefed. let mut iter = use_cx.adjustments.iter(); let mut deref_count = 0usize; @@ -338,10 +333,11 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { }; }; - let stability = use_cx.node.defined_ty(cx).map_or(TyCoercionStability::None, |ty| { - TyCoercionStability::for_defined_ty(cx, ty, use_cx.node.is_return()) + let use_node = use_cx.use_node(cx); + let stability = use_node.defined_ty(cx).map_or(TyCoercionStability::None, |ty| { + TyCoercionStability::for_defined_ty(cx, ty, use_node.is_return()) }); - let can_auto_borrow = match use_cx.node { + let can_auto_borrow = match use_node { ExprUseNode::FieldAccess(_) if !use_cx.moved_before_use && matches!(sub_expr.kind, ExprKind::Field(..)) => { @@ -353,7 +349,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { // deref through `ManuallyDrop<_>` will not compile. !adjust_derefs_manually_drop(use_cx.adjustments, expr_ty) }, - ExprUseNode::Callee | ExprUseNode::FieldAccess(_) => true, + ExprUseNode::Callee | ExprUseNode::FieldAccess(_) if !use_cx.moved_before_use => true, ExprUseNode::MethodArg(hir_id, _, 0) if !use_cx.moved_before_use => { // Check for calls to trait methods where the trait is implemented // on a reference. @@ -363,9 +359,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { // priority. if let Some(fn_id) = typeck.type_dependent_def_id(hir_id) && let Some(trait_id) = cx.tcx.trait_of_item(fn_id) - && let arg_ty = cx - .tcx - .erase_regions(use_cx.adjustments.last().map_or(expr_ty, |a| a.target)) + && let arg_ty = cx.tcx.erase_regions(adjusted_ty) && let ty::Ref(_, sub_ty, _) = *arg_ty.kind() && let args = typeck.node_args_opt(hir_id).map(|args| &args[1..]).unwrap_or_default() @@ -443,7 +437,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { count: deref_count - required_refs, msg, stability, - for_field_access: if let ExprUseNode::FieldAccess(name) = use_cx.node + for_field_access: if let ExprUseNode::FieldAccess(name) = use_node && !use_cx.moved_before_use { Some(name.name) @@ -453,7 +447,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { }), StateData { first_expr: expr, - adjusted_ty: use_cx.adjustments.last().map_or(expr_ty, |a| a.target), + adjusted_ty, }, )); } else if stability.is_deref_stable() @@ -465,12 +459,12 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { State::Borrow { mutability }, StateData { first_expr: expr, - adjusted_ty: use_cx.adjustments.last().map_or(expr_ty, |a| a.target), + adjusted_ty, }, )); } }, - (None, _) | (_, RefOp::Method { .. }) => (), + _ => {}, } }, ( diff --git a/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs b/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs new file mode 100644 index 00000000000..bb74e345703 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs @@ -0,0 +1,75 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use rustc_ast::ast::{Item, ItemKind, VisibilityKind}; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of scoped visibility modifiers, like `pub(crate)`, on fields. These + /// make a field visible within a scope between public and private. + /// + /// ### Why restrict this? + /// Scoped visibility modifiers cause a field to be accessible within some scope between + /// public and private, potentially within an entire crate. This allows for fields to be + /// non-private while upholding internal invariants, but can be a code smell. Scoped visibility + /// requires checking a greater area, potentially an entire crate, to verify that an invariant + /// is upheld, and global analysis requires a lot of effort. + /// + /// ### Example + /// ```no_run + /// pub mod public_module { + /// struct MyStruct { + /// pub(crate) first_field: bool, + /// pub(super) second_field: bool + /// } + /// } + /// ``` + /// Use instead: + /// ```no_run + /// pub mod public_module { + /// struct MyStruct { + /// first_field: bool, + /// second_field: bool + /// } + /// impl MyStruct { + /// pub(crate) fn get_first_field(&self) -> bool { + /// self.first_field + /// } + /// pub(super) fn get_second_field(&self) -> bool { + /// self.second_field + /// } + /// } + /// } + /// ``` + #[clippy::version = "1.78.0"] + pub FIELD_SCOPED_VISIBILITY_MODIFIERS, + restriction, + "checks for usage of a scoped visibility modifier, like `pub(crate)`, on fields" +} + +declare_lint_pass!(FieldScopedVisibilityModifiers => [FIELD_SCOPED_VISIBILITY_MODIFIERS]); + +impl EarlyLintPass for FieldScopedVisibilityModifiers { + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + let ItemKind::Struct(ref st, _) = item.kind else { + return; + }; + for field in st.fields() { + let VisibilityKind::Restricted { path, .. } = &field.vis.kind else { + continue; + }; + if !path.segments.is_empty() && path.segments[0].ident.name == rustc_span::symbol::kw::SelfLower { + // pub(self) is equivalent to not using pub at all, so we ignore it + continue; + } + span_lint_and_help( + cx, + FIELD_SCOPED_VISIBILITY_MODIFIERS, + field.vis.span, + "scoped visibility modifier on a field", + None, + "consider making the field private and adding a scoped visibility method for it", + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs index ca830af3b2f..344a04e6e7e 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs @@ -14,7 +14,7 @@ use rustc_span::symbol::sym; use rustc_span::Span; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::source::{snippet, IntoSpan, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; declare_clippy_lint! { @@ -59,10 +59,8 @@ declare_clippy_lint! { declare_lint_pass!(ImplicitHasher => [IMPLICIT_HASHER]); impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { - #[expect(clippy::cast_possible_truncation, clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - use rustc_span::BytePos; - fn suggestion( cx: &LateContext<'_>, diag: &mut Diag<'_, ()>, @@ -123,10 +121,11 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { } let generics_suggestion_span = impl_.generics.span.substitute_dummy({ - let pos = snippet_opt(cx, item.span.until(target.span())) - .and_then(|snip| Some(item.span.lo() + BytePos(snip.find("impl")? as u32 + 4))); - if let Some(pos) = pos { - Span::new(pos, pos, item.span.ctxt(), item.span.parent()) + let range = (item.span.lo()..target.span().lo()).map_range(cx, |src, range| { + Some(src.get(range.clone())?.find("impl")? + 4..range.end) + }); + if let Some(range) = range { + range.with_ctxt(item.span.ctxt()) } else { return; } @@ -163,21 +162,16 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { continue; } let generics_suggestion_span = generics.span.substitute_dummy({ - let pos = snippet_opt( - cx, - Span::new( - item.span.lo(), - body.params[0].pat.span.lo(), - item.span.ctxt(), - item.span.parent(), - ), - ) - .and_then(|snip| { - let i = snip.find("fn")?; - Some(item.span.lo() + BytePos((i + snip[i..].find('(')?) as u32)) - }) - .expect("failed to create span for type parameters"); - Span::new(pos, pos, item.span.ctxt(), item.span.parent()) + let range = (item.span.lo()..body.params[0].pat.span.lo()).map_range(cx, |src, range| { + let (pre, post) = src.get(range.clone())?.split_once("fn")?; + let pos = post.find('(')? + pre.len() + 2; + Some(pos..pos) + }); + if let Some(range) = range { + range.with_ctxt(item.span.ctxt()) + } else { + return; + } }); let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target); diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs index 2f543781c44..a102b434cfa 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_return.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::{snippet_with_applicability, snippet_with_context, walk_span_to_context}; use clippy_utils::visitors::for_each_expr_without_closures; -use clippy_utils::{get_async_fn_body, is_async_fn}; +use clippy_utils::{get_async_fn_body, is_async_fn, is_from_proc_macro}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; @@ -245,6 +245,10 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn { } else { body.value }; + + if is_from_proc_macro(cx, expr) { + return; + } lint_implicit_returns(cx, expr, expr.span.ctxt(), None); } } diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs index 170ecf896b4..67b48878ca5 100644 --- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs +++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs @@ -246,7 +246,7 @@ fn collect_supertrait_bounds<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds && let [.., path] = poly_trait.trait_ref.path.segments && poly_trait.bound_generic_params.is_empty() && let Some(trait_def_id) = path.res.opt_def_id() - && let predicates = cx.tcx.super_predicates_of(trait_def_id).predicates + && let predicates = cx.tcx.explicit_super_predicates_of(trait_def_id).predicates // If the trait has no supertrait, there is no need to collect anything from that bound && !predicates.is_empty() { diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index ef322786dbc..32fad0f02ce 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -6,7 +6,7 @@ #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(let_chains)] -#![feature(lint_reasons)] +#![cfg_attr(bootstrap, feature(lint_reasons))] #![feature(never_type)] #![feature(rustc_private)] #![feature(stmt_expr_attributes)] @@ -73,7 +73,6 @@ mod renamed_lints; // begin lints modules, do not remove this comment, it’s used in `update_lints` mod absolute_paths; -mod allow_attributes; mod almost_complete_range; mod approx_const; mod arc_with_non_send_sync; @@ -138,6 +137,7 @@ mod exit; mod explicit_write; mod extra_unused_type_parameters; mod fallible_impl_from; +mod field_scoped_visibility_modifiers; mod float_literal; mod floating_point_arithmetic; mod format; @@ -699,7 +699,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(mut_reference::UnnecessaryMutPassed)); store.register_late_pass(|_| Box::<significant_drop_tightening::SignificantDropTightening<'_>>::default()); store.register_late_pass(|_| Box::new(len_zero::LenZero)); - store.register_late_pass(|_| Box::new(attrs::Attributes)); + store.register_late_pass(move |_| Box::new(attrs::Attributes::new(msrv()))); store.register_late_pass(|_| Box::new(blocks_in_conditions::BlocksInConditions)); store.register_late_pass(|_| Box::new(unicode::Unicode)); store.register_late_pass(|_| Box::new(uninit_vec::UninitVec)); @@ -1065,7 +1065,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(needless_maybe_sized::NeedlessMaybeSized)); store.register_late_pass(|_| Box::new(redundant_async_block::RedundantAsyncBlock)); store.register_late_pass(|_| Box::new(let_with_type_underscore::UnderscoreTyped)); - store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute)); store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(msrv()))); store.register_late_pass(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct)); store.register_late_pass(move |_| { @@ -1170,7 +1169,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { ..Default::default() }) }); - store.register_late_pass(|_| Box::new(string_patterns::StringPatterns)); + store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(msrv()))); + store.register_early_pass(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs index 08682942153..64ea591993d 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mod.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs @@ -356,10 +356,10 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for loops which have a range bound that is a mutable variable + /// Checks for loops with a range bound that is a mutable variable. /// /// ### Why is this bad? - /// One might think that modifying the mutable variable changes the loop bounds + /// One might think that modifying the mutable variable changes the loop bounds. It doesn't. /// /// ### Known problems /// False positive when mutation is followed by a `break`, but the `break` is not immediately @@ -381,7 +381,7 @@ declare_clippy_lint! { /// let mut foo = 42; /// for i in 0..foo { /// foo -= 1; - /// println!("{}", i); // prints numbers from 0 to 42, not 0 to 21 + /// println!("{i}"); // prints numbers from 0 to 41, not 0 to 21 /// } /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs index 17399fb2cc2..58b2ebebbf0 100644 --- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs +++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs @@ -53,6 +53,7 @@ declare_lint_pass!(ManualUnwrapOrDefault => [MANUAL_UNWRAP_OR_DEFAULT]); fn get_some<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<HirId> { if let PatKind::TupleStruct(QPath::Resolved(_, path), &[pat], _) = pat.kind + && let PatKind::Binding(_, pat_id, _, _) = pat.kind && let Some(def_id) = path.res.opt_def_id() // Since it comes from a pattern binding, we need to get the parent to actually match // against it. @@ -60,13 +61,7 @@ fn get_some<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<HirId> { && (cx.tcx.lang_items().get(LangItem::OptionSome) == Some(def_id) || cx.tcx.lang_items().get(LangItem::ResultOk) == Some(def_id)) { - let mut bindings = Vec::new(); - pat.each_binding(|_, id, _, _| bindings.push(id)); - if let &[id] = bindings.as_slice() { - Some(id) - } else { - None - } + Some(pat_id) } else { None } diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs index 9edd6c95404..0940fc3219b 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs @@ -3,46 +3,78 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::contains_return_break_continue_macro; -use clippy_utils::{is_res_lang_ctor, path_to_local_id, sugg}; +use clippy_utils::{is_res_lang_ctor, path_to_local_id, peel_blocks, sugg}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::LangItem::{OptionNone, ResultErr}; -use rustc_hir::{Arm, Expr, PatKind}; +use rustc_hir::{Arm, Expr, Pat, PatKind}; use rustc_lint::LateContext; +use rustc_middle::ty::Ty; use rustc_span::sym; use super::MANUAL_UNWRAP_OR; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) { +pub(super) fn check_match<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + scrutinee: &'tcx Expr<'_>, + arms: &'tcx [Arm<'_>], +) { let ty = cx.typeck_results().expr_ty(scrutinee); - if let Some(ty_name) = if is_type_diagnostic_item(cx, ty, sym::Option) { + if let Some((or_arm, unwrap_arm)) = applicable_or_arm(cx, arms) { + check_and_lint(cx, expr, unwrap_arm.pat, scrutinee, unwrap_arm.body, or_arm.body, ty); + } +} + +pub(super) fn check_if_let<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + let_pat: &'tcx Pat<'_>, + let_expr: &'tcx Expr<'_>, + then_expr: &'tcx Expr<'_>, + else_expr: &'tcx Expr<'_>, +) { + let ty = cx.typeck_results().expr_ty(let_expr); + check_and_lint(cx, expr, let_pat, let_expr, then_expr, peel_blocks(else_expr), ty); +} + +fn check_and_lint<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + let_pat: &'tcx Pat<'_>, + let_expr: &'tcx Expr<'_>, + then_expr: &'tcx Expr<'_>, + else_expr: &'tcx Expr<'_>, + ty: Ty<'tcx>, +) { + if let PatKind::TupleStruct(ref qpath, [unwrap_pat], _) = let_pat.kind + && let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, let_pat.hir_id) + && let Some(variant_id) = cx.tcx.opt_parent(ctor_id) + && (cx.tcx.lang_items().option_some_variant() == Some(variant_id) + || cx.tcx.lang_items().result_ok_variant() == Some(variant_id)) + && let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind + && path_to_local_id(peel_blocks(then_expr), binding_hir_id) + && cx.typeck_results().expr_adjustments(then_expr).is_empty() + && let Some(ty_name) = find_type_name(cx, ty) + && let Some(or_body_snippet) = snippet_opt(cx, else_expr.span) + && let Some(indent) = indent_of(cx, expr.span) + && constant_simple(cx, cx.typeck_results(), else_expr).is_some() + { + lint(cx, expr, let_expr, ty_name, or_body_snippet, indent); + } +} + +fn find_type_name<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'static str> { + if is_type_diagnostic_item(cx, ty, sym::Option) { Some("Option") } else if is_type_diagnostic_item(cx, ty, sym::Result) { Some("Result") } else { None - } && let Some(or_arm) = applicable_or_arm(cx, arms) - && let Some(or_body_snippet) = snippet_opt(cx, or_arm.body.span) - && let Some(indent) = indent_of(cx, expr.span) - && constant_simple(cx, cx.typeck_results(), or_arm.body).is_some() - { - let reindented_or_body = reindent_multiline(or_body_snippet.into(), true, Some(indent)); - - let mut app = Applicability::MachineApplicable; - let suggestion = sugg::Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_par(); - span_lint_and_sugg( - cx, - MANUAL_UNWRAP_OR, - expr.span, - format!("this pattern reimplements `{ty_name}::unwrap_or`"), - "replace with", - format!("{suggestion}.unwrap_or({reindented_or_body})",), - app, - ); } } -fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> { +fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<(&'a Arm<'a>, &'a Arm<'a>)> { if arms.len() == 2 && arms.iter().all(|arm| arm.guard.is_none()) && let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| match arm.pat.kind { @@ -54,18 +86,33 @@ fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&' _ => false, }) && let unwrap_arm = &arms[1 - idx] - && let PatKind::TupleStruct(ref qpath, [unwrap_pat], _) = unwrap_arm.pat.kind - && let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, unwrap_arm.pat.hir_id) - && let Some(variant_id) = cx.tcx.opt_parent(ctor_id) - && (cx.tcx.lang_items().option_some_variant() == Some(variant_id) - || cx.tcx.lang_items().result_ok_variant() == Some(variant_id)) - && let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind - && path_to_local_id(unwrap_arm.body, binding_hir_id) - && cx.typeck_results().expr_adjustments(unwrap_arm.body).is_empty() && !contains_return_break_continue_macro(or_arm.body) { - Some(or_arm) + Some((or_arm, unwrap_arm)) } else { None } } + +fn lint<'tcx>( + cx: &LateContext<'tcx>, + expr: &Expr<'tcx>, + scrutinee: &'tcx Expr<'_>, + ty_name: &str, + or_body_snippet: String, + indent: usize, +) { + let reindented_or_body = reindent_multiline(or_body_snippet.into(), true, Some(indent)); + + let mut app = Applicability::MachineApplicable; + let suggestion = sugg::Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_par(); + span_lint_and_sugg( + cx, + MANUAL_UNWRAP_OR, + expr.span, + format!("this pattern reimplements `{ty_name}::unwrap_or`"), + "replace with", + format!("{suggestion}.unwrap_or({reindented_or_body})",), + app, + ); +} diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index 691ecd57535..bf7156cc53e 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -1069,7 +1069,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { redundant_guards::check(cx, arms, &self.msrv); if !in_constant(cx, expr.hir_id) { - manual_unwrap_or::check(cx, expr, ex, arms); + manual_unwrap_or::check_match(cx, expr, ex, arms); manual_map::check_match(cx, expr, ex, arms); manual_filter::check_match(cx, ex, arms, expr); } @@ -1097,6 +1097,14 @@ impl<'tcx> LateLintPass<'tcx> for Matches { ); } if !in_constant(cx, expr.hir_id) { + manual_unwrap_or::check_if_let( + cx, + expr, + if_let.let_pat, + if_let.let_expr, + if_let.if_then, + else_expr, + ); manual_map::check_if_let(cx, expr, if_let.let_pat, if_let.let_expr, if_let.if_then, else_expr); manual_filter::check_if_let( cx, diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs index 69791414f72..99fdbcff890 100644 --- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{expr_block, get_source_text, snippet}; +use clippy_utils::source::{expr_block, snippet, SpanRangeExt}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, peel_mid_ty_refs}; use clippy_utils::{is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs}; use core::cmp::max; @@ -17,7 +17,7 @@ use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE}; /// span, e.g. a string literal `"//"`, but we know that this isn't the case for empty /// match arms. fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool { - if let Some(ff) = get_source_text(cx, span) + if let Some(ff) = span.get_source_text(cx) && let Some(text) = ff.as_str() { text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*") diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs new file mode 100644 index 00000000000..e3ce64c246a --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs @@ -0,0 +1,238 @@ +use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::{IntoSpan, SpanRangeExt}; +use clippy_utils::ty::get_field_by_name; +use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures}; +use clippy_utils::{expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id, ExprUseNode}; +use core::ops::ControlFlow; +use rustc_errors::Applicability; +use rustc_hir::{BindingMode, BorrowKind, ByRef, ClosureKind, Expr, ExprKind, Mutability, Node, PatKind}; +use rustc_lint::LateContext; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; +use rustc_span::{sym, Span, Symbol, DUMMY_SP}; + +use super::MANUAL_INSPECT; + +#[expect(clippy::too_many_lines)] +pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: &str, name_span: Span, msrv: &Msrv) { + if let ExprKind::Closure(c) = arg.kind + && matches!(c.kind, ClosureKind::Closure) + && let typeck = cx.typeck_results() + && let Some(fn_id) = typeck.type_dependent_def_id(expr.hir_id) + && (is_diag_trait_item(cx, fn_id, sym::Iterator) + || (msrv.meets(msrvs::OPTION_RESULT_INSPECT) + && (is_diag_item_method(cx, fn_id, sym::Option) || is_diag_item_method(cx, fn_id, sym::Result)))) + && let body = cx.tcx.hir().body(c.body) + && let [param] = body.params + && let PatKind::Binding(BindingMode(ByRef::No, Mutability::Not), arg_id, _, None) = param.pat.kind + && let arg_ty = typeck.node_type(arg_id) + && let ExprKind::Block(block, _) = body.value.kind + && let Some(final_expr) = block.expr + && !block.stmts.is_empty() + && path_to_local_id(final_expr, arg_id) + && typeck.expr_adjustments(final_expr).is_empty() + { + let mut requires_copy = false; + let mut requires_deref = false; + + // The number of unprocessed return expressions. + let mut ret_count = 0u32; + + // The uses for which processing is delayed until after the visitor. + let mut delayed = vec![]; + + let ctxt = arg.span.ctxt(); + let can_lint = for_each_expr_without_closures(block.stmts, |e| { + if let ExprKind::Closure(c) = e.kind { + // Nested closures don't need to treat returns specially. + let _: Option<!> = for_each_expr(cx, cx.tcx.hir().body(c.body).value, |e| { + if path_to_local_id(e, arg_id) { + let (kind, same_ctxt) = check_use(cx, e); + match (kind, same_ctxt && e.span.ctxt() == ctxt) { + (_, false) | (UseKind::Deref | UseKind::Return(..), true) => { + requires_copy = true; + requires_deref = true; + }, + (UseKind::AutoBorrowed, true) => {}, + (UseKind::WillAutoDeref, true) => { + requires_copy = true; + }, + (kind, true) => delayed.push(kind), + } + } + ControlFlow::Continue(()) + }); + } else if matches!(e.kind, ExprKind::Ret(_)) { + ret_count += 1; + } else if path_to_local_id(e, arg_id) { + let (kind, same_ctxt) = check_use(cx, e); + match (kind, same_ctxt && e.span.ctxt() == ctxt) { + (UseKind::Return(..), false) => { + return ControlFlow::Break(()); + }, + (_, false) | (UseKind::Deref, true) => { + requires_copy = true; + requires_deref = true; + }, + (UseKind::AutoBorrowed, true) => {}, + (UseKind::WillAutoDeref, true) => { + requires_copy = true; + }, + (kind @ UseKind::Return(_), true) => { + ret_count -= 1; + delayed.push(kind); + }, + (kind, true) => delayed.push(kind), + } + } + ControlFlow::Continue(()) + }) + .is_none(); + + if ret_count != 0 { + // A return expression that didn't return the original value was found. + return; + } + + let mut edits = Vec::with_capacity(delayed.len() + 3); + let mut addr_of_edits = Vec::with_capacity(delayed.len()); + for x in delayed { + match x { + UseKind::Return(s) => edits.push((s.with_leading_whitespace(cx).with_ctxt(s.ctxt()), String::new())), + UseKind::Borrowed(s) => { + #[expect(clippy::range_plus_one)] + let range = s.map_range(cx, |src, range| { + let src = src.get(range.clone())?; + let trimmed = src.trim_start_matches([' ', '\t', '\n', '\r', '(']); + trimmed.starts_with('&').then(|| { + let pos = range.start + src.len() - trimmed.len(); + pos..pos + 1 + }) + }); + if let Some(range) = range { + addr_of_edits.push((range.with_ctxt(s.ctxt()), String::new())); + } else { + requires_copy = true; + requires_deref = true; + } + }, + UseKind::FieldAccess(name, e) => { + let Some(mut ty) = get_field_by_name(cx.tcx, arg_ty.peel_refs(), name) else { + requires_copy = true; + continue; + }; + let mut prev_expr = e; + + for (_, parent) in cx.tcx.hir().parent_iter(e.hir_id) { + if let Node::Expr(e) = parent { + match e.kind { + ExprKind::Field(_, name) + if let Some(fty) = get_field_by_name(cx.tcx, ty.peel_refs(), name.name) => + { + ty = fty; + prev_expr = e; + continue; + }, + ExprKind::AddrOf(BorrowKind::Ref, ..) => break, + _ if matches!( + typeck.expr_adjustments(prev_expr).first(), + Some(Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Not)) + | Adjust::Deref(_), + .. + }) + ) => + { + break; + }, + _ => {}, + } + } + requires_copy |= !ty.is_copy_modulo_regions(cx.tcx, cx.param_env); + break; + } + }, + // Already processed uses. + UseKind::AutoBorrowed | UseKind::WillAutoDeref | UseKind::Deref => {}, + } + } + + if can_lint + && (!requires_copy || arg_ty.is_copy_modulo_regions(cx.tcx, cx.param_env)) + // This case could be handled, but a fair bit of care would need to be taken. + && (!requires_deref || arg_ty.is_freeze(cx.tcx, cx.param_env)) + { + if requires_deref { + edits.push((param.span.shrink_to_lo(), "&".into())); + } else { + edits.extend(addr_of_edits); + } + edits.push(( + name_span, + String::from(match name { + "map" => "inspect", + "map_err" => "inspect_err", + _ => return, + }), + )); + edits.push(( + final_expr + .span + .with_leading_whitespace(cx) + .with_ctxt(final_expr.span.ctxt()), + String::new(), + )); + let app = if edits.iter().any(|(s, _)| s.from_expansion()) { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }; + span_lint_and_then(cx, MANUAL_INSPECT, name_span, "", |diag| { + diag.multipart_suggestion("try", edits, app); + }); + } + } +} + +enum UseKind<'tcx> { + AutoBorrowed, + WillAutoDeref, + Deref, + Return(Span), + Borrowed(Span), + FieldAccess(Symbol, &'tcx Expr<'tcx>), +} + +/// Checks how the value is used, and whether it was used in the same `SyntaxContext`. +fn check_use<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (UseKind<'tcx>, bool) { + let use_cx = expr_use_ctxt(cx, e); + if use_cx + .adjustments + .first() + .is_some_and(|a| matches!(a.kind, Adjust::Deref(_))) + { + return (UseKind::AutoBorrowed, use_cx.same_ctxt); + } + let res = match use_cx.use_node(cx) { + ExprUseNode::Return(_) => { + if let ExprKind::Ret(Some(e)) = use_cx.node.expect_expr().kind { + UseKind::Return(e.span) + } else { + return (UseKind::Return(DUMMY_SP), false); + } + }, + ExprUseNode::FieldAccess(name) => UseKind::FieldAccess(name.name, use_cx.node.expect_expr()), + ExprUseNode::Callee | ExprUseNode::MethodArg(_, _, 0) + if use_cx + .adjustments + .first() + .is_some_and(|a| matches!(a.kind, Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Not)))) => + { + UseKind::AutoBorrowed + }, + ExprUseNode::Callee | ExprUseNode::MethodArg(_, _, 0) => UseKind::WillAutoDeref, + ExprUseNode::AddrOf(BorrowKind::Ref, _) => UseKind::Borrowed(use_cx.node.expect_expr().span), + _ => UseKind::Deref, + }; + (res, use_cx.same_ctxt) +} diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 6200716afbe..1408f454820 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -53,6 +53,7 @@ mod iter_with_drain; mod iterator_step_by_zero; mod join_absolute_paths; mod manual_c_str_literals; +mod manual_inspect; mod manual_is_variant_and; mod manual_next_back; mod manual_ok_or; @@ -116,6 +117,7 @@ mod unnecessary_iter_cloned; mod unnecessary_join; mod unnecessary_lazy_eval; mod unnecessary_literal_unwrap; +mod unnecessary_min_or_max; mod unnecessary_result_map_or_else; mod unnecessary_sort_by; mod unnecessary_to_owned; @@ -3946,6 +3948,31 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does + /// Checks for unnecessary calls to `min()` or `max()` in the following cases + /// - Either both side is constant + /// - One side is clearly larger than the other, like i32::MIN and an i32 variable + /// + /// ### Why is this bad? + /// + /// In the aformentioned cases it is not necessary to call `min()` or `max()` + /// to compare values, it may even cause confusion. + /// + /// ### Example + /// ```no_run + /// let _ = 0.min(7_u32); + /// ``` + /// Use instead: + /// ```no_run + /// let _ = 0; + /// ``` + #[clippy::version = "1.78.0"] + pub UNNECESSARY_MIN_OR_MAX, + complexity, + "using 'min()/max()' when there is no need for it" +} + +declare_clippy_lint! { + /// ### What it does /// Checks for usage of `.map_or_else()` "map closure" for `Result` type. /// /// ### Why is this bad? @@ -4079,6 +4106,27 @@ declare_clippy_lint! { "is_ascii() called on a char iterator" } +declare_clippy_lint! { + /// ### What it does + /// Checks for uses of `map` which return the original item. + /// + /// ### Why is this bad? + /// `inspect` is both clearer in intent and shorter. + /// + /// ### Example + /// ```no_run + /// let x = Some(0).map(|x| { println!("{x}"); x }); + /// ``` + /// Use instead: + /// ```no_run + /// let x = Some(0).inspect(|x| println!("{x}")); + /// ``` + #[clippy::version = "1.78.0"] + pub MANUAL_INSPECT, + complexity, + "use of `map` returning the original item" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -4244,6 +4292,8 @@ impl_lint_pass!(Methods => [ MANUAL_C_STR_LITERALS, UNNECESSARY_GET_THEN_CHECK, NEEDLESS_CHARACTER_ITERATION, + MANUAL_INSPECT, + UNNECESSARY_MIN_OR_MAX, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4543,6 +4593,9 @@ impl Methods { Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2), _ => {}, }, + ("min" | "max", [arg]) => { + unnecessary_min_or_max::check(cx, expr, name, recv, arg); + }, ("drain", ..) => { if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.parent_hir_node(expr.hir_id) && matches!(kind, StmtKind::Semi(_)) @@ -4747,6 +4800,7 @@ impl Methods { } } map_identity::check(cx, expr, recv, m_arg, name, span); + manual_inspect::check(cx, expr, m_arg, name, span, &self.msrv); }, ("map_or", [def, map]) => { option_map_or_none::check(cx, expr, recv, def, map); diff --git a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs index 6f9b38fcf83..b62ecef0069 100644 --- a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs +++ b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs @@ -24,7 +24,7 @@ fn is_subtrait_of_any(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { cx.tcx.is_diagnostic_item(sym::Any, tr.def_id) || cx .tcx - .super_predicates_of(tr.def_id) + .explicit_super_predicates_of(tr.def_id) .predicates .iter() .any(|(clause, _)| { diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs new file mode 100644 index 00000000000..78851d4122f --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs @@ -0,0 +1,90 @@ +use std::cmp::Ordering; + +use super::UNNECESSARY_MIN_OR_MAX; +use clippy_utils::diagnostics::span_lint_and_sugg; + +use clippy_utils::consts::{constant, constant_with_source, Constant, ConstantSource, FullInt}; +use clippy_utils::source::snippet; + +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::Span; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + name: &str, + recv: &'tcx Expr<'_>, + arg: &'tcx Expr<'_>, +) { + let typeck_results = cx.typeck_results(); + if let Some((left, ConstantSource::Local | ConstantSource::CoreConstant)) = + constant_with_source(cx, typeck_results, recv) + && let Some((right, ConstantSource::Local | ConstantSource::CoreConstant)) = + constant_with_source(cx, typeck_results, arg) + { + let Some(ord) = Constant::partial_cmp(cx.tcx, typeck_results.expr_ty(recv), &left, &right) else { + return; + }; + + lint(cx, expr, name, recv.span, arg.span, ord); + } else if let Some(extrema) = detect_extrema(cx, recv) { + let ord = match extrema { + Extrema::Minimum => Ordering::Less, + Extrema::Maximum => Ordering::Greater, + }; + lint(cx, expr, name, recv.span, arg.span, ord); + } else if let Some(extrema) = detect_extrema(cx, arg) { + let ord = match extrema { + Extrema::Minimum => Ordering::Greater, + Extrema::Maximum => Ordering::Less, + }; + lint(cx, expr, name, recv.span, arg.span, ord); + } +} + +fn lint(cx: &LateContext<'_>, expr: &Expr<'_>, name: &str, lhs: Span, rhs: Span, order: Ordering) { + let cmp_str = if order.is_ge() { "smaller" } else { "greater" }; + + let suggested_value = if (name == "min" && order.is_ge()) || (name == "max" && order.is_le()) { + snippet(cx, rhs, "..") + } else { + snippet(cx, lhs, "..") + }; + + span_lint_and_sugg( + cx, + UNNECESSARY_MIN_OR_MAX, + expr.span, + format!( + "`{}` is never {} than `{}` and has therefore no effect", + snippet(cx, lhs, ".."), + cmp_str, + snippet(cx, rhs, "..") + ), + "try", + suggested_value.to_string(), + Applicability::MachineApplicable, + ); +} + +#[derive(Debug)] +enum Extrema { + Minimum, + Maximum, +} +fn detect_extrema<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<Extrema> { + let ty = cx.typeck_results().expr_ty(expr); + + let cv = constant(cx, cx.typeck_results(), expr)?; + + match (cv.int_value(cx, ty)?, ty.kind()) { + (FullInt::S(i), &ty::Int(ity)) if i == i128::MIN >> (128 - ity.bit_width()?) => Some(Extrema::Minimum), + (FullInt::S(i), &ty::Int(ity)) if i == i128::MAX >> (128 - ity.bit_width()?) => Some(Extrema::Maximum), + (FullInt::U(i), &ty::Uint(uty)) if i == u128::MAX >> (128 - uty.bit_width()?) => Some(Extrema::Maximum), + (FullInt::U(0), &ty::Uint(_)) => Some(Extrema::Minimum), + _ => None, + } +} diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index 4592324809f..bb0d714a31f 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -1,11 +1,11 @@ use clippy_config::msrvs::{self, Msrv}; -use clippy_utils::diagnostics::span_lint; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method}; -use rustc_hir as hir; +use rustc_errors::Applicability; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_hir::intravisit::FnKind; -use rustc_hir::{Body, Constness, FnDecl, GenericParamKind}; +use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; @@ -120,7 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { } }, FnKind::Method(_, sig, ..) => { - if trait_ref_of_method(cx, def_id).is_some() || already_const(sig.header) { + if already_const(sig.header) || trait_ref_of_method(cx, def_id).is_some() { return; } }, @@ -147,10 +147,22 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { let mir = cx.tcx.optimized_mir(def_id); - if let Ok(()) = is_min_const_fn(cx.tcx, mir, &self.msrv) { - span_lint(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`"); + if let Ok(()) = is_min_const_fn(cx.tcx, mir, &self.msrv) + && let hir::Node::Item(hir::Item { vis_span, .. }) | hir::Node::ImplItem(hir::ImplItem { vis_span, .. }) = + cx.tcx.hir_node_by_def_id(def_id) + { + let suggestion = if vis_span.is_empty() { "const " } else { " const" }; + span_lint_and_then(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`", |diag| { + diag.span_suggestion_verbose( + vis_span.shrink_to_hi(), + "make the function `const`", + suggestion, + Applicability::MachineApplicable, + ); + }); } } + extract_msrv_attr!(LateContext); } diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index ca344dc5c81..250fd5cbd48 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -8,7 +8,7 @@ use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_ast::ast::{self, MetaItem, MetaItemKind}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; @@ -266,8 +266,5 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { } fn span_to_snippet_contains_docs(cx: &LateContext<'_>, search_span: Span) -> bool { - let Some(snippet) = snippet_opt(cx, search_span) else { - return false; - }; - snippet.lines().rev().any(|line| line.trim().starts_with("///")) + search_span.check_source_text(cx, |src| src.lines().rev().any(|line| line.trim().starts_with("///"))) } diff --git a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs index d608f3bf7b4..d276e29bace 100644 --- a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs +++ b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs @@ -6,7 +6,7 @@ use rustc_session::declare_lint_pass; use rustc_span::Span; use clippy_utils::diagnostics::span_lint; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; declare_clippy_lint! { /// ### What it does @@ -54,8 +54,10 @@ impl EarlyLintPass for MultipleBoundLocations { match clause { WherePredicate::BoundPredicate(pred) => { if (!pred.bound_generic_params.is_empty() || !pred.bounds.is_empty()) - && let Some(name) = snippet_opt(cx, pred.bounded_ty.span) - && let Some(bound_span) = generic_params_with_bounds.get(name.as_str()) + && let Some(Some(bound_span)) = pred + .bounded_ty + .span + .with_source_text(cx, |src| generic_params_with_bounds.get(src)) { emit_lint(cx, *bound_span, pred.bounded_ty.span); } diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index f4846a1753f..064ce59c234 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -80,11 +80,13 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if matches!(expr.kind, ExprKind::AddrOf(..)) && !expr.span.from_expansion() - && let Some(use_cx) = expr_use_ctxt(cx, expr) + && let use_cx = expr_use_ctxt(cx, expr) + && use_cx.same_ctxt && !use_cx.is_ty_unified - && let Some(DefinedTy::Mir(ty)) = use_cx.node.defined_ty(cx) + && let use_node = use_cx.use_node(cx) + && let Some(DefinedTy::Mir(ty)) = use_node.defined_ty(cx) && let ty::Param(ty) = *ty.value.skip_binder().kind() - && let Some((hir_id, fn_id, i)) = match use_cx.node { + && let Some((hir_id, fn_id, i)) = match use_node { ExprUseNode::MethodArg(_, _, 0) => None, ExprUseNode::MethodArg(hir_id, None, i) => cx .typeck_results() diff --git a/src/tools/clippy/clippy_lints/src/needless_else.rs b/src/tools/clippy/clippy_lints/src/needless_else.rs index b6aad69d166..f8bb72a16db 100644 --- a/src/tools/clippy/clippy_lints/src/needless_else.rs +++ b/src/tools/clippy/clippy_lints/src/needless_else.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{snippet_opt, trim_span}; +use clippy_utils::source::{IntoSpan, SpanRangeExt}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; declare_clippy_lint! { @@ -41,16 +41,16 @@ impl EarlyLintPass for NeedlessElse { && !expr.span.from_expansion() && !else_clause.span.from_expansion() && block.stmts.is_empty() - && let Some(trimmed) = expr.span.trim_start(then_block.span) - && let span = trim_span(cx.sess().source_map(), trimmed) - && let Some(else_snippet) = snippet_opt(cx, span) - // Ignore else blocks that contain comments or #[cfg]s - && !else_snippet.contains(['/', '#']) + && let range = (then_block.span.hi()..expr.span.hi()).trim_start(cx) + && range.clone().check_source_text(cx, |src| { + // Ignore else blocks that contain comments or #[cfg]s + !src.contains(['/', '#']) + }) { span_lint_and_sugg( cx, NEEDLESS_ELSE, - span, + range.with_ctxt(expr.span.ctxt()), "this `else` branch is empty", "you can remove it", String::new(), diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs index 630018238f4..143acc2b1cb 100644 --- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs @@ -25,14 +25,14 @@ declare_clippy_lint! { /// ```no_run /// let v = vec![0, 1, 2]; /// v.iter().for_each(|elem| { - /// println!("{}", elem); + /// println!("{elem}"); /// }) /// ``` /// Use instead: /// ```no_run /// let v = vec![0, 1, 2]; - /// for elem in v.iter() { - /// println!("{}", elem); + /// for elem in &v { + /// println!("{elem}"); /// } /// ``` /// diff --git a/src/tools/clippy/clippy_lints/src/needless_if.rs b/src/tools/clippy/clippy_lints/src/needless_if.rs index 51bee4b51f6..1d6233d432a 100644 --- a/src/tools/clippy/clippy_lints/src/needless_if.rs +++ b/src/tools/clippy/clippy_lints/src/needless_if.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::If; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::{snippet_opt, SpanRangeExt}; use rustc_errors::Applicability; use rustc_hir::{ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -39,18 +39,24 @@ declare_lint_pass!(NeedlessIf => [NEEDLESS_IF]); impl LateLintPass<'_> for NeedlessIf { fn check_stmt<'tcx>(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'tcx>) { if let StmtKind::Expr(expr) = stmt.kind - && let Some(If {cond, then, r#else: None }) = If::hir(expr) + && let Some(If { + cond, + then, + r#else: None, + }) = If::hir(expr) && let ExprKind::Block(block, ..) = then.kind && block.stmts.is_empty() && block.expr.is_none() && !in_external_macro(cx.sess(), expr.span) - && let Some(then_snippet) = snippet_opt(cx, then.span) - // Ignore - // - empty macro expansions - // - empty reptitions in macro expansions - // - comments - // - #[cfg]'d out code - && then_snippet.chars().all(|ch| matches!(ch, '{' | '}') || ch.is_ascii_whitespace()) + && then.span.check_source_text(cx, |src| { + // Ignore + // - empty macro expansions + // - empty reptitions in macro expansions + // - comments + // - #[cfg]'d out code + src.bytes() + .all(|ch| matches!(ch, b'{' | b'}') || ch.is_ascii_whitespace()) + }) && let Some(cond_snippet) = snippet_opt(cx, cond.span) && !is_from_proc_macro(cx, expr) { diff --git a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs index 4922c87b206..a1d8ec3b32e 100644 --- a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs +++ b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs @@ -91,7 +91,7 @@ fn path_to_sized_bound(cx: &LateContext<'_>, trait_bound: &PolyTraitRef<'_>) -> return true; } - for &(predicate, _) in cx.tcx.super_predicates_of(trait_def_id).predicates { + for &(predicate, _) in cx.tcx.explicit_super_predicates_of(trait_def_id).predicates { if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() && trait_predicate.polarity == PredicatePolarity::Positive && !path.contains(&trait_predicate.def_id()) diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs index 2701d6bdca3..b915df52762 100644 --- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs +++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{snippet_opt, snippet_with_applicability}; +use clippy_utils::source::{snippet_with_applicability, SpanRangeExt}; use clippy_utils::{match_def_path, paths}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; @@ -53,8 +53,9 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did()))) && let ExprKind::Lit(_) = param.kind && param.span.eq_ctxt(expr.span) - && let Some(snip) = snippet_opt(cx, param.span) - && !(snip.starts_with("0o") || snip.starts_with("0b")) + && param + .span + .check_source_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..])) { show_error(cx, param); } @@ -65,8 +66,9 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { && match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE) && let ExprKind::Lit(_) = param.kind && param.span.eq_ctxt(expr.span) - && let Some(snip) = snippet_opt(cx, param.span) - && !(snip.starts_with("0o") || snip.starts_with("0b")) + && param + .span + .check_source_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..])) { show_error(cx, param); } diff --git a/src/tools/clippy/clippy_lints/src/octal_escapes.rs b/src/tools/clippy/clippy_lints/src/octal_escapes.rs index 2fc039ae886..2eae9b23746 100644 --- a/src/tools/clippy/clippy_lints/src/octal_escapes.rs +++ b/src/tools/clippy/clippy_lints/src/octal_escapes.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; -use rustc_ast::ast::{Expr, ExprKind}; -use rustc_ast::token::{Lit, LitKind}; +use clippy_utils::source::SpanRangeExt; +use rustc_ast::token::LitKind; +use rustc_ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::Span; -use std::fmt::Write; +use rustc_span::{BytePos, Pos, SpanData}; declare_clippy_lint! { /// ### What it does @@ -52,104 +52,66 @@ declare_lint_pass!(OctalEscapes => [OCTAL_ESCAPES]); impl EarlyLintPass for OctalEscapes { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if in_external_macro(cx.sess(), expr.span) { - return; - } - - if let ExprKind::Lit(token_lit) = &expr.kind { - if matches!(token_lit.kind, LitKind::Str) { - check_lit(cx, token_lit, expr.span, true); - } else if matches!(token_lit.kind, LitKind::ByteStr) { - check_lit(cx, token_lit, expr.span, false); - } - } - } -} - -fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) { - let contents = lit.symbol.as_str(); - let mut iter = contents.char_indices().peekable(); - let mut found = vec![]; + if let ExprKind::Lit(lit) = &expr.kind + // The number of bytes from the start of the token to the start of literal's text. + && let start_offset = BytePos::from_u32(match lit.kind { + LitKind::Str => 1, + LitKind::ByteStr | LitKind::CStr => 2, + _ => return, + }) + && !in_external_macro(cx.sess(), expr.span) + { + let s = lit.symbol.as_str(); + let mut iter = s.as_bytes().iter(); + while let Some(&c) = iter.next() { + if c == b'\\' + // Always move the iterator to read the escape char. + && let Some(b'0') = iter.next() + { + // C-style octal escapes read from one to three characters. + // The first character (`0`) has already been read. + let (tail, len, c_hi, c_lo) = match *iter.as_slice() { + [c_hi @ b'0'..=b'7', c_lo @ b'0'..=b'7', ref tail @ ..] => (tail, 4, c_hi, c_lo), + [c_lo @ b'0'..=b'7', ref tail @ ..] => (tail, 3, b'0', c_lo), + _ => continue, + }; + iter = tail.iter(); + let offset = start_offset + BytePos::from_usize(s.len() - tail.len()); + let data = expr.span.data(); + let span = SpanData { + lo: data.lo + offset - BytePos::from_u32(len), + hi: data.lo + offset, + ..data + } + .span(); - // go through the string, looking for \0[0-7][0-7]? - while let Some((from, ch)) = iter.next() { - if ch == '\\' { - if let Some((_, '0')) = iter.next() { - // collect up to two further octal digits - if let Some((mut to, _)) = iter.next_if(|(_, ch)| matches!(ch, '0'..='7')) { - if iter.next_if(|(_, ch)| matches!(ch, '0'..='7')).is_some() { - to += 1; + // Last check to make sure the source text matches what we read from the string. + // Macros are involved somehow if this doesn't match. + if span.check_source_text(cx, |src| match *src.as_bytes() { + [b'\\', b'0', lo] => lo == c_lo, + [b'\\', b'0', hi, lo] => hi == c_hi && lo == c_lo, + _ => false, + }) { + span_lint_and_then(cx, OCTAL_ESCAPES, span, "octal-looking escape in a literal", |diag| { + diag.help_once("octal escapes are not supported, `\\0` is always null") + .span_suggestion( + span, + "if an octal escape is intended, use a hex escape instead", + format!("\\x{:02x}", (((c_hi - b'0') << 3) | (c_lo - b'0'))), + Applicability::MaybeIncorrect, + ) + .span_suggestion( + span, + "if a null escape is intended, disambiguate using", + format!("\\x00{}{}", c_hi as char, c_lo as char), + Applicability::MaybeIncorrect, + ); + }); + } else { + break; } - found.push((from, to + 1)); } } } } - - if found.is_empty() { - return; - } - - span_lint_and_then( - cx, - OCTAL_ESCAPES, - span, - format!( - "octal-looking escape in {} literal", - if is_string { "string" } else { "byte string" } - ), - |diag| { - diag.help(format!( - "octal escapes are not supported, `\\0` is always a null {}", - if is_string { "character" } else { "byte" } - )); - - // Generate suggestions if the string is not too long (~ 5 lines) - if contents.len() < 400 { - // construct two suggestion strings, one with \x escapes with octal meaning - // as in C, and one with \x00 for null bytes. - let mut suggest_1 = if is_string { "\"" } else { "b\"" }.to_string(); - let mut suggest_2 = suggest_1.clone(); - let mut index = 0; - for (from, to) in found { - suggest_1.push_str(&contents[index..from]); - suggest_2.push_str(&contents[index..from]); - - // construct a replacement escape - // the maximum value is \077, or \x3f, so u8 is sufficient here - if let Ok(n) = u8::from_str_radix(&contents[from + 1..to], 8) { - write!(suggest_1, "\\x{n:02x}").unwrap(); - } - - // append the null byte as \x00 and the following digits literally - suggest_2.push_str("\\x00"); - suggest_2.push_str(&contents[from + 2..to]); - - index = to; - } - suggest_1.push_str(&contents[index..]); - suggest_2.push_str(&contents[index..]); - - suggest_1.push('"'); - suggest_2.push('"'); - // suggestion 1: equivalent hex escape - diag.span_suggestion( - span, - "if an octal escape was intended, use the hexadecimal representation instead", - suggest_1, - Applicability::MaybeIncorrect, - ); - // suggestion 2: unambiguous null byte - diag.span_suggestion( - span, - format!( - "if the null {} is intended, disambiguate using", - if is_string { "character" } else { "byte" } - ), - suggest_2, - Applicability::MaybeIncorrect, - ); - } - }, - ); } diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index 186e548d373..4fdaa9f00a1 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -1,7 +1,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; +use clippy_utils::source::{snippet, snippet_with_applicability, SpanRangeExt}; use clippy_utils::sugg::Sugg; use clippy_utils::{get_parent_expr, higher, in_constant, is_integer_const, path_to_local}; use rustc_ast::ast::RangeLimits; @@ -285,9 +285,10 @@ fn check_possible_range_contains( if let ExprKind::Binary(ref lhs_op, _left, new_lhs) = left.kind && op == lhs_op.node && let new_span = Span::new(new_lhs.span.lo(), right.span.hi(), expr.span.ctxt(), expr.span.parent()) - && let Some(snip) = &snippet_opt(cx, new_span) - // Do not continue if we have mismatched number of parens, otherwise the suggestion is wrong - && snip.matches('(').count() == snip.matches(')').count() + && new_span.check_source_text(cx, |src| { + // Do not continue if we have mismatched number of parens, otherwise the suggestion is wrong + src.matches('(').count() == src.matches(')').count() + }) { check_possible_range_contains(cx, op, new_lhs, right, expr, new_span); } @@ -363,17 +364,19 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { |diag| { let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string()); let end = Sugg::hir(cx, y, "y").maybe_par(); - if let Some(is_wrapped) = &snippet_opt(cx, span) { - if is_wrapped.starts_with('(') && is_wrapped.ends_with(')') { + match span.with_source_text(cx, |src| src.starts_with('(') && src.ends_with(')')) { + Some(true) => { diag.span_suggestion(span, "use", format!("({start}..={end})"), Applicability::MaybeIncorrect); - } else { + }, + Some(false) => { diag.span_suggestion( span, "use", format!("{start}..={end}"), Applicability::MachineApplicable, // snippet ); - } + }, + None => {}, } }, ); diff --git a/src/tools/clippy/clippy_lints/src/string_patterns.rs b/src/tools/clippy/clippy_lints/src/string_patterns.rs index 64b5b8f9f27..7ba58942a17 100644 --- a/src/tools/clippy/clippy_lints/src/string_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/string_patterns.rs @@ -1,5 +1,6 @@ use std::ops::ControlFlow; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::macros::matching_root_macro_call; @@ -12,7 +13,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { @@ -69,7 +70,18 @@ declare_clippy_lint! { "using a single-character str where a char could be used, e.g., `_.split(\"x\")`" } -declare_lint_pass!(StringPatterns => [MANUAL_PATTERN_CHAR_COMPARISON, SINGLE_CHAR_PATTERN]); +pub struct StringPatterns { + msrv: Msrv, +} + +impl StringPatterns { + #[must_use] + pub fn new(msrv: Msrv) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(StringPatterns => [MANUAL_PATTERN_CHAR_COMPARISON, SINGLE_CHAR_PATTERN]); const PATTERN_METHODS: [(&str, usize); 22] = [ ("contains", 0), @@ -122,7 +134,7 @@ fn get_char_span<'tcx>(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Optio } } -fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<'_>) { +fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<'_>, msrv: &Msrv) { if let ExprKind::Closure(closure) = method_arg.kind && let body = cx.tcx.hir().body(closure.body) && let Some(PatKind::Binding(_, binding, ..)) = body.params.first().map(|p| p.pat.kind) @@ -178,6 +190,9 @@ fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr< { return; } + if set_char_spans.len() > 1 && !msrv.meets(msrvs::PATTERN_TRAIT_CHAR_ARRAY) { + return; + } span_lint_and_then( cx, MANUAL_PATTERN_CHAR_COMPARISON, @@ -221,7 +236,9 @@ impl<'tcx> LateLintPass<'tcx> for StringPatterns { { check_single_char_pattern_lint(cx, arg); - check_manual_pattern_char_comparison(cx, arg); + check_manual_pattern_char_comparison(cx, arg, &self.msrv); } } + + extract_msrv_attr!(LateContext); } diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs index ab1b3043f0c..1c1de805db0 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs @@ -549,7 +549,7 @@ fn ident_difference_expr_with_base_location( | (Assign(_, _, _), Assign(_, _, _)) | (TryBlock(_), TryBlock(_)) | (Await(_, _), Await(_, _)) - | (Gen(_, _, _), Gen(_, _, _)) + | (Gen(_, _, _, _), Gen(_, _, _, _)) | (Block(_, _), Block(_, _)) | (Closure(_), Closure(_)) | (Match(_, _, _), Match(_, _, _)) diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs index f376d349646..72392f8e1f7 100644 --- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs +++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use itertools::Itertools; +use core::mem::replace; use rustc_errors::Applicability; use rustc_hir::{HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -56,55 +56,71 @@ impl UpperCaseAcronyms { impl_lint_pass!(UpperCaseAcronyms => [UPPER_CASE_ACRONYMS]); -fn correct_ident(ident: &str) -> String { - let ident = ident.chars().rev().collect::<String>(); - let fragments = ident - .split_inclusive(|x: char| !x.is_ascii_lowercase()) - .rev() - .map(|x| x.chars().rev().collect::<String>()); - - let mut ident = fragments.clone().next().unwrap(); - for (ref prev, ref curr) in fragments.tuple_windows() { - if <[&String; 2]>::from((prev, curr)) - .iter() - .all(|s| s.len() == 1 && s.chars().next().unwrap().is_ascii_uppercase()) - { - ident.push_str(&curr.to_ascii_lowercase()); +fn contains_acronym(s: &str) -> bool { + let mut count = 0; + for c in s.chars() { + if c.is_ascii_uppercase() { + count += 1; + if count == 3 { + return true; + } } else { - ident.push_str(curr); + count = 0; } } - ident + count == 2 } fn check_ident(cx: &LateContext<'_>, ident: &Ident, hir_id: HirId, be_aggressive: bool) { - let span = ident.span; - let ident = ident.as_str(); - let corrected = correct_ident(ident); - // warn if we have pure-uppercase idents - // assume that two-letter words are some kind of valid abbreviation like FP for false positive - // (and don't warn) - if (ident.chars().all(|c| c.is_ascii_uppercase()) && ident.len() > 2) - // otherwise, warn if we have SOmeTHING lIKE THIs but only warn with the aggressive - // upper-case-acronyms-aggressive config option enabled - || (be_aggressive && ident != corrected) + let s = ident.as_str(); + + // By default, only warn for upper case identifiers with at least 3 characters. + let replacement = if s.len() > 2 && s.bytes().all(|c| c.is_ascii_uppercase()) { + let mut r = String::with_capacity(s.len()); + let mut s = s.chars(); + r.push(s.next().unwrap()); + r.extend(s.map(|c| c.to_ascii_lowercase())); + r + } else if be_aggressive + // Only lint if the ident starts with an upper case character. + && let unprefixed = s.trim_start_matches('_') + && unprefixed.starts_with(|c: char| c.is_ascii_uppercase()) + && contains_acronym(unprefixed) { - span_lint_hir_and_then( - cx, - UPPER_CASE_ACRONYMS, - hir_id, - span, - format!("name `{ident}` contains a capitalized acronym"), - |diag| { - diag.span_suggestion( - span, - "consider making the acronym lowercase, except the initial letter", - corrected, - Applicability::MaybeIncorrect, - ); - }, - ); - } + let mut r = String::with_capacity(s.len()); + let mut s = s.chars(); + let mut prev_upper = false; + while let Some(c) = s.next() { + r.push( + if replace(&mut prev_upper, c.is_ascii_uppercase()) + && s.clone().next().map_or(true, |c| c.is_ascii_uppercase()) + { + c.to_ascii_lowercase() + } else { + c + }, + ); + } + r + } else { + return; + }; + + span_lint_hir_and_then( + cx, + UPPER_CASE_ACRONYMS, + hir_id, + ident.span, + format!("name `{ident}` contains a capitalized acronym"), + |diag| { + diag.span_suggestion( + ident.span, + "consider making the acronym lowercase, except the initial letter", + replacement, + Applicability::MaybeIncorrect, + ); + }, + ); } impl LateLintPass<'_> for UpperCaseAcronyms { diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs index c62ae8d718d..0beb0bb8ed4 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -69,6 +69,7 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool { SimplifiedType::Float(FloatTy::F64), SimplifiedType::Slice, SimplifiedType::Str, + SimplifiedType::Bool, ] .iter() .flat_map(|&ty| cx.tcx.incoherent_impls(ty).into_iter()) diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 785d5ed5dbe..181bbdde8e5 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -226,7 +226,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { && eq_fn_decl(lf, rf) && eq_expr(le, re) }, - (Gen(lc, lb, lk), Gen(rc, rb, rk)) => lc == rc && eq_block(lb, rb) && lk == rk, + (Gen(lc, lb, lk, _), Gen(rc, rb, rk, _)) => lc == rc && eq_block(lb, rb) && lk == rk, (Range(lf, lt, ll), Range(rf, rt, rl)) => ll == rl && eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt), (AddrOf(lbk, lm, le), AddrOf(rbk, rm, re)) => lbk == rbk && lm == rm && eq_expr(le, re), (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp), @@ -724,9 +724,7 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool { (Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)), (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp), (TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, eq_generic_bound), - (ImplTrait(_, lg), ImplTrait(_, rg)) => { - over(lg, rg, eq_generic_bound) - }, + (ImplTrait(_, lg), ImplTrait(_, rg)) => over(lg, rg, eq_generic_bound), (Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value), (MacCall(l), MacCall(r)) => eq_mac_call(l, r), _ => false, diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 553e8999975..7f2234b310b 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -18,8 +18,8 @@ use rustc_ast::AttrStyle; use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl, - ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, MutTy, Node, QPath, Safety, TraitItem, - TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource, + ImplItem, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, QPath, Safety, + TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource, }; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::TyCtxt; @@ -121,6 +121,26 @@ fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) { } } +fn path_search_pat(path: &Path<'_>) -> (Pat, Pat) { + let (head, tail) = match path.segments { + [head, .., tail] => (head, tail), + [p] => (p, p), + [] => return (Pat::Str(""), Pat::Str("")), + }; + ( + if head.ident.name == kw::PathRoot { + Pat::Str("::") + } else { + Pat::Sym(head.ident.name) + }, + if tail.args.is_some() { + Pat::Str(">") + } else { + Pat::Sym(tail.ident.name) + }, + ) +} + /// Get the search patterns to use for the given expression fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { match e.kind { @@ -355,19 +375,21 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) { } } +fn ident_search_pat(ident: Ident) -> (Pat, Pat) { + (Pat::Sym(ident.name), Pat::Sym(ident.name)) +} + pub trait WithSearchPat<'cx> { type Context: LintContext; fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat); fn span(&self) -> Span; } macro_rules! impl_with_search_pat { - ($cx:ident: $ty:ident with $fn:ident $(($tcx:ident))?) => { - impl<'cx> WithSearchPat<'cx> for $ty<'cx> { - type Context = $cx<'cx>; - #[allow(unused_variables)] - fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat) { - $(let $tcx = cx.tcx;)? - $fn($($tcx,)? self) + (($cx_ident:ident: $cx_ty:ident<$cx_lt:lifetime>, $self:tt: $ty:ty) => $fn:ident($($args:tt)*)) => { + impl<$cx_lt> WithSearchPat<$cx_lt> for $ty { + type Context = $cx_ty<$cx_lt>; + fn search_pat(&$self, $cx_ident: &Self::Context) -> (Pat, Pat) { + $fn($($args)*) } fn span(&self) -> Span { self.span @@ -375,13 +397,17 @@ macro_rules! impl_with_search_pat { } }; } -impl_with_search_pat!(LateContext: Expr with expr_search_pat(tcx)); -impl_with_search_pat!(LateContext: Item with item_search_pat); -impl_with_search_pat!(LateContext: TraitItem with trait_item_search_pat); -impl_with_search_pat!(LateContext: ImplItem with impl_item_search_pat); -impl_with_search_pat!(LateContext: FieldDef with field_def_search_pat); -impl_with_search_pat!(LateContext: Variant with variant_search_pat); -impl_with_search_pat!(LateContext: Ty with ty_search_pat); +impl_with_search_pat!((cx: LateContext<'tcx>, self: Expr<'tcx>) => expr_search_pat(cx.tcx, self)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: Item<'_>) => item_search_pat(self)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: TraitItem<'_>) => trait_item_search_pat(self)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: ImplItem<'_>) => impl_item_search_pat(self)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: FieldDef<'_>) => field_def_search_pat(self)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: Variant<'_>) => variant_search_pat(self)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: Ty<'_>) => ty_search_pat(self)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: Attribute) => attr_search_pat(self)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: Ident) => ident_search_pat(*self)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: Lit) => lit_search_pat(&self.node)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: Path<'_>) => path_search_pat(self)); impl<'cx> WithSearchPat<'cx> for (&FnKind<'cx>, &Body<'cx>, HirId, Span) { type Context = LateContext<'cx>; @@ -395,32 +421,6 @@ impl<'cx> WithSearchPat<'cx> for (&FnKind<'cx>, &Body<'cx>, HirId, Span) { } } -// `Attribute` does not have the `hir` associated lifetime, so we cannot use the macro -impl<'cx> WithSearchPat<'cx> for &'cx Attribute { - type Context = LateContext<'cx>; - - fn search_pat(&self, _cx: &Self::Context) -> (Pat, Pat) { - attr_search_pat(self) - } - - fn span(&self) -> Span { - self.span - } -} - -// `Ident` does not have the `hir` associated lifetime, so we cannot use the macro -impl<'cx> WithSearchPat<'cx> for Ident { - type Context = LateContext<'cx>; - - fn search_pat(&self, _cx: &Self::Context) -> (Pat, Pat) { - (Pat::Sym(self.name), Pat::Sym(self.name)) - } - - fn span(&self) -> Span { - self.span - } -} - /// Checks if the item likely came from a proc-macro. /// /// This should be called after `in_external_macro` and the initial pattern matching of the ast as diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 681c86f76d0..de6ccfe476f 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1,6 +1,7 @@ #![allow(clippy::float_cmp)] -use crate::source::{get_source_text, walk_span_to_context}; +use crate::macros::HirNode; +use crate::source::{walk_span_to_context, SpanRangeExt}; use crate::{clip, is_direct_expn_of, sext, unsext}; use rustc_apfloat::ieee::{Half, Quad}; @@ -17,7 +18,7 @@ use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, IntTy, List, use rustc_middle::{bug, mir, span_bug}; use rustc_span::def_id::DefId; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::SyntaxContext; +use rustc_span::{sym, SyntaxContext}; use rustc_target::abi::Size; use std::cmp::Ordering; use std::hash::{Hash, Hasher}; @@ -326,6 +327,8 @@ pub enum ConstantSource { Local, /// The value is dependent on a defined constant. Constant, + /// The value is dependent on a constant defined in `core` crate. + CoreConstant, } impl ConstantSource { pub fn is_local(&self) -> bool { @@ -439,9 +442,19 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value), ExprKind::DropTemps(e) => self.expr(e), ExprKind::Path(ref qpath) => { + let is_core_crate = if let Some(def_id) = self.lcx.qpath_res(qpath, e.hir_id()).opt_def_id() { + self.lcx.tcx.crate_name(def_id.krate) == sym::core + } else { + false + }; self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| { let result = mir_to_const(this.lcx, result)?; - this.source = ConstantSource::Constant; + // If source is already Constant we wouldn't want to override it with CoreConstant + this.source = if is_core_crate && !matches!(this.source, ConstantSource::Constant) { + ConstantSource::CoreConstant + } else { + ConstantSource::Constant + }; Some(result) }) }, @@ -683,7 +696,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt) && let expr_lo = expr_span.lo() && expr_lo >= span.lo - && let Some(src) = get_source_text(self.lcx, span.lo..expr_lo) + && let Some(src) = (span.lo..expr_lo).get_source_text(self.lcx) && let Some(src) = src.as_str() { use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace}; diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs index 801a9852159..277ba8427e0 100644 --- a/src/tools/clippy/clippy_utils/src/higher.rs +++ b/src/tools/clippy/clippy_utils/src/higher.rs @@ -218,51 +218,56 @@ pub struct Range<'a> { impl<'a> Range<'a> { /// Higher a `hir` range to something similar to `ast::ExprKind::Range`. + #[allow(clippy::similar_names)] pub fn hir(expr: &'a Expr<'_>) -> Option<Range<'a>> { - /// Finds the field named `name` in the field. Always return `Some` for - /// convenience. - fn get_field<'c>(name: &str, fields: &'c [hir::ExprField<'_>]) -> Option<&'c Expr<'c>> { - let expr = &fields.iter().find(|field| field.ident.name.as_str() == name)?.expr; - Some(expr) - } - match expr.kind { - ExprKind::Call(path, args) + ExprKind::Call(path, [arg1, arg2]) if matches!( path.kind, ExprKind::Path(QPath::LangItem(hir::LangItem::RangeInclusiveNew, ..)) ) => { Some(Range { - start: Some(&args[0]), - end: Some(&args[1]), + start: Some(arg1), + end: Some(arg2), limits: ast::RangeLimits::Closed, }) }, - ExprKind::Struct(path, fields, None) => match &path { - QPath::LangItem(hir::LangItem::RangeFull, ..) => Some(Range { + ExprKind::Struct(path, fields, None) => match (path, fields) { + (QPath::LangItem(hir::LangItem::RangeFull, ..), []) => Some(Range { start: None, end: None, limits: ast::RangeLimits::HalfOpen, }), - QPath::LangItem(hir::LangItem::RangeFrom, ..) => Some(Range { - start: Some(get_field("start", fields)?), - end: None, - limits: ast::RangeLimits::HalfOpen, - }), - QPath::LangItem(hir::LangItem::Range, ..) => Some(Range { - start: Some(get_field("start", fields)?), - end: Some(get_field("end", fields)?), - limits: ast::RangeLimits::HalfOpen, - }), - QPath::LangItem(hir::LangItem::RangeToInclusive, ..) => Some(Range { - start: None, - end: Some(get_field("end", fields)?), - limits: ast::RangeLimits::Closed, - }), - QPath::LangItem(hir::LangItem::RangeTo, ..) => Some(Range { + (QPath::LangItem(hir::LangItem::RangeFrom, ..), [field]) if field.ident.name == sym::start => { + Some(Range { + start: Some(field.expr), + end: None, + limits: ast::RangeLimits::HalfOpen, + }) + }, + (QPath::LangItem(hir::LangItem::Range, ..), [field1, field2]) => { + let (start, end) = match (field1.ident.name, field2.ident.name) { + (sym::start, sym::end) => (field1.expr, field2.expr), + (sym::end, sym::start) => (field2.expr, field1.expr), + _ => return None, + }; + Some(Range { + start: Some(start), + end: Some(end), + limits: ast::RangeLimits::HalfOpen, + }) + }, + (QPath::LangItem(hir::LangItem::RangeToInclusive, ..), [field]) if field.ident.name == sym::end => { + Some(Range { + start: None, + end: Some(field.expr), + limits: ast::RangeLimits::Closed, + }) + }, + (QPath::LangItem(hir::LangItem::RangeTo, ..), [field]) if field.ident.name == sym::end => Some(Range { start: None, - end: Some(get_field("end", fields)?), + end: Some(field.expr), limits: ast::RangeLimits::HalfOpen, }), _ => None, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 50dd8430ac0..8706cec5d38 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1,6 +1,6 @@ use crate::consts::constant_simple; use crate::macros::macro_backtrace; -use crate::source::{get_source_text, snippet_opt, walk_span_to_context, SpanRange}; +use crate::source::{snippet_opt, walk_span_to_context, SpanRange, SpanRangeExt}; use crate::tokenize_with_text; use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxHasher; @@ -1173,9 +1173,9 @@ fn eq_span_tokens( pred: impl Fn(TokenKind) -> bool, ) -> bool { fn f(cx: &LateContext<'_>, left: Range<BytePos>, right: Range<BytePos>, pred: impl Fn(TokenKind) -> bool) -> bool { - if let Some(lsrc) = get_source_text(cx, left) + if let Some(lsrc) = left.get_source_text(cx) && let Some(lsrc) = lsrc.as_str() - && let Some(rsrc) = get_source_text(cx, right) + && let Some(rsrc) = right.get_source_text(cx) && let Some(rsrc) = rsrc.as_str() { let pred = |t: &(_, _)| pred(t.0); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 6848e8e5c30..935a25d7931 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -5,7 +5,7 @@ #![feature(f16)] #![feature(if_let_guard)] #![feature(let_chains)] -#![feature(lint_reasons)] +#![cfg_attr(bootstrap, feature(lint_reasons))] #![feature(never_type)] #![feature(rustc_private)] #![feature(assert_matches)] @@ -2666,13 +2666,80 @@ pub enum DefinedTy<'tcx> { /// The context an expressions value is used in. pub struct ExprUseCtxt<'tcx> { /// The parent node which consumes the value. - pub node: ExprUseNode<'tcx>, + pub node: Node<'tcx>, + /// The child id of the node the value came from. + pub child_id: HirId, /// Any adjustments applied to the type. pub adjustments: &'tcx [Adjustment<'tcx>], - /// Whether or not the type must unify with another code path. + /// Whether the type must unify with another code path. pub is_ty_unified: bool, - /// Whether or not the value will be moved before it's used. + /// Whether the value will be moved before it's used. pub moved_before_use: bool, + /// Whether the use site has the same `SyntaxContext` as the value. + pub same_ctxt: bool, +} +impl<'tcx> ExprUseCtxt<'tcx> { + pub fn use_node(&self, cx: &LateContext<'tcx>) -> ExprUseNode<'tcx> { + match self.node { + Node::LetStmt(l) => ExprUseNode::LetStmt(l), + Node::ExprField(field) => ExprUseNode::Field(field), + + Node::Item(&Item { + kind: ItemKind::Static(..) | ItemKind::Const(..), + owner_id, + .. + }) + | Node::TraitItem(&TraitItem { + kind: TraitItemKind::Const(..), + owner_id, + .. + }) + | Node::ImplItem(&ImplItem { + kind: ImplItemKind::Const(..), + owner_id, + .. + }) => ExprUseNode::ConstStatic(owner_id), + + Node::Item(&Item { + kind: ItemKind::Fn(..), + owner_id, + .. + }) + | Node::TraitItem(&TraitItem { + kind: TraitItemKind::Fn(..), + owner_id, + .. + }) + | Node::ImplItem(&ImplItem { + kind: ImplItemKind::Fn(..), + owner_id, + .. + }) => ExprUseNode::Return(owner_id), + + Node::Expr(use_expr) => match use_expr.kind { + ExprKind::Ret(_) => ExprUseNode::Return(OwnerId { + def_id: cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()), + }), + + ExprKind::Closure(closure) => ExprUseNode::Return(OwnerId { def_id: closure.def_id }), + ExprKind::Call(func, args) => match args.iter().position(|arg| arg.hir_id == self.child_id) { + Some(i) => ExprUseNode::FnArg(func, i), + None => ExprUseNode::Callee, + }, + ExprKind::MethodCall(name, _, args, _) => ExprUseNode::MethodArg( + use_expr.hir_id, + name.args, + args.iter() + .position(|arg| arg.hir_id == self.child_id) + .map_or(0, |i| i + 1), + ), + ExprKind::Field(_, name) => ExprUseNode::FieldAccess(name), + ExprKind::AddrOf(kind, mutbl, _) => ExprUseNode::AddrOf(kind, mutbl), + _ => ExprUseNode::Other, + }, + _ => ExprUseNode::Other, + } + } } /// The node which consumes a value. @@ -2693,7 +2760,8 @@ pub enum ExprUseNode<'tcx> { Callee, /// Access of a field. FieldAccess(Ident), - Expr, + /// Borrow expression. + AddrOf(ast::BorrowKind, Mutability), Other, } impl<'tcx> ExprUseNode<'tcx> { @@ -2770,26 +2838,25 @@ impl<'tcx> ExprUseNode<'tcx> { let sig = cx.tcx.fn_sig(id).skip_binder(); Some(DefinedTy::Mir(cx.tcx.param_env(id).and(sig.input(i)))) }, - Self::LetStmt(_) | Self::FieldAccess(..) | Self::Callee | Self::Expr | Self::Other => None, + Self::LetStmt(_) | Self::FieldAccess(..) | Self::Callee | Self::Other | Self::AddrOf(..) => None, } } } /// Gets the context an expression's value is used in. -pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Option<ExprUseCtxt<'tcx>> { +pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> ExprUseCtxt<'tcx> { let mut adjustments = [].as_slice(); let mut is_ty_unified = false; let mut moved_before_use = false; + let mut same_ctxt = true; let ctxt = e.span.ctxt(); - walk_to_expr_usage(cx, e, &mut |parent_id, parent, child_id| { + let node = walk_to_expr_usage(cx, e, &mut |parent_id, parent, child_id| -> ControlFlow<!> { if adjustments.is_empty() && let Node::Expr(e) = cx.tcx.hir_node(child_id) { adjustments = cx.typeck_results().expr_adjustments(e); } - if cx.tcx.hir().span(parent_id).ctxt() != ctxt { - return ControlFlow::Break(()); - } + same_ctxt &= cx.tcx.hir().span(parent_id).ctxt() == ctxt; if let Node::Expr(e) = parent { match e.kind { ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id != child_id => { @@ -2805,71 +2872,26 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Optio } } ControlFlow::Continue(()) - })? - .continue_value() - .map(|(use_node, child_id)| { - let node = match use_node { - Node::LetStmt(l) => ExprUseNode::LetStmt(l), - Node::ExprField(field) => ExprUseNode::Field(field), - - Node::Item(&Item { - kind: ItemKind::Static(..) | ItemKind::Const(..), - owner_id, - .. - }) - | Node::TraitItem(&TraitItem { - kind: TraitItemKind::Const(..), - owner_id, - .. - }) - | Node::ImplItem(&ImplItem { - kind: ImplItemKind::Const(..), - owner_id, - .. - }) => ExprUseNode::ConstStatic(owner_id), - - Node::Item(&Item { - kind: ItemKind::Fn(..), - owner_id, - .. - }) - | Node::TraitItem(&TraitItem { - kind: TraitItemKind::Fn(..), - owner_id, - .. - }) - | Node::ImplItem(&ImplItem { - kind: ImplItemKind::Fn(..), - owner_id, - .. - }) => ExprUseNode::Return(owner_id), - - Node::Expr(use_expr) => match use_expr.kind { - ExprKind::Ret(_) => ExprUseNode::Return(OwnerId { - def_id: cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()), - }), - ExprKind::Closure(closure) => ExprUseNode::Return(OwnerId { def_id: closure.def_id }), - ExprKind::Call(func, args) => match args.iter().position(|arg| arg.hir_id == child_id) { - Some(i) => ExprUseNode::FnArg(func, i), - None => ExprUseNode::Callee, - }, - ExprKind::MethodCall(name, _, args, _) => ExprUseNode::MethodArg( - use_expr.hir_id, - name.args, - args.iter().position(|arg| arg.hir_id == child_id).map_or(0, |i| i + 1), - ), - ExprKind::Field(child, name) if child.hir_id == e.hir_id => ExprUseNode::FieldAccess(name), - _ => ExprUseNode::Expr, - }, - _ => ExprUseNode::Other, - }; - ExprUseCtxt { + }); + match node { + Some(ControlFlow::Continue((node, child_id))) => ExprUseCtxt { node, + child_id, adjustments, is_ty_unified, moved_before_use, - } - }) + same_ctxt, + }, + Some(ControlFlow::Break(_)) => unreachable!("type of node is ControlFlow<!>"), + None => ExprUseCtxt { + node: Node::Crate(cx.tcx.hir().root_module()), + child_id: HirId::INVALID, + adjustments: &[], + is_ty_unified: true, + moved_before_use: true, + same_ctxt: false, + }, + } } /// Tokenizes the input while keeping the text associated with each token. diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs index 7b4fd8a210e..07e6705cd3d 100644 --- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs +++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs @@ -69,7 +69,7 @@ impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b, fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) { let lhs = place.local; match rvalue { - mir::Rvalue::Ref(_, _, borrowed) => { + mir::Rvalue::Ref(_, _, borrowed) | mir::Rvalue::CopyForDeref(borrowed) => { self.possible_borrower.add(borrowed.local, lhs); }, other => { diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index 9bf068ee3cd..3f66813801d 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -110,5 +110,4 @@ pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"]; pub const WAKER: [&str; 4] = ["core", "task", "wake", "Waker"]; pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"]; pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"]; -#[expect(clippy::invalid_paths)] // not sure why it thinks this, it works so pub const BOOL_THEN: [&str; 4] = ["core", "bool", "<impl bool>", "then"]; diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index e2e5cde947d..496c8f5b553 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -9,12 +9,16 @@ use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource}; use rustc_lint::{LateContext, LintContext}; use rustc_session::Session; use rustc_span::source_map::{original_sp, SourceMap}; -use rustc_span::{hygiene, BytePos, SourceFileAndLine, Pos, SourceFile, Span, SpanData, SyntaxContext, DUMMY_SP}; +use rustc_span::{ + hygiene, BytePos, FileNameDisplayPreference, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext, + DUMMY_SP, +}; use std::borrow::Cow; +use std::fmt; use std::ops::Range; -/// A type which can be converted to the range portion of a `Span`. -pub trait SpanRange { +/// Conversion of a value into the range portion of a `Span`. +pub trait SpanRange: Sized { fn into_range(self) -> Range<BytePos>; } impl SpanRange for Span { @@ -34,6 +38,182 @@ impl SpanRange for Range<BytePos> { } } +/// Conversion of a value into a `Span` +pub trait IntoSpan: Sized { + fn into_span(self) -> Span; + fn with_ctxt(self, ctxt: SyntaxContext) -> Span; +} +impl IntoSpan for Span { + fn into_span(self) -> Span { + self + } + fn with_ctxt(self, ctxt: SyntaxContext) -> Span { + self.with_ctxt(ctxt) + } +} +impl IntoSpan for SpanData { + fn into_span(self) -> Span { + self.span() + } + fn with_ctxt(self, ctxt: SyntaxContext) -> Span { + Span::new(self.lo, self.hi, ctxt, self.parent) + } +} +impl IntoSpan for Range<BytePos> { + fn into_span(self) -> Span { + Span::with_root_ctxt(self.start, self.end) + } + fn with_ctxt(self, ctxt: SyntaxContext) -> Span { + Span::new(self.start, self.end, ctxt, None) + } +} + +pub trait SpanRangeExt: SpanRange { + /// Gets the source file, and range in the file, of the given span. Returns `None` if the span + /// extends through multiple files, or is malformed. + fn get_source_text(self, cx: &impl LintContext) -> Option<SourceFileRange> { + get_source_text(cx.sess().source_map(), self.into_range()) + } + + /// Calls the given function with the source text referenced and returns the value. Returns + /// `None` if the source text cannot be retrieved. + fn with_source_text<T>(self, cx: &impl LintContext, f: impl for<'a> FnOnce(&'a str) -> T) -> Option<T> { + with_source_text(cx.sess().source_map(), self.into_range(), f) + } + + /// Checks if the referenced source text satisfies the given predicate. Returns `false` if the + /// source text cannot be retrieved. + fn check_source_text(self, cx: &impl LintContext, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool { + self.with_source_text(cx, pred).unwrap_or(false) + } + + /// Calls the given function with the both the text of the source file and the referenced range, + /// and returns the value. Returns `None` if the source text cannot be retrieved. + fn with_source_text_and_range<T>( + self, + cx: &impl LintContext, + f: impl for<'a> FnOnce(&'a str, Range<usize>) -> T, + ) -> Option<T> { + with_source_text_and_range(cx.sess().source_map(), self.into_range(), f) + } + + /// Calls the given function with the both the text of the source file and the referenced range, + /// and creates a new span with the returned range. Returns `None` if the source text cannot be + /// retrieved, or no result is returned. + /// + /// The new range must reside within the same source file. + fn map_range( + self, + cx: &impl LintContext, + f: impl for<'a> FnOnce(&'a str, Range<usize>) -> Option<Range<usize>>, + ) -> Option<Range<BytePos>> { + map_range(cx.sess().source_map(), self.into_range(), f) + } + + /// Extends the range to include all preceding whitespace characters. + fn with_leading_whitespace(self, cx: &impl LintContext) -> Range<BytePos> { + with_leading_whitespace(cx.sess().source_map(), self.into_range()) + } + + /// Trims the leading whitespace from the range. + fn trim_start(self, cx: &impl LintContext) -> Range<BytePos> { + trim_start(cx.sess().source_map(), self.into_range()) + } + + /// Writes the referenced source text to the given writer. Will return `Err` if the source text + /// could not be retrieved. + fn write_source_text_to(self, cx: &impl LintContext, dst: &mut impl fmt::Write) -> fmt::Result { + write_source_text_to(cx.sess().source_map(), self.into_range(), dst) + } + + /// Extracts the referenced source text as an owned string. + fn source_text_to_string(self, cx: &impl LintContext) -> Option<String> { + self.with_source_text(cx, ToOwned::to_owned) + } +} +impl<T: SpanRange> SpanRangeExt for T {} + +fn get_source_text(sm: &SourceMap, sp: Range<BytePos>) -> Option<SourceFileRange> { + let start = sm.lookup_byte_offset(sp.start); + let end = sm.lookup_byte_offset(sp.end); + if !Lrc::ptr_eq(&start.sf, &end.sf) || start.pos > end.pos { + return None; + } + let range = start.pos.to_usize()..end.pos.to_usize(); + Some(SourceFileRange { sf: start.sf, range }) +} + +fn with_source_text<T>(sm: &SourceMap, sp: Range<BytePos>, f: impl for<'a> FnOnce(&'a str) -> T) -> Option<T> { + if let Some(src) = get_source_text(sm, sp) + && let Some(src) = src.as_str() + { + Some(f(src)) + } else { + None + } +} + +fn with_source_text_and_range<T>( + sm: &SourceMap, + sp: Range<BytePos>, + f: impl for<'a> FnOnce(&'a str, Range<usize>) -> T, +) -> Option<T> { + if let Some(src) = get_source_text(sm, sp) + && let Some(text) = &src.sf.src + { + Some(f(text, src.range)) + } else { + None + } +} + +#[expect(clippy::cast_possible_truncation)] +fn map_range( + sm: &SourceMap, + sp: Range<BytePos>, + f: impl for<'a> FnOnce(&'a str, Range<usize>) -> Option<Range<usize>>, +) -> Option<Range<BytePos>> { + if let Some(src) = get_source_text(sm, sp.clone()) + && let Some(text) = &src.sf.src + && let Some(range) = f(text, src.range.clone()) + { + debug_assert!( + range.start <= text.len() && range.end <= text.len(), + "Range `{range:?}` is outside the source file (file `{}`, length `{}`)", + src.sf.name.display(FileNameDisplayPreference::Local), + text.len(), + ); + debug_assert!(range.start <= range.end, "Range `{range:?}` has overlapping bounds"); + let dstart = (range.start as u32).wrapping_sub(src.range.start as u32); + let dend = (range.end as u32).wrapping_sub(src.range.start as u32); + Some(BytePos(sp.start.0.wrapping_add(dstart))..BytePos(sp.start.0.wrapping_add(dend))) + } else { + None + } +} + +fn with_leading_whitespace(sm: &SourceMap, sp: Range<BytePos>) -> Range<BytePos> { + map_range(sm, sp.clone(), |src, range| { + Some(src.get(..range.start)?.trim_end().len()..range.end) + }) + .unwrap_or(sp) +} + +fn trim_start(sm: &SourceMap, sp: Range<BytePos>) -> Range<BytePos> { + map_range(sm, sp.clone(), |src, range| { + let src = src.get(range.clone())?; + Some(range.start + (src.len() - src.trim_start().len())..range.end) + }) + .unwrap_or(sp) +} + +fn write_source_text_to(sm: &SourceMap, sp: Range<BytePos>, dst: &mut impl fmt::Write) -> fmt::Result { + match with_source_text(sm, sp, |src| dst.write_str(src)) { + Some(x) => x, + None => Err(fmt::Error), + } +} + pub struct SourceFileRange { pub sf: Lrc<SourceFile>, pub range: Range<usize>, @@ -46,21 +226,6 @@ impl SourceFileRange { } } -/// Gets the source file, and range in the file, of the given span. Returns `None` if the span -/// extends through multiple files, or is malformed. -pub fn get_source_text(cx: &impl LintContext, sp: impl SpanRange) -> Option<SourceFileRange> { - fn f(sm: &SourceMap, sp: Range<BytePos>) -> Option<SourceFileRange> { - let start = sm.lookup_byte_offset(sp.start); - let end = sm.lookup_byte_offset(sp.end); - if !Lrc::ptr_eq(&start.sf, &end.sf) || start.pos > end.pos { - return None; - } - let range = start.pos.to_usize()..end.pos.to_usize(); - Some(SourceFileRange { sf: start.sf, range }) - } - f(cx.sess().source_map(), sp.into_range()) -} - /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`. pub fn expr_block<T: LintContext>( cx: &T, diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 3790a852f7e..e5d20564196 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -1349,3 +1349,17 @@ pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_n None } } + +/// Get's the type of a field by name. +pub fn get_field_by_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, name: Symbol) -> Option<Ty<'tcx>> { + match *ty.kind() { + ty::Adt(def, args) if def.is_union() || def.is_struct() => def + .non_enum_variant() + .fields + .iter() + .find(|f| f.name == name) + .map(|f| f.ty(tcx, args)), + ty::Tuple(args) => name.as_str().parse::<usize>().ok().and_then(|i| args.get(i).copied()), + _ => None, + } +} diff --git a/src/tools/clippy/lintcheck/Cargo.toml b/src/tools/clippy/lintcheck/Cargo.toml index 8c5a409e25b..ae9e77b8eed 100644 --- a/src/tools/clippy/lintcheck/Cargo.toml +++ b/src/tools/clippy/lintcheck/Cargo.toml @@ -11,28 +11,19 @@ publish = false default-run = "lintcheck" [dependencies] -anyhow = "1.0.69" cargo_metadata = "0.15.3" clap = { version = "4.4", features = ["derive", "env"] } -crates_io_api = "0.8.1" crossbeam-channel = "0.5.6" +diff = "0.1.13" flate2 = "1.0" -indicatif = "0.17.3" rayon = "1.5.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.85" +strip-ansi-escapes = "0.2.0" tar = "0.4" toml = "0.7.3" -ureq = "2.2" +ureq = { version = "2.2", features = ["json"] } walkdir = "2.3" [features] deny-warnings = [] - -[[bin]] -name = "lintcheck" -path = "src/main.rs" - -[[bin]] -name = "popular-crates" -path = "src/popular-crates.rs" diff --git a/src/tools/clippy/lintcheck/README.md b/src/tools/clippy/lintcheck/README.md index 61b581ba0fa..2d6039caeef 100644 --- a/src/tools/clippy/lintcheck/README.md +++ b/src/tools/clippy/lintcheck/README.md @@ -26,11 +26,11 @@ the repo root. The results will then be saved to `lintcheck-logs/custom_logs.toml`. The `custom.toml` file may be built using <https://crates.io> recently most -downloaded crates by using the `popular-crates` binary from the `lintcheck` -directory. For example, to retrieve the 100 recently most downloaded crates: +downloaded crates by using `cargo lintcheck popular`. For example, to retrieve +the 200 recently most downloaded crates: ``` -cargo run --release --bin popular-crates -- -n 100 custom.toml +cargo lintcheck popular -n 200 custom.toml ``` diff --git a/src/tools/clippy/lintcheck/src/config.rs b/src/tools/clippy/lintcheck/src/config.rs index 3f712f453fa..e6cd7c9fdc2 100644 --- a/src/tools/clippy/lintcheck/src/config.rs +++ b/src/tools/clippy/lintcheck/src/config.rs @@ -1,8 +1,9 @@ -use clap::Parser; +use clap::{Parser, Subcommand, ValueEnum}; use std::num::NonZero; use std::path::PathBuf; -#[derive(Clone, Debug, Parser)] +#[derive(Parser, Clone, Debug)] +#[command(args_conflicts_with_subcommands = true)] pub(crate) struct LintcheckConfig { /// Number of threads to use (default: all unless --fix or --recursive) #[clap( @@ -35,12 +36,45 @@ pub(crate) struct LintcheckConfig { /// Apply a filter to only collect specified lints, this also overrides `allow` attributes #[clap(long = "filter", value_name = "clippy_lint_name", use_value_delimiter = true)] pub lint_filter: Vec<String>, - /// Change the reports table to use markdown links - #[clap(long)] - pub markdown: bool, + /// Set the output format of the log file + #[clap(long, short, default_value = "text")] + pub format: OutputFormat, /// Run clippy on the dependencies of crates specified in crates-toml #[clap(long, conflicts_with("max_jobs"))] pub recursive: bool, + #[command(subcommand)] + pub subcommand: Option<Commands>, +} + +#[derive(Subcommand, Clone, Debug)] +pub(crate) enum Commands { + /// Display a markdown diff between two lintcheck log files in JSON format + Diff { old: PathBuf, new: PathBuf }, + /// Create a lintcheck crates TOML file containing the top N popular crates + Popular { + /// Output TOML file name + output: PathBuf, + /// Number of crate names to download + #[clap(short, long, default_value_t = 100)] + number: usize, + }, +} + +#[derive(ValueEnum, Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum OutputFormat { + Text, + Markdown, + Json, +} + +impl OutputFormat { + fn file_extension(self) -> &'static str { + match self { + OutputFormat::Text => "txt", + OutputFormat::Markdown => "md", + OutputFormat::Json => "json", + } + } } impl LintcheckConfig { @@ -53,7 +87,7 @@ impl LintcheckConfig { config.lintcheck_results_path = PathBuf::from(format!( "lintcheck-logs/{}_logs.{}", filename.display(), - if config.markdown { "md" } else { "txt" } + config.format.file_extension(), )); // look at the --threads arg, if 0 is passed, use the threads count diff --git a/src/tools/clippy/lintcheck/src/json.rs b/src/tools/clippy/lintcheck/src/json.rs new file mode 100644 index 00000000000..43d0413c7ce --- /dev/null +++ b/src/tools/clippy/lintcheck/src/json.rs @@ -0,0 +1,122 @@ +use std::collections::HashMap; +use std::fmt::Write; +use std::fs; +use std::hash::Hash; +use std::path::Path; + +use crate::ClippyWarning; + +/// Creates the log file output for [`crate::config::OutputFormat::Json`] +pub(crate) fn output(clippy_warnings: &[ClippyWarning]) -> String { + serde_json::to_string(&clippy_warnings).unwrap() +} + +fn load_warnings(path: &Path) -> Vec<ClippyWarning> { + let file = fs::read(path).unwrap_or_else(|e| panic!("failed to read {}: {e}", path.display())); + + serde_json::from_slice(&file).unwrap_or_else(|e| panic!("failed to deserialize {}: {e}", path.display())) +} + +/// Group warnings by their primary span location + lint name +fn create_map(warnings: &[ClippyWarning]) -> HashMap<impl Eq + Hash + '_, Vec<&ClippyWarning>> { + let mut map = HashMap::<_, Vec<_>>::with_capacity(warnings.len()); + + for warning in warnings { + let span = warning.span(); + let key = (&warning.lint_type, &span.file_name, span.byte_start, span.byte_end); + + map.entry(key).or_default().push(warning); + } + + map +} + +fn print_warnings(title: &str, warnings: &[&ClippyWarning]) { + if warnings.is_empty() { + return; + } + + println!("### {title}"); + println!("```"); + for warning in warnings { + print!("{}", warning.diag); + } + println!("```"); +} + +fn print_changed_diff(changed: &[(&[&ClippyWarning], &[&ClippyWarning])]) { + fn render(warnings: &[&ClippyWarning]) -> String { + let mut rendered = String::new(); + for warning in warnings { + write!(&mut rendered, "{}", warning.diag).unwrap(); + } + rendered + } + + if changed.is_empty() { + return; + } + + println!("### Changed"); + println!("```diff"); + for &(old, new) in changed { + let old_rendered = render(old); + let new_rendered = render(new); + + for change in diff::lines(&old_rendered, &new_rendered) { + use diff::Result::{Both, Left, Right}; + + match change { + Both(unchanged, _) => { + println!(" {unchanged}"); + }, + Left(removed) => { + println!("-{removed}"); + }, + Right(added) => { + println!("+{added}"); + }, + } + } + } + println!("```"); +} + +pub(crate) fn diff(old_path: &Path, new_path: &Path) { + let old_warnings = load_warnings(old_path); + let new_warnings = load_warnings(new_path); + + let old_map = create_map(&old_warnings); + let new_map = create_map(&new_warnings); + + let mut added = Vec::new(); + let mut removed = Vec::new(); + let mut changed = Vec::new(); + + for (key, new) in &new_map { + if let Some(old) = old_map.get(key) { + if old != new { + changed.push((old.as_slice(), new.as_slice())); + } + } else { + added.extend(new); + } + } + + for (key, old) in &old_map { + if !new_map.contains_key(key) { + removed.extend(old); + } + } + + print!( + "{} added, {} removed, {} changed\n\n", + added.len(), + removed.len(), + changed.len() + ); + + print_warnings("Added", &added); + print_warnings("Removed", &removed); + print_changed_diff(&changed); +} diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs index deb06094d83..ec72e0eb5dc 100644 --- a/src/tools/clippy/lintcheck/src/main.rs +++ b/src/tools/clippy/lintcheck/src/main.rs @@ -12,26 +12,29 @@ unused_lifetimes, unused_qualifications )] -#![allow(clippy::collapsible_else_if)] +#![allow(clippy::collapsible_else_if, clippy::needless_borrows_for_generic_args)] mod config; mod driver; +mod json; +mod popular_crates; mod recursive; -use crate::config::LintcheckConfig; +use crate::config::{Commands, LintcheckConfig, OutputFormat}; use crate::recursive::LintcheckServer; use std::collections::{HashMap, HashSet}; use std::env::consts::EXE_SUFFIX; -use std::fmt::{self, Write as _}; +use std::fmt::{self, Display, Write as _}; +use std::hash::Hash; use std::io::{self, ErrorKind}; use std::path::{Path, PathBuf}; -use std::process::{Command, ExitStatus}; +use std::process::{Command, ExitStatus, Stdio}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::Duration; use std::{env, fs, thread}; -use cargo_metadata::diagnostic::Diagnostic; +use cargo_metadata::diagnostic::{Diagnostic, DiagnosticSpan}; use cargo_metadata::Message; use rayon::prelude::*; use serde::{Deserialize, Serialize}; @@ -41,21 +44,21 @@ const LINTCHECK_DOWNLOADS: &str = "target/lintcheck/downloads"; const LINTCHECK_SOURCES: &str = "target/lintcheck/sources"; /// List of sources to check, loaded from a .toml file -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Deserialize)] struct SourceList { crates: HashMap<String, TomlCrate>, #[serde(default)] recursive: RecursiveOptions, } -#[derive(Debug, Serialize, Deserialize, Default)] +#[derive(Debug, Deserialize, Default)] struct RecursiveOptions { ignore: HashSet<String>, } /// A crate source stored inside the .toml /// will be translated into on one of the `CrateSource` variants -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Deserialize)] struct TomlCrate { name: String, versions: Option<Vec<String>>, @@ -67,7 +70,7 @@ struct TomlCrate { /// Represents an archive we download from crates.io, or a git repo, or a local repo/folder /// Once processed (downloaded/extracted/cloned/copied...), this will be translated into a `Crate` -#[derive(Debug, Serialize, Deserialize, Eq, Hash, PartialEq, Ord, PartialOrd)] +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Ord, PartialOrd)] enum CrateSource { CratesIo { name: String, @@ -111,6 +114,17 @@ struct RustcIce { pub crate_name: String, pub ice_content: String, } + +impl Display for RustcIce { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}:\n{}\n========================================\n", + self.crate_name, self.ice_content + ) + } +} + impl RustcIce { pub fn from_stderr_and_status(crate_name: &str, status: ExitStatus, stderr: &str) -> Option<Self> { if status.code().unwrap_or(0) == 101 @@ -127,60 +141,58 @@ impl RustcIce { } /// A single warning that clippy issued while checking a `Crate` -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] struct ClippyWarning { - file: String, - line: usize, - column: usize, + crate_name: String, + crate_version: String, lint_type: String, - message: String, + diag: Diagnostic, } #[allow(unused)] impl ClippyWarning { - fn new(diag: Diagnostic, crate_name: &str, crate_version: &str) -> Option<Self> { - let lint_type = diag.code?.code; + fn new(mut diag: Diagnostic, crate_name: &str, crate_version: &str) -> Option<Self> { + let lint_type = diag.code.clone()?.code; if !(lint_type.contains("clippy") || diag.message.contains("clippy")) || diag.message.contains("could not read cargo metadata") { return None; } - let span = diag.spans.into_iter().find(|span| span.is_primary)?; - - let file = if let Ok(stripped) = Path::new(&span.file_name).strip_prefix(env!("CARGO_HOME")) { - format!("$CARGO_HOME/{}", stripped.display()) - } else { - format!( - "target/lintcheck/sources/{crate_name}-{crate_version}/{}", - span.file_name - ) - }; + // --recursive bypasses cargo so we have to strip the rendered output ourselves + let rendered = diag.rendered.as_mut().unwrap(); + *rendered = strip_ansi_escapes::strip_str(&rendered); Some(Self { - file, - line: span.line_start, - column: span.column_start, + crate_name: crate_name.to_owned(), + crate_version: crate_version.to_owned(), lint_type, - message: diag.message, + diag, }) } - fn to_output(&self, markdown: bool) -> String { - let file_with_pos = format!("{}:{}:{}", &self.file, &self.line, &self.column); - if markdown { - let mut file = self.file.clone(); - if !file.starts_with('$') { - file.insert_str(0, "../"); - } + fn span(&self) -> &DiagnosticSpan { + self.diag.spans.iter().find(|span| span.is_primary).unwrap() + } - let mut output = String::from("| "); - let _: fmt::Result = write!(output, "[`{file_with_pos}`]({file}#L{})", self.line); - let _: fmt::Result = write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.message); - output.push('\n'); - output - } else { - format!("{file_with_pos} {} \"{}\"\n", self.lint_type, self.message) + fn to_output(&self, format: OutputFormat) -> String { + let span = self.span(); + let mut file = span.file_name.clone(); + let file_with_pos = format!("{file}:{}:{}", span.line_start, span.line_end); + match format { + OutputFormat::Text => format!("{file_with_pos} {} \"{}\"\n", self.lint_type, self.diag.message), + OutputFormat::Markdown => { + if file.starts_with("target") { + file.insert_str(0, "../"); + } + + let mut output = String::from("| "); + write!(output, "[`{file_with_pos}`]({file}#L{})", span.line_start).unwrap(); + write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.diag.message).unwrap(); + output.push('\n'); + output + }, + OutputFormat::Json => unreachable!("JSON output is handled via serde"), } } } @@ -333,10 +345,9 @@ impl CrateSource { impl Crate { /// Run `cargo clippy` on the `Crate` and collect and return all the lint warnings that clippy /// issued - #[allow(clippy::too_many_arguments)] + #[allow(clippy::too_many_arguments, clippy::too_many_lines)] fn run_clippy_lints( &self, - cargo_clippy_path: &Path, clippy_driver_path: &Path, target_dir_index: &AtomicUsize, total_crates_to_lint: usize, @@ -362,17 +373,27 @@ impl Crate { ); } - let cargo_clippy_path = fs::canonicalize(cargo_clippy_path).unwrap(); - let shared_target_dir = clippy_project_root().join("target/lintcheck/shared_target_dir"); - let mut cargo_clippy_args = if config.fix { - vec!["--quiet", "--fix", "--"] - } else { - vec!["--quiet", "--message-format=json", "--"] - }; + let cargo_home = env!("CARGO_HOME"); + + // `src/lib.rs` -> `target/lintcheck/sources/crate-1.2.3/src/lib.rs` + let remap_relative = format!("={}", self.path.display()); + // Fallback for other sources, `~/.cargo/...` -> `$CARGO_HOME/...` + let remap_cargo_home = format!("{cargo_home}=$CARGO_HOME"); + // `~/.cargo/registry/src/index.crates.io-6f17d22bba15001f/crate-2.3.4/src/lib.rs` + // -> `crate-2.3.4/src/lib.rs` + let remap_crates_io = format!("{cargo_home}/registry/src/index.crates.io-6f17d22bba15001f/="); + + let mut clippy_args = vec![ + "--remap-path-prefix", + &remap_relative, + "--remap-path-prefix", + &remap_cargo_home, + "--remap-path-prefix", + &remap_crates_io, + ]; - let mut clippy_args = Vec::<&str>::new(); if let Some(options) = &self.options { for opt in options { clippy_args.push(opt); @@ -388,23 +409,23 @@ impl Crate { clippy_args.extend(lint_filter.iter().map(String::as_str)); } - if let Some(server) = server { - let target = shared_target_dir.join("recursive"); + let mut cmd = Command::new("cargo"); + cmd.arg(if config.fix { "fix" } else { "check" }) + .arg("--quiet") + .current_dir(&self.path) + .env("CLIPPY_ARGS", clippy_args.join("__CLIPPY_HACKERY__")); + if let Some(server) = server { // `cargo clippy` is a wrapper around `cargo check` that mainly sets `RUSTC_WORKSPACE_WRAPPER` to // `clippy-driver`. We do the same thing here with a couple changes: // // `RUSTC_WRAPPER` is used instead of `RUSTC_WORKSPACE_WRAPPER` so that we can lint all crate // dependencies rather than only workspace members // - // The wrapper is set to the `lintcheck` so we can force enable linting and ignore certain crates + // The wrapper is set to `lintcheck` itself so we can force enable linting and ignore certain crates // (see `crate::driver`) - let status = Command::new(env::var("CARGO").unwrap_or("cargo".into())) - .arg("check") - .arg("--quiet") - .current_dir(&self.path) - .env("CLIPPY_ARGS", clippy_args.join("__CLIPPY_HACKERY__")) - .env("CARGO_TARGET_DIR", target) + let status = cmd + .env("CARGO_TARGET_DIR", shared_target_dir.join("recursive")) .env("RUSTC_WRAPPER", env::current_exe().unwrap()) // Pass the absolute path so `crate::driver` can find `clippy-driver`, as it's executed in various // different working directories @@ -416,23 +437,19 @@ impl Crate { assert_eq!(status.code(), Some(0)); return Vec::new(); - } + }; - cargo_clippy_args.extend(clippy_args); + if !config.fix { + cmd.arg("--message-format=json"); + } - let all_output = Command::new(&cargo_clippy_path) + let all_output = cmd // use the looping index to create individual target dirs .env("CARGO_TARGET_DIR", shared_target_dir.join(format!("_{thread_index:?}"))) - .args(&cargo_clippy_args) - .current_dir(&self.path) + // Roughly equivalent to `cargo clippy`/`cargo clippy --fix` + .env("RUSTC_WORKSPACE_WRAPPER", clippy_driver_path) .output() - .unwrap_or_else(|error| { - panic!( - "Encountered error:\n{error:?}\ncargo_clippy_path: {}\ncrate path:{}\n", - &cargo_clippy_path.display(), - &self.path.display() - ); - }); + .unwrap(); let stdout = String::from_utf8_lossy(&all_output.stdout); let stderr = String::from_utf8_lossy(&all_output.stderr); let status = &all_output.status; @@ -479,15 +496,17 @@ impl Crate { } /// Builds clippy inside the repo to make sure we have a clippy executable we can use. -fn build_clippy() { - let status = Command::new(env::var("CARGO").unwrap_or("cargo".into())) - .arg("build") - .status() - .expect("Failed to build clippy!"); - if !status.success() { +fn build_clippy() -> String { + let output = Command::new("cargo") + .args(["run", "--bin=clippy-driver", "--", "--version"]) + .stderr(Stdio::inherit()) + .output() + .unwrap(); + if !output.status.success() { eprintln!("Error: Failed to compile Clippy!"); std::process::exit(1); } + String::from_utf8_lossy(&output.stdout).into_owned() } /// Read a `lintcheck_crates.toml` file @@ -554,10 +573,10 @@ fn read_crates(toml_path: &Path) -> (Vec<CrateSource>, RecursiveOptions) { } /// Generate a short list of occurring lints-types and their count -fn gather_stats(clippy_warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) { +fn gather_stats(warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) { // count lint type occurrences let mut counter: HashMap<&String, usize> = HashMap::new(); - clippy_warnings + warnings .iter() .for_each(|wrn| *counter.entry(&wrn.lint_type).or_insert(0) += 1); @@ -580,7 +599,6 @@ fn gather_stats(clippy_warnings: &[ClippyWarning]) -> (String, HashMap<&String, (stats_string, counter) } -#[allow(clippy::too_many_lines)] fn main() { // We're being executed as a `RUSTC_WRAPPER` as part of `--recursive` if let Ok(addr) = env::var("LINTCHECK_SERVER") { @@ -595,31 +613,29 @@ fn main() { let config = LintcheckConfig::new(); - println!("Compiling clippy..."); - build_clippy(); - println!("Done compiling"); + match config.subcommand { + Some(Commands::Diff { old, new }) => json::diff(&old, &new), + Some(Commands::Popular { output, number }) => popular_crates::fetch(output, number).unwrap(), + None => lintcheck(config), + } +} - let cargo_clippy_path = fs::canonicalize(format!("target/debug/cargo-clippy{EXE_SUFFIX}")).unwrap(); +#[allow(clippy::too_many_lines)] +fn lintcheck(config: LintcheckConfig) { + let clippy_ver = build_clippy(); let clippy_driver_path = fs::canonicalize(format!("target/debug/clippy-driver{EXE_SUFFIX}")).unwrap(); // assert that clippy is found assert!( - cargo_clippy_path.is_file(), - "target/debug/cargo-clippy binary not found! {}", - cargo_clippy_path.display() + clippy_driver_path.is_file(), + "target/debug/clippy-driver binary not found! {}", + clippy_driver_path.display() ); - let clippy_ver = Command::new(&cargo_clippy_path) - .arg("--version") - .output() - .map(|o| String::from_utf8_lossy(&o.stdout).into_owned()) - .expect("could not get clippy version!"); - // download and extract the crates, then run clippy on them and collect clippy's warnings // flatten into one big list of warnings let (crates, recursive_options) = read_crates(&config.sources_toml_path); - let old_stats = read_stats_from_file(&config.lintcheck_results_path); let counter = AtomicUsize::new(1); let lint_filter: Vec<String> = config @@ -678,7 +694,6 @@ fn main() { .par_iter() .flat_map(|krate| { krate.run_clippy_lints( - &cargo_clippy_path, &clippy_driver_path, &counter, crates.len(), @@ -711,39 +726,51 @@ fn main() { } } + let text = match config.format { + OutputFormat::Text | OutputFormat::Markdown => output(&warnings, &raw_ices, clippy_ver, &config), + OutputFormat::Json => { + if !raw_ices.is_empty() { + for ice in raw_ices { + println!("{ice}"); + } + panic!("Some crates ICEd"); + } + + json::output(&warnings) + }, + }; + + println!("Writing logs to {}", config.lintcheck_results_path.display()); + fs::create_dir_all(config.lintcheck_results_path.parent().unwrap()).unwrap(); + fs::write(&config.lintcheck_results_path, text).unwrap(); +} + +/// Creates the log file output for [`OutputFormat::Text`] and [`OutputFormat::Markdown`] +fn output(warnings: &[ClippyWarning], ices: &[RustcIce], clippy_ver: String, config: &LintcheckConfig) -> String { // generate some stats - let (stats_formatted, new_stats) = gather_stats(&warnings); + let (stats_formatted, new_stats) = gather_stats(warnings); + let old_stats = read_stats_from_file(&config.lintcheck_results_path); - let mut all_msgs: Vec<String> = warnings.iter().map(|warn| warn.to_output(config.markdown)).collect(); + let mut all_msgs: Vec<String> = warnings.iter().map(|warn| warn.to_output(config.format)).collect(); all_msgs.sort(); all_msgs.push("\n\n### Stats:\n\n".into()); all_msgs.push(stats_formatted); - // save the text into lintcheck-logs/logs.txt let mut text = clippy_ver; // clippy version number on top text.push_str("\n### Reports\n\n"); - if config.markdown { + if config.format == OutputFormat::Markdown { text.push_str("| file | lint | message |\n"); text.push_str("| --- | --- | --- |\n"); } write!(text, "{}", all_msgs.join("")).unwrap(); text.push_str("\n\n### ICEs:\n"); - for ice in &raw_ices { - let _: fmt::Result = write!( - text, - "{}:\n{}\n========================================\n\n", - ice.crate_name, ice.ice_content - ); + for ice in ices { + writeln!(text, "{ice}").unwrap(); } - println!("Writing logs to {}", config.lintcheck_results_path.display()); - if !raw_ices.is_empty() { - println!("WARNING: at least one ICE reported, check log file"); - } - fs::create_dir_all(config.lintcheck_results_path.parent().unwrap()).unwrap(); - fs::write(&config.lintcheck_results_path, text).unwrap(); - print_stats(old_stats, new_stats, &config.lint_filter); + + text } /// read the previous stats from the lintcheck-log file @@ -865,7 +892,7 @@ fn lintcheck_test() { "--crates-toml", "lintcheck/test_sources.toml", ]; - let status = Command::new(env::var("CARGO").unwrap_or("cargo".into())) + let status = Command::new("cargo") .args(args) .current_dir("..") // repo root .status(); diff --git a/src/tools/clippy/lintcheck/src/popular-crates.rs b/src/tools/clippy/lintcheck/src/popular-crates.rs deleted file mode 100644 index fdab984ad86..00000000000 --- a/src/tools/clippy/lintcheck/src/popular-crates.rs +++ /dev/null @@ -1,65 +0,0 @@ -#![deny(clippy::pedantic)] - -use clap::Parser; -use crates_io_api::{CratesQueryBuilder, Sort, SyncClient}; -use indicatif::ProgressBar; -use std::collections::HashSet; -use std::fs::File; -use std::io::{BufWriter, Write}; -use std::path::PathBuf; -use std::time::Duration; - -#[derive(Parser)] -struct Opts { - /// Output TOML file name - output: PathBuf, - /// Number of crate names to download - #[clap(short, long, default_value_t = 100)] - number: usize, - /// Do not output progress - #[clap(short, long)] - quiet: bool, -} - -fn main() -> anyhow::Result<()> { - let opts = Opts::parse(); - let mut output = BufWriter::new(File::create(opts.output)?); - output.write_all(b"[crates]\n")?; - let client = SyncClient::new( - "clippy/lintcheck (github.com/rust-lang/rust-clippy/)", - Duration::from_secs(1), - )?; - let mut seen_crates = HashSet::new(); - let pb = if opts.quiet { - None - } else { - Some(ProgressBar::new(opts.number as u64)) - }; - let mut query = CratesQueryBuilder::new() - .sort(Sort::RecentDownloads) - .page_size(100) - .build(); - while seen_crates.len() < opts.number { - let retrieved = client.crates(query.clone())?.crates; - if retrieved.is_empty() { - eprintln!("No more than {} crates available from API", seen_crates.len()); - break; - } - for c in retrieved { - if seen_crates.insert(c.name.clone()) { - output.write_all( - format!( - "{} = {{ name = '{}', versions = ['{}'] }}\n", - c.name, c.name, c.max_version - ) - .as_bytes(), - )?; - if let Some(pb) = &pb { - pb.inc(1); - } - } - } - query.set_page(query.page() + 1); - } - Ok(()) -} diff --git a/src/tools/clippy/lintcheck/src/popular_crates.rs b/src/tools/clippy/lintcheck/src/popular_crates.rs new file mode 100644 index 00000000000..880a8bd81f0 --- /dev/null +++ b/src/tools/clippy/lintcheck/src/popular_crates.rs @@ -0,0 +1,52 @@ +use serde::Deserialize; +use std::error::Error; +use std::fmt::Write; +use std::fs; +use std::path::PathBuf; + +#[derive(Deserialize, Debug)] +struct Page { + crates: Vec<Crate>, + meta: Meta, +} + +#[derive(Deserialize, Debug)] +struct Crate { + name: String, + max_version: String, +} + +#[derive(Deserialize, Debug)] +struct Meta { + next_page: String, +} + +pub(crate) fn fetch(output: PathBuf, number: usize) -> Result<(), Box<dyn Error>> { + let agent = ureq::builder() + .user_agent("clippy/lintcheck (github.com/rust-lang/rust-clippy/)") + .build(); + + let mut crates = Vec::with_capacity(number); + let mut query = "?sort=recent-downloads&per_page=100".to_string(); + while crates.len() < number { + let page: Page = agent + .get(&format!("https://crates.io/api/v1/crates{query}")) + .call()? + .into_json()?; + + query = page.meta.next_page; + crates.extend(page.crates); + crates.truncate(number); + + let width = number.ilog10() as usize + 1; + println!("Fetched {:>width$}/{number} crates", crates.len()); + } + + let mut out = "[crates]\n".to_string(); + for Crate { name, max_version } in crates { + writeln!(out, "{name} = {{ name = '{name}', versions = ['{max_version}'] }}").unwrap(); + } + fs::write(output, out)?; + + Ok(()) +} diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 842c2f3de0d..72b50d59f7e 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-06-13" +channel = "nightly-2024-06-27" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index 6117e76897f..9b1577f24b8 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -2,7 +2,7 @@ #![allow(rustc::untranslatable_diagnostic)] #![feature(rustc_private)] #![feature(let_chains)] -#![feature(lint_reasons)] +#![cfg_attr(bootstrap, feature(lint_reasons))] #![cfg_attr(feature = "deny-warnings", deny(warnings))] // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] diff --git a/src/tools/clippy/tests/integration.rs b/src/tools/clippy/tests/integration.rs index 7f4500826ff..19c5f3a4133 100644 --- a/src/tools/clippy/tests/integration.rs +++ b/src/tools/clippy/tests/integration.rs @@ -55,6 +55,7 @@ fn integration_test() { "clippy", "--all-targets", "--all-features", + "--message-format=short", "--", "--cap-lints", "warn", diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr index 912ea9bb4d1..b626551e35b 100644 --- a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr +++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr @@ -1,10 +1,10 @@ error: file is loaded as a module multiple times: `src/b.rs` - --> src/main.rs:5:1 + --> src/main.rs:3:1 | -5 | mod b; +3 | mod b; | ^^^^^^ first loaded here -6 | / #[path = "b.rs"] -7 | | mod b2; +4 | / #[path = "b.rs"] +5 | | mod b2; | |_______^ loaded again here | = help: replace all but one `mod` item with `use` items @@ -12,34 +12,34 @@ error: file is loaded as a module multiple times: `src/b.rs` = help: to override `-D warnings` add `#[allow(clippy::duplicate_mod)]` error: file is loaded as a module multiple times: `src/c.rs` - --> src/main.rs:9:1 + --> src/main.rs:7:1 | -9 | mod c; +7 | mod c; | ^^^^^^ first loaded here -10 | / #[path = "c.rs"] -11 | | mod c2; +8 | / #[path = "c.rs"] +9 | | mod c2; | |_______^ loaded again here -12 | / #[path = "c.rs"] -13 | | mod c3; +10 | / #[path = "c.rs"] +11 | | mod c3; | |_______^ loaded again here | = help: replace all but one `mod` item with `use` items error: file is loaded as a module multiple times: `src/d.rs` - --> src/main.rs:18:1 + --> src/main.rs:16:1 | -18 | mod d; +16 | mod d; | ^^^^^^ first loaded here -19 | / #[path = "d.rs"] -20 | | mod d2; +17 | / #[path = "d.rs"] +18 | | mod d2; | |_______^ loaded again here | = help: replace all but one `mod` item with `use` items error: file is loaded as a module multiple times: `src/from_other_module.rs` - --> src/main.rs:15:1 + --> src/main.rs:13:1 | -15 | mod from_other_module; +13 | mod from_other_module; | ^^^^^^^^^^^^^^^^^^^^^^ first loaded here | ::: src/other_module/mod.rs:1:1 diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs index 6478e65ac81..9cbe4b83b25 100644 --- a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs +++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs @@ -1,5 +1,3 @@ -#![feature(lint_reasons)] - mod a; mod b; diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs index f5e01b431ad..a312df5a43a 100644 --- a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs +++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs @@ -1,5 +1,5 @@ //! Tests macro_metavars_in_unsafe with default configuration -#![feature(decl_macro, lint_reasons)] +#![feature(decl_macro)] #![warn(clippy::macro_metavars_in_unsafe)] #![allow(clippy::no_effect)] diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr index 37d69055737..a44c810b135 100644 --- a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr +++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr @@ -1,5 +1,5 @@ error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:271:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:270:19 | LL | /* Safety: */ unsafe {} | ^^^^^^^^^ @@ -9,7 +9,7 @@ LL | /* Safety: */ unsafe {} = help: to override `-D warnings` add `#[allow(clippy::undocumented_unsafe_blocks)]` error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:275:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:274:5 | LL | unsafe {} | ^^^^^^^^^ @@ -17,7 +17,7 @@ LL | unsafe {} = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:279:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:14 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:279:29 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:29 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:279:48 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:48 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:283:18 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:282:18 | LL | let _ = (42, unsafe {}, "test", unsafe {}); | ^^^^^^^^^ @@ -49,7 +49,7 @@ LL | let _ = (42, unsafe {}, "test", unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:283:37 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:282:37 | LL | let _ = (42, unsafe {}, "test", unsafe {}); | ^^^^^^^^^ @@ -57,7 +57,7 @@ LL | let _ = (42, unsafe {}, "test", unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:287:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:286:14 | LL | let _ = *unsafe { &42 }; | ^^^^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | let _ = *unsafe { &42 }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:292:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:291:19 | LL | let _ = match unsafe {} { | ^^^^^^^^^ @@ -73,7 +73,7 @@ LL | let _ = match unsafe {} { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:298:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:297:14 | LL | let _ = &unsafe {}; | ^^^^^^^^^ @@ -81,7 +81,7 @@ LL | let _ = &unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:302:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:301:14 | LL | let _ = [unsafe {}; 5]; | ^^^^^^^^^ @@ -89,7 +89,7 @@ LL | let _ = [unsafe {}; 5]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:306:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:305:13 | LL | let _ = unsafe {}; | ^^^^^^^^^ @@ -97,7 +97,7 @@ LL | let _ = unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:316:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:315:8 | LL | t!(unsafe {}); | ^^^^^^^^^ @@ -105,7 +105,7 @@ LL | t!(unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:322:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:321:13 | LL | unsafe {} | ^^^^^^^^^ @@ -117,7 +117,7 @@ LL | t!(); = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:330:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:329:5 | LL | unsafe {} // SAFETY: | ^^^^^^^^^ @@ -125,7 +125,7 @@ LL | unsafe {} // SAFETY: = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:334:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:333:5 | LL | unsafe { | ^^^^^^^^ @@ -133,7 +133,7 @@ LL | unsafe { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:344:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:343:5 | LL | unsafe {}; | ^^^^^^^^^ @@ -141,7 +141,7 @@ LL | unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:348:20 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:347:20 | LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -149,7 +149,7 @@ LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) }); = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:355:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:354:5 | LL | unsafe impl A for () {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL | unsafe impl A for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:362:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:361:9 | LL | unsafe impl B for (u32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | unsafe impl B for (u32) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:383:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:382:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -177,7 +177,7 @@ LL | no_safety_comment!(()); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:408:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:407:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -189,7 +189,7 @@ LL | no_safety_comment!(()); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:416:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:415:5 | LL | unsafe impl T for (i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -197,7 +197,7 @@ LL | unsafe impl T for (i32) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:408:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:407:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -209,7 +209,7 @@ LL | no_safety_comment!(u32); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:422:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:421:5 | LL | unsafe impl T for (bool) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -217,7 +217,7 @@ LL | unsafe impl T for (bool) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:468:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:467:5 | LL | unsafe impl NoComment for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -225,7 +225,7 @@ LL | unsafe impl NoComment for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:472:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:471:19 | LL | /* SAFETY: */ unsafe impl InlineComment for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -233,7 +233,7 @@ LL | /* SAFETY: */ unsafe impl InlineComment for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:476:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:475:5 | LL | unsafe impl TrailingComment for () {} // SAFETY: | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,13 +241,13 @@ LL | unsafe impl TrailingComment for () {} // SAFETY: = help: consider adding a safety comment on the preceding line error: constant item has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:480:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:479:5 | LL | const BIG_NUMBER: i32 = 1000000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:479:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:478:5 | LL | // SAFETY: | ^^^^^^^^^^ @@ -255,7 +255,7 @@ LL | // SAFETY: = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]` error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:481:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:480:5 | LL | unsafe impl Interference for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -263,7 +263,7 @@ LL | unsafe impl Interference for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:488:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:487:5 | LL | unsafe impl ImplInFn for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -271,7 +271,7 @@ LL | unsafe impl ImplInFn for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:497:1 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:496:1 | LL | unsafe impl CrateRoot for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -279,7 +279,7 @@ LL | unsafe impl CrateRoot for () {} = help: consider adding a safety comment on the preceding line error: statement has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:510:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:509:5 | LL | / let _ = { LL | | if unsafe { true } { @@ -291,13 +291,13 @@ LL | | }; | |______^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:509:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:508:5 | LL | // SAFETY: this is more than one level away, so it should warn | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:511:12 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:510:12 | LL | if unsafe { true } { | ^^^^^^^^^^^^^^^ @@ -305,7 +305,7 @@ LL | if unsafe { true } { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:514:23 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:513:23 | LL | let bar = unsafe {}; | ^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr index 400fde997e9..db5ea5b6289 100644 --- a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr +++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr @@ -1,5 +1,5 @@ error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:271:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:270:19 | LL | /* Safety: */ unsafe {} | ^^^^^^^^^ @@ -9,7 +9,7 @@ LL | /* Safety: */ unsafe {} = help: to override `-D warnings` add `#[allow(clippy::undocumented_unsafe_blocks)]` error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:275:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:274:5 | LL | unsafe {} | ^^^^^^^^^ @@ -17,7 +17,7 @@ LL | unsafe {} = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:279:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:14 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:279:29 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:29 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:279:48 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:48 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:283:18 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:282:18 | LL | let _ = (42, unsafe {}, "test", unsafe {}); | ^^^^^^^^^ @@ -49,7 +49,7 @@ LL | let _ = (42, unsafe {}, "test", unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:283:37 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:282:37 | LL | let _ = (42, unsafe {}, "test", unsafe {}); | ^^^^^^^^^ @@ -57,7 +57,7 @@ LL | let _ = (42, unsafe {}, "test", unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:287:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:286:14 | LL | let _ = *unsafe { &42 }; | ^^^^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | let _ = *unsafe { &42 }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:292:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:291:19 | LL | let _ = match unsafe {} { | ^^^^^^^^^ @@ -73,7 +73,7 @@ LL | let _ = match unsafe {} { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:298:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:297:14 | LL | let _ = &unsafe {}; | ^^^^^^^^^ @@ -81,7 +81,7 @@ LL | let _ = &unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:302:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:301:14 | LL | let _ = [unsafe {}; 5]; | ^^^^^^^^^ @@ -89,7 +89,7 @@ LL | let _ = [unsafe {}; 5]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:306:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:305:13 | LL | let _ = unsafe {}; | ^^^^^^^^^ @@ -97,7 +97,7 @@ LL | let _ = unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:316:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:315:8 | LL | t!(unsafe {}); | ^^^^^^^^^ @@ -105,7 +105,7 @@ LL | t!(unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:322:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:321:13 | LL | unsafe {} | ^^^^^^^^^ @@ -117,7 +117,7 @@ LL | t!(); = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:330:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:329:5 | LL | unsafe {} // SAFETY: | ^^^^^^^^^ @@ -125,7 +125,7 @@ LL | unsafe {} // SAFETY: = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:334:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:333:5 | LL | unsafe { | ^^^^^^^^ @@ -133,7 +133,7 @@ LL | unsafe { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:344:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:343:5 | LL | unsafe {}; | ^^^^^^^^^ @@ -141,7 +141,7 @@ LL | unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:348:20 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:347:20 | LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -149,7 +149,7 @@ LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) }); = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:355:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:354:5 | LL | unsafe impl A for () {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL | unsafe impl A for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:362:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:361:9 | LL | unsafe impl B for (u32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | unsafe impl B for (u32) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:383:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:382:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -177,7 +177,7 @@ LL | no_safety_comment!(()); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:408:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:407:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -189,7 +189,7 @@ LL | no_safety_comment!(()); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:416:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:415:5 | LL | unsafe impl T for (i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -197,7 +197,7 @@ LL | unsafe impl T for (i32) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:408:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:407:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -209,7 +209,7 @@ LL | no_safety_comment!(u32); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:422:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:421:5 | LL | unsafe impl T for (bool) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -217,7 +217,7 @@ LL | unsafe impl T for (bool) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:468:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:467:5 | LL | unsafe impl NoComment for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -225,7 +225,7 @@ LL | unsafe impl NoComment for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:472:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:471:19 | LL | /* SAFETY: */ unsafe impl InlineComment for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -233,7 +233,7 @@ LL | /* SAFETY: */ unsafe impl InlineComment for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:476:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:475:5 | LL | unsafe impl TrailingComment for () {} // SAFETY: | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,13 +241,13 @@ LL | unsafe impl TrailingComment for () {} // SAFETY: = help: consider adding a safety comment on the preceding line error: constant item has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:480:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:479:5 | LL | const BIG_NUMBER: i32 = 1000000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:479:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:478:5 | LL | // SAFETY: | ^^^^^^^^^^ @@ -255,7 +255,7 @@ LL | // SAFETY: = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]` error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:481:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:480:5 | LL | unsafe impl Interference for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -263,7 +263,7 @@ LL | unsafe impl Interference for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:488:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:487:5 | LL | unsafe impl ImplInFn for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -271,7 +271,7 @@ LL | unsafe impl ImplInFn for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:497:1 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:496:1 | LL | unsafe impl CrateRoot for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -279,7 +279,7 @@ LL | unsafe impl CrateRoot for () {} = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:507:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:506:9 | LL | unsafe {}; | ^^^^^^^^^ @@ -287,7 +287,7 @@ LL | unsafe {}; = help: consider adding a safety comment on the preceding line error: statement has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:510:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:509:5 | LL | / let _ = { LL | | if unsafe { true } { @@ -299,13 +299,13 @@ LL | | }; | |______^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:509:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:508:5 | LL | // SAFETY: this is more than one level away, so it should warn | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:511:12 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:510:12 | LL | if unsafe { true } { | ^^^^^^^^^^^^^^^ @@ -313,7 +313,7 @@ LL | if unsafe { true } { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:514:23 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:513:23 | LL | let bar = unsafe {}; | ^^^^^^^^^ @@ -321,7 +321,7 @@ LL | let bar = unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:532:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:531:9 | LL | unsafe { a_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -329,7 +329,7 @@ LL | unsafe { a_function_with_a_very_long_name_to_break_the_line() }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:536:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:535:9 | LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -337,7 +337,7 @@ LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:540:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:539:9 | LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -345,7 +345,7 @@ LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:546:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:545:5 | LL | unsafe {} | ^^^^^^^^^ @@ -353,7 +353,7 @@ LL | unsafe {} = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:550:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:549:5 | LL | unsafe { | ^^^^^^^^ @@ -361,7 +361,7 @@ LL | unsafe { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:557:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:556:9 | LL | unsafe { a_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -369,7 +369,7 @@ LL | unsafe { a_function_with_a_very_long_name_to_break_the_line() }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:562:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:561:9 | LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -377,7 +377,7 @@ LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:568:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:567:9 | LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -385,7 +385,7 @@ LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:573:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:572:5 | LL | unsafe {} | ^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs index e5ef9d35fb6..02170e1f740 100644 --- a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs @@ -10,7 +10,6 @@ clippy::let_unit_value, clippy::missing_safety_doc )] -#![feature(lint_reasons)] extern crate proc_macro_unsafe; diff --git a/src/tools/clippy/tests/ui/allow_attributes.fixed b/src/tools/clippy/tests/ui/allow_attributes.fixed index b506a9890f5..49ee3ee17c7 100644 --- a/src/tools/clippy/tests/ui/allow_attributes.fixed +++ b/src/tools/clippy/tests/ui/allow_attributes.fixed @@ -1,7 +1,6 @@ //@aux-build:proc_macros.rs #![allow(unused)] #![warn(clippy::allow_attributes)] -#![feature(lint_reasons)] #![no_main] extern crate proc_macros; @@ -47,3 +46,15 @@ fn ignore_proc_macro() { fn ignore_inner_attr() { #![allow(unused)] // Should not lint } + +#[clippy::msrv = "1.81"] +fn msrv_1_81() { + #[expect(unused)] + let x = 1; +} + +#[clippy::msrv = "1.80"] +fn msrv_1_80() { + #[allow(unused)] + let x = 1; +} diff --git a/src/tools/clippy/tests/ui/allow_attributes.rs b/src/tools/clippy/tests/ui/allow_attributes.rs index c7daa7abd9d..854acf8348d 100644 --- a/src/tools/clippy/tests/ui/allow_attributes.rs +++ b/src/tools/clippy/tests/ui/allow_attributes.rs @@ -1,7 +1,6 @@ //@aux-build:proc_macros.rs #![allow(unused)] #![warn(clippy::allow_attributes)] -#![feature(lint_reasons)] #![no_main] extern crate proc_macros; @@ -47,3 +46,15 @@ fn ignore_proc_macro() { fn ignore_inner_attr() { #![allow(unused)] // Should not lint } + +#[clippy::msrv = "1.81"] +fn msrv_1_81() { + #[allow(unused)] + let x = 1; +} + +#[clippy::msrv = "1.80"] +fn msrv_1_80() { + #[allow(unused)] + let x = 1; +} diff --git a/src/tools/clippy/tests/ui/allow_attributes.stderr b/src/tools/clippy/tests/ui/allow_attributes.stderr index 9c99e88c796..10dac0bc808 100644 --- a/src/tools/clippy/tests/ui/allow_attributes.stderr +++ b/src/tools/clippy/tests/ui/allow_attributes.stderr @@ -1,5 +1,5 @@ error: #[allow] attribute found - --> tests/ui/allow_attributes.rs:13:3 + --> tests/ui/allow_attributes.rs:12:3 | LL | #[allow(dead_code)] | ^^^^^ help: replace it with: `expect` @@ -8,10 +8,24 @@ LL | #[allow(dead_code)] = help: to override `-D warnings` add `#[allow(clippy::allow_attributes)]` error: #[allow] attribute found - --> tests/ui/allow_attributes.rs:22:30 + --> tests/ui/allow_attributes.rs:21:30 | LL | #[cfg_attr(panic = "unwind", allow(dead_code))] | ^^^^^ help: replace it with: `expect` -error: aborting due to 2 previous errors +error: #[allow] attribute found + --> tests/ui/allow_attributes.rs:52:7 + | +LL | #[allow(unused)] + | ^^^^^ help: replace it with: `expect` + +error: #[allow] attribute found + --> tests/ui/allow_attributes.rs:52:7 + | +LL | #[allow(unused)] + | ^^^^^ help: replace it with: `expect` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/allow_attributes_without_reason.rs b/src/tools/clippy/tests/ui/allow_attributes_without_reason.rs index 523148d6586..86f6b2c5742 100644 --- a/src/tools/clippy/tests/ui/allow_attributes_without_reason.rs +++ b/src/tools/clippy/tests/ui/allow_attributes_without_reason.rs @@ -1,5 +1,4 @@ //@aux-build:proc_macros.rs -#![feature(lint_reasons)] #![deny(clippy::allow_attributes_without_reason)] #![allow(unfulfilled_lint_expectations, clippy::duplicated_attributes)] @@ -42,3 +41,15 @@ pub fn trigger_fp_result() -> Result<(), &'static str> { Err("asdf")?; Ok(()) } + +#[clippy::msrv = "1.81"] +fn msrv_1_81() { + #[allow(unused)] + let _ = 1; +} + +#[clippy::msrv = "1.80"] +fn msrv_1_80() { + #[allow(unused)] + let _ = 1; +} diff --git a/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr b/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr index 770a771ec3d..9bc3ca0f2af 100644 --- a/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr +++ b/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr @@ -1,18 +1,18 @@ error: `allow` attribute without specifying a reason - --> tests/ui/allow_attributes_without_reason.rs:4:1 + --> tests/ui/allow_attributes_without_reason.rs:3:1 | LL | #![allow(unfulfilled_lint_expectations, clippy::duplicated_attributes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: try adding a reason at the end with `, reason = ".."` note: the lint level is defined here - --> tests/ui/allow_attributes_without_reason.rs:3:9 + --> tests/ui/allow_attributes_without_reason.rs:2:9 | LL | #![deny(clippy::allow_attributes_without_reason)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `allow` attribute without specifying a reason - --> tests/ui/allow_attributes_without_reason.rs:10:1 + --> tests/ui/allow_attributes_without_reason.rs:9:1 | LL | #[allow(dead_code)] | ^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | #[allow(dead_code)] = help: try adding a reason at the end with `, reason = ".."` error: `allow` attribute without specifying a reason - --> tests/ui/allow_attributes_without_reason.rs:11:1 + --> tests/ui/allow_attributes_without_reason.rs:10:1 | LL | #[allow(dead_code, deprecated)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,12 +28,29 @@ LL | #[allow(dead_code, deprecated)] = help: try adding a reason at the end with `, reason = ".."` error: `expect` attribute without specifying a reason - --> tests/ui/allow_attributes_without_reason.rs:12:1 + --> tests/ui/allow_attributes_without_reason.rs:11:1 | LL | #[expect(dead_code)] | ^^^^^^^^^^^^^^^^^^^^ | = help: try adding a reason at the end with `, reason = ".."` -error: aborting due to 4 previous errors +error: `allow` attribute without specifying a reason + --> tests/ui/allow_attributes_without_reason.rs:47:5 + | +LL | #[allow(unused)] + | ^^^^^^^^^^^^^^^^ + | + = help: try adding a reason at the end with `, reason = ".."` + +error: `allow` attribute without specifying a reason + --> tests/ui/allow_attributes_without_reason.rs:47:5 + | +LL | #[allow(unused)] + | ^^^^^^^^^^^^^^^^ + | + = help: try adding a reason at the end with `, reason = ".."` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/assigning_clones.fixed b/src/tools/clippy/tests/ui/assigning_clones.fixed index 70ab43b49b3..60f6a385fc5 100644 --- a/src/tools/clippy/tests/ui/assigning_clones.fixed +++ b/src/tools/clippy/tests/ui/assigning_clones.fixed @@ -272,3 +272,59 @@ impl<'a> Add for &'a mut HasCloneFrom { self } } + +mod borrowck_conflicts { + //! Cases where clone_into and friends cannot be used because the src/dest have conflicting + //! borrows. + use std::path::PathBuf; + + fn issue12444(mut name: String) { + let parts = name.split(", ").collect::<Vec<_>>(); + let first = *parts.first().unwrap(); + name = first.to_owned(); + } + + fn issue12444_simple() { + let mut s = String::new(); + let s2 = &s; + s = s2.to_owned(); + } + + fn issue12444_nodrop_projections() { + struct NoDrop; + + impl Clone for NoDrop { + fn clone(&self) -> Self { + todo!() + } + fn clone_from(&mut self, other: &Self) { + todo!() + } + } + + let mut s = NoDrop; + let s2 = &s; + s = s2.clone(); + + let mut s = (NoDrop, NoDrop); + let s2 = &s.0; + s.0 = s2.clone(); + + // This *could* emit a warning, but PossibleBorrowerMap only works with locals so it + // considers `s` fully borrowed + let mut s = (NoDrop, NoDrop); + let s2 = &s.1; + s.0 = s2.clone(); + } + + fn issue12460(mut name: String) { + if let Some(stripped_name) = name.strip_prefix("baz-") { + name = stripped_name.to_owned(); + } + } + + fn issue12749() { + let mut path = PathBuf::from("/a/b/c"); + path = path.components().as_path().to_owned(); + } +} diff --git a/src/tools/clippy/tests/ui/assigning_clones.rs b/src/tools/clippy/tests/ui/assigning_clones.rs index 9699fed100c..6eb85be511a 100644 --- a/src/tools/clippy/tests/ui/assigning_clones.rs +++ b/src/tools/clippy/tests/ui/assigning_clones.rs @@ -272,3 +272,59 @@ impl<'a> Add for &'a mut HasCloneFrom { self } } + +mod borrowck_conflicts { + //! Cases where clone_into and friends cannot be used because the src/dest have conflicting + //! borrows. + use std::path::PathBuf; + + fn issue12444(mut name: String) { + let parts = name.split(", ").collect::<Vec<_>>(); + let first = *parts.first().unwrap(); + name = first.to_owned(); + } + + fn issue12444_simple() { + let mut s = String::new(); + let s2 = &s; + s = s2.to_owned(); + } + + fn issue12444_nodrop_projections() { + struct NoDrop; + + impl Clone for NoDrop { + fn clone(&self) -> Self { + todo!() + } + fn clone_from(&mut self, other: &Self) { + todo!() + } + } + + let mut s = NoDrop; + let s2 = &s; + s = s2.clone(); + + let mut s = (NoDrop, NoDrop); + let s2 = &s.0; + s.0 = s2.clone(); + + // This *could* emit a warning, but PossibleBorrowerMap only works with locals so it + // considers `s` fully borrowed + let mut s = (NoDrop, NoDrop); + let s2 = &s.1; + s.0 = s2.clone(); + } + + fn issue12460(mut name: String) { + if let Some(stripped_name) = name.strip_prefix("baz-") { + name = stripped_name.to_owned(); + } + } + + fn issue12749() { + let mut path = PathBuf::from("/a/b/c"); + path = path.components().as_path().to_owned(); + } +} diff --git a/src/tools/clippy/tests/ui/async_yields_async.fixed b/src/tools/clippy/tests/ui/async_yields_async.fixed index cfad7813805..208651bab1f 100644 --- a/src/tools/clippy/tests/ui/async_yields_async.fixed +++ b/src/tools/clippy/tests/ui/async_yields_async.fixed @@ -1,4 +1,3 @@ -#![feature(lint_reasons)] #![feature(async_closure)] #![warn(clippy::async_yields_async)] #![allow(clippy::redundant_async_block)] diff --git a/src/tools/clippy/tests/ui/async_yields_async.rs b/src/tools/clippy/tests/ui/async_yields_async.rs index 7bc26647943..b124c994442 100644 --- a/src/tools/clippy/tests/ui/async_yields_async.rs +++ b/src/tools/clippy/tests/ui/async_yields_async.rs @@ -1,4 +1,3 @@ -#![feature(lint_reasons)] #![feature(async_closure)] #![warn(clippy::async_yields_async)] #![allow(clippy::redundant_async_block)] diff --git a/src/tools/clippy/tests/ui/async_yields_async.stderr b/src/tools/clippy/tests/ui/async_yields_async.stderr index 991ad7ae0ae..861c3f2ce4a 100644 --- a/src/tools/clippy/tests/ui/async_yields_async.stderr +++ b/src/tools/clippy/tests/ui/async_yields_async.stderr @@ -1,5 +1,5 @@ error: an async construct yields a type which is itself awaitable - --> tests/ui/async_yields_async.rs:39:9 + --> tests/ui/async_yields_async.rs:38:9 | LL | let _h = async { | _____________________- @@ -20,7 +20,7 @@ LL + }.await | error: an async construct yields a type which is itself awaitable - --> tests/ui/async_yields_async.rs:44:9 + --> tests/ui/async_yields_async.rs:43:9 | LL | let _i = async { | ____________________- @@ -33,7 +33,7 @@ LL | | }; | |_____- outer async construct error: an async construct yields a type which is itself awaitable - --> tests/ui/async_yields_async.rs:50:9 + --> tests/ui/async_yields_async.rs:49:9 | LL | let _j = async || { | ________________________- @@ -52,7 +52,7 @@ LL + }.await | error: an async construct yields a type which is itself awaitable - --> tests/ui/async_yields_async.rs:55:9 + --> tests/ui/async_yields_async.rs:54:9 | LL | let _k = async || { | _______________________- @@ -65,7 +65,7 @@ LL | | }; | |_____- outer async construct error: an async construct yields a type which is itself awaitable - --> tests/ui/async_yields_async.rs:57:23 + --> tests/ui/async_yields_async.rs:56:23 | LL | let _l = async || CustomFutureType; | ^^^^^^^^^^^^^^^^ @@ -75,7 +75,7 @@ LL | let _l = async || CustomFutureType; | help: consider awaiting this value: `CustomFutureType.await` error: an async construct yields a type which is itself awaitable - --> tests/ui/async_yields_async.rs:63:9 + --> tests/ui/async_yields_async.rs:62:9 | LL | let _m = async || { | _______________________- diff --git a/src/tools/clippy/tests/ui/auxiliary/external_consts.rs b/src/tools/clippy/tests/ui/auxiliary/external_consts.rs new file mode 100644 index 00000000000..1885ba341f5 --- /dev/null +++ b/src/tools/clippy/tests/ui/auxiliary/external_consts.rs @@ -0,0 +1 @@ +pub const MAGIC_NUMBER: i32 = 1; diff --git a/src/tools/clippy/tests/ui/boxed_local.rs b/src/tools/clippy/tests/ui/boxed_local.rs index e888154c46d..fbd9e12fc18 100644 --- a/src/tools/clippy/tests/ui/boxed_local.rs +++ b/src/tools/clippy/tests/ui/boxed_local.rs @@ -1,4 +1,3 @@ -#![feature(lint_reasons)] #![allow( clippy::borrowed_box, clippy::needless_pass_by_value, diff --git a/src/tools/clippy/tests/ui/boxed_local.stderr b/src/tools/clippy/tests/ui/boxed_local.stderr index d3156c820b2..7710233fa4d 100644 --- a/src/tools/clippy/tests/ui/boxed_local.stderr +++ b/src/tools/clippy/tests/ui/boxed_local.stderr @@ -1,5 +1,5 @@ error: local variable doesn't need to be boxed here - --> tests/ui/boxed_local.rs:40:13 + --> tests/ui/boxed_local.rs:39:13 | LL | fn warn_arg(x: Box<A>) { | ^ @@ -8,19 +8,19 @@ LL | fn warn_arg(x: Box<A>) { = help: to override `-D warnings` add `#[allow(clippy::boxed_local)]` error: local variable doesn't need to be boxed here - --> tests/ui/boxed_local.rs:123:12 + --> tests/ui/boxed_local.rs:122:12 | LL | pub fn new(_needs_name: Box<PeekableSeekable<&()>>) -> () {} | ^^^^^^^^^^^ error: local variable doesn't need to be boxed here - --> tests/ui/boxed_local.rs:188:44 + --> tests/ui/boxed_local.rs:187:44 | LL | fn default_impl_x(self: Box<Self>, x: Box<u32>) -> u32 { | ^ error: local variable doesn't need to be boxed here - --> tests/ui/boxed_local.rs:196:16 + --> tests/ui/boxed_local.rs:195:16 | LL | fn foo(x: Box<u32>) {} | ^ diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs index c39f65a43e3..146b04ab813 100644 --- a/src/tools/clippy/tests/ui/cast.rs +++ b/src/tools/clippy/tests/ui/cast.rs @@ -12,6 +12,7 @@ #![allow( clippy::cast_abs_to_unsigned, clippy::no_effect, + clippy::unnecessary_min_or_max, clippy::unnecessary_operation, clippy::unnecessary_literal_unwrap, clippy::identity_op diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr index 452482fc88e..7824bdfac25 100644 --- a/src/tools/clippy/tests/ui/cast.stderr +++ b/src/tools/clippy/tests/ui/cast.stderr @@ -1,5 +1,5 @@ error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:25:5 + --> tests/ui/cast.rs:26:5 | LL | x0 as f32; | ^^^^^^^^^ @@ -8,37 +8,37 @@ LL | x0 as f32; = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:29:5 + --> tests/ui/cast.rs:30:5 | LL | x1 as f32; | ^^^^^^^^^ error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:31:5 + --> tests/ui/cast.rs:32:5 | LL | x1 as f64; | ^^^^^^^^^ error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:34:5 + --> tests/ui/cast.rs:35:5 | LL | x2 as f32; | ^^^^^^^^^ error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:37:5 + --> tests/ui/cast.rs:38:5 | LL | x3 as f32; | ^^^^^^^^^ error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:39:5 + --> tests/ui/cast.rs:40:5 | LL | x3 as f64; | ^^^^^^^^^ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:42:5 + --> tests/ui/cast.rs:43:5 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | 1f32 as i32; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]` error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:44:5 + --> tests/ui/cast.rs:45:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | 1f32 as u32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:44:5 + --> tests/ui/cast.rs:45:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | 1f32 as u32; = help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]` error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:48:5 + --> tests/ui/cast.rs:49:5 | LL | 1f64 as f32; | ^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | 1f64 as f32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:50:5 + --> tests/ui/cast.rs:51:5 | LL | 1i32 as i8; | ^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | i8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u8` may truncate the value - --> tests/ui/cast.rs:52:5 + --> tests/ui/cast.rs:53:5 | LL | 1i32 as u8; | ^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | u8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `f64` to `isize` may truncate the value - --> tests/ui/cast.rs:54:5 + --> tests/ui/cast.rs:55:5 | LL | 1f64 as isize; | ^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | 1f64 as isize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may truncate the value - --> tests/ui/cast.rs:56:5 + --> tests/ui/cast.rs:57:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ @@ -113,13 +113,13 @@ LL | 1f64 as usize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:56:5 + --> tests/ui/cast.rs:57:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting `u32` to `u16` may truncate the value - --> tests/ui/cast.rs:59:5 + --> tests/ui/cast.rs:60:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | u16::try_from(1f32 as u32); | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:59:5 + --> tests/ui/cast.rs:60:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ @@ -139,13 +139,13 @@ LL | 1f32 as u32 as u16; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:59:5 + --> tests/ui/cast.rs:60:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:64:22 + --> tests/ui/cast.rs:65:22 | LL | let _x: i8 = 1i32 as _; | ^^^^^^^^^ @@ -157,7 +157,7 @@ LL | let _x: i8 = 1i32.try_into(); | ~~~~~~~~~~~~~~~ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:66:9 + --> tests/ui/cast.rs:67:9 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | 1f32 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `i32` may truncate the value - --> tests/ui/cast.rs:68:9 + --> tests/ui/cast.rs:69:9 | LL | 1f64 as i32; | ^^^^^^^^^^^ @@ -173,7 +173,7 @@ LL | 1f64 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may truncate the value - --> tests/ui/cast.rs:70:9 + --> tests/ui/cast.rs:71:9 | LL | 1f32 as u8; | ^^^^^^^^^^ @@ -181,13 +181,13 @@ LL | 1f32 as u8; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:70:9 + --> tests/ui/cast.rs:71:9 | LL | 1f32 as u8; | ^^^^^^^^^^ error: casting `u8` to `i8` may wrap around the value - --> tests/ui/cast.rs:75:5 + --> tests/ui/cast.rs:76:5 | LL | 1u8 as i8; | ^^^^^^^^^ @@ -196,31 +196,31 @@ LL | 1u8 as i8; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` error: casting `u16` to `i16` may wrap around the value - --> tests/ui/cast.rs:78:5 + --> tests/ui/cast.rs:79:5 | LL | 1u16 as i16; | ^^^^^^^^^^^ error: casting `u32` to `i32` may wrap around the value - --> tests/ui/cast.rs:80:5 + --> tests/ui/cast.rs:81:5 | LL | 1u32 as i32; | ^^^^^^^^^^^ error: casting `u64` to `i64` may wrap around the value - --> tests/ui/cast.rs:82:5 + --> tests/ui/cast.rs:83:5 | LL | 1u64 as i64; | ^^^^^^^^^^^ error: casting `usize` to `isize` may wrap around the value - --> tests/ui/cast.rs:84:5 + --> tests/ui/cast.rs:85:5 | LL | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting `usize` to `i8` may truncate the value - --> tests/ui/cast.rs:87:5 + --> tests/ui/cast.rs:88:5 | LL | 1usize as i8; | ^^^^^^^^^^^^ @@ -232,7 +232,7 @@ LL | i8::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may truncate the value - --> tests/ui/cast.rs:90:5 + --> tests/ui/cast.rs:91:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -244,7 +244,7 @@ LL | i16::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:90:5 + --> tests/ui/cast.rs:91:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -253,7 +253,7 @@ LL | 1usize as i16; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:95:5 + --> tests/ui/cast.rs:96:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -265,19 +265,19 @@ LL | i32::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:95:5 + --> tests/ui/cast.rs:96:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:99:5 + --> tests/ui/cast.rs:100:5 | LL | 1usize as i64; | ^^^^^^^^^^^^^ error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:104:5 + --> tests/ui/cast.rs:105:5 | LL | 1u16 as isize; | ^^^^^^^^^^^^^ @@ -286,13 +286,13 @@ LL | 1u16 as isize; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:108:5 + --> tests/ui/cast.rs:109:5 | LL | 1u32 as isize; | ^^^^^^^^^^^^^ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:111:5 + --> tests/ui/cast.rs:112:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ @@ -304,55 +304,55 @@ LL | isize::try_from(1u64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:111:5 + --> tests/ui/cast.rs:112:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:116:5 + --> tests/ui/cast.rs:117:5 | LL | -1i32 as u32; | ^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:119:5 + --> tests/ui/cast.rs:120:5 | LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ error: casting `i8` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:130:5 + --> tests/ui/cast.rs:131:5 | LL | (i8::MIN).abs() as u8; | ^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:134:5 + --> tests/ui/cast.rs:135:5 | LL | (-1i64).abs() as u64; | ^^^^^^^^^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:135:5 + --> tests/ui/cast.rs:136:5 | LL | (-1isize).abs() as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:142:5 + --> tests/ui/cast.rs:143:5 | LL | (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:157:5 + --> tests/ui/cast.rs:158:5 | LL | (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `i8` may truncate the value - --> tests/ui/cast.rs:208:5 + --> tests/ui/cast.rs:209:5 | LL | (-99999999999i64).min(1) as i8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -364,7 +364,7 @@ LL | i8::try_from((-99999999999i64).min(1)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:222:5 + --> tests/ui/cast.rs:223:5 | LL | 999999u64.clamp(0, 256) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -376,7 +376,7 @@ LL | u8::try_from(999999u64.clamp(0, 256)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E2` to `u8` may truncate the value - --> tests/ui/cast.rs:245:21 + --> tests/ui/cast.rs:246:21 | LL | let _ = self as u8; | ^^^^^^^^^^ @@ -388,7 +388,7 @@ LL | let _ = u8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E2::B` to `u8` will truncate the value - --> tests/ui/cast.rs:247:21 + --> tests/ui/cast.rs:248:21 | LL | let _ = Self::B as u8; | ^^^^^^^^^^^^^ @@ -397,7 +397,7 @@ LL | let _ = Self::B as u8; = help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]` error: casting `main::E5` to `i8` may truncate the value - --> tests/ui/cast.rs:289:21 + --> tests/ui/cast.rs:290:21 | LL | let _ = self as i8; | ^^^^^^^^^^ @@ -409,13 +409,13 @@ LL | let _ = i8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E5::A` to `i8` will truncate the value - --> tests/ui/cast.rs:291:21 + --> tests/ui/cast.rs:292:21 | LL | let _ = Self::A as i8; | ^^^^^^^^^^^^^ error: casting `main::E6` to `i16` may truncate the value - --> tests/ui/cast.rs:308:21 + --> tests/ui/cast.rs:309:21 | LL | let _ = self as i16; | ^^^^^^^^^^^ @@ -427,7 +427,7 @@ LL | let _ = i16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:327:21 + --> tests/ui/cast.rs:328:21 | LL | let _ = self as usize; | ^^^^^^^^^^^^^ @@ -439,7 +439,7 @@ LL | let _ = usize::try_from(self); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E10` to `u16` may truncate the value - --> tests/ui/cast.rs:374:21 + --> tests/ui/cast.rs:375:21 | LL | let _ = self as u16; | ^^^^^^^^^^^ @@ -451,7 +451,7 @@ LL | let _ = u16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:385:13 + --> tests/ui/cast.rs:386:13 | LL | let c = (q >> 16) as u8; | ^^^^^^^^^^^^^^^ @@ -463,7 +463,7 @@ LL | let c = u8::try_from(q >> 16); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:389:13 + --> tests/ui/cast.rs:390:13 | LL | let c = (q / 1000) as u8; | ^^^^^^^^^^^^^^^^ @@ -475,85 +475,85 @@ LL | let c = u8::try_from(q / 1000); | ~~~~~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:401:9 + --> tests/ui/cast.rs:402:9 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:406:32 + --> tests/ui/cast.rs:407:32 | LL | let _a = |x: i32| -> u32 { (x * x * x * x) as u32 }; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:408:5 + --> tests/ui/cast.rs:409:5 | LL | (2_i32).checked_pow(3).unwrap() as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:409:5 + --> tests/ui/cast.rs:410:5 | LL | (-2_i32).pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:414:5 + --> tests/ui/cast.rs:415:5 | LL | (-5_i32 % 2) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:416:5 + --> tests/ui/cast.rs:417:5 | LL | (-5_i32 % -2) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:419:5 + --> tests/ui/cast.rs:420:5 | LL | (-2_i32 >> 1) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:423:5 + --> tests/ui/cast.rs:424:5 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:424:5 + --> tests/ui/cast.rs:425:5 | LL | (x * x * x) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:428:5 + --> tests/ui/cast.rs:429:5 | LL | (y * y * y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:430:5 + --> tests/ui/cast.rs:431:5 | LL | (y * y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:431:5 + --> tests/ui/cast.rs:432:5 | LL | (y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:433:5 + --> tests/ui/cast.rs:434:5 | LL | (y / y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `/` - --> tests/ui/cast.rs:433:6 + --> tests/ui/cast.rs:434:6 | LL | (y / y * y * -2) as u16; | ^^^^^ @@ -561,97 +561,97 @@ LL | (y / y * y * -2) as u16; = note: `#[deny(clippy::eq_op)]` on by default error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:436:5 + --> tests/ui/cast.rs:437:5 | LL | (y + y + y + -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:438:5 + --> tests/ui/cast.rs:439:5 | LL | (y + y + y + 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:442:5 + --> tests/ui/cast.rs:443:5 | LL | (z + -2) as u16; | ^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:444:5 + --> tests/ui/cast.rs:445:5 | LL | (z + z + 2) as u16; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:447:9 + --> tests/ui/cast.rs:448:9 | LL | (a * a * b * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:448:9 + --> tests/ui/cast.rs:449:9 | LL | (a * b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:450:9 + --> tests/ui/cast.rs:451:9 | LL | (a * -b * c) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:452:9 + --> tests/ui/cast.rs:453:9 | LL | (a * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:453:9 + --> tests/ui/cast.rs:454:9 | LL | (a * -2) as u32; | ^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:455:9 + --> tests/ui/cast.rs:456:9 | LL | (a * b * c * -2) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:457:9 + --> tests/ui/cast.rs:458:9 | LL | (a / b) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:458:9 + --> tests/ui/cast.rs:459:9 | LL | (a / b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:460:9 + --> tests/ui/cast.rs:461:9 | LL | (a / b + b * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:462:9 + --> tests/ui/cast.rs:463:9 | LL | a.saturating_pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:464:9 + --> tests/ui/cast.rs:465:9 | LL | (a.abs() * b.pow(2) / c.abs()) as u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:472:21 + --> tests/ui/cast.rs:473:21 | LL | let _ = i32::MIN as u32; // cast_sign_loss | ^^^^^^^^^^^^^^^ @@ -662,7 +662,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:473:21 + --> tests/ui/cast.rs:474:21 | LL | let _ = u32::MAX as u8; // cast_possible_truncation | ^^^^^^^^^^^^^^ @@ -678,7 +678,7 @@ LL | let _ = u8::try_from(u32::MAX); // cast_possible_truncation | ~~~~~~~~~~~~~~~~~~~~~~ error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:474:21 + --> tests/ui/cast.rs:475:21 | LL | let _ = std::f64::consts::PI as f32; // cast_possible_truncation | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -690,7 +690,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:483:5 + --> tests/ui/cast.rs:484:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -702,13 +702,13 @@ LL | usize::try_from(bar.unwrap().unwrap()) | error: casting `i64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:483:5 + --> tests/ui/cast.rs:484:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:498:5 + --> tests/ui/cast.rs:499:5 | LL | (256 & 999999u64) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -720,7 +720,7 @@ LL | u8::try_from(256 & 999999u64); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:500:5 + --> tests/ui/cast.rs:501:5 | LL | (255 % 999999u64) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/cast_size.32bit.stderr b/src/tools/clippy/tests/ui/cast_size.32bit.stderr index eb6c59deabb..8ff3464676c 100644 --- a/src/tools/clippy/tests/ui/cast_size.32bit.stderr +++ b/src/tools/clippy/tests/ui/cast_size.32bit.stderr @@ -12,35 +12,35 @@ help: ... or use `try_from` and handle the error accordingly LL | i8::try_from(1isize); | ~~~~~~~~~~~~~~~~~~~~ -error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast_size.rs:18:5 +error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) + --> tests/ui/cast_size.rs:21:5 | -LL | x0 as f64; +LL | x0 as f32; | ^^^^^^^^^ | = note: `-D clippy::cast-precision-loss` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` -error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast_size.rs:19:5 +error: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) + --> tests/ui/cast_size.rs:22:5 | -LL | x1 as f64; +LL | x1 as f32; | ^^^^^^^^^ -error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast_size.rs:20:5 +error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) + --> tests/ui/cast_size.rs:23:5 | -LL | x0 as f32; +LL | x0 as f64; | ^^^^^^^^^ -error: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast_size.rs:21:5 +error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) + --> tests/ui/cast_size.rs:24:5 | -LL | x1 as f32; +LL | x1 as f64; | ^^^^^^^^^ error: casting `isize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:22:5 + --> tests/ui/cast_size.rs:28:5 | LL | 1isize as i32; | ^^^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL | i32::try_from(1isize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `isize` to `u32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:23:5 + --> tests/ui/cast_size.rs:29:5 | LL | 1isize as u32; | ^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | u32::try_from(1isize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:24:5 + --> tests/ui/cast_size.rs:30:5 | LL | 1usize as u32; | ^^^^^^^^^^^^^ @@ -76,7 +76,7 @@ LL | u32::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:25:5 + --> tests/ui/cast_size.rs:31:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | i32::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:25:5 + --> tests/ui/cast_size.rs:31:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | 1usize as i32; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` error: casting `i64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:26:5 + --> tests/ui/cast_size.rs:32:5 | LL | 1i64 as isize; | ^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL | isize::try_from(1i64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:27:5 + --> tests/ui/cast_size.rs:33:5 | LL | 1i64 as usize; | ^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL | usize::try_from(1i64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:28:5 + --> tests/ui/cast_size.rs:34:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ @@ -133,13 +133,13 @@ LL | isize::try_from(1u64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:28:5 + --> tests/ui/cast_size.rs:34:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:29:5 + --> tests/ui/cast_size.rs:35:5 | LL | 1u64 as usize; | ^^^^^^^^^^^^^ @@ -151,25 +151,25 @@ LL | usize::try_from(1u64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:30:5 + --> tests/ui/cast_size.rs:36:5 | LL | 1u32 as isize; | ^^^^^^^^^^^^^ error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast_size.rs:35:5 + --> tests/ui/cast_size.rs:43:5 | LL | 999_999_999 as f32; | ^^^^^^^^^^^^^^^^^^ error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast_size.rs:36:5 + --> tests/ui/cast_size.rs:44:5 | LL | 9_999_999_999_999_999usize as f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: literal out of range for `usize` - --> tests/ui/cast_size.rs:36:5 + --> tests/ui/cast_size.rs:44:5 | LL | 9_999_999_999_999_999usize as f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs index 02f80cc52ac..c3c8562edff 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs +++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs @@ -1,5 +1,4 @@ //@no-rustfix: overlapping suggestions -#![feature(lint_reasons)] #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] #![allow( clippy::if_same_then_else, diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr index bae62133760..ddd600418af 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr +++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr @@ -1,5 +1,5 @@ error: called `unwrap` on `x` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:47:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:46:9 | LL | if x.is_some() { | -------------- help: try: `if let Some(..) = x` @@ -8,13 +8,13 @@ LL | x.unwrap(); | ^^^^^^^^^^ | note: the lint level is defined here - --> tests/ui/checked_unwrap/simple_conditionals.rs:3:35 + --> tests/ui/checked_unwrap/simple_conditionals.rs:2:35 | LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `expect` on `x` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:50:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:49:9 | LL | if x.is_some() { | -------------- help: try: `if let Some(..) = x` @@ -23,7 +23,7 @@ LL | x.expect("an error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:54:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:53:9 | LL | if x.is_some() { | ----------- because of this check @@ -32,13 +32,13 @@ LL | x.unwrap(); | ^^^^^^^^^^ | note: the lint level is defined here - --> tests/ui/checked_unwrap/simple_conditionals.rs:3:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:2:9 | LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `expect()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:57:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:56:9 | LL | if x.is_some() { | ----------- because of this check @@ -47,7 +47,7 @@ LL | x.expect("an error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:62:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:61:9 | LL | if x.is_none() { | ----------- because of this check @@ -56,7 +56,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: called `unwrap` on `x` after checking its variant with `is_none` - --> tests/ui/checked_unwrap/simple_conditionals.rs:66:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:65:9 | LL | if x.is_none() { | -------------- help: try: `if let Some(..) = x` @@ -65,7 +65,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: called `unwrap` on `x` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:14:13 + --> tests/ui/checked_unwrap/simple_conditionals.rs:13:13 | LL | if $a.is_some() { | --------------- help: try: `if let Some(..) = x` @@ -79,7 +79,7 @@ LL | m!(x); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: called `unwrap` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:79:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:78:9 | LL | if x.is_ok() { | ------------ help: try: `if let Ok(..) = x` @@ -88,7 +88,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: called `expect` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:82:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:81:9 | LL | if x.is_ok() { | ------------ help: try: `if let Ok(..) = x` @@ -97,7 +97,7 @@ LL | x.expect("an error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap_err()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:85:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:84:9 | LL | if x.is_ok() { | --------- because of this check @@ -106,7 +106,7 @@ LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:89:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:88:9 | LL | if x.is_ok() { | --------- because of this check @@ -115,7 +115,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: this call to `expect()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:92:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:91:9 | LL | if x.is_ok() { | --------- because of this check @@ -124,7 +124,7 @@ LL | x.expect("an error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap_err` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:95:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:94:9 | LL | if x.is_ok() { | ------------ help: try: `if let Err(..) = x` @@ -133,7 +133,7 @@ LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:100:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:99:9 | LL | if x.is_err() { | ---------- because of this check @@ -142,7 +142,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `x` after checking its variant with `is_err` - --> tests/ui/checked_unwrap/simple_conditionals.rs:103:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:102:9 | LL | if x.is_err() { | ------------- help: try: `if let Err(..) = x` @@ -151,7 +151,7 @@ LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ error: called `unwrap` on `x` after checking its variant with `is_err` - --> tests/ui/checked_unwrap/simple_conditionals.rs:107:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:106:9 | LL | if x.is_err() { | ------------- help: try: `if let Ok(..) = x` @@ -160,7 +160,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: this call to `unwrap_err()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:110:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:109:9 | LL | if x.is_err() { | ---------- because of this check @@ -169,7 +169,7 @@ LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ error: called `unwrap` on `option` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:135:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:134:9 | LL | if option.is_some() { | ------------------- help: try: `if let Some(..) = &option` @@ -177,7 +177,7 @@ LL | option.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:138:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:137:9 | LL | if option.is_some() { | ---------------- because of this check @@ -186,7 +186,7 @@ LL | option.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap` on `result` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:145:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:144:9 | LL | if result.is_ok() { | ----------------- help: try: `if let Ok(..) = &result` @@ -194,7 +194,7 @@ LL | result.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:148:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:147:9 | LL | if result.is_ok() { | -------------- because of this check @@ -203,7 +203,7 @@ LL | result.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap` on `option` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:154:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:153:9 | LL | if option.is_some() { | ------------------- help: try: `if let Some(..) = &mut option` @@ -211,7 +211,7 @@ LL | option.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:157:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:156:9 | LL | if option.is_some() { | ---------------- because of this check @@ -220,7 +220,7 @@ LL | option.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap` on `result` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:163:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:162:9 | LL | if result.is_ok() { | ----------------- help: try: `if let Ok(..) = &mut result` @@ -228,7 +228,7 @@ LL | result.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:166:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:165:9 | LL | if result.is_ok() { | -------------- because of this check diff --git a/src/tools/clippy/tests/ui/copy_iterator.rs b/src/tools/clippy/tests/ui/copy_iterator.rs index c0e5fc3e446..ea3a4face93 100644 --- a/src/tools/clippy/tests/ui/copy_iterator.rs +++ b/src/tools/clippy/tests/ui/copy_iterator.rs @@ -1,4 +1,5 @@ #![warn(clippy::copy_iterator)] +#![allow(clippy::manual_inspect)] #[derive(Copy, Clone)] struct Countdown(u8); diff --git a/src/tools/clippy/tests/ui/copy_iterator.stderr b/src/tools/clippy/tests/ui/copy_iterator.stderr index 533bddaadb5..990b1ce628d 100644 --- a/src/tools/clippy/tests/ui/copy_iterator.stderr +++ b/src/tools/clippy/tests/ui/copy_iterator.stderr @@ -1,5 +1,5 @@ error: you are implementing `Iterator` on a `Copy` type - --> tests/ui/copy_iterator.rs:6:1 + --> tests/ui/copy_iterator.rs:7:1 | LL | / impl Iterator for Countdown { LL | | diff --git a/src/tools/clippy/tests/ui/crashes/ice-12284.rs b/src/tools/clippy/tests/ui/crashes/ice-12284.rs new file mode 100644 index 00000000000..8d1dbface8e --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-12284.rs @@ -0,0 +1,10 @@ +#![allow(incomplete_features)] +#![feature(unnamed_fields)] + +#[repr(C)] +struct Foo { + _: struct { + }, +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed index e7038082c08..f28ae04fd0a 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed @@ -1,6 +1,5 @@ //@aux-build:proc_macros.rs -#![feature(lint_reasons)] #![warn(clippy::default_numeric_fallback)] #![allow( unused, diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs index d8eeda70491..78a5006444e 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs @@ -1,6 +1,5 @@ //@aux-build:proc_macros.rs -#![feature(lint_reasons)] #![warn(clippy::default_numeric_fallback)] #![allow( unused, diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr index 9961a3669ef..67ab923ecf5 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr @@ -1,5 +1,5 @@ error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:21:17 + --> tests/ui/default_numeric_fallback_i32.rs:20:17 | LL | let x = 22; | ^^ help: consider adding suffix: `22_i32` @@ -8,145 +8,145 @@ LL | let x = 22; = help: to override `-D warnings` add `#[allow(clippy::default_numeric_fallback)]` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:22:18 + --> tests/ui/default_numeric_fallback_i32.rs:21:18 | LL | let x = [1, 2, 3]; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:22:21 + --> tests/ui/default_numeric_fallback_i32.rs:21:21 | LL | let x = [1, 2, 3]; | ^ help: consider adding suffix: `2_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:22:24 + --> tests/ui/default_numeric_fallback_i32.rs:21:24 | LL | let x = [1, 2, 3]; | ^ help: consider adding suffix: `3_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:23:28 + --> tests/ui/default_numeric_fallback_i32.rs:22:28 | LL | let x = if true { (1, 2) } else { (3, 4) }; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:23:31 + --> tests/ui/default_numeric_fallback_i32.rs:22:31 | LL | let x = if true { (1, 2) } else { (3, 4) }; | ^ help: consider adding suffix: `2_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:23:44 + --> tests/ui/default_numeric_fallback_i32.rs:22:44 | LL | let x = if true { (1, 2) } else { (3, 4) }; | ^ help: consider adding suffix: `3_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:23:47 + --> tests/ui/default_numeric_fallback_i32.rs:22:47 | LL | let x = if true { (1, 2) } else { (3, 4) }; | ^ help: consider adding suffix: `4_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:24:23 + --> tests/ui/default_numeric_fallback_i32.rs:23:23 | LL | let x = match 1 { | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:25:13 + --> tests/ui/default_numeric_fallback_i32.rs:24:13 | LL | 1 => 1, | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:25:18 + --> tests/ui/default_numeric_fallback_i32.rs:24:18 | LL | 1 => 1, | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:26:18 + --> tests/ui/default_numeric_fallback_i32.rs:25:18 | LL | _ => 2, | ^ help: consider adding suffix: `2_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:45:21 + --> tests/ui/default_numeric_fallback_i32.rs:44:21 | LL | let y = 1; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:53:21 + --> tests/ui/default_numeric_fallback_i32.rs:52:21 | LL | let y = 1; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:59:21 + --> tests/ui/default_numeric_fallback_i32.rs:58:21 | LL | let y = 1; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:67:21 + --> tests/ui/default_numeric_fallback_i32.rs:66:21 | LL | let y = 1; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:83:27 + --> tests/ui/default_numeric_fallback_i32.rs:82:27 | LL | let f = || -> _ { 1 }; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:87:29 + --> tests/ui/default_numeric_fallback_i32.rs:86:29 | LL | let f = || -> i32 { 1 }; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:101:21 + --> tests/ui/default_numeric_fallback_i32.rs:100:21 | LL | generic_arg(1); | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:104:32 + --> tests/ui/default_numeric_fallback_i32.rs:103:32 | LL | let x: _ = generic_arg(1); | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:122:28 + --> tests/ui/default_numeric_fallback_i32.rs:121:28 | LL | GenericStruct { x: 1 }; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:125:36 + --> tests/ui/default_numeric_fallback_i32.rs:124:36 | LL | let _ = GenericStruct { x: 1 }; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:143:24 + --> tests/ui/default_numeric_fallback_i32.rs:142:24 | LL | GenericEnum::X(1); | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:163:23 + --> tests/ui/default_numeric_fallback_i32.rs:162:23 | LL | s.generic_arg(1); | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:173:25 + --> tests/ui/default_numeric_fallback_i32.rs:172:25 | LL | inline!(let x = 22;); | ^^ help: consider adding suffix: `22_i32` @@ -154,19 +154,19 @@ LL | inline!(let x = 22;); = note: this error originates in the macro `__inline_mac_fn_internal` (in Nightly builds, run with -Z macro-backtrace for more info) error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:215:29 + --> tests/ui/default_numeric_fallback_i32.rs:214:29 | LL | let data_i32 = vec![1, 2, 3]; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:215:32 + --> tests/ui/default_numeric_fallback_i32.rs:214:32 | LL | let data_i32 = vec![1, 2, 3]; | ^ help: consider adding suffix: `2_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:215:35 + --> tests/ui/default_numeric_fallback_i32.rs:214:35 | LL | let data_i32 = vec![1, 2, 3]; | ^ help: consider adding suffix: `3_i32` diff --git a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed index eb93eb8e8ed..e4a33193a1a 100644 --- a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed +++ b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed @@ -1,4 +1,3 @@ -#![feature(lint_reasons)] #![allow(unused)] #![warn(clippy::derive_partial_eq_without_eq)] diff --git a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs index 42dc435bdd5..a418b38e349 100644 --- a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs +++ b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs @@ -1,4 +1,3 @@ -#![feature(lint_reasons)] #![allow(unused)] #![warn(clippy::derive_partial_eq_without_eq)] diff --git a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.stderr b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.stderr index 29cd7da6b77..7436114fadb 100644 --- a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.stderr +++ b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.stderr @@ -1,5 +1,5 @@ error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:12:17 + --> tests/ui/derive_partial_eq_without_eq.rs:11:17 | LL | #[derive(Debug, PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` @@ -8,73 +8,73 @@ LL | #[derive(Debug, PartialEq)] = help: to override `-D warnings` add `#[allow(clippy::derive_partial_eq_without_eq)]` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:70:10 + --> tests/ui/derive_partial_eq_without_eq.rs:69:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:76:10 + --> tests/ui/derive_partial_eq_without_eq.rs:75:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:82:10 + --> tests/ui/derive_partial_eq_without_eq.rs:81:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:85:10 + --> tests/ui/derive_partial_eq_without_eq.rs:84:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:91:10 + --> tests/ui/derive_partial_eq_without_eq.rs:90:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:97:10 + --> tests/ui/derive_partial_eq_without_eq.rs:96:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:110:17 + --> tests/ui/derive_partial_eq_without_eq.rs:109:17 | LL | #[derive(Debug, PartialEq, Clone)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:113:10 + --> tests/ui/derive_partial_eq_without_eq.rs:112:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:120:14 + --> tests/ui/derive_partial_eq_without_eq.rs:119:14 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:123:14 + --> tests/ui/derive_partial_eq_without_eq.rs:122:14 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:183:14 + --> tests/ui/derive_partial_eq_without_eq.rs:182:14 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:191:14 + --> tests/ui/derive_partial_eq_without_eq.rs:190:14 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs index 72097bfabd7..2634c56794e 100644 --- a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs +++ b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs @@ -1,4 +1,3 @@ -#![feature(lint_reasons)] //! This file tests the `#[expect]` attribute implementation for tool lints. The same //! file is used to test clippy and rustdoc. Any changes to this file should be synced //! to the other test files as well. diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr index 43e0b9279e4..f70d3408aa4 100644 --- a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr +++ b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr @@ -1,5 +1,5 @@ error: this lint expectation is unfulfilled - --> tests/ui/expect_tool_lint_rfc_2383.rs:31:14 + --> tests/ui/expect_tool_lint_rfc_2383.rs:30:14 | LL | #[expect(dead_code)] | ^^^^^^^^^ @@ -8,31 +8,31 @@ LL | #[expect(dead_code)] = help: to override `-D warnings` add `#[allow(unfulfilled_lint_expectations)]` error: this lint expectation is unfulfilled - --> tests/ui/expect_tool_lint_rfc_2383.rs:37:18 + --> tests/ui/expect_tool_lint_rfc_2383.rs:36:18 | LL | #[expect(invalid_nan_comparisons)] | ^^^^^^^^^^^^^^^^^^^^^^^ error: this lint expectation is unfulfilled - --> tests/ui/expect_tool_lint_rfc_2383.rs:108:14 + --> tests/ui/expect_tool_lint_rfc_2383.rs:107:14 | LL | #[expect(clippy::almost_swapped)] | ^^^^^^^^^^^^^^^^^^^^^^ error: this lint expectation is unfulfilled - --> tests/ui/expect_tool_lint_rfc_2383.rs:116:14 + --> tests/ui/expect_tool_lint_rfc_2383.rs:115:14 | LL | #[expect(clippy::bytes_nth)] | ^^^^^^^^^^^^^^^^^ error: this lint expectation is unfulfilled - --> tests/ui/expect_tool_lint_rfc_2383.rs:122:14 + --> tests/ui/expect_tool_lint_rfc_2383.rs:121:14 | LL | #[expect(clippy::if_same_then_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: this lint expectation is unfulfilled - --> tests/ui/expect_tool_lint_rfc_2383.rs:128:14 + --> tests/ui/expect_tool_lint_rfc_2383.rs:127:14 | LL | #[expect(clippy::overly_complex_bool_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.rs b/src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.rs new file mode 100644 index 00000000000..5789dbf9b1d --- /dev/null +++ b/src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.rs @@ -0,0 +1,21 @@ +#![warn(clippy::field_scoped_visibility_modifiers)] + +pub mod pub_module { + pub(in crate::pub_module) mod pub_in_path_module {} + pub(super) mod pub_super_module {} + struct MyStruct { + private_field: bool, + pub pub_field: bool, + pub(crate) pub_crate_field: bool, + pub(in crate::pub_module) pub_in_path_field: bool, + pub(super) pub_super_field: bool, + #[allow(clippy::needless_pub_self)] + pub(self) pub_self_field: bool, + } +} +pub(crate) mod pub_crate_module {} + +#[allow(clippy::needless_pub_self)] +pub(self) mod pub_self_module {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.stderr b/src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.stderr new file mode 100644 index 00000000000..beea6c92107 --- /dev/null +++ b/src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.stderr @@ -0,0 +1,28 @@ +error: scoped visibility modifier on a field + --> tests/ui/field_scoped_visibility_modifiers.rs:9:9 + | +LL | pub(crate) pub_crate_field: bool, + | ^^^^^^^^^^ + | + = help: consider making the field private and adding a scoped visibility method for it + = note: `-D clippy::field-scoped-visibility-modifiers` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::field_scoped_visibility_modifiers)]` + +error: scoped visibility modifier on a field + --> tests/ui/field_scoped_visibility_modifiers.rs:10:9 + | +LL | pub(in crate::pub_module) pub_in_path_field: bool, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider making the field private and adding a scoped visibility method for it + +error: scoped visibility modifier on a field + --> tests/ui/field_scoped_visibility_modifiers.rs:11:9 + | +LL | pub(super) pub_super_field: bool, + | ^^^^^^^^^^ + | + = help: consider making the field private and adding a scoped visibility method for it + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/implicit_return.fixed b/src/tools/clippy/tests/ui/implicit_return.fixed index 897f1b76616..56fe29b4e67 100644 --- a/src/tools/clippy/tests/ui/implicit_return.fixed +++ b/src/tools/clippy/tests/ui/implicit_return.fixed @@ -1,7 +1,11 @@ -#![feature(lint_reasons)] +//@aux-build: proc_macros.rs + #![warn(clippy::implicit_return)] #![allow(clippy::needless_return, clippy::needless_bool, unused, clippy::never_loop)] +extern crate proc_macros; +use proc_macros::with_span; + fn test_end_of_fn() -> bool { if true { // no error! @@ -137,3 +141,11 @@ fn check_expect() -> bool { #[expect(clippy::implicit_return)] true } + +with_span!( + span + + fn dont_lint_proc_macro(x: usize) -> usize{ + x + } +); diff --git a/src/tools/clippy/tests/ui/implicit_return.rs b/src/tools/clippy/tests/ui/implicit_return.rs index fcff67b5807..f066ce20cfd 100644 --- a/src/tools/clippy/tests/ui/implicit_return.rs +++ b/src/tools/clippy/tests/ui/implicit_return.rs @@ -1,7 +1,11 @@ -#![feature(lint_reasons)] +//@aux-build: proc_macros.rs + #![warn(clippy::implicit_return)] #![allow(clippy::needless_return, clippy::needless_bool, unused, clippy::never_loop)] +extern crate proc_macros; +use proc_macros::with_span; + fn test_end_of_fn() -> bool { if true { // no error! @@ -137,3 +141,11 @@ fn check_expect() -> bool { #[expect(clippy::implicit_return)] true } + +with_span!( + span + + fn dont_lint_proc_macro(x: usize) -> usize{ + x + } +); diff --git a/src/tools/clippy/tests/ui/implicit_return.stderr b/src/tools/clippy/tests/ui/implicit_return.stderr index 3ffed273e0f..f06d4e983c5 100644 --- a/src/tools/clippy/tests/ui/implicit_return.stderr +++ b/src/tools/clippy/tests/ui/implicit_return.stderr @@ -1,5 +1,5 @@ error: missing `return` statement - --> tests/ui/implicit_return.rs:11:5 + --> tests/ui/implicit_return.rs:15:5 | LL | true | ^^^^ help: add `return` as shown: `return true` @@ -8,85 +8,85 @@ LL | true = help: to override `-D warnings` add `#[allow(clippy::implicit_return)]` error: missing `return` statement - --> tests/ui/implicit_return.rs:15:15 + --> tests/ui/implicit_return.rs:19:15 | LL | if true { true } else { false } | ^^^^ help: add `return` as shown: `return true` error: missing `return` statement - --> tests/ui/implicit_return.rs:15:29 + --> tests/ui/implicit_return.rs:19:29 | LL | if true { true } else { false } | ^^^^^ help: add `return` as shown: `return false` error: missing `return` statement - --> tests/ui/implicit_return.rs:21:17 + --> tests/ui/implicit_return.rs:25:17 | LL | true => false, | ^^^^^ help: add `return` as shown: `return false` error: missing `return` statement - --> tests/ui/implicit_return.rs:22:20 + --> tests/ui/implicit_return.rs:26:20 | LL | false => { true }, | ^^^^ help: add `return` as shown: `return true` error: missing `return` statement - --> tests/ui/implicit_return.rs:35:9 + --> tests/ui/implicit_return.rs:39:9 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing `return` statement - --> tests/ui/implicit_return.rs:42:13 + --> tests/ui/implicit_return.rs:46:13 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing `return` statement - --> tests/ui/implicit_return.rs:50:13 + --> tests/ui/implicit_return.rs:54:13 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing `return` statement - --> tests/ui/implicit_return.rs:68:18 + --> tests/ui/implicit_return.rs:72:18 | LL | let _ = || { true }; | ^^^^ help: add `return` as shown: `return true` error: missing `return` statement - --> tests/ui/implicit_return.rs:69:16 + --> tests/ui/implicit_return.rs:73:16 | LL | let _ = || true; | ^^^^ help: add `return` as shown: `return true` error: missing `return` statement - --> tests/ui/implicit_return.rs:77:5 + --> tests/ui/implicit_return.rs:81:5 | LL | format!("test {}", "test") | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `return` as shown: `return format!("test {}", "test")` error: missing `return` statement - --> tests/ui/implicit_return.rs:86:5 + --> tests/ui/implicit_return.rs:90:5 | LL | m!(true, false) | ^^^^^^^^^^^^^^^ help: add `return` as shown: `return m!(true, false)` error: missing `return` statement - --> tests/ui/implicit_return.rs:92:13 + --> tests/ui/implicit_return.rs:96:13 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing `return` statement - --> tests/ui/implicit_return.rs:97:17 + --> tests/ui/implicit_return.rs:101:17 | LL | break 'outer false; | ^^^^^^^^^^^^^^^^^^ help: change `break` to `return` as shown: `return false` error: missing `return` statement - --> tests/ui/implicit_return.rs:112:5 + --> tests/ui/implicit_return.rs:116:5 | LL | / loop { LL | | m!(true); @@ -101,7 +101,7 @@ LL + } | error: missing `return` statement - --> tests/ui/implicit_return.rs:126:5 + --> tests/ui/implicit_return.rs:130:5 | LL | true | ^^^^ help: add `return` as shown: `return true` diff --git a/src/tools/clippy/tests/ui/let_unit.fixed b/src/tools/clippy/tests/ui/let_unit.fixed index 20940daffa7..3456e274f6a 100644 --- a/src/tools/clippy/tests/ui/let_unit.fixed +++ b/src/tools/clippy/tests/ui/let_unit.fixed @@ -1,4 +1,3 @@ -#![feature(lint_reasons)] #![warn(clippy::let_unit_value)] #![allow(unused, clippy::no_effect, clippy::needless_late_init, path_statements)] diff --git a/src/tools/clippy/tests/ui/let_unit.rs b/src/tools/clippy/tests/ui/let_unit.rs index dca66f2e3ed..e2dafbcb771 100644 --- a/src/tools/clippy/tests/ui/let_unit.rs +++ b/src/tools/clippy/tests/ui/let_unit.rs @@ -1,4 +1,3 @@ -#![feature(lint_reasons)] #![warn(clippy::let_unit_value)] #![allow(unused, clippy::no_effect, clippy::needless_late_init, path_statements)] diff --git a/src/tools/clippy/tests/ui/let_unit.stderr b/src/tools/clippy/tests/ui/let_unit.stderr index aafb77bcd0d..2f62c33c887 100644 --- a/src/tools/clippy/tests/ui/let_unit.stderr +++ b/src/tools/clippy/tests/ui/let_unit.stderr @@ -1,5 +1,5 @@ error: this let-binding has unit value - --> tests/ui/let_unit.rs:12:5 + --> tests/ui/let_unit.rs:11:5 | LL | let _x = println!("x"); | ^^^^^^^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `println!("x");` @@ -8,7 +8,7 @@ LL | let _x = println!("x"); = help: to override `-D warnings` add `#[allow(clippy::let_unit_value)]` error: this let-binding has unit value - --> tests/ui/let_unit.rs:60:5 + --> tests/ui/let_unit.rs:59:5 | LL | / let _ = v LL | | .into_iter() @@ -31,7 +31,7 @@ LL + .unwrap(); | error: this let-binding has unit value - --> tests/ui/let_unit.rs:109:5 + --> tests/ui/let_unit.rs:108:5 | LL | / let x = match Some(0) { LL | | None => f2(1), @@ -52,7 +52,7 @@ LL + }; | error: this let-binding has unit value - --> tests/ui/let_unit.rs:190:9 + --> tests/ui/let_unit.rs:189:9 | LL | let res = returns_unit(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/macro_use_imports.fixed b/src/tools/clippy/tests/ui/macro_use_imports.fixed index 46c053b779e..38ed5a957e7 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.fixed +++ b/src/tools/clippy/tests/ui/macro_use_imports.fixed @@ -4,7 +4,6 @@ //@ignore-32bit -#![feature(lint_reasons)] #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] #![allow(clippy::single_component_path_imports)] #![warn(clippy::macro_use_imports)] diff --git a/src/tools/clippy/tests/ui/macro_use_imports.rs b/src/tools/clippy/tests/ui/macro_use_imports.rs index 47f5c9bf884..ae6cc16ed27 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.rs +++ b/src/tools/clippy/tests/ui/macro_use_imports.rs @@ -4,7 +4,6 @@ //@ignore-32bit -#![feature(lint_reasons)] #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] #![allow(clippy::single_component_path_imports)] #![warn(clippy::macro_use_imports)] diff --git a/src/tools/clippy/tests/ui/macro_use_imports.stderr b/src/tools/clippy/tests/ui/macro_use_imports.stderr index a3733b1c0c9..ea0670d3666 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.stderr +++ b/src/tools/clippy/tests/ui/macro_use_imports.stderr @@ -1,5 +1,5 @@ error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> tests/ui/macro_use_imports.rs:19:5 + --> tests/ui/macro_use_imports.rs:18:5 | LL | #[macro_use] | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};` @@ -8,19 +8,19 @@ LL | #[macro_use] = help: to override `-D warnings` add `#[allow(clippy::macro_use_imports)]` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> tests/ui/macro_use_imports.rs:23:5 + --> tests/ui/macro_use_imports.rs:22:5 | LL | #[macro_use] | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::mut_mut, inner::try_err};` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> tests/ui/macro_use_imports.rs:25:5 + --> tests/ui/macro_use_imports.rs:24:5 | LL | #[macro_use] | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> tests/ui/macro_use_imports.rs:21:5 + --> tests/ui/macro_use_imports.rs:20:5 | LL | #[macro_use] | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;` diff --git a/src/tools/clippy/tests/ui/macro_use_imports_expect.rs b/src/tools/clippy/tests/ui/macro_use_imports_expect.rs index b9677851b92..df6d5b9fbab 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports_expect.rs +++ b/src/tools/clippy/tests/ui/macro_use_imports_expect.rs @@ -3,7 +3,6 @@ //@aux-build:proc_macro_derive.rs //@ignore-32bit -#![feature(lint_reasons)] #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] #![allow(clippy::single_component_path_imports)] #![warn(clippy::macro_use_imports)] diff --git a/src/tools/clippy/tests/ui/manual_inspect.fixed b/src/tools/clippy/tests/ui/manual_inspect.fixed new file mode 100644 index 00000000000..0e1b8fe3edb --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_inspect.fixed @@ -0,0 +1,174 @@ +#![warn(clippy::manual_inspect)] +#![allow(clippy::no_effect, clippy::op_ref)] + +fn main() { + let _ = Some(0).inspect(|&x| { + println!("{}", x); + }); + + let _ = Some(0).inspect(|&x| { + println!("{x}"); + }); + + let _ = Some(0).inspect(|&x| { + println!("{}", x * 5 + 1); + }); + + let _ = Some(0).inspect(|&x| { + if x == 0 { + panic!(); + } + }); + + let _ = Some(0).inspect(|&x| { + if &x == &0 { + let _y = x; + panic!(); + } + }); + + let _ = Some(0).map(|x| { + let y = x + 1; + if y > 5 { + return y; + } + x + }); + + { + #[derive(PartialEq)] + struct Foo(i32); + + let _ = Some(Foo(0)).map(|x| { + if x == Foo(0) { + panic!(); + } + x + }); + + let _ = Some(Foo(0)).map(|x| { + if &x == &Foo(0) { + let _y = x; + panic!(); + } + x + }); + } + + { + macro_rules! maybe_ret { + ($e:expr) => { + if $e == 0 { + return $e; + } + }; + } + + let _ = Some(0).map(|x| { + maybe_ret!(x); + x + }); + } + + let _ = Some((String::new(), 0u32)).inspect(|x| { + if x.1 == 0 { + let _x = x.1; + panic!(); + } + }); + + let _ = Some((String::new(), 0u32)).map(|x| { + if x.1 == 0 { + let _x = x.0; + panic!(); + } + x + }); + + let _ = Some(String::new()).map(|x| { + if x.is_empty() { + let _ = || { + let _x = x; + }; + panic!(); + } + x + }); + + let _ = Some(String::new()).inspect(|x| { + if x.is_empty() { + let _ = || { + let _x = x; + }; + return; + } + println!("test"); + }); + + let _ = Some(0).inspect(|&x| { + if x == 0 { + let _ = || { + let _x = x; + }; + panic!(); + } + }); + + { + use core::cell::Cell; + #[derive(Debug)] + struct Cell2(core::cell::Cell<u32>); + + let _ = Some(Cell2(Cell::new(0u32))).inspect(|x| { + x.0.set(1); + }); + + let _ = Some(Cell2(Cell::new(0u32))).map(|x| { + let y = &x; + if x.0.get() == 0 { + y.0.set(1) + } else { + println!("{x:?}"); + } + x + }); + } + + let _: Result<_, ()> = Ok(0).inspect(|&x| { + println!("{}", x); + }); + + let _: Result<(), _> = Err(0).inspect_err(|&x| { + println!("{}", x); + }); + + let _ = [0] + .into_iter() + .inspect(|&x| { + println!("{}", x); + }) + .count(); + + { + struct S<T>(T); + impl<T> S<T> { + fn map<U>(self, f: impl FnOnce(T) -> U) -> S<U> { + S(f(self.0)) + } + + fn map_err<U>(self, f: impl FnOnce(T) -> U) -> S<U> { + S(f(self.0)) + } + } + + let _ = S(0).map(|x| { + println!("{}", x); + x + }); + + let _ = S(0).map_err(|x| { + println!("{}", x); + x + }); + } +} diff --git a/src/tools/clippy/tests/ui/manual_inspect.rs b/src/tools/clippy/tests/ui/manual_inspect.rs new file mode 100644 index 00000000000..94cdfe39140 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_inspect.rs @@ -0,0 +1,186 @@ +#![warn(clippy::manual_inspect)] +#![allow(clippy::no_effect, clippy::op_ref)] + +fn main() { + let _ = Some(0).map(|x| { + println!("{}", x); + x + }); + + let _ = Some(0).map(|x| { + println!("{x}"); + x + }); + + let _ = Some(0).map(|x| { + println!("{}", x * 5 + 1); + x + }); + + let _ = Some(0).map(|x| { + if x == 0 { + panic!(); + } + x + }); + + let _ = Some(0).map(|x| { + if &x == &0 { + let _y = x; + panic!(); + } + x + }); + + let _ = Some(0).map(|x| { + let y = x + 1; + if y > 5 { + return y; + } + x + }); + + { + #[derive(PartialEq)] + struct Foo(i32); + + let _ = Some(Foo(0)).map(|x| { + if x == Foo(0) { + panic!(); + } + x + }); + + let _ = Some(Foo(0)).map(|x| { + if &x == &Foo(0) { + let _y = x; + panic!(); + } + x + }); + } + + { + macro_rules! maybe_ret { + ($e:expr) => { + if $e == 0 { + return $e; + } + }; + } + + let _ = Some(0).map(|x| { + maybe_ret!(x); + x + }); + } + + let _ = Some((String::new(), 0u32)).map(|x| { + if x.1 == 0 { + let _x = x.1; + panic!(); + } + x + }); + + let _ = Some((String::new(), 0u32)).map(|x| { + if x.1 == 0 { + let _x = x.0; + panic!(); + } + x + }); + + let _ = Some(String::new()).map(|x| { + if x.is_empty() { + let _ = || { + let _x = x; + }; + panic!(); + } + x + }); + + let _ = Some(String::new()).map(|x| { + if x.is_empty() { + let _ = || { + let _x = &x; + }; + return x; + } + println!("test"); + x + }); + + let _ = Some(0).map(|x| { + if x == 0 { + let _ = || { + let _x = x; + }; + panic!(); + } + x + }); + + { + use core::cell::Cell; + #[derive(Debug)] + struct Cell2(core::cell::Cell<u32>); + + let _ = Some(Cell2(Cell::new(0u32))).map(|x| { + x.0.set(1); + x + }); + + let _ = Some(Cell2(Cell::new(0u32))).map(|x| { + let y = &x; + if x.0.get() == 0 { + y.0.set(1) + } else { + println!("{x:?}"); + } + x + }); + } + + let _: Result<_, ()> = Ok(0).map(|x| { + println!("{}", x); + x + }); + + let _: Result<(), _> = Err(0).map_err(|x| { + println!("{}", x); + x + }); + + let _ = [0] + .into_iter() + .map(|x| { + println!("{}", x); + x + }) + .count(); + + { + struct S<T>(T); + impl<T> S<T> { + fn map<U>(self, f: impl FnOnce(T) -> U) -> S<U> { + S(f(self.0)) + } + + fn map_err<U>(self, f: impl FnOnce(T) -> U) -> S<U> { + S(f(self.0)) + } + } + + let _ = S(0).map(|x| { + println!("{}", x); + x + }); + + let _ = S(0).map_err(|x| { + println!("{}", x); + x + }); + } +} diff --git a/src/tools/clippy/tests/ui/manual_inspect.stderr b/src/tools/clippy/tests/ui/manual_inspect.stderr new file mode 100644 index 00000000000..8548c0cd294 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_inspect.stderr @@ -0,0 +1,182 @@ +error: + --> tests/ui/manual_inspect.rs:5:21 + | +LL | let _ = Some(0).map(|x| { + | ^^^ + | + = note: `-D clippy::manual-inspect` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_inspect)]` +help: try + | +LL ~ let _ = Some(0).inspect(|&x| { +LL ~ println!("{}", x); + | + +error: + --> tests/ui/manual_inspect.rs:10:21 + | +LL | let _ = Some(0).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(0).inspect(|&x| { +LL ~ println!("{x}"); + | + +error: + --> tests/ui/manual_inspect.rs:15:21 + | +LL | let _ = Some(0).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(0).inspect(|&x| { +LL ~ println!("{}", x * 5 + 1); + | + +error: + --> tests/ui/manual_inspect.rs:20:21 + | +LL | let _ = Some(0).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(0).inspect(|&x| { +LL | if x == 0 { +LL | panic!(); +LL ~ } + | + +error: + --> tests/ui/manual_inspect.rs:27:21 + | +LL | let _ = Some(0).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(0).inspect(|&x| { +LL | if &x == &0 { +LL | let _y = x; +LL | panic!(); +LL ~ } + | + +error: + --> tests/ui/manual_inspect.rs:78:41 + | +LL | let _ = Some((String::new(), 0u32)).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some((String::new(), 0u32)).inspect(|x| { +LL | if x.1 == 0 { +LL | let _x = x.1; +LL | panic!(); +LL ~ } + | + +error: + --> tests/ui/manual_inspect.rs:104:33 + | +LL | let _ = Some(String::new()).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(String::new()).inspect(|x| { +LL | if x.is_empty() { +LL | let _ = || { +LL ~ let _x = x; +LL | }; +LL ~ return; +LL | } +LL ~ println!("test"); + | + +error: + --> tests/ui/manual_inspect.rs:115:21 + | +LL | let _ = Some(0).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(0).inspect(|&x| { +LL | if x == 0 { +... +LL | panic!(); +LL ~ } + | + +error: + --> tests/ui/manual_inspect.rs:130:46 + | +LL | let _ = Some(Cell2(Cell::new(0u32))).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(Cell2(Cell::new(0u32))).inspect(|x| { +LL ~ x.0.set(1); + | + +error: + --> tests/ui/manual_inspect.rs:146:34 + | +LL | let _: Result<_, ()> = Ok(0).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _: Result<_, ()> = Ok(0).inspect(|&x| { +LL ~ println!("{}", x); + | + +error: + --> tests/ui/manual_inspect.rs:151:35 + | +LL | let _: Result<(), _> = Err(0).map_err(|x| { + | ^^^^^^^ + | +help: try + | +LL ~ let _: Result<(), _> = Err(0).inspect_err(|&x| { +LL ~ println!("{}", x); + | + +error: this call to `map()` won't have an effect on the call to `count()` + --> tests/ui/manual_inspect.rs:156:13 + | +LL | let _ = [0] + | _____________^ +LL | | .into_iter() +LL | | .map(|x| { +LL | | println!("{}", x); +LL | | x +LL | | }) +LL | | .count(); + | |________________^ + | + = help: make sure you did not confuse `map` with `filter`, `for_each` or `inspect` + = note: `-D clippy::suspicious-map` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suspicious_map)]` + +error: + --> tests/ui/manual_inspect.rs:158:10 + | +LL | .map(|x| { + | ^^^ + | +help: try + | +LL ~ .inspect(|&x| { +LL ~ println!("{}", x); + | + +error: aborting due to 13 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs index eb387532031..31c3cc80137 100644 --- a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs +++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs @@ -1,4 +1,3 @@ -#![feature(lint_reasons)] #![warn(clippy::manual_non_exhaustive)] #![allow(unused)] //@no-rustfix diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr index ee43b8ddc02..dc669568dd2 100644 --- a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr +++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr @@ -1,5 +1,5 @@ error: this seems like a manual implementation of the non-exhaustive pattern - --> tests/ui/manual_non_exhaustive_enum.rs:5:1 + --> tests/ui/manual_non_exhaustive_enum.rs:4:1 | LL | enum E { | ^----- @@ -15,7 +15,7 @@ LL | | } | |_^ | help: remove this variant - --> tests/ui/manual_non_exhaustive_enum.rs:10:5 + --> tests/ui/manual_non_exhaustive_enum.rs:9:5 | LL | _C, | ^^ @@ -23,7 +23,7 @@ LL | _C, = help: to override `-D warnings` add `#[allow(clippy::manual_non_exhaustive)]` error: this seems like a manual implementation of the non-exhaustive pattern - --> tests/ui/manual_non_exhaustive_enum.rs:30:1 + --> tests/ui/manual_non_exhaustive_enum.rs:29:1 | LL | enum NoUnderscore { | ^---------------- @@ -38,7 +38,7 @@ LL | | } | |_^ | help: remove this variant - --> tests/ui/manual_non_exhaustive_enum.rs:34:5 + --> tests/ui/manual_non_exhaustive_enum.rs:33:5 | LL | C, | ^ diff --git a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.fixed b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.fixed index 588226b87e8..03e621d95ba 100644 --- a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.fixed +++ b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.fixed @@ -47,3 +47,15 @@ fn main() { } "".find(|c| m!(c)); } + +#[clippy::msrv = "1.57"] +fn msrv_1_57() { + let sentence = "Hello, world!"; + sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?'); +} + +#[clippy::msrv = "1.58"] +fn msrv_1_58() { + let sentence = "Hello, world!"; + sentence.trim_end_matches(['.', ',', '!', '?']); +} diff --git a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.rs b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.rs index 5078f3ee27f..43e883cd325 100644 --- a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.rs +++ b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.rs @@ -47,3 +47,15 @@ fn main() { } "".find(|c| m!(c)); } + +#[clippy::msrv = "1.57"] +fn msrv_1_57() { + let sentence = "Hello, world!"; + sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?'); +} + +#[clippy::msrv = "1.58"] +fn msrv_1_58() { + let sentence = "Hello, world!"; + sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?'); +} diff --git a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.stderr b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.stderr index b6b51794a11..f185d7c8f67 100644 --- a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.stderr +++ b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.stderr @@ -55,5 +55,11 @@ error: this manual char comparison can be written more succinctly LL | sentence.find(|c| c == '🎈'); | ^^^^^^^^^^^^^ help: consider using a `char`: `'🎈'` -error: aborting due to 9 previous errors +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:60:31 + | +LL | sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['.', ',', '!', '?']` + +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed index dffd44b6a7c..74afa00e12f 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed +++ b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed @@ -68,6 +68,32 @@ fn option_unwrap_or() { Some(s) => s, None => &format!("{} {}!", "hello", "world"), }; + + Some(1).unwrap_or(42); + + //don't lint + if let Some(x) = Some(1) { + x + 1 + } else { + 42 + }; + if let Some(x) = Some(1) { + x + } else { + return; + }; + for j in 0..4 { + if let Some(x) = Some(j) { + x + } else { + continue; + }; + if let Some(x) = Some(j) { + x + } else { + break; + }; + } } fn result_unwrap_or() { @@ -138,6 +164,32 @@ fn result_unwrap_or() { Ok(s) => s, Err(s) => "Bob", }; + + Ok::<i32, i32>(1).unwrap_or(42); + + //don't lint + if let Ok(x) = Ok::<i32, i32>(1) { + x + 1 + } else { + 42 + }; + if let Ok(x) = Ok::<i32, i32>(1) { + x + } else { + return; + }; + for j in 0..4 { + if let Ok(x) = Ok::<i32, i32>(j) { + x + } else { + continue; + }; + if let Ok(x) = Ok::<i32, i32>(j) { + x + } else { + break; + }; + } } // don't lint in const fn diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.rs b/src/tools/clippy/tests/ui/manual_unwrap_or.rs index 67427132c1a..2d01b8ceaaa 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or.rs +++ b/src/tools/clippy/tests/ui/manual_unwrap_or.rs @@ -83,6 +83,36 @@ fn option_unwrap_or() { Some(s) => s, None => &format!("{} {}!", "hello", "world"), }; + + if let Some(x) = Some(1) { + x + } else { + 42 + }; + + //don't lint + if let Some(x) = Some(1) { + x + 1 + } else { + 42 + }; + if let Some(x) = Some(1) { + x + } else { + return; + }; + for j in 0..4 { + if let Some(x) = Some(j) { + x + } else { + continue; + }; + if let Some(x) = Some(j) { + x + } else { + break; + }; + } } fn result_unwrap_or() { @@ -177,6 +207,36 @@ fn result_unwrap_or() { Ok(s) => s, Err(s) => "Bob", }; + + if let Ok(x) = Ok::<i32, i32>(1) { + x + } else { + 42 + }; + + //don't lint + if let Ok(x) = Ok::<i32, i32>(1) { + x + 1 + } else { + 42 + }; + if let Ok(x) = Ok::<i32, i32>(1) { + x + } else { + return; + }; + for j in 0..4 { + if let Ok(x) = Ok::<i32, i32>(j) { + x + } else { + continue; + }; + if let Ok(x) = Ok::<i32, i32>(j) { + x + } else { + break; + }; + } } // don't lint in const fn diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.stderr b/src/tools/clippy/tests/ui/manual_unwrap_or.stderr index 33a099680ce..c93a8952a08 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or.stderr +++ b/src/tools/clippy/tests/ui/manual_unwrap_or.stderr @@ -58,8 +58,18 @@ LL | | None => "Alice", LL | | }; | |_____^ help: replace with: `Some("Bob").unwrap_or("Alice")` +error: this pattern reimplements `Option::unwrap_or` + --> tests/ui/manual_unwrap_or.rs:87:5 + | +LL | / if let Some(x) = Some(1) { +LL | | x +LL | | } else { +LL | | 42 +LL | | }; + | |_____^ help: replace with: `Some(1).unwrap_or(42)` + error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:90:5 + --> tests/ui/manual_unwrap_or.rs:120:5 | LL | / match Ok::<i32, &str>(1) { LL | | Ok(i) => i, @@ -68,7 +78,7 @@ LL | | }; | |_____^ help: replace with: `Ok::<i32, &str>(1).unwrap_or(42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:97:5 + --> tests/ui/manual_unwrap_or.rs:127:5 | LL | / match a { LL | | Ok(i) => i, @@ -77,7 +87,7 @@ LL | | }; | |_____^ help: replace with: `a.unwrap_or(42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:103:5 + --> tests/ui/manual_unwrap_or.rs:133:5 | LL | / match Ok(1) as Result<i32, &str> { LL | | Ok(i) => i, @@ -86,7 +96,7 @@ LL | | }; | |_____^ help: replace with: `(Ok(1) as Result<i32, &str>).unwrap_or(42)` error: this pattern reimplements `Option::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:116:5 + --> tests/ui/manual_unwrap_or.rs:146:5 | LL | / match s.method() { LL | | Some(i) => i, @@ -95,7 +105,7 @@ LL | | }; | |_____^ help: replace with: `s.method().unwrap_or(42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:122:5 + --> tests/ui/manual_unwrap_or.rs:152:5 | LL | / match Ok::<i32, &str>(1) { LL | | Err(_) => 42, @@ -104,7 +114,7 @@ LL | | }; | |_____^ help: replace with: `Ok::<i32, &str>(1).unwrap_or(42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:128:5 + --> tests/ui/manual_unwrap_or.rs:158:5 | LL | / match Ok::<i32, &str>(1) { LL | | Ok(i) => i, @@ -113,7 +123,7 @@ LL | | }; | |_____^ help: replace with: `Ok::<i32, &str>(1).unwrap_or(1 + 42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:135:5 + --> tests/ui/manual_unwrap_or.rs:165:5 | LL | / match Ok::<i32, &str>(1) { LL | | Ok(i) => i, @@ -134,7 +144,7 @@ LL ~ }); | error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:145:5 + --> tests/ui/manual_unwrap_or.rs:175:5 | LL | / match Ok::<&str, &str>("Bob") { LL | | Ok(i) => i, @@ -142,8 +152,18 @@ LL | | Err(_) => "Alice", LL | | }; | |_____^ help: replace with: `Ok::<&str, &str>("Bob").unwrap_or("Alice")` +error: this pattern reimplements `Result::unwrap_or` + --> tests/ui/manual_unwrap_or.rs:211:5 + | +LL | / if let Ok(x) = Ok::<i32, i32>(1) { +LL | | x +LL | | } else { +LL | | 42 +LL | | }; + | |_____^ help: replace with: `Ok::<i32, i32>(1).unwrap_or(42)` + error: this pattern reimplements `Option::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:205:17 + --> tests/ui/manual_unwrap_or.rs:265:17 | LL | let _ = match some_macro!() { | _________________^ @@ -152,5 +172,5 @@ LL | | None => 0, LL | | }; | |_________^ help: replace with: `some_macro!().unwrap_or(0)` -error: aborting due to 14 previous errors +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed b/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed index 663de1a5f06..832376fa5af 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed +++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed @@ -1,5 +1,5 @@ #![warn(clippy::manual_unwrap_or_default)] -#![allow(clippy::unnecessary_literal_unwrap)] +#![allow(clippy::unnecessary_literal_unwrap, clippy::manual_unwrap_or)] fn main() { let x: Option<Vec<String>> = None; @@ -78,3 +78,24 @@ fn issue_12569() { 0 }; } + +// Should not warn! +fn issue_12928() { + let x = Some((1, 2)); + let y = if let Some((a, _)) = x { a } else { 0 }; + let y = if let Some((a, ..)) = x { a } else { 0 }; + let x = Some([1, 2]); + let y = if let Some([a, _]) = x { a } else { 0 }; + let y = if let Some([a, ..]) = x { a } else { 0 }; + + struct X { + a: u8, + b: u8, + } + let x = Some(X { a: 0, b: 0 }); + let y = if let Some(X { a, .. }) = x { a } else { 0 }; + struct Y(u8, u8); + let x = Some(Y(0, 0)); + let y = if let Some(Y(a, _)) = x { a } else { 0 }; + let y = if let Some(Y(a, ..)) = x { a } else { 0 }; +} diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs b/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs index 75ffe09be9d..649f65c89fb 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs +++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs @@ -1,5 +1,5 @@ #![warn(clippy::manual_unwrap_or_default)] -#![allow(clippy::unnecessary_literal_unwrap)] +#![allow(clippy::unnecessary_literal_unwrap, clippy::manual_unwrap_or)] fn main() { let x: Option<Vec<String>> = None; @@ -111,3 +111,24 @@ fn issue_12569() { 0 }; } + +// Should not warn! +fn issue_12928() { + let x = Some((1, 2)); + let y = if let Some((a, _)) = x { a } else { 0 }; + let y = if let Some((a, ..)) = x { a } else { 0 }; + let x = Some([1, 2]); + let y = if let Some([a, _]) = x { a } else { 0 }; + let y = if let Some([a, ..]) = x { a } else { 0 }; + + struct X { + a: u8, + b: u8, + } + let x = Some(X { a: 0, b: 0 }); + let y = if let Some(X { a, .. }) = x { a } else { 0 }; + struct Y(u8, u8); + let x = Some(Y(0, 0)); + let y = if let Some(Y(a, _)) = x { a } else { 0 }; + let y = if let Some(Y(a, ..)) = x { a } else { 0 }; +} diff --git a/src/tools/clippy/tests/ui/match_result_ok.fixed b/src/tools/clippy/tests/ui/match_result_ok.fixed index 76b26f5e438..117e0bc68cc 100644 --- a/src/tools/clippy/tests/ui/match_result_ok.fixed +++ b/src/tools/clippy/tests/ui/match_result_ok.fixed @@ -1,6 +1,11 @@ #![warn(clippy::match_result_ok)] #![allow(dead_code)] -#![allow(clippy::boxed_local, clippy::uninlined_format_args, clippy::manual_unwrap_or_default)] +#![allow( + clippy::boxed_local, + clippy::uninlined_format_args, + clippy::manual_unwrap_or_default, + clippy::manual_unwrap_or +)] // Checking `if` cases diff --git a/src/tools/clippy/tests/ui/match_result_ok.rs b/src/tools/clippy/tests/ui/match_result_ok.rs index d6f2475ba79..f8a5269024d 100644 --- a/src/tools/clippy/tests/ui/match_result_ok.rs +++ b/src/tools/clippy/tests/ui/match_result_ok.rs @@ -1,6 +1,11 @@ #![warn(clippy::match_result_ok)] #![allow(dead_code)] -#![allow(clippy::boxed_local, clippy::uninlined_format_args, clippy::manual_unwrap_or_default)] +#![allow( + clippy::boxed_local, + clippy::uninlined_format_args, + clippy::manual_unwrap_or_default, + clippy::manual_unwrap_or +)] // Checking `if` cases diff --git a/src/tools/clippy/tests/ui/match_result_ok.stderr b/src/tools/clippy/tests/ui/match_result_ok.stderr index 0d42d59dc01..b5b91cbe553 100644 --- a/src/tools/clippy/tests/ui/match_result_ok.stderr +++ b/src/tools/clippy/tests/ui/match_result_ok.stderr @@ -1,5 +1,5 @@ error: matching on `Some` with `ok()` is redundant - --> tests/ui/match_result_ok.rs:8:5 + --> tests/ui/match_result_ok.rs:13:5 | LL | if let Some(y) = x.parse().ok() { y } else { 0 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | if let Ok(y) = x.parse() { y } else { 0 } | ~~~~~~~~~~~~~~~~~~~~~~~~ error: matching on `Some` with `ok()` is redundant - --> tests/ui/match_result_ok.rs:18:9 + --> tests/ui/match_result_ok.rs:23:9 | LL | if let Some(y) = x . parse() . ok () { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | if let Ok(y) = x . parse() { | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: matching on `Some` with `ok()` is redundant - --> tests/ui/match_result_ok.rs:44:5 + --> tests/ui/match_result_ok.rs:49:5 | LL | while let Some(a) = wat.next().ok() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed new file mode 100644 index 00000000000..f8fc935f367 --- /dev/null +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed @@ -0,0 +1,176 @@ +#![warn(clippy::missing_const_for_fn)] +#![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)] +#![feature(const_mut_refs)] +#![feature(const_trait_impl)] + +use std::mem::transmute; + +struct Game { + guess: i32, +} + +impl Game { + // Could be const + pub const fn new() -> Self { + //~^ ERROR: this could be a `const fn` + //~| NOTE: `-D clippy::missing-const-for-fn` implied by `-D warnings` + Self { guess: 42 } + } + + const fn const_generic_params<'a, T, const N: usize>(&self, b: &'a [T; N]) -> &'a [T; N] { + //~^ ERROR: this could be a `const fn` + b + } +} + +// Could be const +const fn one() -> i32 { + //~^ ERROR: this could be a `const fn` + 1 +} + +// Could also be const +const fn two() -> i32 { + //~^ ERROR: this could be a `const fn` + let abc = 2; + abc +} + +// Could be const (since Rust 1.39) +const fn string() -> String { + //~^ ERROR: this could be a `const fn` + String::new() +} + +// Could be const +const unsafe fn four() -> i32 { + //~^ ERROR: this could be a `const fn` + 4 +} + +// Could also be const +const fn generic<T>(t: T) -> T { + //~^ ERROR: this could be a `const fn` + t +} + +fn sub(x: u32) -> usize { + unsafe { transmute(&x) } +} + +const fn generic_arr<T: Copy>(t: [T; 1]) -> T { + //~^ ERROR: this could be a `const fn` + t[0] +} + +mod with_drop { + pub struct A; + pub struct B; + impl Drop for A { + fn drop(&mut self) {} + } + + impl B { + // This can be const, because `a` is passed by reference + pub const fn b(self, a: &A) -> B { + //~^ ERROR: this could be a `const fn` + B + } + } +} + +#[clippy::msrv = "1.47.0"] +mod const_fn_stabilized_before_msrv { + // This could be const because `u8::is_ascii_digit` is a stable const function in 1.47. + const fn const_fn_stabilized_before_msrv(byte: u8) { + //~^ ERROR: this could be a `const fn` + byte.is_ascii_digit(); + } +} + +#[clippy::msrv = "1.45"] +fn msrv_1_45() -> i32 { + 45 +} + +#[clippy::msrv = "1.46"] +const fn msrv_1_46() -> i32 { + //~^ ERROR: this could be a `const fn` + 46 +} + +// Should not be const +fn main() {} + +struct D; + +/* FIXME(effects) +impl const Drop for D { + fn drop(&mut self) { + todo!(); + } +} +*/ + +// Lint this, since it can be dropped in const contexts +// FIXME(effects) +const fn d(this: D) {} +//~^ ERROR: this could be a `const fn` + +mod msrv { + struct Foo(*const u8, &'static u8); + + impl Foo { + #[clippy::msrv = "1.58"] + const fn deref_ptr_can_be_const(self) -> usize { + //~^ ERROR: this could be a `const fn` + unsafe { *self.0 as usize } + } + + const fn deref_copied_val(self) -> usize { + //~^ ERROR: this could be a `const fn` + *self.1 as usize + } + } + + union Bar { + val: u8, + } + + #[clippy::msrv = "1.56"] + const fn union_access_can_be_const() { + //~^ ERROR: this could be a `const fn` + let bar = Bar { val: 1 }; + let _ = unsafe { bar.val }; + } +} + +mod issue12677 { + pub struct Wrapper { + pub strings: Vec<String>, + } + + impl Wrapper { + #[must_use] + pub const fn new(strings: Vec<String>) -> Self { + Self { strings } + } + + #[must_use] + pub const fn empty() -> Self { + Self { strings: Vec::new() } + } + } + + pub struct Other { + pub text: String, + pub vec: Vec<String>, + } + + impl Other { + pub const fn new(text: String) -> Self { + let vec = Vec::new(); + Self { text, vec } + } + } +} diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs index 58e639cc7fd..5e4e2c58e5a 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs @@ -104,15 +104,18 @@ fn main() {} struct D; +/* FIXME(effects) impl const Drop for D { fn drop(&mut self) { todo!(); } } +*/ // Lint this, since it can be dropped in const contexts // FIXME(effects) fn d(this: D) {} +//~^ ERROR: this could be a `const fn` mod msrv { struct Foo(*const u8, &'static u8); diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr index 1c61c3e8713..8302b074127 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -10,6 +10,10 @@ LL | | } | = note: `-D clippy::missing-const-for-fn` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_fn)]` +help: make the function `const` + | +LL | pub const fn new() -> Self { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:20:5 @@ -19,6 +23,11 @@ LL | | LL | | b LL | | } | |_____^ + | +help: make the function `const` + | +LL | const fn const_generic_params<'a, T, const N: usize>(&self, b: &'a [T; N]) -> &'a [T; N] { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:27:1 @@ -28,6 +37,11 @@ LL | | LL | | 1 LL | | } | |_^ + | +help: make the function `const` + | +LL | const fn one() -> i32 { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:33:1 @@ -38,6 +52,11 @@ LL | | let abc = 2; LL | | abc LL | | } | |_^ + | +help: make the function `const` + | +LL | const fn two() -> i32 { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:40:1 @@ -47,6 +66,11 @@ LL | | LL | | String::new() LL | | } | |_^ + | +help: make the function `const` + | +LL | const fn string() -> String { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:46:1 @@ -56,6 +80,11 @@ LL | | LL | | 4 LL | | } | |_^ + | +help: make the function `const` + | +LL | const unsafe fn four() -> i32 { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:52:1 @@ -65,6 +94,11 @@ LL | | LL | | t LL | | } | |_^ + | +help: make the function `const` + | +LL | const fn generic<T>(t: T) -> T { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:61:1 @@ -74,6 +108,11 @@ LL | | LL | | t[0] LL | | } | |_^ + | +help: make the function `const` + | +LL | const fn generic_arr<T: Copy>(t: [T; 1]) -> T { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:75:9 @@ -83,6 +122,11 @@ LL | | LL | | B LL | | } | |_________^ + | +help: make the function `const` + | +LL | pub const fn b(self, a: &A) -> B { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:85:5 @@ -92,6 +136,11 @@ LL | | LL | | byte.is_ascii_digit(); LL | | } | |_____^ + | +help: make the function `const` + | +LL | const fn const_fn_stabilized_before_msrv(byte: u8) { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:97:1 @@ -101,27 +150,53 @@ LL | | LL | | 46 LL | | } | |_^ + | +help: make the function `const` + | +LL | const fn msrv_1_46() -> i32 { + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:117:1 + | +LL | fn d(this: D) {} + | ^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const fn d(this: D) {} + | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:122:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:125:9 | LL | / fn deref_ptr_can_be_const(self) -> usize { LL | | LL | | unsafe { *self.0 as usize } LL | | } | |_________^ + | +help: make the function `const` + | +LL | const fn deref_ptr_can_be_const(self) -> usize { + | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:127:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:130:9 | LL | / fn deref_copied_val(self) -> usize { LL | | LL | | *self.1 as usize LL | | } | |_________^ + | +help: make the function `const` + | +LL | const fn deref_copied_val(self) -> usize { + | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:138:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:141:5 | LL | / fn union_access_can_be_const() { LL | | @@ -129,31 +204,51 @@ LL | | let bar = Bar { val: 1 }; LL | | let _ = unsafe { bar.val }; LL | | } | |_____^ + | +help: make the function `const` + | +LL | const fn union_access_can_be_const() { + | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:152:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:155:9 | LL | / pub fn new(strings: Vec<String>) -> Self { LL | | Self { strings } LL | | } | |_________^ + | +help: make the function `const` + | +LL | pub const fn new(strings: Vec<String>) -> Self { + | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:157:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:160:9 | LL | / pub fn empty() -> Self { LL | | Self { strings: Vec::new() } LL | | } | |_________^ + | +help: make the function `const` + | +LL | pub const fn empty() -> Self { + | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:168:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:171:9 | LL | / pub fn new(text: String) -> Self { LL | | let vec = Vec::new(); LL | | Self { text, vec } LL | | } | |_________^ + | +help: make the function `const` + | +LL | pub const fn new(text: String) -> Self { + | +++++ -error: aborting due to 17 previous errors +error: aborting due to 18 previous errors diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed index 5121077b4ca..cabdc22bda8 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.fixed +++ b/src/tools/clippy/tests/ui/needless_borrow.fixed @@ -1,4 +1,3 @@ -#![feature(lint_reasons)] #![allow( unused, non_local_definitions, diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs index e3a5cb280ba..50062589645 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.rs +++ b/src/tools/clippy/tests/ui/needless_borrow.rs @@ -1,4 +1,3 @@ -#![feature(lint_reasons)] #![allow( unused, non_local_definitions, diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr index 4b2b17e7e57..bf0e265c250 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.stderr +++ b/src/tools/clippy/tests/ui/needless_borrow.stderr @@ -1,5 +1,5 @@ error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:16:15 + --> tests/ui/needless_borrow.rs:15:15 | LL | let _ = x(&&a); // warn | ^^^ help: change this to: `&a` @@ -8,163 +8,163 @@ LL | let _ = x(&&a); // warn = help: to override `-D warnings` add `#[allow(clippy::needless_borrow)]` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:20:13 + --> tests/ui/needless_borrow.rs:19:13 | LL | mut_ref(&mut &mut b); // warn | ^^^^^^^^^^^ help: change this to: `&mut b` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:32:13 + --> tests/ui/needless_borrow.rs:31:13 | LL | &&a | ^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:34:15 + --> tests/ui/needless_borrow.rs:33:15 | LL | 46 => &&a, | ^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:40:27 + --> tests/ui/needless_borrow.rs:39:27 | LL | break &ref_a; | ^^^^^^ help: change this to: `ref_a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:47:15 + --> tests/ui/needless_borrow.rs:46:15 | LL | let _ = x(&&&a); | ^^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:48:15 + --> tests/ui/needless_borrow.rs:47:15 | LL | let _ = x(&mut &&a); | ^^^^^^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:49:15 + --> tests/ui/needless_borrow.rs:48:15 | LL | let _ = x(&&&mut b); | ^^^^^^^^ help: change this to: `&mut b` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:50:15 + --> tests/ui/needless_borrow.rs:49:15 | LL | let _ = x(&&ref_a); | ^^^^^^^ help: change this to: `ref_a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:53:11 + --> tests/ui/needless_borrow.rs:52:11 | LL | x(&b); | ^^ help: change this to: `b` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:60:13 + --> tests/ui/needless_borrow.rs:59:13 | LL | mut_ref(&mut x); | ^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:61:13 + --> tests/ui/needless_borrow.rs:60:13 | LL | mut_ref(&mut &mut x); | ^^^^^^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:62:23 + --> tests/ui/needless_borrow.rs:61:23 | LL | let y: &mut i32 = &mut x; | ^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:63:23 + --> tests/ui/needless_borrow.rs:62:23 | LL | let y: &mut i32 = &mut &mut x; | ^^^^^^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:72:14 + --> tests/ui/needless_borrow.rs:71:14 | LL | 0 => &mut x, | ^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:78:14 + --> tests/ui/needless_borrow.rs:77:14 | LL | 0 => &mut x, | ^^^^^^ help: change this to: `x` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:90:13 + --> tests/ui/needless_borrow.rs:89:13 | LL | let _ = (&x).0; | ^^^^ help: change this to: `x` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:92:22 + --> tests/ui/needless_borrow.rs:91:22 | LL | let _ = unsafe { (&*x).0 }; | ^^^^^ help: change this to: `(*x)` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:102:5 + --> tests/ui/needless_borrow.rs:101:5 | LL | (&&()).foo(); | ^^^^^^ help: change this to: `(&())` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:111:5 + --> tests/ui/needless_borrow.rs:110:5 | LL | (&&5).foo(); | ^^^^^ help: change this to: `(&5)` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:137:23 + --> tests/ui/needless_borrow.rs:136:23 | LL | let x: (&str,) = (&"",); | ^^^ help: change this to: `""` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:179:13 + --> tests/ui/needless_borrow.rs:178:13 | LL | (&self.f)() | ^^^^^^^^^ help: change this to: `(self.f)` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:188:13 + --> tests/ui/needless_borrow.rs:187:13 | LL | (&mut self.f)() | ^^^^^^^^^^^^^ help: change this to: `(self.f)` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:225:22 + --> tests/ui/needless_borrow.rs:224:22 | LL | let _ = &mut (&mut { x.u }).x; | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:232:22 + --> tests/ui/needless_borrow.rs:231:22 | LL | let _ = &mut (&mut { x.u }).x; | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:236:22 + --> tests/ui/needless_borrow.rs:235:22 | LL | let _ = &mut (&mut x.u).x; | ^^^^^^^^^^ help: change this to: `x.u` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:237:22 + --> tests/ui/needless_borrow.rs:236:22 | LL | let _ = &mut (&mut { x.u }).x; | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:258:23 + --> tests/ui/needless_borrow.rs:257:23 | LL | option.unwrap_or((&x.0,)); | ^^^^ help: change this to: `x.0` diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs index 3f5f55f4002..eee62122fdf 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs @@ -5,7 +5,6 @@ clippy::ptr_arg )] #![warn(clippy::needless_pass_by_ref_mut)] -#![feature(lint_reasons)] //@no-rustfix use std::ptr::NonNull; diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr index 21ca393dcb6..51e3ba37ded 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr @@ -1,5 +1,5 @@ error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:12:11 + --> tests/ui/needless_pass_by_ref_mut.rs:11:11 | LL | fn foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>` @@ -8,79 +8,79 @@ LL | fn foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) { = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:37:12 + --> tests/ui/needless_pass_by_ref_mut.rs:36:12 | LL | fn foo6(s: &mut Vec<u32>) { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:47:12 + --> tests/ui/needless_pass_by_ref_mut.rs:46:12 | LL | fn bar(&mut self) {} | ^^^^^^^^^ help: consider changing to: `&self` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:50:29 + --> tests/ui/needless_pass_by_ref_mut.rs:49:29 | LL | fn mushroom(&self, vec: &mut Vec<i32>) -> usize { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:127:16 + --> tests/ui/needless_pass_by_ref_mut.rs:126:16 | LL | async fn a1(x: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:131:16 + --> tests/ui/needless_pass_by_ref_mut.rs:130:16 | LL | async fn a2(x: &mut i32, y: String) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:135:16 + --> tests/ui/needless_pass_by_ref_mut.rs:134:16 | LL | async fn a3(x: &mut i32, y: String, z: String) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:139:16 + --> tests/ui/needless_pass_by_ref_mut.rs:138:16 | LL | async fn a4(x: &mut i32, y: i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:143:24 + --> tests/ui/needless_pass_by_ref_mut.rs:142:24 | LL | async fn a5(x: i32, y: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:147:24 + --> tests/ui/needless_pass_by_ref_mut.rs:146:24 | LL | async fn a6(x: i32, y: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:151:32 + --> tests/ui/needless_pass_by_ref_mut.rs:150:32 | LL | async fn a7(x: i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:155:24 + --> tests/ui/needless_pass_by_ref_mut.rs:154:24 | LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:155:45 + --> tests/ui/needless_pass_by_ref_mut.rs:154:45 | LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:189:16 + --> tests/ui/needless_pass_by_ref_mut.rs:188:16 | LL | fn cfg_warn(s: &mut u32) {} | ^^^^^^^^ help: consider changing to: `&u32` @@ -88,7 +88,7 @@ LL | fn cfg_warn(s: &mut u32) {} = note: this is cfg-gated and may require further changes error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:195:20 + --> tests/ui/needless_pass_by_ref_mut.rs:194:20 | LL | fn cfg_warn(s: &mut u32) {} | ^^^^^^^^ help: consider changing to: `&u32` @@ -96,19 +96,19 @@ LL | fn cfg_warn(s: &mut u32) {} = note: this is cfg-gated and may require further changes error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:209:39 + --> tests/ui/needless_pass_by_ref_mut.rs:208:39 | LL | async fn inner_async2(x: &mut i32, y: &mut u32) { | ^^^^^^^^ help: consider changing to: `&u32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:217:26 + --> tests/ui/needless_pass_by_ref_mut.rs:216:26 | LL | async fn inner_async3(x: &mut i32, y: &mut u32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:236:34 + --> tests/ui/needless_pass_by_ref_mut.rs:235:34 | LL | pub async fn call_in_closure1(n: &mut str) { | ^^^^^^^^ help: consider changing to: `&str` @@ -116,7 +116,7 @@ LL | pub async fn call_in_closure1(n: &mut str) { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:255:20 + --> tests/ui/needless_pass_by_ref_mut.rs:254:20 | LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { | ^^^^^^^^^^ help: consider changing to: `&usize` @@ -124,7 +124,7 @@ LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:266:26 + --> tests/ui/needless_pass_by_ref_mut.rs:265:26 | LL | pub async fn closure4(n: &mut usize) { | ^^^^^^^^^^ help: consider changing to: `&usize` @@ -132,85 +132,85 @@ LL | pub async fn closure4(n: &mut usize) { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:315:12 + --> tests/ui/needless_pass_by_ref_mut.rs:314:12 | LL | fn bar(&mut self) {} | ^^^^^^^^^ help: consider changing to: `&self` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:317:18 + --> tests/ui/needless_pass_by_ref_mut.rs:316:18 | LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) { | ^^^^^^^^^ help: consider changing to: `&self` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:317:45 + --> tests/ui/needless_pass_by_ref_mut.rs:316:45 | LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) { | ^^^^^^^^ help: consider changing to: `&u32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:325:46 + --> tests/ui/needless_pass_by_ref_mut.rs:324:46 | LL | async fn foo2(&mut self, u: &mut i32, v: &mut u32) { | ^^^^^^^^ help: consider changing to: `&u32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:341:18 + --> tests/ui/needless_pass_by_ref_mut.rs:340:18 | LL | fn _empty_tup(x: &mut (())) {} | ^^^^^^^^^ help: consider changing to: `&()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:342:19 + --> tests/ui/needless_pass_by_ref_mut.rs:341:19 | LL | fn _single_tup(x: &mut ((i32,))) {} | ^^^^^^^^^^^^^ help: consider changing to: `&(i32,)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:343:18 + --> tests/ui/needless_pass_by_ref_mut.rs:342:18 | LL | fn _multi_tup(x: &mut ((i32, u32))) {} | ^^^^^^^^^^^^^^^^^ help: consider changing to: `&(i32, u32)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:344:11 + --> tests/ui/needless_pass_by_ref_mut.rs:343:11 | LL | fn _fn(x: &mut (fn())) {} | ^^^^^^^^^^^ help: consider changing to: `&fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:346:23 + --> tests/ui/needless_pass_by_ref_mut.rs:345:23 | LL | fn _extern_rust_fn(x: &mut extern "Rust" fn()) {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "Rust" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:347:20 + --> tests/ui/needless_pass_by_ref_mut.rs:346:20 | LL | fn _extern_c_fn(x: &mut extern "C" fn()) {} | ^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "C" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:348:18 + --> tests/ui/needless_pass_by_ref_mut.rs:347:18 | LL | fn _unsafe_fn(x: &mut unsafe fn()) {} | ^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:349:25 + --> tests/ui/needless_pass_by_ref_mut.rs:348:25 | LL | fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:350:20 + --> tests/ui/needless_pass_by_ref_mut.rs:349:20 | LL | fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn(i32)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:351:20 + --> tests/ui/needless_pass_by_ref_mut.rs:350:20 | LL | fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn() -> (i32)` diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed index a9271cb399d..853f685f04c 100644 --- a/src/tools/clippy/tests/ui/needless_return.fixed +++ b/src/tools/clippy/tests/ui/needless_return.fixed @@ -1,4 +1,3 @@ -#![feature(lint_reasons)] #![feature(yeet_expr)] #![allow(unused)] #![allow( diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs index dc888bf667f..e9c1e0e8ae8 100644 --- a/src/tools/clippy/tests/ui/needless_return.rs +++ b/src/tools/clippy/tests/ui/needless_return.rs @@ -1,4 +1,3 @@ -#![feature(lint_reasons)] #![feature(yeet_expr)] #![allow(unused)] #![allow( diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr index b49f199ba5a..6c891fe7ad3 100644 --- a/src/tools/clippy/tests/ui/needless_return.stderr +++ b/src/tools/clippy/tests/ui/needless_return.stderr @@ -1,5 +1,5 @@ error: unneeded `return` statement - --> tests/ui/needless_return.rs:26:5 + --> tests/ui/needless_return.rs:25:5 | LL | return true; | ^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:30:5 + --> tests/ui/needless_return.rs:29:5 | LL | return true; | ^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:35:5 + --> tests/ui/needless_return.rs:34:5 | LL | return true;;; | ^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:40:5 + --> tests/ui/needless_return.rs:39:5 | LL | return true;; ; ; | ^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:45:9 + --> tests/ui/needless_return.rs:44:9 | LL | return true; | ^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:47:9 + --> tests/ui/needless_return.rs:46:9 | LL | return false; | ^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + false | error: unneeded `return` statement - --> tests/ui/needless_return.rs:53:17 + --> tests/ui/needless_return.rs:52:17 | LL | true => return false, | ^^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL | true => false, | ~~~~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:55:13 + --> tests/ui/needless_return.rs:54:13 | LL | return true; | ^^^^^^^^^^^ @@ -96,7 +96,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:62:9 + --> tests/ui/needless_return.rs:61:9 | LL | return true; | ^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:64:16 + --> tests/ui/needless_return.rs:63:16 | LL | let _ = || return true; | ^^^^^^^^^^^ @@ -119,7 +119,7 @@ LL | let _ = || true; | ~~~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:68:5 + --> tests/ui/needless_return.rs:67:5 | LL | return the_answer!(); | ^^^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL + the_answer!() | error: unneeded `return` statement - --> tests/ui/needless_return.rs:71:21 + --> tests/ui/needless_return.rs:70:21 | LL | fn test_void_fun() { | _____________________^ @@ -146,7 +146,7 @@ LL + fn test_void_fun() { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:76:11 + --> tests/ui/needless_return.rs:75:11 | LL | if b { | ___________^ @@ -161,7 +161,7 @@ LL + if b { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:78:13 + --> tests/ui/needless_return.rs:77:13 | LL | } else { | _____________^ @@ -176,7 +176,7 @@ LL + } else { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:86:14 + --> tests/ui/needless_return.rs:85:14 | LL | _ => return, | ^^^^^^ @@ -187,7 +187,7 @@ LL | _ => (), | ~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:94:24 + --> tests/ui/needless_return.rs:93:24 | LL | let _ = 42; | ________________________^ @@ -202,7 +202,7 @@ LL + let _ = 42; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:97:14 + --> tests/ui/needless_return.rs:96:14 | LL | _ => return, | ^^^^^^ @@ -213,7 +213,7 @@ LL | _ => (), | ~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:110:9 + --> tests/ui/needless_return.rs:109:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -225,7 +225,7 @@ LL + String::from("test") | error: unneeded `return` statement - --> tests/ui/needless_return.rs:112:9 + --> tests/ui/needless_return.rs:111:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^ @@ -237,7 +237,7 @@ LL + String::new() | error: unneeded `return` statement - --> tests/ui/needless_return.rs:134:32 + --> tests/ui/needless_return.rs:133:32 | LL | bar.unwrap_or_else(|_| return) | ^^^^^^ @@ -248,7 +248,7 @@ LL | bar.unwrap_or_else(|_| {}) | ~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:138:21 + --> tests/ui/needless_return.rs:137:21 | LL | let _ = || { | _____________________^ @@ -263,7 +263,7 @@ LL + let _ = || { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:141:20 + --> tests/ui/needless_return.rs:140:20 | LL | let _ = || return; | ^^^^^^ @@ -274,7 +274,7 @@ LL | let _ = || {}; | ~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:147:32 + --> tests/ui/needless_return.rs:146:32 | LL | res.unwrap_or_else(|_| return Foo) | ^^^^^^^^^^ @@ -285,7 +285,7 @@ LL | res.unwrap_or_else(|_| Foo) | ~~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:156:5 + --> tests/ui/needless_return.rs:155:5 | LL | return true; | ^^^^^^^^^^^ @@ -297,7 +297,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:160:5 + --> tests/ui/needless_return.rs:159:5 | LL | return true; | ^^^^^^^^^^^ @@ -309,7 +309,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:165:9 + --> tests/ui/needless_return.rs:164:9 | LL | return true; | ^^^^^^^^^^^ @@ -321,7 +321,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:167:9 + --> tests/ui/needless_return.rs:166:9 | LL | return false; | ^^^^^^^^^^^^ @@ -333,7 +333,7 @@ LL + false | error: unneeded `return` statement - --> tests/ui/needless_return.rs:173:17 + --> tests/ui/needless_return.rs:172:17 | LL | true => return false, | ^^^^^^^^^^^^ @@ -344,7 +344,7 @@ LL | true => false, | ~~~~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:175:13 + --> tests/ui/needless_return.rs:174:13 | LL | return true; | ^^^^^^^^^^^ @@ -356,7 +356,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:182:9 + --> tests/ui/needless_return.rs:181:9 | LL | return true; | ^^^^^^^^^^^ @@ -368,7 +368,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:184:16 + --> tests/ui/needless_return.rs:183:16 | LL | let _ = || return true; | ^^^^^^^^^^^ @@ -379,7 +379,7 @@ LL | let _ = || true; | ~~~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:188:5 + --> tests/ui/needless_return.rs:187:5 | LL | return the_answer!(); | ^^^^^^^^^^^^^^^^^^^^ @@ -391,7 +391,7 @@ LL + the_answer!() | error: unneeded `return` statement - --> tests/ui/needless_return.rs:191:33 + --> tests/ui/needless_return.rs:190:33 | LL | async fn async_test_void_fun() { | _________________________________^ @@ -406,7 +406,7 @@ LL + async fn async_test_void_fun() { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:196:11 + --> tests/ui/needless_return.rs:195:11 | LL | if b { | ___________^ @@ -421,7 +421,7 @@ LL + if b { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:198:13 + --> tests/ui/needless_return.rs:197:13 | LL | } else { | _____________^ @@ -436,7 +436,7 @@ LL + } else { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:206:14 + --> tests/ui/needless_return.rs:205:14 | LL | _ => return, | ^^^^^^ @@ -447,7 +447,7 @@ LL | _ => (), | ~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:219:9 + --> tests/ui/needless_return.rs:218:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -459,7 +459,7 @@ LL + String::from("test") | error: unneeded `return` statement - --> tests/ui/needless_return.rs:221:9 + --> tests/ui/needless_return.rs:220:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^ @@ -471,7 +471,7 @@ LL + String::new() | error: unneeded `return` statement - --> tests/ui/needless_return.rs:237:5 + --> tests/ui/needless_return.rs:236:5 | LL | return format!("Hello {}", "world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -483,7 +483,7 @@ LL + format!("Hello {}", "world!") | error: unneeded `return` statement - --> tests/ui/needless_return.rs:249:9 + --> tests/ui/needless_return.rs:248:9 | LL | return true; | ^^^^^^^^^^^ @@ -497,7 +497,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:251:9 + --> tests/ui/needless_return.rs:250:9 | LL | return false; | ^^^^^^^^^^^^ @@ -509,7 +509,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:258:13 + --> tests/ui/needless_return.rs:257:13 | LL | return 10; | ^^^^^^^^^ @@ -524,7 +524,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:261:13 + --> tests/ui/needless_return.rs:260:13 | LL | return 100; | ^^^^^^^^^^ @@ -537,7 +537,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:269:9 + --> tests/ui/needless_return.rs:268:9 | LL | return 0; | ^^^^^^^^ @@ -549,7 +549,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:276:13 + --> tests/ui/needless_return.rs:275:13 | LL | return *(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -564,7 +564,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:278:13 + --> tests/ui/needless_return.rs:277:13 | LL | return !*(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -577,7 +577,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:285:20 + --> tests/ui/needless_return.rs:284:20 | LL | let _ = 42; | ____________________^ @@ -594,7 +594,7 @@ LL + let _ = 42; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:292:20 + --> tests/ui/needless_return.rs:291:20 | LL | let _ = 42; return; | ^^^^^^^ @@ -606,7 +606,7 @@ LL + let _ = 42; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:304:9 + --> tests/ui/needless_return.rs:303:9 | LL | return Ok(format!("ok!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -618,7 +618,7 @@ LL + Ok(format!("ok!")) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:306:9 + --> tests/ui/needless_return.rs:305:9 | LL | return Err(format!("err!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -630,7 +630,7 @@ LL + Err(format!("err!")) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:312:9 + --> tests/ui/needless_return.rs:311:9 | LL | return if true { 1 } else { 2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -642,7 +642,7 @@ LL + if true { 1 } else { 2 } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:316:9 + --> tests/ui/needless_return.rs:315:9 | LL | return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -654,7 +654,7 @@ LL + (if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else | error: unneeded `return` statement - --> tests/ui/needless_return.rs:337:5 + --> tests/ui/needless_return.rs:336:5 | LL | return { "a".to_string() } + "b" + { "c" }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.rs b/src/tools/clippy/tests/ui/nonminimal_bool.rs index 38157116e91..d117e8bf9c7 100644 --- a/src/tools/clippy/tests/ui/nonminimal_bool.rs +++ b/src/tools/clippy/tests/ui/nonminimal_bool.rs @@ -1,6 +1,4 @@ //@no-rustfix: overlapping suggestions - -#![feature(lint_reasons)] #![allow( unused, clippy::diverging_sub_expression, diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.stderr b/src/tools/clippy/tests/ui/nonminimal_bool.stderr index b6af06d845a..eafffdaf8a6 100644 --- a/src/tools/clippy/tests/ui/nonminimal_bool.stderr +++ b/src/tools/clippy/tests/ui/nonminimal_bool.stderr @@ -1,5 +1,5 @@ error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:19:13 + --> tests/ui/nonminimal_bool.rs:17:13 | LL | let _ = !true; | ^^^^^ help: try: `false` @@ -8,43 +8,43 @@ LL | let _ = !true; = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:22:13 + --> tests/ui/nonminimal_bool.rs:20:13 | LL | let _ = !false; | ^^^^^^ help: try: `true` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:24:13 + --> tests/ui/nonminimal_bool.rs:22:13 | LL | let _ = !!a; | ^^^ help: try: `a` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:26:13 + --> tests/ui/nonminimal_bool.rs:24:13 | LL | let _ = false || a; | ^^^^^^^^^^ help: try: `a` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:31:13 + --> tests/ui/nonminimal_bool.rs:29:13 | LL | let _ = !(!a && b); | ^^^^^^^^^^ help: try: `a || !b` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:33:13 + --> tests/ui/nonminimal_bool.rs:31:13 | LL | let _ = !(!a || b); | ^^^^^^^^^^ help: try: `a && !b` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:35:13 + --> tests/ui/nonminimal_bool.rs:33:13 | LL | let _ = !a && !(b && c); | ^^^^^^^^^^^^^^^ help: try: `!(a || b && c)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:44:13 + --> tests/ui/nonminimal_bool.rs:42:13 | LL | let _ = a == b && c == 5 && a == b; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -57,7 +57,7 @@ LL | let _ = a == b && c == 5; | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:46:13 + --> tests/ui/nonminimal_bool.rs:44:13 | LL | let _ = a == b || c == 5 || a == b; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -70,7 +70,7 @@ LL | let _ = a == b || c == 5; | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:48:13 + --> tests/ui/nonminimal_bool.rs:46:13 | LL | let _ = a == b && c == 5 && b == a; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -83,7 +83,7 @@ LL | let _ = a == b && c == 5; | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:50:13 + --> tests/ui/nonminimal_bool.rs:48:13 | LL | let _ = a != b || !(a != b || c == d); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -96,7 +96,7 @@ LL | let _ = a != b || c != d; | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:52:13 + --> tests/ui/nonminimal_bool.rs:50:13 | LL | let _ = a != b && !(a != b && c == d); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -109,43 +109,43 @@ LL | let _ = a != b && c != d; | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:83:8 + --> tests/ui/nonminimal_bool.rs:81:8 | LL | if matches!(true, true) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(true, true)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:163:8 + --> tests/ui/nonminimal_bool.rs:161:8 | LL | if !(12 == a) {} | ^^^^^^^^^^ help: try: `12 != a` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:164:8 + --> tests/ui/nonminimal_bool.rs:162:8 | LL | if !(a == 12) {} | ^^^^^^^^^^ help: try: `a != 12` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:165:8 + --> tests/ui/nonminimal_bool.rs:163:8 | LL | if !(12 != a) {} | ^^^^^^^^^^ help: try: `12 == a` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:166:8 + --> tests/ui/nonminimal_bool.rs:164:8 | LL | if !(a != 12) {} | ^^^^^^^^^^ help: try: `a == 12` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:170:8 + --> tests/ui/nonminimal_bool.rs:168:8 | LL | if !b == true {} | ^^^^^^^^^^ help: try: `b != true` error: this comparison might be written more concisely - --> tests/ui/nonminimal_bool.rs:170:8 + --> tests/ui/nonminimal_bool.rs:168:8 | LL | if !b == true {} | ^^^^^^^^^^ help: try simplifying it as shown: `b != true` @@ -154,61 +154,61 @@ LL | if !b == true {} = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]` error: equality checks against true are unnecessary - --> tests/ui/nonminimal_bool.rs:170:8 + --> tests/ui/nonminimal_bool.rs:168:8 | LL | if !b == true {} | ^^^^^^^^^^ help: try simplifying it as shown: `!b` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:171:8 + --> tests/ui/nonminimal_bool.rs:169:8 | LL | if !b != true {} | ^^^^^^^^^^ help: try: `b == true` error: inequality checks against true can be replaced by a negation - --> tests/ui/nonminimal_bool.rs:171:8 + --> tests/ui/nonminimal_bool.rs:169:8 | LL | if !b != true {} | ^^^^^^^^^^ help: try simplifying it as shown: `!(!b)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:172:8 + --> tests/ui/nonminimal_bool.rs:170:8 | LL | if true == !b {} | ^^^^^^^^^^ help: try: `true != b` error: this comparison might be written more concisely - --> tests/ui/nonminimal_bool.rs:172:8 + --> tests/ui/nonminimal_bool.rs:170:8 | LL | if true == !b {} | ^^^^^^^^^^ help: try simplifying it as shown: `true != b` error: equality checks against true are unnecessary - --> tests/ui/nonminimal_bool.rs:172:8 + --> tests/ui/nonminimal_bool.rs:170:8 | LL | if true == !b {} | ^^^^^^^^^^ help: try simplifying it as shown: `!b` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:173:8 + --> tests/ui/nonminimal_bool.rs:171:8 | LL | if true != !b {} | ^^^^^^^^^^ help: try: `true == b` error: inequality checks against true can be replaced by a negation - --> tests/ui/nonminimal_bool.rs:173:8 + --> tests/ui/nonminimal_bool.rs:171:8 | LL | if true != !b {} | ^^^^^^^^^^ help: try simplifying it as shown: `!(!b)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:174:8 + --> tests/ui/nonminimal_bool.rs:172:8 | LL | if !b == !c {} | ^^^^^^^^ help: try: `b == c` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:175:8 + --> tests/ui/nonminimal_bool.rs:173:8 | LL | if !b != !c {} | ^^^^^^^^ help: try: `b != c` diff --git a/src/tools/clippy/tests/ui/octal_escapes.rs b/src/tools/clippy/tests/ui/octal_escapes.rs index 3915dfdb841..f2664e2fa67 100644 --- a/src/tools/clippy/tests/ui/octal_escapes.rs +++ b/src/tools/clippy/tests/ui/octal_escapes.rs @@ -2,25 +2,20 @@ #![warn(clippy::octal_escapes)] fn main() { - let _bad1 = "\033[0m"; - //~^ ERROR: octal-looking escape in string literal - let _bad2 = b"\033[0m"; - //~^ ERROR: octal-looking escape in byte string literal - let _bad3 = "\\\033[0m"; - //~^ ERROR: octal-looking escape in string literal + let _bad1 = "\033[0m"; //~ octal_escapes + let _bad2 = b"\033[0m"; //~ octal_escapes + let _bad3 = "\\\033[0m"; //~ octal_escapes // maximum 3 digits (\012 is the escape) - let _bad4 = "\01234567"; - //~^ ERROR: octal-looking escape in string literal - let _bad5 = "\0\03"; - //~^ ERROR: octal-looking escape in string literal + let _bad4 = "\01234567"; //~ octal_escapes + let _bad5 = "\0\03"; //~ octal_escapes let _bad6 = "Text-\055\077-MoreText"; - //~^ ERROR: octal-looking escape in string literal + //~^ octal_escapes + //~| octal_escapes let _bad7 = "EvenMoreText-\01\02-ShortEscapes"; - //~^ ERROR: octal-looking escape in string literal - let _bad8 = "锈\01锈"; - //~^ ERROR: octal-looking escape in string literal - let _bad9 = "锈\011锈"; - //~^ ERROR: octal-looking escape in string literal + //~^ octal_escapes + //~| octal_escapes + let _bad8 = "锈\01锈"; //~ octal_escapes + let _bad9 = "锈\011锈"; //~ octal_escapes let _good1 = "\\033[0m"; let _good2 = "\0\\0"; diff --git a/src/tools/clippy/tests/ui/octal_escapes.stderr b/src/tools/clippy/tests/ui/octal_escapes.stderr index 7ed9ee3ae2f..9343ba64a30 100644 --- a/src/tools/clippy/tests/ui/octal_escapes.stderr +++ b/src/tools/clippy/tests/ui/octal_escapes.stderr @@ -1,148 +1,170 @@ -error: octal-looking escape in string literal - --> tests/ui/octal_escapes.rs:5:17 +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:5:18 | LL | let _bad1 = "\033[0m"; - | ^^^^^^^^^ + | ^^^^ | - = help: octal escapes are not supported, `\0` is always a null character + = help: octal escapes are not supported, `\0` is always null = note: `-D clippy::octal-escapes` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::octal_escapes)]` -help: if an octal escape was intended, use the hexadecimal representation instead +help: if an octal escape is intended, use a hex escape instead | LL | let _bad1 = "\x1b[0m"; - | ~~~~~~~~~ -help: if the null character is intended, disambiguate using + | ~~~~ +help: if a null escape is intended, disambiguate using | LL | let _bad1 = "\x0033[0m"; - | ~~~~~~~~~~~ + | ~~~~~~ -error: octal-looking escape in byte string literal - --> tests/ui/octal_escapes.rs:7:17 +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:6:19 | LL | let _bad2 = b"\033[0m"; - | ^^^^^^^^^^ + | ^^^^ | - = help: octal escapes are not supported, `\0` is always a null byte -help: if an octal escape was intended, use the hexadecimal representation instead +help: if an octal escape is intended, use a hex escape instead | LL | let _bad2 = b"\x1b[0m"; - | ~~~~~~~~~~ -help: if the null byte is intended, disambiguate using + | ~~~~ +help: if a null escape is intended, disambiguate using | LL | let _bad2 = b"\x0033[0m"; - | ~~~~~~~~~~~~ + | ~~~~~~ -error: octal-looking escape in string literal - --> tests/ui/octal_escapes.rs:9:17 +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:7:20 | LL | let _bad3 = "\\\033[0m"; - | ^^^^^^^^^^^ + | ^^^^ | - = help: octal escapes are not supported, `\0` is always a null character -help: if an octal escape was intended, use the hexadecimal representation instead +help: if an octal escape is intended, use a hex escape instead | LL | let _bad3 = "\\\x1b[0m"; - | ~~~~~~~~~~~ -help: if the null character is intended, disambiguate using + | ~~~~ +help: if a null escape is intended, disambiguate using | LL | let _bad3 = "\\\x0033[0m"; - | ~~~~~~~~~~~~~ + | ~~~~~~ -error: octal-looking escape in string literal - --> tests/ui/octal_escapes.rs:12:17 +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:9:18 | LL | let _bad4 = "\01234567"; - | ^^^^^^^^^^^ + | ^^^^ | - = help: octal escapes are not supported, `\0` is always a null character -help: if an octal escape was intended, use the hexadecimal representation instead +help: if an octal escape is intended, use a hex escape instead | LL | let _bad4 = "\x0a34567"; - | ~~~~~~~~~~~ -help: if the null character is intended, disambiguate using + | ~~~~ +help: if a null escape is intended, disambiguate using | LL | let _bad4 = "\x001234567"; - | ~~~~~~~~~~~~~ + | ~~~~~~ -error: octal-looking escape in string literal - --> tests/ui/octal_escapes.rs:14:17 +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:10:20 | LL | let _bad5 = "\0\03"; - | ^^^^^^^ + | ^^^ | - = help: octal escapes are not supported, `\0` is always a null character -help: if an octal escape was intended, use the hexadecimal representation instead +help: if an octal escape is intended, use a hex escape instead | LL | let _bad5 = "\0\x03"; - | ~~~~~~~~ -help: if the null character is intended, disambiguate using + | ~~~~ +help: if a null escape is intended, disambiguate using | -LL | let _bad5 = "\0\x003"; - | ~~~~~~~~~ +LL | let _bad5 = "\0\x0003"; + | ~~~~~~ -error: octal-looking escape in string literal - --> tests/ui/octal_escapes.rs:16:17 +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:11:23 | LL | let _bad6 = "Text-\055\077-MoreText"; - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ | - = help: octal escapes are not supported, `\0` is always a null character -help: if an octal escape was intended, use the hexadecimal representation instead +help: if an octal escape is intended, use a hex escape instead | -LL | let _bad6 = "Text-\x2d\x3f-MoreText"; - | ~~~~~~~~~~~~~~~~~~~~~~~~ -help: if the null character is intended, disambiguate using +LL | let _bad6 = "Text-\x2d\077-MoreText"; + | ~~~~ +help: if a null escape is intended, disambiguate using | -LL | let _bad6 = "Text-\x0055\x0077-MoreText"; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | let _bad6 = "Text-\x0055\077-MoreText"; + | ~~~~~~ -error: octal-looking escape in string literal - --> tests/ui/octal_escapes.rs:18:17 +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:11:27 + | +LL | let _bad6 = "Text-\055\077-MoreText"; + | ^^^^ + | +help: if an octal escape is intended, use a hex escape instead + | +LL | let _bad6 = "Text-\055\x3f-MoreText"; + | ~~~~ +help: if a null escape is intended, disambiguate using + | +LL | let _bad6 = "Text-\055\x0077-MoreText"; + | ~~~~~~ + +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:14:31 + | +LL | let _bad7 = "EvenMoreText-\01\02-ShortEscapes"; + | ^^^ + | +help: if an octal escape is intended, use a hex escape instead + | +LL | let _bad7 = "EvenMoreText-\x01\02-ShortEscapes"; + | ~~~~ +help: if a null escape is intended, disambiguate using + | +LL | let _bad7 = "EvenMoreText-\x0001\02-ShortEscapes"; + | ~~~~~~ + +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:14:34 | LL | let _bad7 = "EvenMoreText-\01\02-ShortEscapes"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^ | - = help: octal escapes are not supported, `\0` is always a null character -help: if an octal escape was intended, use the hexadecimal representation instead +help: if an octal escape is intended, use a hex escape instead | -LL | let _bad7 = "EvenMoreText-\x01\x02-ShortEscapes"; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: if the null character is intended, disambiguate using +LL | let _bad7 = "EvenMoreText-\01\x02-ShortEscapes"; + | ~~~~ +help: if a null escape is intended, disambiguate using | -LL | let _bad7 = "EvenMoreText-\x001\x002-ShortEscapes"; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | let _bad7 = "EvenMoreText-\01\x0002-ShortEscapes"; + | ~~~~~~ -error: octal-looking escape in string literal - --> tests/ui/octal_escapes.rs:20:17 +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:17:19 | LL | let _bad8 = "锈\01锈"; - | ^^^^^^^^^ + | ^^^ | - = help: octal escapes are not supported, `\0` is always a null character -help: if an octal escape was intended, use the hexadecimal representation instead +help: if an octal escape is intended, use a hex escape instead | LL | let _bad8 = "锈\x01锈"; - | ~~~~~~~~~~ -help: if the null character is intended, disambiguate using + | ~~~~ +help: if a null escape is intended, disambiguate using | -LL | let _bad8 = "锈\x001锈"; - | ~~~~~~~~~~~ +LL | let _bad8 = "锈\x0001锈"; + | ~~~~~~ -error: octal-looking escape in string literal - --> tests/ui/octal_escapes.rs:22:17 +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:18:19 | LL | let _bad9 = "锈\011锈"; - | ^^^^^^^^^^ + | ^^^^ | - = help: octal escapes are not supported, `\0` is always a null character -help: if an octal escape was intended, use the hexadecimal representation instead +help: if an octal escape is intended, use a hex escape instead | LL | let _bad9 = "锈\x09锈"; - | ~~~~~~~~~~ -help: if the null character is intended, disambiguate using + | ~~~~ +help: if a null escape is intended, disambiguate using | LL | let _bad9 = "锈\x0011锈"; - | ~~~~~~~~~~~~ + | ~~~~~~ -error: aborting due to 9 previous errors +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed index eeab801b7da..0ac89bf0d8e 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.fixed +++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed @@ -4,7 +4,8 @@ clippy::equatable_if_let, clippy::let_unit_value, clippy::redundant_locals, - clippy::manual_unwrap_or_default + clippy::manual_unwrap_or_default, + clippy::manual_unwrap_or )] fn bad1(string: Option<&str>) -> (bool, &str) { diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs index 3e5b96d7c31..b4f1b2cd1f7 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.rs +++ b/src/tools/clippy/tests/ui/option_if_let_else.rs @@ -4,7 +4,8 @@ clippy::equatable_if_let, clippy::let_unit_value, clippy::redundant_locals, - clippy::manual_unwrap_or_default + clippy::manual_unwrap_or_default, + clippy::manual_unwrap_or )] fn bad1(string: Option<&str>) -> (bool, &str) { diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr index f5359a0c34f..37ef791edb0 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.stderr +++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr @@ -1,5 +1,5 @@ error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:11:5 + --> tests/ui/option_if_let_else.rs:12:5 | LL | / if let Some(x) = string { LL | | (true, x) @@ -12,19 +12,19 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::option_if_let_else)]` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:29:13 + --> tests/ui/option_if_let_else.rs:30:13 | LL | let _ = if let Some(s) = *string { s.len() } else { 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:30:13 + --> tests/ui/option_if_let_else.rs:31:13 | LL | let _ = if let Some(s) = &num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:31:13 + --> tests/ui/option_if_let_else.rs:32:13 | LL | let _ = if let Some(s) = &mut num { | _____________^ @@ -44,13 +44,13 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:37:13 + --> tests/ui/option_if_let_else.rs:38:13 | LL | let _ = if let Some(ref s) = num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:38:13 + --> tests/ui/option_if_let_else.rs:39:13 | LL | let _ = if let Some(mut s) = num { | _____________^ @@ -70,7 +70,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:44:13 + --> tests/ui/option_if_let_else.rs:45:13 | LL | let _ = if let Some(ref mut s) = num { | _____________^ @@ -90,7 +90,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:53:5 + --> tests/ui/option_if_let_else.rs:54:5 | LL | / if let Some(x) = arg { LL | | let y = x * x; @@ -109,7 +109,7 @@ LL + }) | error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:66:13 + --> tests/ui/option_if_let_else.rs:67:13 | LL | let _ = if let Some(x) = arg { | _____________^ @@ -121,7 +121,7 @@ LL | | }; | |_____^ help: try: `arg.map_or_else(side_effect, |x| x)` error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:75:13 + --> tests/ui/option_if_let_else.rs:76:13 | LL | let _ = if let Some(x) = arg { | _____________^ @@ -144,7 +144,7 @@ LL ~ }, |x| x * x * x * x); | error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:108:13 + --> tests/ui/option_if_let_else.rs:109:13 | LL | / if let Some(idx) = s.find('.') { LL | | vec![s[..idx].to_string(), s[idx..].to_string()] @@ -154,7 +154,7 @@ LL | | } | |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])` error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:119:5 + --> tests/ui/option_if_let_else.rs:120:5 | LL | / if let Ok(binding) = variable { LL | | println!("Ok {binding}"); @@ -177,13 +177,13 @@ LL + }) | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:143:13 + --> tests/ui/option_if_let_else.rs:144:13 | LL | let _ = if let Some(x) = optional { x + 2 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:153:13 + --> tests/ui/option_if_let_else.rs:154:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -205,13 +205,13 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:181:13 + --> tests/ui/option_if_let_else.rs:182:13 | LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:185:13 + --> tests/ui/option_if_let_else.rs:186:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -231,7 +231,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:224:13 + --> tests/ui/option_if_let_else.rs:225:13 | LL | let _ = match s { | _____________^ @@ -241,7 +241,7 @@ LL | | }; | |_____^ help: try: `s.map_or(1, |string| string.len())` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:228:13 + --> tests/ui/option_if_let_else.rs:229:13 | LL | let _ = match Some(10) { | _____________^ @@ -251,7 +251,7 @@ LL | | }; | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:234:13 + --> tests/ui/option_if_let_else.rs:235:13 | LL | let _ = match res { | _____________^ @@ -261,7 +261,7 @@ LL | | }; | |_____^ help: try: `res.map_or(1, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:238:13 + --> tests/ui/option_if_let_else.rs:239:13 | LL | let _ = match res { | _____________^ @@ -271,13 +271,13 @@ LL | | }; | |_____^ help: try: `res.map_or(1, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:242:13 + --> tests/ui/option_if_let_else.rs:243:13 | LL | let _ = if let Ok(a) = res { a + 1 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:259:17 + --> tests/ui/option_if_let_else.rs:260:17 | LL | let _ = match initial { | _________________^ @@ -287,7 +287,7 @@ LL | | }; | |_________^ help: try: `initial.as_ref().map_or(42, |value| do_something(value))` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:266:17 + --> tests/ui/option_if_let_else.rs:267:17 | LL | let _ = match initial { | _________________^ @@ -297,7 +297,7 @@ LL | | }; | |_________^ help: try: `initial.as_mut().map_or(42, |value| do_something2(value))` error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:289:24 + --> tests/ui/option_if_let_else.rs:290:24 | LL | let mut _hashmap = if let Some(hm) = &opt { | ________________________^ @@ -308,7 +308,7 @@ LL | | }; | |_____^ help: try: `opt.as_ref().map_or_else(HashMap::new, |hm| hm.clone())` error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:295:19 + --> tests/ui/option_if_let_else.rs:296:19 | LL | let mut _hm = if let Some(hm) = &opt { hm.clone() } else { new_map!() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.as_ref().map_or_else(|| new_map!(), |hm| hm.clone())` diff --git a/src/tools/clippy/tests/ui/overly_complex_bool_expr.fixed b/src/tools/clippy/tests/ui/overly_complex_bool_expr.fixed index 439b1145431..b21e91aa3ad 100644 --- a/src/tools/clippy/tests/ui/overly_complex_bool_expr.fixed +++ b/src/tools/clippy/tests/ui/overly_complex_bool_expr.fixed @@ -1,4 +1,3 @@ -#![feature(lint_reasons)] #![allow(unused, clippy::diverging_sub_expression)] #![warn(clippy::overly_complex_bool_expr)] diff --git a/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs b/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs index b96fd1adf11..35ef0a1240a 100644 --- a/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs +++ b/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs @@ -1,4 +1,3 @@ -#![feature(lint_reasons)] #![allow(unused, clippy::diverging_sub_expression)] #![warn(clippy::overly_complex_bool_expr)] diff --git a/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr b/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr index 21dd5ade535..5a754236fe4 100644 --- a/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr +++ b/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr @@ -1,11 +1,11 @@ error: this boolean expression contains a logic bug - --> tests/ui/overly_complex_bool_expr.rs:11:13 + --> tests/ui/overly_complex_bool_expr.rs:10:13 | LL | let _ = a && b || a; | ^^^^^^^^^^^ help: it would look like the following: `a` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> tests/ui/overly_complex_bool_expr.rs:11:18 + --> tests/ui/overly_complex_bool_expr.rs:10:18 | LL | let _ = a && b || a; | ^ @@ -13,49 +13,49 @@ LL | let _ = a && b || a; = help: to override `-D warnings` add `#[allow(clippy::overly_complex_bool_expr)]` error: this boolean expression contains a logic bug - --> tests/ui/overly_complex_bool_expr.rs:14:13 + --> tests/ui/overly_complex_bool_expr.rs:13:13 | LL | let _ = false && a; | ^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> tests/ui/overly_complex_bool_expr.rs:14:22 + --> tests/ui/overly_complex_bool_expr.rs:13:22 | LL | let _ = false && a; | ^ error: this boolean expression contains a logic bug - --> tests/ui/overly_complex_bool_expr.rs:25:13 + --> tests/ui/overly_complex_bool_expr.rs:24:13 | LL | let _ = a == b && a != b; | ^^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> tests/ui/overly_complex_bool_expr.rs:25:13 + --> tests/ui/overly_complex_bool_expr.rs:24:13 | LL | let _ = a == b && a != b; | ^^^^^^ error: this boolean expression contains a logic bug - --> tests/ui/overly_complex_bool_expr.rs:27:13 + --> tests/ui/overly_complex_bool_expr.rs:26:13 | LL | let _ = a < b && a >= b; | ^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> tests/ui/overly_complex_bool_expr.rs:27:13 + --> tests/ui/overly_complex_bool_expr.rs:26:13 | LL | let _ = a < b && a >= b; | ^^^^^ error: this boolean expression contains a logic bug - --> tests/ui/overly_complex_bool_expr.rs:29:13 + --> tests/ui/overly_complex_bool_expr.rs:28:13 | LL | let _ = a > b && a <= b; | ^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> tests/ui/overly_complex_bool_expr.rs:29:13 + --> tests/ui/overly_complex_bool_expr.rs:28:13 | LL | let _ = a > b && a <= b; | ^^^^^ diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs index 5d6e488972c..e6ef6268121 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.rs +++ b/src/tools/clippy/tests/ui/ptr_arg.rs @@ -1,4 +1,3 @@ -#![feature(lint_reasons)] #![allow( unused, clippy::many_single_char_names, diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr index 0342130c992..1848ef80fc4 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.stderr +++ b/src/tools/clippy/tests/ui/ptr_arg.stderr @@ -1,5 +1,5 @@ error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:14:14 + --> tests/ui/ptr_arg.rs:13:14 | LL | fn do_vec(x: &Vec<i64>) { | ^^^^^^^^^ help: change this to: `&[i64]` @@ -8,49 +8,49 @@ LL | fn do_vec(x: &Vec<i64>) { = help: to override `-D warnings` add `#[allow(clippy::ptr_arg)]` error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:20:18 + --> tests/ui/ptr_arg.rs:19:18 | LL | fn do_vec_mut(x: &mut Vec<i64>) { | ^^^^^^^^^^^^^ help: change this to: `&mut [i64]` error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:25:19 + --> tests/ui/ptr_arg.rs:24:19 | LL | fn do_vec_mut2(x: &mut Vec<i64>) { | ^^^^^^^^^^^^^ help: change this to: `&mut [i64]` error: writing `&String` instead of `&str` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:31:14 + --> tests/ui/ptr_arg.rs:30:14 | LL | fn do_str(x: &String) { | ^^^^^^^ help: change this to: `&str` error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:36:18 + --> tests/ui/ptr_arg.rs:35:18 | LL | fn do_str_mut(x: &mut String) { | ^^^^^^^^^^^ help: change this to: `&mut str` error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:41:15 + --> tests/ui/ptr_arg.rs:40:15 | LL | fn do_path(x: &PathBuf) { | ^^^^^^^^ help: change this to: `&Path` error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:46:19 + --> tests/ui/ptr_arg.rs:45:19 | LL | fn do_path_mut(x: &mut PathBuf) { | ^^^^^^^^^^^^ help: change this to: `&mut Path` error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:55:18 + --> tests/ui/ptr_arg.rs:54:18 | LL | fn do_vec(x: &Vec<i64>); | ^^^^^^^^^ help: change this to: `&[i64]` error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:69:14 + --> tests/ui/ptr_arg.rs:68:14 | LL | fn cloned(x: &Vec<u8>) -> Vec<u8> { | ^^^^^^^^ @@ -68,7 +68,7 @@ LL ~ x.to_owned() | error: writing `&String` instead of `&str` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:79:18 + --> tests/ui/ptr_arg.rs:78:18 | LL | fn str_cloned(x: &String) -> String { | ^^^^^^^ @@ -85,7 +85,7 @@ LL ~ x.to_owned() | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:88:19 + --> tests/ui/ptr_arg.rs:87:19 | LL | fn path_cloned(x: &PathBuf) -> PathBuf { | ^^^^^^^^ @@ -102,7 +102,7 @@ LL ~ x.to_path_buf() | error: writing `&String` instead of `&str` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:97:44 + --> tests/ui/ptr_arg.rs:96:44 | LL | fn false_positive_capacity(x: &Vec<u8>, y: &String) { | ^^^^^^^ @@ -117,19 +117,19 @@ LL ~ let c = y; | error: using a reference to `Cow` is not recommended - --> tests/ui/ptr_arg.rs:112:25 + --> tests/ui/ptr_arg.rs:111:25 | LL | fn test_cow_with_ref(c: &Cow<[i32]>) {} | ^^^^^^^^^^^ help: change this to: `&[i32]` error: writing `&String` instead of `&str` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:142:66 + --> tests/ui/ptr_arg.rs:141:66 | LL | fn some_allowed(#[allow(clippy::ptr_arg)] _v: &Vec<u32>, _s: &String) {} | ^^^^^^^ help: change this to: `&str` error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:172:21 + --> tests/ui/ptr_arg.rs:171:21 | LL | fn foo_vec(vec: &Vec<u8>) { | ^^^^^^^^ @@ -143,7 +143,7 @@ LL ~ let _ = vec.to_owned().clone(); | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:178:23 + --> tests/ui/ptr_arg.rs:177:23 | LL | fn foo_path(path: &PathBuf) { | ^^^^^^^^ @@ -157,7 +157,7 @@ LL ~ let _ = path.to_path_buf().clone(); | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:184:21 + --> tests/ui/ptr_arg.rs:183:21 | LL | fn foo_str(str: &PathBuf) { | ^^^^^^^^ @@ -171,43 +171,43 @@ LL ~ let _ = str.to_path_buf().clone(); | error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:191:29 + --> tests/ui/ptr_arg.rs:190:29 | LL | fn mut_vec_slice_methods(v: &mut Vec<u32>) { | ^^^^^^^^^^^^^ help: change this to: `&mut [u32]` error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:254:17 + --> tests/ui/ptr_arg.rs:253:17 | LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) { | ^^^^^^^^^^^^^ help: change this to: `&mut [u32]` error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:254:35 + --> tests/ui/ptr_arg.rs:253:35 | LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) { | ^^^^^^^^^^^ help: change this to: `&mut str` error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:254:51 + --> tests/ui/ptr_arg.rs:253:51 | LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) { | ^^^^^^^^^^^^ help: change this to: `&mut Path` error: using a reference to `Cow` is not recommended - --> tests/ui/ptr_arg.rs:280:39 + --> tests/ui/ptr_arg.rs:279:39 | LL | fn cow_elided_lifetime<'a>(input: &'a Cow<str>) -> &'a str { | ^^^^^^^^^^^^ help: change this to: `&str` error: using a reference to `Cow` is not recommended - --> tests/ui/ptr_arg.rs:286:36 + --> tests/ui/ptr_arg.rs:285:36 | LL | fn cow_bad_ret_ty_1<'a>(input: &'a Cow<'a, str>) -> &'static str { | ^^^^^^^^^^^^^^^^ help: change this to: `&str` error: using a reference to `Cow` is not recommended - --> tests/ui/ptr_arg.rs:290:40 + --> tests/ui/ptr_arg.rs:289:40 | LL | fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str { | ^^^^^^^^^^^^^^^^ help: change this to: `&str` diff --git a/src/tools/clippy/tests/ui/redundant_clone.fixed b/src/tools/clippy/tests/ui/redundant_clone.fixed index 867f5b21017..1f79b5e5360 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.fixed +++ b/src/tools/clippy/tests/ui/redundant_clone.fixed @@ -1,5 +1,4 @@ // rustfix-only-machine-applicable -#![feature(lint_reasons)] #![warn(clippy::redundant_clone)] #![allow( clippy::drop_non_drop, diff --git a/src/tools/clippy/tests/ui/redundant_clone.rs b/src/tools/clippy/tests/ui/redundant_clone.rs index adcbd01e819..6909faebc99 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.rs +++ b/src/tools/clippy/tests/ui/redundant_clone.rs @@ -1,5 +1,4 @@ // rustfix-only-machine-applicable -#![feature(lint_reasons)] #![warn(clippy::redundant_clone)] #![allow( clippy::drop_non_drop, diff --git a/src/tools/clippy/tests/ui/redundant_clone.stderr b/src/tools/clippy/tests/ui/redundant_clone.stderr index 3c37288f550..d66972bcb5b 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.stderr +++ b/src/tools/clippy/tests/ui/redundant_clone.stderr @@ -1,11 +1,11 @@ error: redundant clone - --> tests/ui/redundant_clone.rs:15:42 + --> tests/ui/redundant_clone.rs:14:42 | LL | let _s = ["lorem", "ipsum"].join(" ").to_string(); | ^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:15:14 + --> tests/ui/redundant_clone.rs:14:14 | LL | let _s = ["lorem", "ipsum"].join(" ").to_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -13,169 +13,169 @@ LL | let _s = ["lorem", "ipsum"].join(" ").to_string(); = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]` error: redundant clone - --> tests/ui/redundant_clone.rs:18:15 + --> tests/ui/redundant_clone.rs:17:15 | LL | let _s = s.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:18:14 + --> tests/ui/redundant_clone.rs:17:14 | LL | let _s = s.clone(); | ^ error: redundant clone - --> tests/ui/redundant_clone.rs:21:15 + --> tests/ui/redundant_clone.rs:20:15 | LL | let _s = s.to_string(); | ^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:21:14 + --> tests/ui/redundant_clone.rs:20:14 | LL | let _s = s.to_string(); | ^ error: redundant clone - --> tests/ui/redundant_clone.rs:24:15 + --> tests/ui/redundant_clone.rs:23:15 | LL | let _s = s.to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:24:14 + --> tests/ui/redundant_clone.rs:23:14 | LL | let _s = s.to_owned(); | ^ error: redundant clone - --> tests/ui/redundant_clone.rs:26:42 + --> tests/ui/redundant_clone.rs:25:42 | LL | let _s = Path::new("/a/b/").join("c").to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:26:14 + --> tests/ui/redundant_clone.rs:25:14 | LL | let _s = Path::new("/a/b/").join("c").to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> tests/ui/redundant_clone.rs:28:42 + --> tests/ui/redundant_clone.rs:27:42 | LL | let _s = Path::new("/a/b/").join("c").to_path_buf(); | ^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:28:14 + --> tests/ui/redundant_clone.rs:27:14 | LL | let _s = Path::new("/a/b/").join("c").to_path_buf(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> tests/ui/redundant_clone.rs:30:29 + --> tests/ui/redundant_clone.rs:29:29 | LL | let _s = OsString::new().to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:30:14 + --> tests/ui/redundant_clone.rs:29:14 | LL | let _s = OsString::new().to_owned(); | ^^^^^^^^^^^^^^^ error: redundant clone - --> tests/ui/redundant_clone.rs:32:29 + --> tests/ui/redundant_clone.rs:31:29 | LL | let _s = OsString::new().to_os_string(); | ^^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:32:14 + --> tests/ui/redundant_clone.rs:31:14 | LL | let _s = OsString::new().to_os_string(); | ^^^^^^^^^^^^^^^ error: redundant clone - --> tests/ui/redundant_clone.rs:43:19 + --> tests/ui/redundant_clone.rs:42:19 | LL | let _t = tup.0.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:43:14 + --> tests/ui/redundant_clone.rs:42:14 | LL | let _t = tup.0.clone(); | ^^^^^ error: redundant clone - --> tests/ui/redundant_clone.rs:75:25 + --> tests/ui/redundant_clone.rs:74:25 | LL | if b { (a.clone(), a.clone()) } else { (Alpha, a) } | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:75:24 + --> tests/ui/redundant_clone.rs:74:24 | LL | if b { (a.clone(), a.clone()) } else { (Alpha, a) } | ^ error: redundant clone - --> tests/ui/redundant_clone.rs:132:15 + --> tests/ui/redundant_clone.rs:131:15 | LL | let _s = s.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:132:14 + --> tests/ui/redundant_clone.rs:131:14 | LL | let _s = s.clone(); | ^ error: redundant clone - --> tests/ui/redundant_clone.rs:133:15 + --> tests/ui/redundant_clone.rs:132:15 | LL | let _t = t.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:133:14 + --> tests/ui/redundant_clone.rs:132:14 | LL | let _t = t.clone(); | ^ error: redundant clone - --> tests/ui/redundant_clone.rs:143:19 + --> tests/ui/redundant_clone.rs:142:19 | LL | let _f = f.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:143:18 + --> tests/ui/redundant_clone.rs:142:18 | LL | let _f = f.clone(); | ^ error: redundant clone - --> tests/ui/redundant_clone.rs:155:14 + --> tests/ui/redundant_clone.rs:154:14 | LL | let y = x.clone().join("matthias"); | ^^^^^^^^ help: remove this | note: cloned value is neither consumed nor mutated - --> tests/ui/redundant_clone.rs:155:13 + --> tests/ui/redundant_clone.rs:154:13 | LL | let y = x.clone().join("matthias"); | ^^^^^^^^^ error: redundant clone - --> tests/ui/redundant_clone.rs:209:11 + --> tests/ui/redundant_clone.rs:208:11 | LL | foo(&x.clone(), move || { | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:209:10 + --> tests/ui/redundant_clone.rs:208:10 | LL | foo(&x.clone(), move || { | ^ diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.rs b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs index a4444c95e33..001ed311949 100644 --- a/src/tools/clippy/tests/ui/ref_binding_to_reference.rs +++ b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs @@ -1,6 +1,5 @@ // FIXME: run-rustfix waiting on multi-span suggestions //@no-rustfix -#![feature(lint_reasons)] #![warn(clippy::ref_binding_to_reference)] #![allow(clippy::needless_borrowed_reference, clippy::explicit_auto_deref)] diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr index 96886f80265..25ab9822382 100644 --- a/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr +++ b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr @@ -1,5 +1,5 @@ error: this pattern creates a reference to a reference - --> tests/ui/ref_binding_to_reference.rs:31:14 + --> tests/ui/ref_binding_to_reference.rs:30:14 | LL | Some(ref x) => x, | ^^^^^ @@ -12,7 +12,7 @@ LL | Some(x) => &x, | ~ ~~ error: this pattern creates a reference to a reference - --> tests/ui/ref_binding_to_reference.rs:39:14 + --> tests/ui/ref_binding_to_reference.rs:38:14 | LL | Some(ref x) => { | ^^^^^ @@ -27,7 +27,7 @@ LL ~ &x | error: this pattern creates a reference to a reference - --> tests/ui/ref_binding_to_reference.rs:50:14 + --> tests/ui/ref_binding_to_reference.rs:49:14 | LL | Some(ref x) => m2!(x), | ^^^^^ @@ -38,7 +38,7 @@ LL | Some(x) => m2!(&x), | ~ ~~ error: this pattern creates a reference to a reference - --> tests/ui/ref_binding_to_reference.rs:56:15 + --> tests/ui/ref_binding_to_reference.rs:55:15 | LL | let _ = |&ref x: &&String| { | ^^^^^ @@ -51,7 +51,7 @@ LL ~ let _: &&String = &x; | error: this pattern creates a reference to a reference - --> tests/ui/ref_binding_to_reference.rs:63:12 + --> tests/ui/ref_binding_to_reference.rs:62:12 | LL | fn f2<'a>(&ref x: &&'a String) -> &'a String { | ^^^^^ @@ -65,7 +65,7 @@ LL ~ x | error: this pattern creates a reference to a reference - --> tests/ui/ref_binding_to_reference.rs:71:11 + --> tests/ui/ref_binding_to_reference.rs:70:11 | LL | fn f(&ref x: &&String) { | ^^^^^ @@ -78,7 +78,7 @@ LL ~ let _: &&String = &x; | error: this pattern creates a reference to a reference - --> tests/ui/ref_binding_to_reference.rs:80:11 + --> tests/ui/ref_binding_to_reference.rs:79:11 | LL | fn f(&ref x: &&String) { | ^^^^^ diff --git a/src/tools/clippy/tests/ui/same_name_method.rs b/src/tools/clippy/tests/ui/same_name_method.rs index 26b1a299ba1..ba876c2b5a3 100644 --- a/src/tools/clippy/tests/ui/same_name_method.rs +++ b/src/tools/clippy/tests/ui/same_name_method.rs @@ -1,4 +1,3 @@ -#![feature(lint_reasons)] #![warn(clippy::same_name_method)] #![allow(dead_code, non_camel_case_types)] diff --git a/src/tools/clippy/tests/ui/same_name_method.stderr b/src/tools/clippy/tests/ui/same_name_method.stderr index 6c87a64b505..fefdb5c9c23 100644 --- a/src/tools/clippy/tests/ui/same_name_method.stderr +++ b/src/tools/clippy/tests/ui/same_name_method.stderr @@ -1,11 +1,11 @@ error: method's name is the same as an existing method in a trait - --> tests/ui/same_name_method.rs:21:13 + --> tests/ui/same_name_method.rs:20:13 | LL | fn foo() {} | ^^^^^^^^^^^ | note: existing `foo` defined here - --> tests/ui/same_name_method.rs:26:13 + --> tests/ui/same_name_method.rs:25:13 | LL | fn foo() {} | ^^^^^^^^^^^ @@ -13,62 +13,62 @@ LL | fn foo() {} = help: to override `-D warnings` add `#[allow(clippy::same_name_method)]` error: method's name is the same as an existing method in a trait - --> tests/ui/same_name_method.rs:36:13 + --> tests/ui/same_name_method.rs:35:13 | LL | fn clone() {} | ^^^^^^^^^^^^^ | note: existing `clone` defined here - --> tests/ui/same_name_method.rs:32:18 + --> tests/ui/same_name_method.rs:31:18 | LL | #[derive(Clone)] | ^^^^^ = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) error: method's name is the same as an existing method in a trait - --> tests/ui/same_name_method.rs:47:13 + --> tests/ui/same_name_method.rs:46:13 | LL | fn foo() {} | ^^^^^^^^^^^ | note: existing `foo` defined here - --> tests/ui/same_name_method.rs:52:13 + --> tests/ui/same_name_method.rs:51:13 | LL | fn foo() {} | ^^^^^^^^^^^ error: method's name is the same as an existing method in a trait - --> tests/ui/same_name_method.rs:62:13 + --> tests/ui/same_name_method.rs:61:13 | LL | fn foo() {} | ^^^^^^^^^^^ | note: existing `foo` defined here - --> tests/ui/same_name_method.rs:66:9 + --> tests/ui/same_name_method.rs:65:9 | LL | impl T1 for S {} | ^^^^^^^^^^^^^^^^ error: method's name is the same as an existing method in a trait - --> tests/ui/same_name_method.rs:75:13 + --> tests/ui/same_name_method.rs:74:13 | LL | fn foo() {} | ^^^^^^^^^^^ | note: existing `foo` defined here - --> tests/ui/same_name_method.rs:80:9 + --> tests/ui/same_name_method.rs:79:9 | LL | impl T1 for S {} | ^^^^^^^^^^^^^^^^ error: method's name is the same as an existing method in a trait - --> tests/ui/same_name_method.rs:75:13 + --> tests/ui/same_name_method.rs:74:13 | LL | fn foo() {} | ^^^^^^^^^^^ | note: existing `foo` defined here - --> tests/ui/same_name_method.rs:82:9 + --> tests/ui/same_name_method.rs:81:9 | LL | impl T2 for S {} | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unnecessary_min_or_max.fixed b/src/tools/clippy/tests/ui/unnecessary_min_or_max.fixed new file mode 100644 index 00000000000..392f6dd1fee --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_min_or_max.fixed @@ -0,0 +1,67 @@ +//@aux-build:external_consts.rs + +#![allow(unused)] +#![warn(clippy::unnecessary_min_or_max)] +#![allow(clippy::identity_op)] + +extern crate external_consts; + +const X: i32 = 1; + +fn main() { + // Both are Literals + let _ = (-6_i32); + let _ = 9; + let _ = 6; + let _ = 9_u32; + let _ = 6; + let _ = 7_u8; + + let x: u32 = 42; + // unsigned with zero + let _ = 0; + let _ = x; + let _ = 0_u32; + let _ = x; + + let x: i32 = 42; + // signed MIN + let _ = i32::MIN; + let _ = x; + let _ = i32::MIN; + let _ = x; + + let _ = i32::MIN - 0; + let _ = x; + + let _ = i32::MIN - 0; + + // The below cases shouldn't be lint + let mut min = u32::MAX; + for _ in 0..1000 { + min = min.min(random_u32()); + } + + let _ = 2.min(external_consts::MAGIC_NUMBER); + let _ = 2.max(external_consts::MAGIC_NUMBER); + let _ = external_consts::MAGIC_NUMBER.min(2); + let _ = external_consts::MAGIC_NUMBER.max(2); + + let _ = X.min(external_consts::MAGIC_NUMBER); + let _ = X.max(external_consts::MAGIC_NUMBER); + let _ = external_consts::MAGIC_NUMBER.min(X); + let _ = external_consts::MAGIC_NUMBER.max(X); + + let _ = X.max(12); + let _ = X.min(12); + let _ = 12.min(X); + let _ = 12.max(X); + let _ = (X + 1).max(12); + let _ = (X + 1).min(12); + let _ = 12.min(X - 1); + let _ = 12.max(X - 1); +} +fn random_u32() -> u32 { + // random number generator + 0 +} diff --git a/src/tools/clippy/tests/ui/unnecessary_min_or_max.rs b/src/tools/clippy/tests/ui/unnecessary_min_or_max.rs new file mode 100644 index 00000000000..b03755e6d23 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_min_or_max.rs @@ -0,0 +1,67 @@ +//@aux-build:external_consts.rs + +#![allow(unused)] +#![warn(clippy::unnecessary_min_or_max)] +#![allow(clippy::identity_op)] + +extern crate external_consts; + +const X: i32 = 1; + +fn main() { + // Both are Literals + let _ = (-6_i32).min(9); + let _ = (-6_i32).max(9); + let _ = 9_u32.min(6); + let _ = 9_u32.max(6); + let _ = 6.min(7_u8); + let _ = 6.max(7_u8); + + let x: u32 = 42; + // unsigned with zero + let _ = 0.min(x); + let _ = 0.max(x); + let _ = x.min(0_u32); + let _ = x.max(0_u32); + + let x: i32 = 42; + // signed MIN + let _ = i32::MIN.min(x); + let _ = i32::MIN.max(x); + let _ = x.min(i32::MIN); + let _ = x.max(i32::MIN); + + let _ = x.min(i32::MIN - 0); + let _ = x.max(i32::MIN); + + let _ = x.min(i32::MIN - 0); + + // The below cases shouldn't be lint + let mut min = u32::MAX; + for _ in 0..1000 { + min = min.min(random_u32()); + } + + let _ = 2.min(external_consts::MAGIC_NUMBER); + let _ = 2.max(external_consts::MAGIC_NUMBER); + let _ = external_consts::MAGIC_NUMBER.min(2); + let _ = external_consts::MAGIC_NUMBER.max(2); + + let _ = X.min(external_consts::MAGIC_NUMBER); + let _ = X.max(external_consts::MAGIC_NUMBER); + let _ = external_consts::MAGIC_NUMBER.min(X); + let _ = external_consts::MAGIC_NUMBER.max(X); + + let _ = X.max(12); + let _ = X.min(12); + let _ = 12.min(X); + let _ = 12.max(X); + let _ = (X + 1).max(12); + let _ = (X + 1).min(12); + let _ = 12.min(X - 1); + let _ = 12.max(X - 1); +} +fn random_u32() -> u32 { + // random number generator + 0 +} diff --git a/src/tools/clippy/tests/ui/unnecessary_min_or_max.stderr b/src/tools/clippy/tests/ui/unnecessary_min_or_max.stderr new file mode 100644 index 00000000000..f5cd31fbaf2 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_min_or_max.stderr @@ -0,0 +1,107 @@ +error: `(-6_i32)` is never greater than `9` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:13:13 + | +LL | let _ = (-6_i32).min(9); + | ^^^^^^^^^^^^^^^ help: try: `(-6_i32)` + | + = note: `-D clippy::unnecessary-min-or-max` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_min_or_max)]` + +error: `(-6_i32)` is never greater than `9` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:14:13 + | +LL | let _ = (-6_i32).max(9); + | ^^^^^^^^^^^^^^^ help: try: `9` + +error: `9_u32` is never smaller than `6` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:15:13 + | +LL | let _ = 9_u32.min(6); + | ^^^^^^^^^^^^ help: try: `6` + +error: `9_u32` is never smaller than `6` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:16:13 + | +LL | let _ = 9_u32.max(6); + | ^^^^^^^^^^^^ help: try: `9_u32` + +error: `6` is never greater than `7_u8` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:17:13 + | +LL | let _ = 6.min(7_u8); + | ^^^^^^^^^^^ help: try: `6` + +error: `6` is never greater than `7_u8` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:18:13 + | +LL | let _ = 6.max(7_u8); + | ^^^^^^^^^^^ help: try: `7_u8` + +error: `0` is never greater than `x` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:22:13 + | +LL | let _ = 0.min(x); + | ^^^^^^^^ help: try: `0` + +error: `0` is never greater than `x` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:23:13 + | +LL | let _ = 0.max(x); + | ^^^^^^^^ help: try: `x` + +error: `x` is never smaller than `0_u32` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:24:13 + | +LL | let _ = x.min(0_u32); + | ^^^^^^^^^^^^ help: try: `0_u32` + +error: `x` is never smaller than `0_u32` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:25:13 + | +LL | let _ = x.max(0_u32); + | ^^^^^^^^^^^^ help: try: `x` + +error: `i32::MIN` is never greater than `x` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:29:13 + | +LL | let _ = i32::MIN.min(x); + | ^^^^^^^^^^^^^^^ help: try: `i32::MIN` + +error: `i32::MIN` is never greater than `x` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:30:13 + | +LL | let _ = i32::MIN.max(x); + | ^^^^^^^^^^^^^^^ help: try: `x` + +error: `x` is never smaller than `i32::MIN` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:31:13 + | +LL | let _ = x.min(i32::MIN); + | ^^^^^^^^^^^^^^^ help: try: `i32::MIN` + +error: `x` is never smaller than `i32::MIN` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:32:13 + | +LL | let _ = x.max(i32::MIN); + | ^^^^^^^^^^^^^^^ help: try: `x` + +error: `x` is never smaller than `i32::MIN - 0` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:34:13 + | +LL | let _ = x.min(i32::MIN - 0); + | ^^^^^^^^^^^^^^^^^^^ help: try: `i32::MIN - 0` + +error: `x` is never smaller than `i32::MIN` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:35:13 + | +LL | let _ = x.max(i32::MIN); + | ^^^^^^^^^^^^^^^ help: try: `x` + +error: `x` is never smaller than `i32::MIN - 0` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:37:13 + | +LL | let _ = x.min(i32::MIN - 0); + | ^^^^^^^^^^^^^^^^^^^ help: try: `i32::MIN - 0` + +error: aborting due to 17 previous errors + diff --git a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs index 5187e079042..14371bc203b 100644 --- a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs +++ b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs @@ -1,4 +1,3 @@ -#![feature(lint_reasons)] #![warn(clippy::unsafe_derive_deserialize)] #![allow(unused, clippy::missing_safety_doc)] diff --git a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr index 06719f23d57..f2d4429f707 100644 --- a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr +++ b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr @@ -1,5 +1,5 @@ error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe` - --> tests/ui/unsafe_derive_deserialize.rs:9:10 + --> tests/ui/unsafe_derive_deserialize.rs:8:10 | LL | #[derive(Deserialize)] | ^^^^^^^^^^^ @@ -10,7 +10,7 @@ LL | #[derive(Deserialize)] = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe` - --> tests/ui/unsafe_derive_deserialize.rs:18:10 + --> tests/ui/unsafe_derive_deserialize.rs:17:10 | LL | #[derive(Deserialize)] | ^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | #[derive(Deserialize)] = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe` - --> tests/ui/unsafe_derive_deserialize.rs:25:10 + --> tests/ui/unsafe_derive_deserialize.rs:24:10 | LL | #[derive(Deserialize)] | ^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | #[derive(Deserialize)] = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe` - --> tests/ui/unsafe_derive_deserialize.rs:34:10 + --> tests/ui/unsafe_derive_deserialize.rs:33:10 | LL | #[derive(Deserialize)] | ^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/used_underscore_binding.rs b/src/tools/clippy/tests/ui/used_underscore_binding.rs index a8f404b1400..84dccf28f3b 100644 --- a/src/tools/clippy/tests/ui/used_underscore_binding.rs +++ b/src/tools/clippy/tests/ui/used_underscore_binding.rs @@ -1,5 +1,5 @@ //@aux-build:proc_macro_derive.rs -#![feature(rustc_private, lint_reasons)] +#![feature(rustc_private)] #![warn(clippy::used_underscore_binding)] #![allow(clippy::disallowed_names, clippy::eq_op, clippy::uninlined_format_args)] diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml index 4d66b728b76..0f0e62670ff 100644 --- a/src/tools/clippy/triagebot.toml +++ b/src/tools/clippy/triagebot.toml @@ -22,7 +22,6 @@ contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIB users_on_vacation = [ "matthiaskrgr", "giraffate", - "Centri3", ] [assign.owners] @@ -32,10 +31,10 @@ users_on_vacation = [ "*" = [ "@Manishearth", "@llogiq", - "@xFrednet", "@Alexendoo", "@dswij", "@Jarcho", "@blyxyas", "@y21", + "@Centri3", ] diff --git a/src/tools/clippy/util/gh-pages/index.html b/src/tools/clippy/util/gh-pages/index.html index c88c298d5d7..8de36fc4005 100644 --- a/src/tools/clippy/util/gh-pages/index.html +++ b/src/tools/clippy/util/gh-pages/index.html @@ -103,6 +103,7 @@ Otherwise, have a great day =^.^= @media (min-width: 405px) { #upper-filters { display: flex; + flex-wrap: wrap; } } @@ -404,7 +405,7 @@ Otherwise, have a great day =^.^= <div class="panel panel-default" ng-show="data"> <div class="panel-body row"> - <div id="upper-filters" class="col-12 col-md-4"> + <div id="upper-filters" class="col-12 col-md-6"> <div class="btn-group" filter-dropdown> <button type="button" class="btn btn-default dropdown-toggle"> Lint levels <span class="badge">{{selectedValuesCount(levels)}}</span> <span class="caret"></span> @@ -496,9 +497,34 @@ Otherwise, have a great day =^.^= </ul> </div> </div> - + <div class="btn-group" filter-dropdown> + <button type="button" class="btn btn-default dropdown-toggle"> + Applicability <span class="badge">{{selectedValuesCount(applicabilities)}}</span> <span class="caret"></span> + </button> + <ul class="dropdown-menu"> + <li class="checkbox"> + <label ng-click="toggleApplicabilities(true)"> + <input type="checkbox" class="invisible" /> + All + </label> + </li> + <li class="checkbox"> + <label ng-click="toggleApplicabilities(false)"> + <input type="checkbox" class="invisible" /> + None + </label> + </li> + <li role="separator" class="divider"></li> + <li class="checkbox" ng-repeat="(applicability, enabled) in applicabilities"> + <label class="text-capitalize"> + <input type="checkbox" ng-model="applicabilities[applicability]" /> + {{applicability}} + </label> + </li> + </ul> + </div> </div> - <div class="col-12 col-md-7 search-control"> + <div class="col-12 col-md-6 search-control"> <div class="input-group"> <label class="input-group-addon" id="filter-label" for="search-input">Filter:</label> <input type="text" class="form-control filter-input" placeholder="Keywords or search string" id="search-input" @@ -514,7 +540,7 @@ Otherwise, have a great day =^.^= </div> </div> <!-- The order of the filters should be from most likely to remove a lint to least likely to improve performance. --> - <article class="panel panel-default" id="{{lint.id}}" ng-repeat="lint in data | filter:bySearch | filter:byGroups | filter:byLevels | filter:byVersion"> + <article class="panel panel-default" id="{{lint.id}}" ng-repeat="lint in data | filter:bySearch | filter:byGroups | filter:byLevels | filter:byVersion | filter:byApplicabilities"> <header class="panel-heading" ng-click="open[lint.id] = !open[lint.id]"> <h2 class="panel-title"> <div class="panel-title-name"> diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js index 7cca298df8e..921bb0376f6 100644 --- a/src/tools/clippy/util/gh-pages/script.js +++ b/src/tools/clippy/util/gh-pages/script.js @@ -156,6 +156,18 @@ Object.entries(versionFilterKeyMap).map(([key, value]) => [value, key]) ); + const APPLICABILITIES_FILTER_DEFAULT = { + Unspecified: true, + Unresolved: true, + MachineApplicable: true, + MaybeIncorrect: true, + HasPlaceholders: true + }; + + $scope.applicabilities = { + ...APPLICABILITIES_FILTER_DEFAULT + } + // loadFromURLParameters retrieves filter settings from the URL parameters and assigns them // to corresponding $scope variables. function loadFromURLParameters() { @@ -182,6 +194,7 @@ handleParameter('levels', $scope.levels, LEVEL_FILTERS_DEFAULT); handleParameter('groups', $scope.groups, GROUPS_FILTER_DEFAULT); + handleParameter('applicabilities', $scope.applicabilities, APPLICABILITIES_FILTER_DEFAULT); // Handle 'versions' parameter separately because it needs additional processing if (urlParameters.versions) { @@ -249,6 +262,7 @@ updateURLParameter($scope.levels, 'levels', LEVEL_FILTERS_DEFAULT); updateURLParameter($scope.groups, 'groups', GROUPS_FILTER_DEFAULT); updateVersionURLParameter($scope.versionFilters); + updateURLParameter($scope.applicabilities, 'applicabilities', APPLICABILITIES_FILTER_DEFAULT); } // Add $watches to automatically update URL parameters when the data changes @@ -270,6 +284,12 @@ } }, true); + $scope.$watch('applicabilities', function (newVal, oldVal) { + if (newVal !== oldVal) { + updateURLParameter(newVal, 'applicabilities', APPLICABILITIES_FILTER_DEFAULT) + } + }, true); + // Watch for changes in the URL path and update the search and lint display $scope.$watch(function () { return $location.path(); }, function (newPath) { const searchParameter = newPath.substring(1); @@ -327,6 +347,15 @@ } }; + $scope.toggleApplicabilities = function (value) { + const applicabilities = $scope.applicabilities; + for (const key in applicabilities) { + if (applicabilities.hasOwnProperty(key)) { + applicabilities[key] = value; + } + } + } + $scope.resetGroupsToDefault = function () { $scope.groups = { ...GROUPS_FILTER_DEFAULT @@ -430,6 +459,10 @@ return true; } + $scope.byApplicabilities = function (lint) { + return $scope.applicabilities[lint.applicability.applicability]; + }; + // Show details for one lint $scope.openLint = function (lint) { $scope.open[lint.id] = true; diff --git a/src/tools/compiletest/src/command-list.rs b/src/tools/compiletest/src/command-list.rs index 6e1685a8a94..6735e9faa7a 100644 --- a/src/tools/compiletest/src/command-list.rs +++ b/src/tools/compiletest/src/command-list.rs @@ -53,6 +53,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-gnu", "ignore-haiku", "ignore-horizon", + "ignore-i686-pc-windows-gnu", "ignore-i686-pc-windows-msvc", "ignore-illumos", "ignore-ios", @@ -174,6 +175,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-bpf", "only-cdb", "only-gnu", + "only-i686-pc-windows-gnu", "only-i686-pc-windows-msvc", "only-ios", "only-linux", diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 3bc4163ab52..fc4e484fa38 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -33,50 +33,7 @@ jobs: HOST_TARGET: ${{ matrix.host_target }} steps: - uses: actions/checkout@v4 - - - name: Show Rust version (stable toolchain) - run: | - rustup show - rustc -Vv - cargo -V - - # Cache the global cargo directory, but NOT the local `target` directory which - # we cannot reuse anyway when the nightly changes (and it grows quite large - # over time). - - name: Add cache for cargo - id: cache - uses: actions/cache@v4 - with: - path: | - # Taken from <https://doc.rust-lang.org/nightly/cargo/guide/cargo-home.html#caching-the-cargo-home-in-ci>. - # Cache package/registry information - ~/.cargo/registry/index - ~/.cargo/registry/cache - ~/.cargo/git/db - # Cache installed binaries - ~/.cargo/bin - ~/.cargo/.crates.toml - ~/.cargo/.crates2.json - key: cargo-${{ runner.os }}-reset20240425-${{ hashFiles('**/Cargo.lock') }} - restore-keys: cargo-${{ runner.os }}-reset20240425 - - - name: Install tools - if: steps.cache.outputs.cache-hit != 'true' - run: cargo install -f rustup-toolchain-install-master hyperfine - - - name: Install miri toolchain - run: | - if [[ ${{ github.event_name }} == 'schedule' ]]; then - echo "Building against latest rustc git version" - git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1 > rust-version - fi - ./miri toolchain --host ${{ matrix.host_target }} - - - name: Show Rust version (miri toolchain) - run: | - rustup show - rustc -Vv - cargo -V + - uses: ./.github/workflows/setup # The `style` job only runs on Linux; this makes sure the Windows-host-specific # code is also covered by clippy. @@ -92,47 +49,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - # This is exactly duplicated from above. GHA is pretty terrible when it comes - # to avoiding code duplication. - - # Cache the global cargo directory, but NOT the local `target` directory which - # we cannot reuse anyway when the nightly changes (and it grows quite large - # over time). - - name: Add cache for cargo - id: cache - uses: actions/cache@v4 - with: - path: | - # Taken from <https://doc.rust-lang.org/nightly/cargo/guide/cargo-home.html#caching-the-cargo-home-in-ci>. - # Cache package/registry information - ~/.cargo/registry/index - ~/.cargo/registry/cache - ~/.cargo/git/db - # Cache installed binaries - ~/.cargo/bin - ~/.cargo/.crates.toml - ~/.cargo/.crates2.json - key: cargo-${{ runner.os }}-reset20240331-${{ hashFiles('**/Cargo.lock') }} - restore-keys: cargo-${{ runner.os }}-reset20240331 - - - name: Install rustup-toolchain-install-master - if: steps.cache.outputs.cache-hit != 'true' - run: cargo install -f rustup-toolchain-install-master - - - name: Install "master" toolchain - run: | - if [[ ${{ github.event_name }} == 'schedule' ]]; then - echo "Building against latest rustc git version" - git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1 > rust-version - fi - ./miri toolchain - - - name: Show Rust version - run: | - rustup show - rustc -Vv - cargo -V + - uses: ./.github/workflows/setup - name: rustfmt run: ./miri fmt --check diff --git a/src/tools/miri/.github/workflows/setup/action.yml b/src/tools/miri/.github/workflows/setup/action.yml new file mode 100644 index 00000000000..8f54b5b8d81 --- /dev/null +++ b/src/tools/miri/.github/workflows/setup/action.yml @@ -0,0 +1,52 @@ +name: "Miri CI setup" +description: "Sets up Miri CI" +runs: + using: "composite" + steps: + - name: Show Rust version (stable toolchain) + run: | + rustup show + rustc -Vv + cargo -V + shell: bash + + # Cache the global cargo directory, but NOT the local `target` directory which + # we cannot reuse anyway when the nightly changes (and it grows quite large + # over time). + - name: Add cache for cargo + id: cache + uses: actions/cache@v4 + with: + path: | + # Taken from <https://doc.rust-lang.org/nightly/cargo/guide/cargo-home.html#caching-the-cargo-home-in-ci>. + # Cache package/registry information + ~/.cargo/registry/index + ~/.cargo/registry/cache + ~/.cargo/git/db + # Cache installed binaries + ~/.cargo/bin + ~/.cargo/.crates.toml + ~/.cargo/.crates2.json + key: cargo-${{ runner.os }}-${{ hashFiles('**/Cargo.lock', '.github/workflows/**/*.yml') }} + restore-keys: cargo-${{ runner.os }} + + - name: Install rustup-toolchain-install-master + if: steps.cache.outputs.cache-hit != 'true' + run: cargo install -f rustup-toolchain-install-master hyperfine + shell: bash + + - name: Install "master" toolchain + run: | + if [[ ${{ github.event_name }} == 'schedule' ]]; then + echo "Building against latest rustc git version" + git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1 > rust-version + fi + ./miri toolchain + shell: bash + + - name: Show Rust version (miri toolchain) + run: | + rustup show + rustc -Vv + cargo -V + shell: bash diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 4b4f2f83062..b1be596c006 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -72,11 +72,13 @@ Further caveats that Miri users should be aware of: when `SeqCst` fences are used that are not actually permitted by the Rust memory model, and it cannot produce all behaviors possibly observable on real hardware. -Moreover, Miri fundamentally cannot tell you whether your code is *sound*. [Soundness] is the property -of never causing undefined behavior when invoked from arbitrary safe code, even in combination with +Moreover, Miri fundamentally cannot ensure that your code is *sound*. [Soundness] is the property of +never causing undefined behavior when invoked from arbitrary safe code, even in combination with other sound code. In contrast, Miri can just tell you if *a particular way of interacting with your -code* (e.g., a test suite) causes any undefined behavior. It is up to you to ensure sufficient -coverage. +code* (e.g., a test suite) causes any undefined behavior *in a particular execution* (of which there +may be many, e.g. when concurrency or other forms of non-determinism are involved). When Miri finds +UB, your code is definitely unsound, but when Miri does not find UB, then you may just have to test +more inputs or more possible non-deterministic choices. [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md @@ -425,8 +427,12 @@ to Miri failing to detect cases of undefined behavior in a program. value from a load. This can help diagnose problems that disappear under `-Zmiri-disable-weak-memory-emulation`. * `-Zmiri-tree-borrows` replaces [Stacked Borrows] with the [Tree Borrows] rules. - The soundness rules are already experimental without this flag, but even more - so with this flag. + Tree Borrows is even more experimental than Stacked Borrows. While Tree Borrows + is still sound in the sense of catching all aliasing violations that current versions + of the compiler might exploit, it is likely that the eventual final aliasing model + of Rust will be stricter than Tree Borrows. In other words, if you use Tree Borrows, + even if your code is accepted today, it might be declared UB in the future. + This is much less likely with Stacked Borrows. * `-Zmiri-force-page-size=<num>` overrides the default page size for an architecture, in multiples of 1k. `4` is default for most targets. This value should always be a power of 2 and nonzero. * `-Zmiri-unique-is-unique` performs additional aliasing checks for `core::ptr::Unique` to ensure diff --git a/src/tools/miri/build.rs b/src/tools/miri/build.rs index 0977c0ba016..0918c9b1321 100644 --- a/src/tools/miri/build.rs +++ b/src/tools/miri/build.rs @@ -1,8 +1,10 @@ fn main() { // Don't rebuild miri when nothing changed. println!("cargo:rerun-if-changed=build.rs"); - // Re-export the TARGET environment variable so it can - // be accessed by miri. + // Re-export the TARGET environment variable so it can be accessed by miri. Needed to know the + // "host" triple inside Miri. let target = std::env::var("TARGET").unwrap(); println!("cargo:rustc-env=TARGET={target}"); + // Allow some cfgs. + println!("cargo::rustc-check-cfg=cfg(bootstrap)"); } diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index 3c36f606d84..8d48b9c8ad1 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -23,6 +23,12 @@ Subcommands: clean Clean the Miri cache & target directory The cargo options are exactly the same as for `cargo run` and `cargo test`, respectively. +Furthermore, the following extra flags and environment variables are recognized for `run` and `test`: + + --many-seeds[=from..to] Run the program/tests many times with different seeds in the given range. + The range defaults to `0..64`. + + MIRIFLAGS Extra flags to pass to the Miri driver. Use this to pass `-Zmiri-...` flags. Examples: cargo miri run diff --git a/src/tools/miri/miri b/src/tools/miri/miri index 5f71fc94438..07383bb59eb 100755 --- a/src/tools/miri/miri +++ b/src/tools/miri/miri @@ -3,5 +3,6 @@ set -e # Instead of doing just `cargo run --manifest-path .. $@`, we invoke miri-script binary directly. Invoking `cargo run` goes through # rustup (that sets it's own environmental variables), which is undesirable. MIRI_SCRIPT_TARGET_DIR="$(dirname "$0")"/miri-script/target -cargo +stable build $CARGO_EXTRA_FLAGS -q --target-dir "$MIRI_SCRIPT_TARGET_DIR" --manifest-path "$(dirname "$0")"/miri-script/Cargo.toml +cargo +stable build $CARGO_EXTRA_FLAGS -q --target-dir "$MIRI_SCRIPT_TARGET_DIR" --manifest-path "$(dirname "$0")"/miri-script/Cargo.toml || \ + ( echo "Failed to build miri-script. Is the 'stable' toolchain installed?"; exit 1 ) "$MIRI_SCRIPT_TARGET_DIR"/debug/miri-script "$@" diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 57bdfbad9af..62a3ab2c34c 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -252,12 +252,11 @@ impl Command { // Fetch given rustc commit. cmd!(sh, "git fetch http://localhost:{JOSH_PORT}/rust-lang/rust.git@{commit}{JOSH_FILTER}.git") .run() - .map_err(|e| { + .inspect_err(|_| { // Try to un-do the previous `git commit`, to leave the repo in the state we found it. cmd!(sh, "git reset --hard HEAD^") .run() .expect("FAILED to clean up again after failed `git fetch`, sorry for that"); - e }) .context("FAILED to fetch new commits, something went wrong (committing the rust-version file has been undone)")?; @@ -545,9 +544,8 @@ impl Command { if let Some(seed_range) = many_seeds { e.run_many_times(seed_range, |sh, seed| { eprintln!("Trying seed: {seed}"); - run_miri(sh, Some(format!("-Zmiri-seed={seed}"))).map_err(|err| { + run_miri(sh, Some(format!("-Zmiri-seed={seed}"))).inspect_err(|_| { eprintln!("FAILING SEED: {seed}"); - err }) })?; } else { diff --git a/src/tools/miri/miri-script/src/util.rs b/src/tools/miri/miri-script/src/util.rs index e9095a45fce..e1b77be192e 100644 --- a/src/tools/miri/miri-script/src/util.rs +++ b/src/tools/miri/miri-script/src/util.rs @@ -219,10 +219,9 @@ impl MiriEnv { break; } // Run the command with this seed. - run(&local_shell, cur).map_err(|err| { + run(&local_shell, cur).inspect_err(|_| { // If we failed, tell everyone about this. failed.store(true, Ordering::Relaxed); - err })?; // Check if some other command failed (in which case we'll stop as well). if failed.load(Ordering::Relaxed) { diff --git a/src/tools/miri/miri.bat b/src/tools/miri/miri.bat index 18baa683f65..6f9a8f38d65 100644 --- a/src/tools/miri/miri.bat +++ b/src/tools/miri/miri.bat @@ -5,7 +5,8 @@ set MIRI_SCRIPT_TARGET_DIR=%0\..\miri-script\target :: If any other steps are added, the "|| exit /b" must be appended to early :: return from the script. If not, it will continue execution. -cargo +stable build %CARGO_EXTRA_FLAGS% -q --target-dir %MIRI_SCRIPT_TARGET_DIR% --manifest-path %0\..\miri-script\Cargo.toml || exit /b +cargo +stable build %CARGO_EXTRA_FLAGS% -q --target-dir %MIRI_SCRIPT_TARGET_DIR% --manifest-path %0\..\miri-script\Cargo.toml ^ + || (echo Failed to build miri-script. Is the 'stable' toolchain installed? & exit /b) :: Forwards all arguments to this file to the executable. :: We invoke the binary directly to avoid going through rustup, which would set some extra diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index e49680ba75a..fd59ad3b8f1 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -f6b4b71ef10307201b52c17b0f9dcf9557cd90ba +9ed2ab3790ff41bf741dd690befd6a1c1e2b23ca diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index ae95d28d3eb..d0f977f8143 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -97,7 +97,7 @@ impl GlobalStateInner { fn align_addr(addr: u64, align: u64) -> u64 { match addr % align { 0 => addr, - rem => addr.checked_add(align).unwrap() - rem, + rem => addr.strict_add(align) - rem, } } diff --git a/src/tools/miri/src/alloc_bytes.rs b/src/tools/miri/src/alloc_bytes.rs index 8f691456a59..84225d83b6a 100644 --- a/src/tools/miri/src/alloc_bytes.rs +++ b/src/tools/miri/src/alloc_bytes.rs @@ -64,17 +64,19 @@ impl MiriAllocBytes { /// If `size == 0` we allocate using a different `alloc_layout` with `size = 1`, to ensure each allocation has a unique address. /// Returns `Err(alloc_layout)` if the allocation function returns a `ptr` where `ptr.is_null()`. fn alloc_with( - size: usize, - align: usize, + size: u64, + align: u64, alloc_fn: impl FnOnce(Layout) -> *mut u8, - ) -> Result<MiriAllocBytes, Layout> { - let layout = Layout::from_size_align(size, align).unwrap(); + ) -> Result<MiriAllocBytes, ()> { + let size = usize::try_from(size).map_err(|_| ())?; + let align = usize::try_from(align).map_err(|_| ())?; + let layout = Layout::from_size_align(size, align).map_err(|_| ())?; // When size is 0 we allocate 1 byte anyway, to ensure each allocation has a unique address. let alloc_layout = if size == 0 { Layout::from_size_align(1, align).unwrap() } else { layout }; let ptr = alloc_fn(alloc_layout); if ptr.is_null() { - Err(alloc_layout) + Err(()) } else { // SAFETY: All `MiriAllocBytes` invariants are fulfilled. Ok(Self { ptr, layout }) @@ -86,11 +88,13 @@ impl AllocBytes for MiriAllocBytes { fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, align: Align) -> Self { let slice = slice.into(); let size = slice.len(); - let align = align.bytes_usize(); + let align = align.bytes(); // SAFETY: `alloc_fn` will only be used with `size != 0`. let alloc_fn = |layout| unsafe { alloc::alloc(layout) }; - let alloc_bytes = MiriAllocBytes::alloc_with(size, align, alloc_fn) - .unwrap_or_else(|layout| alloc::handle_alloc_error(layout)); + let alloc_bytes = MiriAllocBytes::alloc_with(size.try_into().unwrap(), align, alloc_fn) + .unwrap_or_else(|()| { + panic!("Miri ran out of memory: cannot create allocation of {size} bytes") + }); // SAFETY: `alloc_bytes.ptr` and `slice.as_ptr()` are non-null, properly aligned // and valid for the `size`-many bytes to be copied. unsafe { alloc_bytes.ptr.copy_from(slice.as_ptr(), size) }; @@ -98,8 +102,8 @@ impl AllocBytes for MiriAllocBytes { } fn zeroed(size: Size, align: Align) -> Option<Self> { - let size = size.bytes_usize(); - let align = align.bytes_usize(); + let size = size.bytes(); + let align = align.bytes(); // SAFETY: `alloc_fn` will only be used with `size != 0`. let alloc_fn = |layout| unsafe { alloc::alloc_zeroed(layout) }; MiriAllocBytes::alloc_with(size, align, alloc_fn).ok() diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 829bfa7cd70..9d8e44ce409 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -98,10 +98,9 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } if tcx.sess.opts.optimize != OptLevel::No { - tcx.dcx().warn("Miri does not support optimizations. If you have enabled optimizations \ - by selecting a Cargo profile (such as --release) which changes other profile settings \ - such as whether debug assertions and overflow checks are enabled, those settings are \ - still applied."); + tcx.dcx().warn("Miri does not support optimizations: the opt-level is ignored. The only effect \ + of selecting a Cargo profile that enables optimizations (such as --release) is to apply \ + its remaining settings, such as whether debug assertions and overflow checks are enabled."); } if tcx.sess.mir_opt_level() > 0 { tcx.dcx().warn("You have explicitly enabled MIR optimizations, overriding Miri's default \ diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 6a2b99825ad..718daf93ea0 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -643,8 +643,7 @@ impl<'tcx> ThreadManager<'tcx> { if !self.threads[joined_thread_id].state.is_terminated() { trace!( "{:?} blocked on {:?} when trying to join", - self.active_thread, - joined_thread_id + self.active_thread, joined_thread_id ); // The joined thread is still running, we need to wait for it. // Unce we get unblocked, perform the appropriate synchronization. diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 1b70a1a1cf0..647d7d44bb1 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -227,8 +227,8 @@ pub fn report_error<'tcx>( let helps = match info { UnsupportedInIsolation(_) => vec![ - (None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation;")), - (None, format!("or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")), + (None, format!("set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation;")), + (None, format!("or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning")), ], UnsupportedForeignItem(_) => { vec![ @@ -465,19 +465,22 @@ pub fn report_leaks<'tcx>( ) { let mut any_pruned = false; for (id, kind, mut alloc) in leaks { + let mut title = format!( + "memory leaked: {id:?} ({}, size: {:?}, align: {:?})", + kind, + alloc.size().bytes(), + alloc.align.bytes() + ); let Some(backtrace) = alloc.extra.backtrace.take() else { + ecx.tcx.dcx().err(title); continue; }; + title.push_str(", allocated here:"); let (backtrace, pruned) = prune_stacktrace(backtrace, &ecx.machine); any_pruned |= pruned; report_msg( DiagLevel::Error, - format!( - "memory leaked: {id:?} ({}, size: {:?}, align: {:?}), allocated here:", - kind, - alloc.size().bytes(), - alloc.align.bytes() - ), + title, vec![], vec![], vec![], @@ -644,15 +647,11 @@ impl<'tcx> MiriMachine<'tcx> { ( None, format!( - "This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`," + "This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program." ), ), ( None, - format!("which means that Miri might miss pointer bugs in this program."), - ), - ( - None, format!( "See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation." ), @@ -666,13 +665,13 @@ impl<'tcx> MiriMachine<'tcx> { ( None, format!( - "You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics." + "You can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics." ), ), ( None, format!( - "Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning." + "Alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning." ), ), ], diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 35f7f43f123..c0827cce263 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -303,7 +303,7 @@ pub fn create_ecx<'tcx>( let mut argvs = Vec::<Immediate<Provenance>>::with_capacity(config.args.len()); for arg in config.args.iter() { // Make space for `0` terminator. - let size = u64::try_from(arg.len()).unwrap().checked_add(1).unwrap(); + let size = u64::try_from(arg.len()).unwrap().strict_add(1); let arg_type = Ty::new_array(tcx, tcx.types.u8, size); let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into())?; @@ -468,7 +468,7 @@ pub fn eval_entry<'tcx>( // Check for thread leaks. if !ecx.have_all_terminated() { tcx.dcx().err("the main thread terminated without waiting for all remaining threads"); - tcx.dcx().note("pass `-Zmiri-ignore-leaks` to disable this check"); + tcx.dcx().note("set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check"); return None; } // Check for memory leaks. @@ -476,14 +476,7 @@ pub fn eval_entry<'tcx>( let leaks = ecx.find_leaked_allocations(&ecx.machine.static_roots); if !leaks.is_empty() { report_leaks(&ecx, leaks); - let leak_message = "the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check"; - if ecx.machine.collect_leak_backtraces { - // If we are collecting leak backtraces, each leak is a distinct error diagnostic. - tcx.dcx().note(leak_message); - } else { - // If we do not have backtraces, we just report an error without any span. - tcx.dcx().err(leak_message); - }; + tcx.dcx().note("set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check"); // Ignore the provided return code - let the reported error // determine the return code. return None; diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 843aff02495..a7a6f8cfd87 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -14,6 +14,7 @@ use rustc_hir::{ def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}, }; use rustc_index::IndexVec; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::ExportedSymbol; use rustc_middle::mir; @@ -163,22 +164,39 @@ pub fn iter_exported_symbols<'tcx>( tcx: TyCtxt<'tcx>, mut f: impl FnMut(CrateNum, DefId) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { + // First, the symbols in the local crate. We can't use `exported_symbols` here as that + // skips `#[used]` statics (since `reachable_set` skips them in binary crates). + // So we walk all HIR items ourselves instead. + let crate_items = tcx.hir_crate_items(()); + for def_id in crate_items.definitions() { + let exported = tcx.def_kind(def_id).has_codegen_attrs() && { + let codegen_attrs = tcx.codegen_fn_attrs(def_id); + codegen_attrs.contains_extern_indicator() + || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) + || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED) + || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) + }; + if exported { + f(LOCAL_CRATE, def_id.into())?; + } + } + + // Next, all our dependencies. // `dependency_formats` includes all the transitive informations needed to link a crate, // which is what we need here since we need to dig out `exported_symbols` from all transitive // dependencies. let dependency_formats = tcx.dependency_formats(()); + // Find the dependencies of the executable we are running. let dependency_format = dependency_formats .iter() .find(|(crate_type, _)| *crate_type == CrateType::Executable) .expect("interpreting a non-executable crate"); - for cnum in iter::once(LOCAL_CRATE).chain(dependency_format.1.iter().enumerate().filter_map( - |(num, &linkage)| { - // We add 1 to the number because that's what rustc also does everywhere it - // calls `CrateNum::new`... - #[allow(clippy::arithmetic_side_effects)] - (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1)) - }, - )) { + for cnum in dependency_format.1.iter().enumerate().filter_map(|(num, &linkage)| { + // We add 1 to the number because that's what rustc also does everywhere it + // calls `CrateNum::new`... + #[allow(clippy::arithmetic_side_effects)] + (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1)) + }) { // We can ignore `_export_info` here: we are a Rust crate, and everything is exported // from a Rust crate. for &(symbol, _export_info) in tcx.exported_symbols(cnum) { @@ -273,6 +291,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Helper function to get a `libc` constant as a `Scalar`. fn eval_libc(&self, name: &str) -> Scalar { + if self.eval_context_ref().tcx.sess.target.os == "windows" { + panic!( + "`libc` crate is not reliably available on Windows targets; Miri should not use it there" + ); + } self.eval_path_scalar(&["libc", name]) } @@ -316,6 +339,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Helper function to get the `TyAndLayout` of a `libc` type fn libc_ty_layout(&self, name: &str) -> TyAndLayout<'tcx> { let this = self.eval_context_ref(); + if this.tcx.sess.target.os == "windows" { + panic!( + "`libc` crate is not reliably available on Windows targets; Miri should not use it there" + ); + } let ty = this .resolve_path(&["libc", name], Namespace::TypeNS) .ty(*this.tcx, ty::ParamEnv::reveal_all()); @@ -963,7 +991,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. let string_length = u64::try_from(c_str.len()).unwrap(); - let string_length = string_length.checked_add(1).unwrap(); + let string_length = string_length.strict_add(1); if size < string_length { return Ok((false, string_length)); } @@ -1027,7 +1055,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required // 0x0000 terminator to memory would cause an out-of-bounds access. let string_length = u64::try_from(wide_str.len()).unwrap(); - let string_length = string_length.checked_add(1).unwrap(); + let string_length = string_length.strict_add(1); if size < string_length { return Ok((false, string_length)); } @@ -1048,7 +1076,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Always returns a `Vec<u32>` no matter the size of `wchar_t`. fn read_wchar_t_str(&self, ptr: Pointer) -> InterpResult<'tcx, Vec<u32>> { let this = self.eval_context_ref(); - let wchar_t = this.libc_ty_layout("wchar_t"); + let wchar_t = if this.tcx.sess.target.os == "windows" { + // We don't have libc on Windows so we have to hard-code the type ourselves. + this.machine.layouts.u16 + } else { + this.libc_ty_layout("wchar_t") + }; self.read_c_str_with_char_size(ptr, wchar_t.size, wchar_t.align.abi) } @@ -1391,7 +1424,7 @@ pub(crate) fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 { if success { // If the function succeeds, the return value is the number of characters stored in the target buffer, // not including the terminating null character. - u32::try_from(len.checked_sub(1).unwrap()).unwrap() + u32::try_from(len.strict_sub(1)).unwrap() } else { // If the target buffer was not large enough to hold the data, the return value is the buffer size, in characters, // required to hold the string and its terminating null character. diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index f8410db4dd0..8da00861f90 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -10,7 +10,7 @@ #![feature(yeet_expr)] #![feature(nonzero_ops)] #![feature(let_chains)] -#![feature(lint_reasons)] +#![cfg_attr(bootstrap, feature(lint_reasons))] #![feature(trait_upcasting)] #![feature(strict_overflow_ops)] #![feature(is_none_or)] diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs index 7b0c54d763e..a33657d33a2 100644 --- a/src/tools/miri/src/shims/alloc.rs +++ b/src/tools/miri/src/shims/alloc.rs @@ -5,18 +5,6 @@ use rustc_target::abi::{Align, Size}; use crate::*; -/// Check some basic requirements for this allocation request: -/// non-zero size, power-of-two alignment. -pub(super) fn check_alloc_request<'tcx>(size: u64, align: u64) -> InterpResult<'tcx> { - if size == 0 { - throw_ub_format!("creating allocation with size 0"); - } - if !align.is_power_of_two() { - throw_ub_format!("creating allocation with non-power-of-two alignment {}", align); - } - Ok(()) -} - impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Returns the alignment that `malloc` would guarantee for requests of the given size. diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 911958e558c..f9ccc6ad4d2 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -12,7 +12,7 @@ use rustc_target::{ spec::abi::Abi, }; -use super::alloc::{check_alloc_request, EvalContextExt as _}; +use super::alloc::EvalContextExt as _; use super::backtrace::EvalContextExt as _; use crate::*; use helpers::{ToHost, ToSoft}; @@ -204,6 +204,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { + /// Check some basic requirements for this allocation request: + /// non-zero size, power-of-two alignment. + fn check_rustc_alloc_request(&self, size: u64, align: u64) -> InterpResult<'tcx> { + let this = self.eval_context_ref(); + if size == 0 { + throw_ub_format!("creating allocation with size 0"); + } + if i128::from(size) > this.tcx.data_layout.pointer_size.signed_int_max() { + throw_ub_format!("creating an allocation larger than half the address space"); + } + if !align.is_power_of_two() { + throw_ub_format!("creating allocation with non-power-of-two alignment {}", align); + } + Ok(()) + } + fn emulate_foreign_item_inner( &mut self, link_name: Symbol, @@ -386,7 +402,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { }); let (_, addr) = ptr.into_parts(); // we know the offset is absolute // Cannot panic since `align` is a power of 2 and hence non-zero. - if addr.bytes().checked_rem(align.bytes()).unwrap() != 0 { + if addr.bytes().strict_rem(align.bytes()) != 0 { throw_unsup_format!( "`miri_promise_symbolic_alignment`: pointer is not actually aligned" ); @@ -462,7 +478,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let size = this.read_target_usize(size)?; let align = this.read_target_usize(align)?; - check_alloc_request(size, align)?; + this.check_rustc_alloc_request(size, align)?; let memory_kind = match link_name.as_str() { "__rust_alloc" => MiriMemoryKind::Rust, @@ -496,7 +512,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let size = this.read_target_usize(size)?; let align = this.read_target_usize(align)?; - check_alloc_request(size, align)?; + this.check_rustc_alloc_request(size, align)?; let ptr = this.allocate_ptr( Size::from_bytes(size), @@ -560,7 +576,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let new_size = this.read_target_usize(new_size)?; // No need to check old_size; we anyway check that they match the allocation. - check_alloc_request(new_size, align)?; + this.check_rustc_alloc_request(new_size, align)?; let align = Align::from_bytes(align).unwrap(); let new_ptr = this.reallocate_ptr( @@ -698,7 +714,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // That is probably overly cautious, but there also is no fundamental // reason to have `strcpy` destroy pointer provenance. // This reads at least 1 byte, so we are already enforcing that this is a valid pointer. - let n = this.read_c_str(ptr_src)?.len().checked_add(1).unwrap(); + let n = this.read_c_str(ptr_src)?.len().strict_add(1); this.mem_copy(ptr_src, ptr_dest, Size::from_bytes(n), true)?; this.write_pointer(ptr_dest, dest)?; } diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index ae17196f0b7..e8f906d37e8 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -165,7 +165,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ("tm_hour", dt.hour().into()), ("tm_mday", dt.day().into()), ("tm_mon", dt.month0().into()), - ("tm_year", dt.year().checked_sub(1900).unwrap().into()), + ("tm_year", dt.year().strict_sub(1900).into()), ("tm_wday", dt.weekday().num_days_from_sunday().into()), ("tm_yday", dt.ordinal0().into()), ("tm_isdst", tm_isdst), diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs index 2f78d0f4296..405431f4327 100644 --- a/src/tools/miri/src/shims/unix/env.rs +++ b/src/tools/miri/src/shims/unix/env.rs @@ -81,10 +81,8 @@ impl<'tcx> UnixEnvVars<'tcx> { return Ok(None); }; // The offset is used to strip the "{name}=" part of the string. - let var_ptr = var_ptr.offset( - Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), - ecx, - )?; + let var_ptr = var_ptr + .offset(Size::from_bytes(u64::try_from(name.len()).unwrap().strict_add(1)), ecx)?; Ok(Some(var_ptr)) } diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index b6ac841dc9f..599f78e712a 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -240,7 +240,7 @@ impl FdTable { let new_fd = candidate_new_fd.unwrap_or_else(|| { // find_map ran out of BTreeMap entries before finding a free fd, use one plus the // maximum fd in the map - self.fds.last_key_value().map(|(fd, _)| fd.checked_add(1).unwrap()).unwrap_or(min_fd) + self.fds.last_key_value().map(|(fd, _)| fd.strict_add(1)).unwrap_or(min_fd) }); self.fds.try_insert(new_fd, file_handle).unwrap(); diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 2282099fa0d..53ad40cfd2c 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -51,7 +51,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern. #[rustfmt::skip] match link_name.as_str() { - // Environment variables + // Environment related shims "getenv" => { let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.getenv(name)?; @@ -78,6 +78,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let result = this.chdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "getpid" => { + let [] = this.check_shim(abi, Abi::C { unwind: false}, link_name, args)?; + let result = this.getpid()?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // File descriptors "read" => { @@ -583,11 +588,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let ret = if complete { 0 } else { this.eval_libc_i32("ERANGE") }; this.write_int(ret, dest)?; } - "getpid" => { - let [] = this.check_shim(abi, Abi::C { unwind: false}, link_name, args)?; - let result = this.getpid()?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } "getentropy" => { // This function is non-standard but exists with the same signature and behavior on // Linux, macOS, FreeBSD and Solaris/Illumos. diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 262e71756c6..e34aa5c09df 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -395,7 +395,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Isolation check is done via `FileDescriptor` trait. let seek_from = if whence == this.eval_libc_i32("SEEK_SET") { - SeekFrom::Start(u64::try_from(offset).unwrap()) + if offset < 0 { + // Negative offsets return `EINVAL`. + let einval = this.eval_libc("EINVAL"); + this.set_last_error(einval)?; + return Ok(Scalar::from_i64(-1)); + } else { + SeekFrom::Start(u64::try_from(offset).unwrap()) + } } else if whence == this.eval_libc_i32("SEEK_CUR") { SeekFrom::Current(i64::try_from(offset).unwrap()) } else if whence == this.eval_libc_i32("SEEK_END") { diff --git a/src/tools/miri/src/shims/unix/socket.rs b/src/tools/miri/src/shims/unix/socket.rs index c639ea2f846..6d3d63b4efa 100644 --- a/src/tools/miri/src/shims/unix/socket.rs +++ b/src/tools/miri/src/shims/unix/socket.rs @@ -116,7 +116,7 @@ impl FileDescription for SocketPair { }; let mut writebuf = writebuf.borrow_mut(); let data_size = writebuf.buf.len(); - let available_space = MAX_SOCKETPAIR_BUFFER_CAPACITY.checked_sub(data_size).unwrap(); + let available_space = MAX_SOCKETPAIR_BUFFER_CAPACITY.strict_sub(data_size); if available_space == 0 { if self.is_nonblock { // Non-blocking socketpair with a full buffer. diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index bfa14bcb5fa..c9db798caad 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -138,6 +138,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let result = this.GetUserProfileDirectoryW(token, buf, size)?; this.write_scalar(result, dest)?; } + "GetCurrentProcessId" => { + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let result = this.GetCurrentProcessId()?; + this.write_int(result, dest)?; + } // File related shims "NtWriteFile" => { @@ -647,7 +652,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // If the function succeeds, the return value is the length of the string that // is copied to the buffer, in characters, not including the terminating null // character. - this.write_int(size_needed.checked_sub(1).unwrap(), dest)?; + this.write_int(size_needed.strict_sub(1), dest)?; } else { // If the buffer is too small to hold the module name, the string is truncated // to nSize characters including the terminating null character, the function @@ -689,7 +694,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { throw_unsup_format!("FormatMessageW: buffer not big enough"); } // The return value is the number of characters stored *excluding* the null terminator. - this.write_int(length.checked_sub(1).unwrap(), dest)?; + this.write_int(length.strict_sub(1), dest)?; } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. @@ -743,11 +748,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_int(1, dest)?; } - "GetCurrentProcessId" if this.frame_in_std() => { - let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - let result = this.GetCurrentProcessId()?; - this.write_int(result, dest)?; - } // this is only callable from std because we know that std ignores the return value "SwitchToThread" if this.frame_in_std() => { let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs index 58c8683ff27..ec461a4cd36 100644 --- a/src/tools/miri/src/shims/windows/handle.rs +++ b/src/tools/miri/src/shims/windows/handle.rs @@ -74,7 +74,7 @@ impl Handle { /// None of this layout is guaranteed to applications by Windows or Miri. fn to_packed(self) -> u32 { let disc_size = Self::packed_disc_size(); - let data_size = u32::BITS.checked_sub(disc_size).unwrap(); + let data_size = u32::BITS.strict_sub(disc_size); let discriminant = self.discriminant(); let data = self.data(); @@ -103,7 +103,7 @@ impl Handle { /// see docs for `to_packed` fn from_packed(handle: u32) -> Option<Self> { let disc_size = Self::packed_disc_size(); - let data_size = u32::BITS.checked_sub(disc_size).unwrap(); + let data_size = u32::BITS.strict_sub(disc_size); // the lower `data_size` bits of this mask are 1 #[allow(clippy::arithmetic_side_effects)] // cannot overflow diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs index 016c525e57b..7f6c9336a97 100644 --- a/src/tools/miri/src/shims/x86/avx2.rs +++ b/src/tools/miri/src/shims/x86/avx2.rs @@ -75,7 +75,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { assert_eq!(dest_len, mask_len); let mask_item_size = mask.layout.field(this, 0).size; - let high_bit_offset = mask_item_size.bits().checked_sub(1).unwrap(); + let high_bit_offset = mask_item_size.bits().strict_sub(1); let scale = this.read_scalar(scale)?.to_i8()?; if !matches!(scale, 1 | 2 | 4 | 8) { @@ -93,8 +93,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let offset = i64::try_from(this.read_scalar(&offset)?.to_int(offset.layout.size)?) .unwrap(); - let ptr = slice - .wrapping_signed_offset(offset.checked_mul(scale).unwrap(), &this.tcx); + let ptr = slice.wrapping_signed_offset(offset.strict_mul(scale), &this.tcx); // Unaligned copy, which is what we want. this.mem_copy( ptr, @@ -124,22 +123,22 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let (dest, dest_len) = this.mplace_to_simd(dest)?; assert_eq!(left_len, right_len); - assert_eq!(dest_len.checked_mul(2).unwrap(), left_len); + assert_eq!(dest_len.strict_mul(2), left_len); for i in 0..dest_len { - let j1 = i.checked_mul(2).unwrap(); + let j1 = i.strict_mul(2); let left1 = this.read_scalar(&this.project_index(&left, j1)?)?.to_i16()?; let right1 = this.read_scalar(&this.project_index(&right, j1)?)?.to_i16()?; - let j2 = j1.checked_add(1).unwrap(); + let j2 = j1.strict_add(1); let left2 = this.read_scalar(&this.project_index(&left, j2)?)?.to_i16()?; let right2 = this.read_scalar(&this.project_index(&right, j2)?)?.to_i16()?; let dest = this.project_index(&dest, i)?; // Multiplications are i16*i16->i32, which will not overflow. - let mul1 = i32::from(left1).checked_mul(right1.into()).unwrap(); - let mul2 = i32::from(left2).checked_mul(right2.into()).unwrap(); + let mul1 = i32::from(left1).strict_mul(right1.into()); + let mul2 = i32::from(left2).strict_mul(right2.into()); // However, this addition can overflow in the most extreme case // (-0x8000)*(-0x8000)+(-0x8000)*(-0x8000) = 0x80000000 let res = mul1.wrapping_add(mul2); @@ -161,22 +160,22 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let (dest, dest_len) = this.mplace_to_simd(dest)?; assert_eq!(left_len, right_len); - assert_eq!(dest_len.checked_mul(2).unwrap(), left_len); + assert_eq!(dest_len.strict_mul(2), left_len); for i in 0..dest_len { - let j1 = i.checked_mul(2).unwrap(); + let j1 = i.strict_mul(2); let left1 = this.read_scalar(&this.project_index(&left, j1)?)?.to_u8()?; let right1 = this.read_scalar(&this.project_index(&right, j1)?)?.to_i8()?; - let j2 = j1.checked_add(1).unwrap(); + let j2 = j1.strict_add(1); let left2 = this.read_scalar(&this.project_index(&left, j2)?)?.to_u8()?; let right2 = this.read_scalar(&this.project_index(&right, j2)?)?.to_i8()?; let dest = this.project_index(&dest, i)?; // Multiplication of a u8 and an i8 into an i16 cannot overflow. - let mul1 = i16::from(left1).checked_mul(right1.into()).unwrap(); - let mul2 = i16::from(left2).checked_mul(right2.into()).unwrap(); + let mul1 = i16::from(left1).strict_mul(right1.into()); + let mul2 = i16::from(left2).strict_mul(right2.into()); let res = mul1.saturating_add(mul2); this.write_scalar(Scalar::from_i16(res), &dest)?; @@ -309,7 +308,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { for i in 0..2 { let dest = this.project_index(&dest, i)?; - let src = match (imm >> i.checked_mul(4).unwrap()) & 0b11 { + let src = match (imm >> i.strict_mul(4)) & 0b11 { 0 => this.project_index(&left, 0)?, 1 => this.project_index(&left, 1)?, 2 => this.project_index(&right, 0)?, @@ -336,14 +335,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let (dest, dest_len) = this.mplace_to_simd(dest)?; assert_eq!(left_len, right_len); - assert_eq!(left_len, dest_len.checked_mul(8).unwrap()); + assert_eq!(left_len, dest_len.strict_mul(8)); for i in 0..dest_len { let dest = this.project_index(&dest, i)?; let mut acc: u16 = 0; for j in 0..8 { - let src_index = i.checked_mul(8).unwrap().checked_add(j).unwrap(); + let src_index = i.strict_mul(8).strict_add(j); let left = this.project_index(&left, src_index)?; let left = this.read_scalar(&left)?.to_u8()?; @@ -351,7 +350,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let right = this.project_index(&right, src_index)?; let right = this.read_scalar(&right)?.to_u8()?; - acc = acc.checked_add(left.abs_diff(right).into()).unwrap(); + acc = acc.strict_add(left.abs_diff(right).into()); } this.write_scalar(Scalar::from_u64(acc.into()), &dest)?; @@ -377,7 +376,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let res = if right & 0x80 == 0 { // Shuffle each 128-bit (16-byte) block independently. - let j = u64::from(right % 16).checked_add(i & !15).unwrap(); + let j = u64::from(right % 16).strict_add(i & !15); this.read_scalar(&this.project_index(&left, j)?)? } else { // If the highest bit in `right` is 1, write zero. diff --git a/src/tools/miri/src/shims/x86/bmi.rs b/src/tools/miri/src/shims/x86/bmi.rs new file mode 100644 index 00000000000..e70757f4397 --- /dev/null +++ b/src/tools/miri/src/shims/x86/bmi.rs @@ -0,0 +1,108 @@ +use rustc_span::Symbol; +use rustc_target::spec::abi::Abi; + +use crate::*; + +impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} +pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + fn emulate_x86_bmi_intrinsic( + &mut self, + link_name: Symbol, + abi: Abi, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx, EmulateItemResult> { + let this = self.eval_context_mut(); + + // Prefix should have already been checked. + let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.bmi.").unwrap(); + + // The intrinsics are suffixed with the bit size of their operands. + let (is_64_bit, unprefixed_name) = if unprefixed_name.ends_with("64") { + (true, unprefixed_name.strip_suffix(".64").unwrap_or("")) + } else { + (false, unprefixed_name.strip_suffix(".32").unwrap_or("")) + }; + + // All intrinsics of the "bmi" namespace belong to the "bmi2" ISA extension. + // The exception is "bextr", which belongs to "bmi1". + let target_feature = if unprefixed_name == "bextr" { "bmi1" } else { "bmi2" }; + this.expect_target_feature_for_intrinsic(link_name, target_feature)?; + + if is_64_bit && this.tcx.sess.target.arch != "x86_64" { + return Ok(EmulateItemResult::NotSupported); + } + + let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let left = this.read_scalar(left)?; + let right = this.read_scalar(right)?; + + let left = if is_64_bit { left.to_u64()? } else { u64::from(left.to_u32()?) }; + let right = if is_64_bit { right.to_u64()? } else { u64::from(right.to_u32()?) }; + + let result = match unprefixed_name { + // Extract a contigous range of bits from an unsigned integer. + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_bextr_u32 + "bextr" => { + let start = u32::try_from(right & 0xff).unwrap(); + let len = u32::try_from((right >> 8) & 0xff).unwrap(); + let shifted = left.checked_shr(start).unwrap_or(0); + // Keep the `len` lowest bits of `shifted`, or all bits if `len` is too big. + if len >= 64 { shifted } else { shifted & 1u64.wrapping_shl(len).wrapping_sub(1) } + } + // Create a copy of an unsigned integer with bits above a certain index cleared. + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_bzhi_u32 + "bzhi" => { + let index = u32::try_from(right & 0xff).unwrap(); + // Keep the `index` lowest bits of `left`, or all bits if `index` is too big. + if index >= 64 { left } else { left & 1u64.wrapping_shl(index).wrapping_sub(1) } + } + // Extract bit values of an unsigned integer at positions marked by a mask. + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_pext_u32 + "pext" => { + let mut mask = right; + let mut i = 0u32; + let mut result = 0; + // Iterate over the mask one 1-bit at a time, from + // the least significant bit to the most significant bit. + while mask != 0 { + // Extract the bit marked by the mask's least significant set bit + // and put it at position `i` of the result. + result |= u64::from(left & (1 << mask.trailing_zeros()) != 0) << i; + i = i.wrapping_add(1); + // Clear the least significant set bit. + mask &= mask.wrapping_sub(1); + } + result + } + // Deposit bit values of an unsigned integer to positions marked by a mask. + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_pdep_u32 + "pdep" => { + let mut mask = right; + let mut set = left; + let mut result = 0; + // Iterate over the mask one 1-bit at a time, from + // the least significant bit to the most significant bit. + while mask != 0 { + // Put rightmost bit of `set` at the position of the current `mask` bit. + result |= (set & 1) << mask.trailing_zeros(); + // Go to next bit of `set`. + set >>= 1; + // Clear the least significant set bit. + mask &= mask.wrapping_sub(1); + } + result + } + _ => return Ok(EmulateItemResult::NotSupported), + }; + + let result = if is_64_bit { + Scalar::from_u64(result) + } else { + Scalar::from_u32(u32::try_from(result).unwrap()) + }; + this.write_scalar(result, dest)?; + + Ok(EmulateItemResult::NeedsReturn) + } +} diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index b71aec02166..0bbf2a8e13e 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -14,6 +14,7 @@ use helpers::bool_to_simd_element; mod aesni; mod avx; mod avx2; +mod bmi; mod sse; mod sse2; mod sse3; @@ -34,63 +35,49 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Prefix should have already been checked. let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.").unwrap(); match unprefixed_name { - // Used to implement the `_addcarry_u32` and `_addcarry_u64` functions. - // Computes a + b with input and output carry. The input carry is an 8-bit - // value, which is interpreted as 1 if it is non-zero. The output carry is - // an 8-bit value that will be 0 or 1. + // Used to implement the `_addcarry_u{32, 64}` and the `_subborrow_u{32, 64}` functions. + // Computes a + b or a - b with input and output carry/borrow. The input carry/borrow is an 8-bit + // value, which is interpreted as 1 if it is non-zero. The output carry/borrow is an 8-bit value that will be 0 or 1. // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/addcarry-u32-addcarry-u64.html - "addcarry.32" | "addcarry.64" => { - if unprefixed_name == "addcarry.64" && this.tcx.sess.target.arch != "x86_64" { + // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/subborrow-u32-subborrow-u64.html + "addcarry.32" | "addcarry.64" | "subborrow.32" | "subborrow.64" => { + if unprefixed_name.ends_with("64") && this.tcx.sess.target.arch != "x86_64" { return Ok(EmulateItemResult::NotSupported); } - let [c_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; - let c_in = this.read_scalar(c_in)?.to_u8()? != 0; - let a = this.read_immediate(a)?; - let b = this.read_immediate(b)?; - - let (sum, overflow1) = - this.binary_op(mir::BinOp::AddWithOverflow, &a, &b)?.to_pair(this); - let (sum, overflow2) = this - .binary_op( - mir::BinOp::AddWithOverflow, - &sum, - &ImmTy::from_uint(c_in, a.layout), - )? - .to_pair(this); - let c_out = overflow1.to_scalar().to_bool()? | overflow2.to_scalar().to_bool()?; - - this.write_scalar(Scalar::from_u8(c_out.into()), &this.project_field(dest, 0)?)?; + let [cb_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; + + let op = if unprefixed_name.starts_with("add") { + mir::BinOp::AddWithOverflow + } else { + mir::BinOp::SubWithOverflow + }; + + let (sum, cb_out) = carrying_add(this, cb_in, a, b, op)?; + this.write_scalar(cb_out, &this.project_field(dest, 0)?)?; this.write_immediate(*sum, &this.project_field(dest, 1)?)?; } - // Used to implement the `_subborrow_u32` and `_subborrow_u64` functions. - // Computes a - b with input and output borrow. The input borrow is an 8-bit - // value, which is interpreted as 1 if it is non-zero. The output borrow is - // an 8-bit value that will be 0 or 1. - // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/subborrow-u32-subborrow-u64.html - "subborrow.32" | "subborrow.64" => { - if unprefixed_name == "subborrow.64" && this.tcx.sess.target.arch != "x86_64" { + + // Used to implement the `_addcarryx_u{32, 64}` functions. They are semantically identical with the `_addcarry_u{32, 64}` functions, + // except for a slightly different type signature and the requirement for the "adx" target feature. + // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/addcarryx-u32-addcarryx-u64.html + "addcarryx.u32" | "addcarryx.u64" => { + this.expect_target_feature_for_intrinsic(link_name, "adx")?; + + let is_u64 = unprefixed_name.ends_with("64"); + if is_u64 && this.tcx.sess.target.arch != "x86_64" { return Ok(EmulateItemResult::NotSupported); } - let [b_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; - let b_in = this.read_scalar(b_in)?.to_u8()? != 0; - let a = this.read_immediate(a)?; - let b = this.read_immediate(b)?; - - let (sub, overflow1) = - this.binary_op(mir::BinOp::SubWithOverflow, &a, &b)?.to_pair(this); - let (sub, overflow2) = this - .binary_op( - mir::BinOp::SubWithOverflow, - &sub, - &ImmTy::from_uint(b_in, a.layout), - )? - .to_pair(this); - let b_out = overflow1.to_scalar().to_bool()? | overflow2.to_scalar().to_bool()?; - - this.write_scalar(Scalar::from_u8(b_out.into()), &this.project_field(dest, 0)?)?; - this.write_immediate(*sub, &this.project_field(dest, 1)?)?; + let [c_in, a, b, out] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; + let out = this.deref_pointer_as( + out, + if is_u64 { this.machine.layouts.u64 } else { this.machine.layouts.u32 }, + )?; + + let (sum, c_out) = carrying_add(this, c_in, a, b, mir::BinOp::AddWithOverflow)?; + this.write_scalar(c_out, dest)?; + this.write_immediate(*sum, &out)?; } // Used to implement the `_mm_pause` function. @@ -113,6 +100,11 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { pclmulqdq(this, left, right, imm, dest)?; } + name if name.starts_with("bmi.") => { + return bmi::EvalContextExt::emulate_x86_bmi_intrinsic( + this, link_name, abi, args, dest, + ); + } name if name.starts_with("sse.") => { return sse::EvalContextExt::emulate_x86_sse_intrinsic( this, link_name, abi, args, dest, @@ -435,8 +427,7 @@ fn apply_random_float_error<F: rustc_apfloat::Float>( ) -> F { let rng = this.machine.rng.get_mut(); // generates rand(0, 2^64) * 2^(scale - 64) = rand(0, 1) * 2^scale - let err = - F::from_u128(rng.gen::<u64>().into()).value.scalbn(err_scale.checked_sub(64).unwrap()); + let err = F::from_u128(rng.gen::<u64>().into()).value.scalbn(err_scale.strict_sub(64)); // give it a random sign let err = if rng.gen::<bool>() { -err } else { err }; // multiple the value with (1+err) @@ -787,7 +778,7 @@ fn split_simd_to_128bit_chunks<'tcx, P: Projectable<'tcx, Provenance>>( assert_eq!(simd_layout.size.bits() % 128, 0); let num_chunks = simd_layout.size.bits() / 128; - let items_per_chunk = simd_len.checked_div(num_chunks).unwrap(); + let items_per_chunk = simd_len.strict_div(num_chunks); // Transmute to `[[T; items_per_chunk]; num_chunks]` let chunked_layout = this @@ -835,13 +826,11 @@ fn horizontal_bin_op<'tcx>( for j in 0..items_per_chunk { // `j` is the index in `dest` // `k` is the index of the 2-item chunk in `src` - let (k, src) = - if j < middle { (j, &left) } else { (j.checked_sub(middle).unwrap(), &right) }; + let (k, src) = if j < middle { (j, &left) } else { (j.strict_sub(middle), &right) }; // `base_i` is the index of the first item of the 2-item chunk in `src` - let base_i = k.checked_mul(2).unwrap(); + let base_i = k.strict_mul(2); let lhs = this.read_immediate(&this.project_index(src, base_i)?)?; - let rhs = - this.read_immediate(&this.project_index(src, base_i.checked_add(1).unwrap())?)?; + let rhs = this.read_immediate(&this.project_index(src, base_i.strict_add(1))?)?; let res = if saturating { Immediate::from(this.saturating_arith(which, &lhs, &rhs)?) @@ -894,7 +883,7 @@ fn conditional_dot_product<'tcx>( // for the initial value because the representation of 0.0 is all zero bits. let mut sum = ImmTy::from_int(0u8, element_layout); for j in 0..items_per_chunk { - if imm & (1 << j.checked_add(4).unwrap()) != 0 { + if imm & (1 << j.strict_add(4)) != 0 { let left = this.read_immediate(&this.project_index(&left, j)?)?; let right = this.read_immediate(&this.project_index(&right, j)?)?; @@ -965,7 +954,7 @@ fn test_high_bits_masked<'tcx>( assert_eq!(op_len, mask_len); - let high_bit_offset = op.layout.field(this, 0).size.bits().checked_sub(1).unwrap(); + let high_bit_offset = op.layout.field(this, 0).size.bits().strict_sub(1); let mut direct = true; let mut negated = true; @@ -996,7 +985,7 @@ fn mask_load<'tcx>( assert_eq!(dest_len, mask_len); let mask_item_size = mask.layout.field(this, 0).size; - let high_bit_offset = mask_item_size.bits().checked_sub(1).unwrap(); + let high_bit_offset = mask_item_size.bits().strict_sub(1); let ptr = this.read_pointer(ptr)?; for i in 0..dest_len { @@ -1029,7 +1018,7 @@ fn mask_store<'tcx>( assert_eq!(value_len, mask_len); let mask_item_size = mask.layout.field(this, 0).size; - let high_bit_offset = mask_item_size.bits().checked_sub(1).unwrap(); + let high_bit_offset = mask_item_size.bits().strict_sub(1); let ptr = this.read_pointer(ptr)?; for i in 0..value_len { @@ -1071,15 +1060,15 @@ fn mpsadbw<'tcx>( let (_, _, right) = split_simd_to_128bit_chunks(this, right)?; let (_, dest_items_per_chunk, dest) = split_simd_to_128bit_chunks(this, dest)?; - assert_eq!(op_items_per_chunk, dest_items_per_chunk.checked_mul(2).unwrap()); + assert_eq!(op_items_per_chunk, dest_items_per_chunk.strict_mul(2)); let imm = this.read_scalar(imm)?.to_uint(imm.layout.size)?; // Bit 2 of `imm` specifies the offset for indices of `left`. // The offset is 0 when the bit is 0 or 4 when the bit is 1. - let left_offset = u64::try_from((imm >> 2) & 1).unwrap().checked_mul(4).unwrap(); + let left_offset = u64::try_from((imm >> 2) & 1).unwrap().strict_mul(4); // Bits 0..=1 of `imm` specify the offset for indices of // `right` in blocks of 4 elements. - let right_offset = u64::try_from(imm & 0b11).unwrap().checked_mul(4).unwrap(); + let right_offset = u64::try_from(imm & 0b11).unwrap().strict_mul(4); for i in 0..num_chunks { let left = this.project_index(&left, i)?; @@ -1087,18 +1076,16 @@ fn mpsadbw<'tcx>( let dest = this.project_index(&dest, i)?; for j in 0..dest_items_per_chunk { - let left_offset = left_offset.checked_add(j).unwrap(); + let left_offset = left_offset.strict_add(j); let mut res: u16 = 0; for k in 0..4 { let left = this - .read_scalar(&this.project_index(&left, left_offset.checked_add(k).unwrap())?)? + .read_scalar(&this.project_index(&left, left_offset.strict_add(k))?)? .to_u8()?; let right = this - .read_scalar( - &this.project_index(&right, right_offset.checked_add(k).unwrap())?, - )? + .read_scalar(&this.project_index(&right, right_offset.strict_add(k))?)? .to_u8()?; - res = res.checked_add(left.abs_diff(right).into()).unwrap(); + res = res.strict_add(left.abs_diff(right).into()); } this.write_scalar(Scalar::from_u16(res), &this.project_index(&dest, j)?)?; } @@ -1132,8 +1119,7 @@ fn pmulhrsw<'tcx>( let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i16()?; let dest = this.project_index(&dest, i)?; - let res = - (i32::from(left).checked_mul(right.into()).unwrap() >> 14).checked_add(1).unwrap() >> 1; + let res = (i32::from(left).strict_mul(right.into()) >> 14).strict_add(1) >> 1; // The result of this operation can overflow a signed 16-bit integer. // When `left` and `right` are -0x8000, the result is 0x8000. @@ -1229,7 +1215,7 @@ fn pack_generic<'tcx>( let (_, _, right) = split_simd_to_128bit_chunks(this, right)?; let (_, dest_items_per_chunk, dest) = split_simd_to_128bit_chunks(this, dest)?; - assert_eq!(dest_items_per_chunk, op_items_per_chunk.checked_mul(2).unwrap()); + assert_eq!(dest_items_per_chunk, op_items_per_chunk.strict_mul(2)); for i in 0..num_chunks { let left = this.project_index(&left, i)?; @@ -1240,8 +1226,7 @@ fn pack_generic<'tcx>( let left = this.read_scalar(&this.project_index(&left, j)?)?; let right = this.read_scalar(&this.project_index(&right, j)?)?; let left_dest = this.project_index(&dest, j)?; - let right_dest = - this.project_index(&dest, j.checked_add(op_items_per_chunk).unwrap())?; + let right_dest = this.project_index(&dest, j.strict_add(op_items_per_chunk))?; let left_res = f(left)?; let right_res = f(right)?; @@ -1360,3 +1345,27 @@ fn psign<'tcx>( Ok(()) } + +/// Calcultates either `a + b + cb_in` or `a - b - cb_in` depending on the value +/// of `op` and returns both the sum and the overflow bit. `op` is expected to be +/// either one of `mir::BinOp::AddWithOverflow` and `mir::BinOp::SubWithOverflow`. +fn carrying_add<'tcx>( + this: &mut crate::MiriInterpCx<'tcx>, + cb_in: &OpTy<'tcx>, + a: &OpTy<'tcx>, + b: &OpTy<'tcx>, + op: mir::BinOp, +) -> InterpResult<'tcx, (ImmTy<'tcx>, Scalar)> { + assert!(op == mir::BinOp::AddWithOverflow || op == mir::BinOp::SubWithOverflow); + + let cb_in = this.read_scalar(cb_in)?.to_u8()? != 0; + let a = this.read_immediate(a)?; + let b = this.read_immediate(b)?; + + let (sum, overflow1) = this.binary_op(op, &a, &b)?.to_pair(this); + let (sum, overflow2) = + this.binary_op(op, &sum, &ImmTy::from_uint(cb_in, a.layout))?.to_pair(this); + let cb_out = overflow1.to_scalar().to_bool()? | overflow2.to_scalar().to_bool()?; + + Ok((sum, Scalar::from_u8(cb_out.into()))) +} diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs index e10047fefe6..3efdd561d6c 100644 --- a/src/tools/miri/src/shims/x86/sse2.rs +++ b/src/tools/miri/src/shims/x86/sse2.rs @@ -47,22 +47,22 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let (dest, dest_len) = this.mplace_to_simd(dest)?; assert_eq!(left_len, right_len); - assert_eq!(dest_len.checked_mul(2).unwrap(), left_len); + assert_eq!(dest_len.strict_mul(2), left_len); for i in 0..dest_len { - let j1 = i.checked_mul(2).unwrap(); + let j1 = i.strict_mul(2); let left1 = this.read_scalar(&this.project_index(&left, j1)?)?.to_i16()?; let right1 = this.read_scalar(&this.project_index(&right, j1)?)?.to_i16()?; - let j2 = j1.checked_add(1).unwrap(); + let j2 = j1.strict_add(1); let left2 = this.read_scalar(&this.project_index(&left, j2)?)?.to_i16()?; let right2 = this.read_scalar(&this.project_index(&right, j2)?)?.to_i16()?; let dest = this.project_index(&dest, i)?; // Multiplications are i16*i16->i32, which will not overflow. - let mul1 = i32::from(left1).checked_mul(right1.into()).unwrap(); - let mul2 = i32::from(left2).checked_mul(right2.into()).unwrap(); + let mul1 = i32::from(left1).strict_mul(right1.into()); + let mul2 = i32::from(left2).strict_mul(right2.into()); // However, this addition can overflow in the most extreme case // (-0x8000)*(-0x8000)+(-0x8000)*(-0x8000) = 0x80000000 let res = mul1.wrapping_add(mul2); @@ -94,14 +94,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let dest = this.project_index(&dest, i)?; let mut res: u16 = 0; - let n = left_len.checked_div(dest_len).unwrap(); + let n = left_len.strict_div(dest_len); for j in 0..n { - let op_i = j.checked_add(i.checked_mul(n).unwrap()).unwrap(); + let op_i = j.strict_add(i.strict_mul(n)); let left = this.read_scalar(&this.project_index(&left, op_i)?)?.to_u8()?; let right = this.read_scalar(&this.project_index(&right, op_i)?)?.to_u8()?; - res = res.checked_add(left.abs_diff(right).into()).unwrap(); + res = res.strict_add(left.abs_diff(right).into()); } this.write_scalar(Scalar::from_u64(res.into()), &dest)?; diff --git a/src/tools/miri/src/shims/x86/ssse3.rs b/src/tools/miri/src/shims/x86/ssse3.rs index 6a815e4cea3..ecacaeb9af5 100644 --- a/src/tools/miri/src/shims/x86/ssse3.rs +++ b/src/tools/miri/src/shims/x86/ssse3.rs @@ -89,22 +89,22 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let (dest, dest_len) = this.mplace_to_simd(dest)?; assert_eq!(left_len, right_len); - assert_eq!(dest_len.checked_mul(2).unwrap(), left_len); + assert_eq!(dest_len.strict_mul(2), left_len); for i in 0..dest_len { - let j1 = i.checked_mul(2).unwrap(); + let j1 = i.strict_mul(2); let left1 = this.read_scalar(&this.project_index(&left, j1)?)?.to_u8()?; let right1 = this.read_scalar(&this.project_index(&right, j1)?)?.to_i8()?; - let j2 = j1.checked_add(1).unwrap(); + let j2 = j1.strict_add(1); let left2 = this.read_scalar(&this.project_index(&left, j2)?)?.to_u8()?; let right2 = this.read_scalar(&this.project_index(&right, j2)?)?.to_i8()?; let dest = this.project_index(&dest, i)?; // Multiplication of a u8 and an i8 into an i16 cannot overflow. - let mul1 = i16::from(left1).checked_mul(right1.into()).unwrap(); - let mul2 = i16::from(left2).checked_mul(right2.into()).unwrap(); + let mul1 = i16::from(left1).strict_mul(right1.into()); + let mul2 = i16::from(left2).strict_mul(right2.into()); let res = mul1.saturating_add(mul2); this.write_scalar(Scalar::from_i16(res), &dest)?; diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.stderr index 078b7d2e0d8..9d6be16b83a 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.stderr @@ -1,6 +1,6 @@ error: the main thread terminated without waiting for all remaining threads -note: pass `-Zmiri-ignore-leaks` to disable this check +note: set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.stderr b/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.stderr index b0756d57212..91c67823320 100644 --- a/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.stderr +++ b/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.stderr @@ -9,7 +9,7 @@ LL | aligned_alloc(2, 0); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check +note: set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr b/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr index 1d6626dda70..9abe145ea9e 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr +++ b/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr @@ -4,8 +4,8 @@ error: unsupported operation: `read` from stdin not available when isolation is LL | libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `read` from stdin not available when isolation is enabled | - = help: pass the flag `-Zmiri-disable-isolation` to disable isolation; - = help: or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning + = help: set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation; + = help: or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning = note: BACKTRACE: = note: inside `main` at $DIR/isolated_stdin.rs:LL:CC diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr b/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr index 65ce0dcdcdd..657262b8d41 100644 --- a/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr +++ b/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr @@ -9,7 +9,7 @@ LL | let _ptr = libc::malloc(0); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check +note: set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.stderr b/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.stderr index 7ea0fa31469..2639031f1cc 100644 --- a/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.stderr +++ b/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.stderr @@ -9,7 +9,7 @@ LL | let _ = unsafe { libc::posix_memalign(&mut ptr, align, size) }; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check +note: set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/alloc/too_large.rs b/src/tools/miri/tests/fail/alloc/too_large.rs new file mode 100644 index 00000000000..4e28d2401d7 --- /dev/null +++ b/src/tools/miri/tests/fail/alloc/too_large.rs @@ -0,0 +1,10 @@ +extern "Rust" { + fn __rust_alloc(size: usize, align: usize) -> *mut u8; +} + +fn main() { + let bytes = isize::MAX as usize + 1; + unsafe { + __rust_alloc(bytes, 1); //~ERROR: larger than half the address space + } +} diff --git a/src/tools/miri/tests/fail/alloc/too_large.stderr b/src/tools/miri/tests/fail/alloc/too_large.stderr new file mode 100644 index 00000000000..77dcf91d843 --- /dev/null +++ b/src/tools/miri/tests/fail/alloc/too_large.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: creating an allocation larger than half the address space + --> $DIR/too_large.rs:LL:CC + | +LL | __rust_alloc(bytes, 1); + | ^^^^^^^^^^^^^^^^^^^^^^ creating an allocation larger than half the address space + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/too_large.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr index 4e2e7218432..217bc82010d 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr @@ -4,12 +4,11 @@ warning: integer-to-pointer cast LL | (*p.as_mut_ptr().cast::<[*const i32; 2]>())[0] = 4 as *const i32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast | - = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, - = help: which means that Miri might miss pointer bugs in this program. + = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program. = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation. = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. - = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics. - = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning. + = help: You can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics. + = help: Alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning. = note: BACKTRACE: = note: inside `main` at $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC diff --git a/src/tools/miri/tests/fail/memleak.stderr b/src/tools/miri/tests/fail/memleak.stderr index 8ba78ef6644..a9ee76fbe8a 100644 --- a/src/tools/miri/tests/fail/memleak.stderr +++ b/src/tools/miri/tests/fail/memleak.stderr @@ -18,7 +18,7 @@ LL | std::mem::forget(Box::new(42)); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check +note: set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/memleak_no_backtrace.rs b/src/tools/miri/tests/fail/memleak_no_backtrace.rs index a1f8d9957ff..1f8d8ba7a7c 100644 --- a/src/tools/miri/tests/fail/memleak_no_backtrace.rs +++ b/src/tools/miri/tests/fail/memleak_no_backtrace.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-disable-leak-backtraces -//@error-in-other-file: the evaluated program leaked memory +//@error-in-other-file: memory leaked //@normalize-stderr-test: ".*│.*" -> "$$stripped$$" fn main() { diff --git a/src/tools/miri/tests/fail/memleak_no_backtrace.stderr b/src/tools/miri/tests/fail/memleak_no_backtrace.stderr index 22e8c558061..6850928e150 100644 --- a/src/tools/miri/tests/fail/memleak_no_backtrace.stderr +++ b/src/tools/miri/tests/fail/memleak_no_backtrace.stderr @@ -1,4 +1,6 @@ -error: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check +error: memory leaked: ALLOC (Rust heap, size: 4, align: 4) + +note: set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/memleak_rc.32bit.stderr b/src/tools/miri/tests/fail/memleak_rc.32bit.stderr deleted file mode 100644 index 781e1458db9..00000000000 --- a/src/tools/miri/tests/fail/memleak_rc.32bit.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error: memory leaked: ALLOC (Rust heap, size: 16, align: 4), allocated here: - --> RUSTLIB/alloc/src/alloc.rs:LL:CC - | -LL | __rust_alloc(layout.size(), layout.align()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: BACKTRACE: - = note: inside `std::alloc::alloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `std::alloc::Global::alloc_impl` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `<std::alloc::Global as std::alloc::Allocator>::allocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `alloc::alloc::exchange_malloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `std::boxed::Box::<std::rc::RcBox<std::cell::RefCell<std::option::Option<Dummy>>>>::new` at RUSTLIB/alloc/src/boxed.rs:LL:CC - = note: inside `std::rc::Rc::<std::cell::RefCell<std::option::Option<Dummy>>>::new` at RUSTLIB/alloc/src/rc.rs:LL:CC -note: inside `main` - --> $DIR/memleak_rc.rs:LL:CC - | -LL | let x = Dummy(Rc::new(RefCell::new(None))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/fail/memleak_rc.rs b/src/tools/miri/tests/fail/memleak_rc.rs index 0927612d08e..2d12c1223cf 100644 --- a/src/tools/miri/tests/fail/memleak_rc.rs +++ b/src/tools/miri/tests/fail/memleak_rc.rs @@ -1,6 +1,6 @@ //@error-in-other-file: memory leaked -//@stderr-per-bitwidth //@normalize-stderr-test: ".*│.*" -> "$$stripped$$" +//@normalize-stderr-test: "Rust heap, size: [0-9]+, align: [0-9]+" -> "Rust heap, SIZE, ALIGN" use std::cell::RefCell; use std::rc::Rc; diff --git a/src/tools/miri/tests/fail/memleak_rc.64bit.stderr b/src/tools/miri/tests/fail/memleak_rc.stderr index 1c85a0f9d9f..dbf2daf818c 100644 --- a/src/tools/miri/tests/fail/memleak_rc.64bit.stderr +++ b/src/tools/miri/tests/fail/memleak_rc.stderr @@ -1,4 +1,4 @@ -error: memory leaked: ALLOC (Rust heap, size: 32, align: 8), allocated here: +error: memory leaked: ALLOC (Rust heap, SIZE, ALIGN), allocated here: --> RUSTLIB/alloc/src/alloc.rs:LL:CC | LL | __rust_alloc(layout.size(), layout.align()) @@ -19,7 +19,7 @@ LL | let x = Dummy(Rc::new(RefCell::new(None))); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check +note: set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr index 1f08649428a..ec956f83348 100644 --- a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr +++ b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr @@ -4,8 +4,8 @@ error: unsupported operation: `open` not available when isolation is enabled LL | let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `open` not available when isolation is enabled | - = help: pass the flag `-Zmiri-disable-isolation` to disable isolation; - = help: or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning + = help: set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation; + = help: or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC = note: inside `std::sys::pal::PLATFORM::cvt_r::<i32, {closure@std::sys::pal::PLATFORM::fs::File::open_c::{closure#0}}>` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC diff --git a/src/tools/miri/tests/fail/tls_macro_leak.stderr b/src/tools/miri/tests/fail/tls_macro_leak.stderr index 40b21f8625a..c7c641a30f1 100644 --- a/src/tools/miri/tests/fail/tls_macro_leak.stderr +++ b/src/tools/miri/tests/fail/tls_macro_leak.stderr @@ -27,7 +27,7 @@ LL | | }); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check +note: set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/tls_static_leak.stderr b/src/tools/miri/tests/fail/tls_static_leak.stderr index 580b52c1512..f7b90a1118c 100644 --- a/src/tools/miri/tests/fail/tls_static_leak.stderr +++ b/src/tools/miri/tests/fail/tls_static_leak.stderr @@ -18,7 +18,7 @@ LL | TLS.set(Some(Box::leak(Box::new(123)))); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check +note: set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/pass/box.stack.stderr b/src/tools/miri/tests/pass/box.stack.stderr index 1a4d52ee314..341f84c8992 100644 --- a/src/tools/miri/tests/pass/box.stack.stderr +++ b/src/tools/miri/tests/pass/box.stack.stderr @@ -4,12 +4,11 @@ warning: integer-to-pointer cast LL | let r2 = ((r as usize) + 0) as *mut i32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast | - = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, - = help: which means that Miri might miss pointer bugs in this program. + = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program. = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation. = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. - = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics. - = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning. + = help: You can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics. + = help: Alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning. = note: BACKTRACE: = note: inside `into_raw` at $DIR/box.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/pass/extern_types.stack.stderr b/src/tools/miri/tests/pass/extern_types.stack.stderr index 275d718129b..03a9167abbc 100644 --- a/src/tools/miri/tests/pass/extern_types.stack.stderr +++ b/src/tools/miri/tests/pass/extern_types.stack.stderr @@ -4,12 +4,11 @@ warning: integer-to-pointer cast LL | let x: &Foo = unsafe { &*(16 as *const Foo) }; | ^^^^^^^^^^^^^^^^^^ integer-to-pointer cast | - = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, - = help: which means that Miri might miss pointer bugs in this program. + = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program. = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation. = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. - = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics. - = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning. + = help: You can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics. + = help: Alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning. = note: BACKTRACE: = note: inside `main` at $DIR/extern_types.rs:LL:CC diff --git a/src/tools/miri/tests/pass/issues/issue-miri-3680.rs b/src/tools/miri/tests/pass/issues/issue-miri-3680.rs new file mode 100644 index 00000000000..55b896c91ad --- /dev/null +++ b/src/tools/miri/tests/pass/issues/issue-miri-3680.rs @@ -0,0 +1,21 @@ +//@ignore-target-windows: File handling is not implemented yet +//@compile-flags: -Zmiri-disable-isolation + +use std::fs::remove_file; +use std::io::{ErrorKind, Seek}; + +#[path = "../../utils/mod.rs"] +mod utils; + +fn main() { + let path = utils::prepare("miri_test_fs_seek_i64_max_plus_1.txt"); + + let mut f = std::fs::File::create(&path).unwrap(); + let error = f.seek(std::io::SeekFrom::Start(i64::MAX as u64 + 1)).unwrap_err(); + + // It should be error due to negative offset. + assert_eq!(error.kind(), ErrorKind::InvalidInput); + + // Cleanup + remove_file(&path).unwrap(); +} diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-adx.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-adx.rs new file mode 100644 index 00000000000..431e7f2c5eb --- /dev/null +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-adx.rs @@ -0,0 +1,70 @@ +// Ignore everything except x86 and x86_64 +// Any new targets that are added to CI should be ignored here. +// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.) +//@ignore-target-aarch64 +//@ignore-target-arm +//@ignore-target-avr +//@ignore-target-s390x +//@ignore-target-thumbv7em +//@ignore-target-wasm32 +//@compile-flags: -C target-feature=+adx + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +mod x86 { + #[cfg(target_arch = "x86")] + use core::arch::x86 as arch; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64 as arch; + + fn adc(c_in: u8, a: u32, b: u32) -> (u8, u32) { + let mut sum = 0; + // SAFETY: There are no safety requirements for calling `_addcarry_u32`. + // It's just unsafe for API consistency with other intrinsics. + let c_out = unsafe { arch::_addcarryx_u32(c_in, a, b, &mut sum) }; + (c_out, sum) + } + + pub fn main() { + assert_eq!(adc(0, 1, 1), (0, 2)); + assert_eq!(adc(1, 1, 1), (0, 3)); + assert_eq!(adc(2, 1, 1), (0, 3)); // any non-zero carry acts as 1! + assert_eq!(adc(u8::MAX, 1, 1), (0, 3)); + assert_eq!(adc(0, u32::MAX, u32::MAX), (1, u32::MAX - 1)); + assert_eq!(adc(1, u32::MAX, u32::MAX), (1, u32::MAX)); + assert_eq!(adc(2, u32::MAX, u32::MAX), (1, u32::MAX)); + assert_eq!(adc(u8::MAX, u32::MAX, u32::MAX), (1, u32::MAX)); + } +} + +#[cfg(target_arch = "x86_64")] +mod x86_64 { + use core::arch::x86_64 as arch; + + fn adc(c_in: u8, a: u64, b: u64) -> (u8, u64) { + let mut sum = 0; + // SAFETY: There are no safety requirements for calling `_addcarry_u64`. + // It's just unsafe for API consistency with other intrinsics. + let c_out = unsafe { arch::_addcarryx_u64(c_in, a, b, &mut sum) }; + (c_out, sum) + } + + pub fn main() { + assert_eq!(adc(0, 1, 1), (0, 2)); + assert_eq!(adc(1, 1, 1), (0, 3)); + assert_eq!(adc(2, 1, 1), (0, 3)); // any non-zero carry acts as 1! + assert_eq!(adc(u8::MAX, 1, 1), (0, 3)); + assert_eq!(adc(0, u64::MAX, u64::MAX), (1, u64::MAX - 1)); + assert_eq!(adc(1, u64::MAX, u64::MAX), (1, u64::MAX)); + assert_eq!(adc(2, u64::MAX, u64::MAX), (1, u64::MAX)); + assert_eq!(adc(u8::MAX, u64::MAX, u64::MAX), (1, u64::MAX)); + } +} + +fn main() { + assert!(is_x86_feature_detected!("adx")); + + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + x86::main(); + #[cfg(target_arch = "x86_64")] + x86_64::main(); +} diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-bmi.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-bmi.rs new file mode 100644 index 00000000000..33424117c45 --- /dev/null +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-bmi.rs @@ -0,0 +1,216 @@ +// Ignore everything except x86 and x86_64 +// Any new targets that are added to CI should be ignored here. +// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.) +//@ignore-target-aarch64 +//@ignore-target-arm +//@ignore-target-avr +//@ignore-target-s390x +//@ignore-target-thumbv7em +//@ignore-target-wasm32 +//@compile-flags: -C target-feature=+bmi1,+bmi2 + +#[cfg(target_arch = "x86")] +use std::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use std::arch::x86_64::*; + +fn main() { + // BMI1 and BMI2 are independent from each other, so both must be checked. + assert!(is_x86_feature_detected!("bmi1")); + assert!(is_x86_feature_detected!("bmi2")); + + unsafe { + test_bmi_32(); + test_bmi_64(); + } +} + +/// Test the 32-bit variants of the intrinsics. +unsafe fn test_bmi_32() { + unsafe fn test_bextr_u32() { + let r = _bextr_u32(0b0101_0000u32, 4, 4); + assert_eq!(r, 0b0000_0101u32); + + for i in 0..16 { + assert_eq!(_bextr_u32(u32::MAX, i, 4), 0b1111); + assert_eq!(_bextr_u32(u32::MAX, 4, i), (1 << i) - 1); + } + + // Ensure that indices larger than the bit count are covered. + // It is important to go above 32 in order to verify the bit selection + // of the instruction. + + for i in 0..256 { + // If the index is out of bounds, the original input won't be changed, thus the `min(32)`. + assert_eq!(_bextr_u32(u32::MAX, 0, i).count_ones(), i.min(32)); + } + + for i in 0..256 { + assert_eq!(_bextr_u32(u32::MAX, i, 0), 0); + } + + // Test cases with completly random values. These cases also test + // that the function works even if upper bits of the control value are set. + assert_eq!(_bextr2_u32(0x7408a392, 0x54ef705), 0x3a0451c); + assert_eq!(_bextr2_u32(0xbc5a3494, 0xdd193203), 0x178b4692); + assert_eq!(_bextr2_u32(0xc0332325, 0xf96e207), 0x1806646); + } + test_bextr_u32(); + + unsafe fn test_pext_u32() { + let n = 0b1011_1110_1001_0011u32; + + let m0 = 0b0110_0011_1000_0101u32; + let s0 = 0b0000_0000_0011_0101u32; + + let m1 = 0b1110_1011_1110_1111u32; + let s1 = 0b0001_0111_0100_0011u32; + + // Testing of random values. + assert_eq!(_pext_u32(n, m0), s0); + assert_eq!(_pext_u32(n, m1), s1); + assert_eq!(_pext_u32(0x12345678, 0xff00fff0), 0x00012567); + + // Testing of various identities. + assert_eq!(_pext_u32(u32::MAX, u32::MAX), u32::MAX); + assert_eq!(_pext_u32(u32::MAX, 0), 0); + assert_eq!(_pext_u32(0, u32::MAX), 0); + } + test_pext_u32(); + + unsafe fn test_pdep_u32() { + let n = 0b1011_1110_1001_0011u32; + + let m0 = 0b0110_0011_1000_0101u32; + let s0 = 0b0000_0010_0000_0101u32; + + let m1 = 0b1110_1011_1110_1111u32; + let s1 = 0b1110_1001_0010_0011u32; + + // Testing of random values. + assert_eq!(_pdep_u32(n, m0), s0); + assert_eq!(_pdep_u32(n, m1), s1); + assert_eq!(_pdep_u32(0x00012567, 0xff00fff0), 0x12005670); + + // Testing of various identities. + assert_eq!(_pdep_u32(u32::MAX, u32::MAX), u32::MAX); + assert_eq!(_pdep_u32(0, u32::MAX), 0); + assert_eq!(_pdep_u32(u32::MAX, 0), 0); + } + test_pdep_u32(); + + unsafe fn test_bzhi_u32() { + let n = 0b1111_0010u32; + let s = 0b0001_0010u32; + assert_eq!(_bzhi_u32(n, 5), s); + + // Ensure that indices larger than the bit count are covered. + // It is important to go above 32 in order to verify the bit selection + // of the instruction. + for i in 0..=512 { + // The instruction only takes the lowest eight bits to generate the index, hence `i & 0xff`. + // If the index is out of bounds, the original input won't be changed, thus the `min(32)`. + let expected = 1u32.checked_shl((i & 0xff).min(32)).unwrap_or(0).wrapping_sub(1); + let actual = _bzhi_u32(u32::MAX, i); + assert_eq!(expected, actual); + } + } + test_bzhi_u32(); +} + +#[cfg(not(target_arch = "x86_64"))] +unsafe fn test_bmi_64() {} + +/// Test the 64-bit variants of the intrinsics. +#[cfg(target_arch = "x86_64")] +unsafe fn test_bmi_64() { + unsafe fn test_bextr_u64() { + let r = _bextr_u64(0b0101_0000u64, 4, 4); + assert_eq!(r, 0b0000_0101u64); + + for i in 0..16 { + assert_eq!(_bextr_u64(u64::MAX, i, 4), 0b1111); + assert_eq!(_bextr_u64(u64::MAX, 32, i), (1 << i) - 1); + } + + // Ensure that indices larger than the bit count are covered. + // It is important to go above 64 in order to verify the bit selection + // of the instruction. + + for i in 0..256 { + // If the index is out of bounds, the original input won't be changed, thus the `min(64)`. + assert_eq!(_bextr_u64(u64::MAX, 0, i).count_ones(), i.min(64)); + } + + for i in 0..256 { + assert_eq!(_bextr_u64(u64::MAX, i, 0), 0); + } + + // Test cases with completly random values. These cases also test + // that the function works even if upper bits of the control value are set. + assert_eq!(_bextr2_u64(0x4ff6cfbcea75f055, 0x216642e228425719), 0x27fb67de75); + assert_eq!(_bextr2_u64(0xb05e991e6f6e1b6, 0xc76dd5d7f67dfc14), 0xb05e991e6f); + assert_eq!(_bextr2_u64(0x5a3a629e323d848f, 0x95ac507d20e7719), 0x2d1d314f19); + } + test_bextr_u64(); + + unsafe fn test_pext_u64() { + let n = 0b1011_1110_1001_0011u64; + + let m0 = 0b0110_0011_1000_0101u64; + let s0 = 0b0000_0000_0011_0101u64; + + let m1 = 0b1110_1011_1110_1111u64; + let s1 = 0b0001_0111_0100_0011u64; + + // Testing of random values. + assert_eq!(_pext_u64(n, m0), s0); + assert_eq!(_pext_u64(n, m1), s1); + assert_eq!(_pext_u64(0x12345678, 0xff00fff0), 0x00012567); + + // Testing of various identities. + assert_eq!(_pext_u64(u64::MAX, u64::MAX), u64::MAX); + assert_eq!(_pext_u64(u64::MAX, 0), 0); + assert_eq!(_pext_u64(0, u64::MAX), 0); + } + test_pext_u64(); + + unsafe fn test_pdep_u64() { + let n = 0b1011_1110_1001_0011u64; + + let m0 = 0b0110_0011_1000_0101u64; + let s0 = 0b0000_0010_0000_0101u64; + + let m1 = 0b1110_1011_1110_1111u64; + let s1 = 0b1110_1001_0010_0011u64; + + // Testing of random values. + assert_eq!(_pdep_u64(n, m0), s0); + assert_eq!(_pdep_u64(n, m1), s1); + assert_eq!(_pdep_u64(0x00012567, 0xff00fff0), 0x12005670); + + // Testing of various identities. + assert_eq!(_pdep_u64(u64::MAX, u64::MAX), u64::MAX); + assert_eq!(_pdep_u64(0, u64::MAX), 0); + assert_eq!(_pdep_u64(u64::MAX, 0), 0); + } + test_pdep_u64(); + + unsafe fn test_bzhi_u64() { + let n = 0b1111_0010u64; + let s = 0b0001_0010u64; + assert_eq!(_bzhi_u64(n, 5), s); + + // Ensure that indices larger than the bit count are covered. + // It is important to go above 255 in order to verify the bit selection + // of the instruction. + for i in 0..=512 { + // The instruction only takes the lowest eight bits to generate the index, hence `i & 0xff`. + // If the index is out of bounds, the original input won't be changed, thus the `min(64)`. + let expected = 1u64.checked_shl((i & 0xff).min(64)).unwrap_or(0).wrapping_sub(1); + let actual = _bzhi_u64(u64::MAX, i); + assert_eq!(expected, actual); + } + } + test_bzhi_u64(); +} diff --git a/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr b/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr index 7cbfad3942b..b0e1adf27d1 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr +++ b/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr @@ -4,12 +4,11 @@ warning: integer-to-pointer cast LL | let wildcard = &root0 as *const Cell<i32> as usize as *const Cell<i32>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast | - = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, - = help: which means that Miri might miss pointer bugs in this program. + = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program. = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation. = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. - = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics. - = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning. + = help: You can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics. + = help: Alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning. = note: BACKTRACE: = note: inside `main` at $DIR/issue-miri-2389.rs:LL:CC diff --git a/src/tools/miri/tests/pass/tls/tls_macro_drop.rs b/src/tools/miri/tests/pass/tls/tls_macro_drop.rs index bd06eec9cd5..0d8a1cef511 100644 --- a/src/tools/miri/tests/pass/tls/tls_macro_drop.rs +++ b/src/tools/miri/tests/pass/tls/tls_macro_drop.rs @@ -4,27 +4,28 @@ use std::cell::RefCell; use std::thread; -struct TestCell { - value: RefCell<u8>, -} +/// Check that destructors of the library thread locals are executed immediately +/// after a thread terminates. +fn check_destructors() { + struct TestCell { + value: RefCell<u8>, + } -impl Drop for TestCell { - fn drop(&mut self) { - for _ in 0..10 { - thread::yield_now(); + impl Drop for TestCell { + fn drop(&mut self) { + for _ in 0..10 { + thread::yield_now(); + } + println!("Dropping: {} (should be before 'Continue main 1').", *self.value.borrow()) } - println!("Dropping: {} (should be before 'Continue main 1').", *self.value.borrow()) } -} -thread_local! { - static A: TestCell = TestCell { value: RefCell::new(0) }; - static A_CONST: TestCell = const { TestCell { value: RefCell::new(10) } }; -} + // Test both regular and `const` thread-locals. + thread_local! { + static A: TestCell = TestCell { value: RefCell::new(0) }; + static A_CONST: TestCell = const { TestCell { value: RefCell::new(10) } }; + } -/// Check that destructors of the library thread locals are executed immediately -/// after a thread terminates. -fn check_destructors() { // We use the same value for both of them, since destructor order differs between Miri on Linux // (which uses `register_dtor_fallback`, in the end using a single pthread_key to manage a // thread-local linked list of dtors to call), real Linux rustc (which uses @@ -44,26 +45,29 @@ fn check_destructors() { println!("Continue main 1.") } -struct JoinCell { - value: RefCell<Option<thread::JoinHandle<u8>>>, -} +/// Check that the destructor can be blocked joining another thread. +fn check_blocking() { + struct JoinCell { + value: RefCell<Option<thread::JoinHandle<u8>>>, + } -impl Drop for JoinCell { - fn drop(&mut self) { - for _ in 0..10 { - thread::yield_now(); + impl Drop for JoinCell { + fn drop(&mut self) { + for _ in 0..10 { + thread::yield_now(); + } + let join_handle = self.value.borrow_mut().take().unwrap(); + println!( + "Joining: {} (should be before 'Continue main 2').", + join_handle.join().unwrap() + ); } - let join_handle = self.value.borrow_mut().take().unwrap(); - println!("Joining: {} (should be before 'Continue main 2').", join_handle.join().unwrap()); } -} -thread_local! { - static B: JoinCell = JoinCell { value: RefCell::new(None) }; -} + thread_local! { + static B: JoinCell = JoinCell { value: RefCell::new(None) }; + } -/// Check that the destructor can be blocked joining another thread. -fn check_blocking() { thread::spawn(|| { B.with(|f| { assert!(f.value.borrow().is_none()); @@ -74,10 +78,36 @@ fn check_blocking() { .join() .unwrap(); println!("Continue main 2."); - // Preempt the main thread so that the destructor gets executed and can join - // the thread. - thread::yield_now(); - thread::yield_now(); +} + +fn check_tls_init_in_dtor() { + struct Bar; + + impl Drop for Bar { + fn drop(&mut self) { + println!("Bar dtor (should be before `Continue main 3`)."); + } + } + + struct Foo; + + impl Drop for Foo { + fn drop(&mut self) { + println!("Foo dtor (should be before `Bar dtor`)."); + // We initialize another thread-local inside the dtor, which is an interesting corner case. + thread_local!(static BAR: Bar = Bar); + BAR.with(|_| {}); + } + } + + thread_local!(static FOO: Foo = Foo); + + thread::spawn(|| { + FOO.with(|_| {}); + }) + .join() + .unwrap(); + println!("Continue main 3."); } // This test tests that TLS destructors have run before the thread joins. The @@ -248,6 +278,8 @@ fn dtors_in_dtors_in_dtors() { fn main() { check_destructors(); check_blocking(); + check_tls_init_in_dtor(); + join_orders_after_tls_destructors(); dtors_in_dtors_in_dtors(); } diff --git a/src/tools/miri/tests/pass/tls/tls_macro_drop.stack.stdout b/src/tools/miri/tests/pass/tls/tls_macro_drop.stack.stdout index b7877820a0c..3e17acc8328 100644 --- a/src/tools/miri/tests/pass/tls/tls_macro_drop.stack.stdout +++ b/src/tools/miri/tests/pass/tls/tls_macro_drop.stack.stdout @@ -3,3 +3,6 @@ Dropping: 8 (should be before 'Continue main 1'). Continue main 1. Joining: 7 (should be before 'Continue main 2'). Continue main 2. +Foo dtor (should be before `Bar dtor`). +Bar dtor (should be before `Continue main 3`). +Continue main 3. diff --git a/src/tools/miri/tests/pass/tls/tls_macro_drop.tree.stdout b/src/tools/miri/tests/pass/tls/tls_macro_drop.tree.stdout index b7877820a0c..3e17acc8328 100644 --- a/src/tools/miri/tests/pass/tls/tls_macro_drop.tree.stdout +++ b/src/tools/miri/tests/pass/tls/tls_macro_drop.tree.stdout @@ -3,3 +3,6 @@ Dropping: 8 (should be before 'Continue main 1'). Continue main 1. Joining: 7 (should be before 'Continue main 2'). Continue main 2. +Foo dtor (should be before `Bar dtor`). +Bar dtor (should be before `Continue main 3`). +Continue main 3. diff --git a/src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.rs b/src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.rs index f36c460ae53..082a6f17838 100644 --- a/src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.rs +++ b/src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.rs @@ -1,31 +1,27 @@ -//! Check that destructors of the thread locals are executed on all OSes -//! (even when we do not support concurrency, and cannot run the other test). +//! Check that destructors of main thread thread locals are executed. -use std::cell::RefCell; +struct Bar; -struct TestCell { - value: RefCell<u8>, +impl Drop for Bar { + fn drop(&mut self) { + println!("Bar dtor"); + } } -impl Drop for TestCell { +struct Foo; + +impl Drop for Foo { fn drop(&mut self) { - eprintln!("Dropping: {}", *self.value.borrow()) + println!("Foo dtor"); + // We initialize another thread-local inside the dtor, which is an interesting corner case. + // Also we use a `const` thread-local here, just to also have that code path covered. + thread_local!(static BAR: Bar = const { Bar }); + BAR.with(|_| {}); } } -thread_local! { - static A: TestCell = TestCell { value: RefCell::new(0) }; - static A_CONST: TestCell = const { TestCell { value: RefCell::new(10) } }; -} +thread_local!(static FOO: Foo = Foo); fn main() { - A.with(|f| { - assert_eq!(*f.value.borrow(), 0); - *f.value.borrow_mut() = 5; - }); - A_CONST.with(|f| { - assert_eq!(*f.value.borrow(), 10); - *f.value.borrow_mut() = 5; // Same value as above since the drop order is different on different platforms - }); - eprintln!("Continue main.") + FOO.with(|_| {}); } diff --git a/src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.stderr b/src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.stderr deleted file mode 100644 index 09ec1c3c2c5..00000000000 --- a/src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.stderr +++ /dev/null @@ -1,3 +0,0 @@ -Continue main. -Dropping: 5 -Dropping: 5 diff --git a/src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.stdout b/src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.stdout new file mode 100644 index 00000000000..6160f272649 --- /dev/null +++ b/src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.stdout @@ -0,0 +1,2 @@ +Foo dtor +Bar dtor diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 2f7f51442f1..ec3b8a96ef3 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -4,8 +4,10 @@ version = "0.2.0" edition = "2021" [dependencies] +bstr = "1.6.0" object = "0.34.0" similar = "2.5.0" wasmparser = "0.118.2" regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace gimli = "0.28.1" +ar = "0.9.0" diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 487132683e9..31b913810b6 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -21,6 +21,7 @@ use std::io; use std::panic; use std::path::{Path, PathBuf}; +pub use bstr; pub use gimli; pub use object; pub use regex; @@ -61,6 +62,19 @@ pub fn target() -> String { env_var("TARGET") } +/// `AR` +#[track_caller] +pub fn ar(inputs: &[impl AsRef<Path>], output_path: impl AsRef<Path>) { + let output = fs::File::create(&output_path).expect(&format!( + "the file in path \"{}\" could not be created", + output_path.as_ref().display() + )); + let mut builder = ar::Builder::new(output); + for input in inputs { + builder.append_path(input).unwrap(); + } +} + /// Check if target is windows-like. #[must_use] pub fn is_windows() -> bool { diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index 28ece1dff12..df843d74fc9 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -106,6 +106,17 @@ impl Rustc { self } + /// Remap source path prefixes in all output. + pub fn remap_path_prefix<P: AsRef<Path>>(&mut self, from: P, to: P) -> &mut Self { + let from = from.as_ref().to_string_lossy(); + let to = to.as_ref().to_string_lossy(); + + self.cmd.arg("--remap-path-prefix"); + self.cmd.arg(format!("{from}={to}")); + + self + } + /// Specify path to the input file. pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self { self.cmd.arg(path.as_ref()); diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs index 35fd85bf451..7ead7e93901 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs @@ -142,9 +142,9 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk, @only_local: true, ), - gated!( - expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk, - lint_reasons, experimental!(expect) + ungated!( + expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + DuplicatesOk, @only_local: true, ), ungated!( forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), diff --git a/src/tools/rustc-perf-wrapper/Cargo.toml b/src/tools/rustc-perf-wrapper/Cargo.toml new file mode 100644 index 00000000000..416bfef41d7 --- /dev/null +++ b/src/tools/rustc-perf-wrapper/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "rustc-perf-wrapper" +version = "0.1.0" +edition = "2021" + +[dependencies] +clap = { version = "4.5.7", features = ["derive", "env"] } diff --git a/src/tools/rustc-perf-wrapper/README.md b/src/tools/rustc-perf-wrapper/README.md new file mode 100644 index 00000000000..d7655459a2f --- /dev/null +++ b/src/tools/rustc-perf-wrapper/README.md @@ -0,0 +1,3 @@ +# rustc-perf wrapper +Utility tool for invoking [`rustc-perf`](https://github.com/rust-lang/rustc-perf) for benchmarking/profiling +a stage1/2 compiler built by bootstrap using `x perf -- <command>`. diff --git a/src/tools/rustc-perf-wrapper/src/config.rs b/src/tools/rustc-perf-wrapper/src/config.rs new file mode 100644 index 00000000000..a88abfe4723 --- /dev/null +++ b/src/tools/rustc-perf-wrapper/src/config.rs @@ -0,0 +1,45 @@ +use std::fmt::{Display, Formatter}; + +#[derive(Clone, Copy, Debug, clap::ValueEnum)] +#[value(rename_all = "PascalCase")] +pub enum Profile { + Check, + Debug, + Doc, + Opt, + Clippy, +} + +impl Display for Profile { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let name = match self { + Profile::Check => "Check", + Profile::Debug => "Debug", + Profile::Doc => "Doc", + Profile::Opt => "Opt", + Profile::Clippy => "Clippy", + }; + f.write_str(name) + } +} + +#[derive(Clone, Copy, Debug, clap::ValueEnum)] +#[value(rename_all = "PascalCase")] +pub enum Scenario { + Full, + IncrFull, + IncrUnchanged, + IncrPatched, +} + +impl Display for Scenario { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let name = match self { + Scenario::Full => "Full", + Scenario::IncrFull => "IncrFull", + Scenario::IncrUnchanged => "IncrUnchanged", + Scenario::IncrPatched => "IncrPatched", + }; + f.write_str(name) + } +} diff --git a/src/tools/rustc-perf-wrapper/src/main.rs b/src/tools/rustc-perf-wrapper/src/main.rs new file mode 100644 index 00000000000..1c0d1745f3d --- /dev/null +++ b/src/tools/rustc-perf-wrapper/src/main.rs @@ -0,0 +1,130 @@ +use crate::config::{Profile, Scenario}; +use clap::Parser; +use std::path::PathBuf; +use std::process::Command; + +mod config; + +/// Performs profiling or benchmarking with [`rustc-perf`](https://github.com/rust-lang/rustc-perf) +/// using a locally built compiler. +#[derive(Debug, clap::Parser)] +// Hide arguments from BuildContext in the default usage string. +// Clap does not seem to have a way of disabling the usage of these arguments. +#[clap(override_usage = "rustc-perf-wrapper [OPTIONS] <COMMAND>")] +pub struct Args { + #[clap(subcommand)] + cmd: PerfCommand, + + #[clap(flatten)] + opts: SharedOpts, + + #[clap(flatten)] + ctx: BuildContext, +} + +#[derive(Debug, clap::Parser)] +enum PerfCommand { + /// Run `profile_local eprintln`. + /// This executes the compiler on the given benchmarks and stores its stderr output. + Eprintln, + /// Run `profile_local samply` + /// This executes the compiler on the given benchmarks and profiles it with `samply`. + /// You need to install `samply`, e.g. using `cargo install samply`. + Samply, + /// Run `profile_local cachegrind`. + /// This executes the compiler on the given benchmarks under `Cachegrind`. + Cachegrind, +} + +impl PerfCommand { + fn is_profiling(&self) -> bool { + match self { + PerfCommand::Eprintln | PerfCommand::Samply | PerfCommand::Cachegrind => true, + } + } +} + +#[derive(Debug, clap::Parser)] +struct SharedOpts { + /// Select the benchmarks that you want to run (separated by commas). + /// If unspecified, all benchmarks will be executed. + #[clap(long, global = true, value_delimiter = ',')] + include: Vec<String>, + /// Select the scenarios that should be benchmarked. + #[clap( + long, + global = true, + value_delimiter = ',', + default_value = "Full,IncrFull,IncrUnchanged,IncrPatched" + )] + scenarios: Vec<Scenario>, + /// Select the profiles that should be benchmarked. + #[clap(long, global = true, value_delimiter = ',', default_value = "Check,Debug,Opt")] + profiles: Vec<Profile>, +} + +/// These arguments are mostly designed to be passed from bootstrap, not by users +/// directly. +#[derive(Debug, clap::Parser)] +struct BuildContext { + /// Compiler binary that will be benchmarked/profiled. + #[clap(long, hide = true, env = "RUSTC_REAL")] + compiler: PathBuf, + /// rustc-perf collector binary that will be used for running benchmarks/profilers. + #[clap(long, hide = true, env = "PERF_COLLECTOR")] + collector: PathBuf, + /// Directory where to store results. + #[clap(long, hide = true, env = "PERF_RESULT_DIR")] + results_dir: PathBuf, +} + +fn main() { + let args = Args::parse(); + run(args); +} + +fn run(args: Args) { + let mut cmd = Command::new(args.ctx.collector); + match &args.cmd { + PerfCommand::Eprintln => { + cmd.arg("profile_local").arg("eprintln"); + } + PerfCommand::Samply => { + cmd.arg("profile_local").arg("samply"); + } + PerfCommand::Cachegrind => { + cmd.arg("profile_local").arg("cachegrind"); + } + } + if args.cmd.is_profiling() { + cmd.arg("--out-dir").arg(&args.ctx.results_dir); + } + + if !args.opts.include.is_empty() { + cmd.arg("--include").arg(args.opts.include.join(",")); + } + if !args.opts.profiles.is_empty() { + cmd.arg("--profiles") + .arg(args.opts.profiles.iter().map(|p| p.to_string()).collect::<Vec<_>>().join(",")); + } + if !args.opts.scenarios.is_empty() { + cmd.arg("--scenarios") + .arg(args.opts.scenarios.iter().map(|p| p.to_string()).collect::<Vec<_>>().join(",")); + } + cmd.arg(&args.ctx.compiler); + + println!("Running `rustc-perf` using `{}`", args.ctx.compiler.display()); + + const MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR"); + + let rustc_perf_dir = PathBuf::from(MANIFEST_DIR).join("../rustc-perf"); + + // We need to set the working directory to `src/tools/perf`, so that it can find the directory + // with compile-time benchmarks. + let cmd = cmd.current_dir(rustc_perf_dir); + cmd.status().expect("error while running rustc-perf collector"); + + if args.cmd.is_profiling() { + println!("You can find the results at `{}`", args.ctx.results_dir.display()); + } +} diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 8266f95fd70..c7c4b680b07 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -372,7 +372,7 @@ pub(crate) fn format_expr( )) } } - ast::ExprKind::Gen(capture_by, ref block, ref kind) => { + ast::ExprKind::Gen(capture_by, ref block, ref kind, _) => { let mover = if matches!(capture_by, ast::CaptureBy::Value { .. }) { "move " } else { diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index 0b05d5add52..1acdf9fbc7f 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -15,6 +15,7 @@ semver = "1.0" termcolor = "1.1.3" rustc-hash = "1.1.0" fluent-syntax = "0.11.1" +similar = "2.5.0" [[bin]] name = "rust-tidy" diff --git a/src/tools/tidy/config/requirements.in b/src/tools/tidy/config/requirements.in index 833d62a864b..8938dc03243 100644 --- a/src/tools/tidy/config/requirements.in +++ b/src/tools/tidy/config/requirements.in @@ -8,3 +8,4 @@ black==24.4.2 ruff==0.4.9 +clang-format==18.1.7 diff --git a/src/tools/tidy/config/requirements.txt b/src/tools/tidy/config/requirements.txt index d5236868ad1..790eabf5cf8 100644 --- a/src/tools/tidy/config/requirements.txt +++ b/src/tools/tidy/config/requirements.txt @@ -28,6 +28,23 @@ black==24.4.2 \ --hash=sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063 \ --hash=sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e # via -r src/tools/tidy/config/requirements.in +clang-format==18.1.7 \ + --hash=sha256:035204410f65d03f98cb81c9c39d6d193f9987917cc88de9d0dbd01f2aa9c302 \ + --hash=sha256:05c482a854287a5d21f7567186c0bd4b8dbd4a871751e655a45849185f30b931 \ + --hash=sha256:0b352ec51b291fe04c25a0f0ed15ba1a55b9c9c8eaa7fdf14de3d3585aef4f72 \ + --hash=sha256:217526c8189c18fd175e19bb3e4da2d1bdf14a2bf79d97108c9b6a98d9938351 \ + --hash=sha256:42d0b580ab7a45348155944adebe0bef53d1de9357b925830a59bbc351a25560 \ + --hash=sha256:57090c40a8f0a898e0db8be150a19be2551302d5f5620d2a01de07e7c9220a53 \ + --hash=sha256:607772cf474c1ebe0de44f44c1324e57a2d5b45a1d96d4aff166645532d99b43 \ + --hash=sha256:a49c44d7cc00431be8285aa120a7a21fa0475786c03c53b04a26882c4e626a43 \ + --hash=sha256:a62fca204293893badde0ab004df8b6df1d13eac4d452051554d9684d0a8254e \ + --hash=sha256:a914592a51f77c3563563c7a8970f19bc1ed59174ab992f095a78f4e142382ac \ + --hash=sha256:b3a0a09428cdd656ed87074543222a80660bc506407ed21b8e4bcb3d6d3a5a3c \ + --hash=sha256:c151d42e6ac7c3cc03d7fec61bed3211ce8f75528e1efd8fc64bdb33840987b2 \ + --hash=sha256:d6a2f051124d6ae506ba2a68accfe4ea4c8cb90d13b422c3131bb124413bac32 \ + --hash=sha256:f4f77ac0f4f9a659213fedda0f2d216886c410132e6e7dd4b13f92b34e925554 \ + --hash=sha256:f935d34152a2e11e55120eb9182862f432bc9789ab819f680c9f6db4edebf9e3 + # via -r src/tools/tidy/config/requirements.in click==8.1.3 \ --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \ --hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48 diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index cb68589d8a4..741bb46d1a7 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -18,7 +18,6 @@ run-make/cross-lang-lto-clang/Makefile run-make/cross-lang-lto-pgo-smoketest/Makefile run-make/cross-lang-lto-upstream-rlibs/Makefile run-make/cross-lang-lto/Makefile -run-make/debug-assertions/Makefile run-make/dep-info-doesnt-run-much/Makefile run-make/dep-info-spaces/Makefile run-make/dep-info/Makefile @@ -27,7 +26,6 @@ run-make/dump-mono-stats/Makefile run-make/dylib-chain/Makefile run-make/emit-path-unhashed/Makefile run-make/emit-shared-files/Makefile -run-make/emit-stack-sizes/Makefile run-make/emit-to-stdout/Makefile run-make/env-dep-info/Makefile run-make/export-executable-symbols/Makefile @@ -54,7 +52,6 @@ run-make/incr-add-rust-src-component/Makefile run-make/incr-foreign-head-span/Makefile run-make/interdependent-c-libraries/Makefile run-make/intrinsic-unreachable/Makefile -run-make/invalid-library/Makefile run-make/issue-107094/Makefile run-make/issue-109934-lto-debuginfo/Makefile run-make/issue-14698/Makefile @@ -71,7 +68,6 @@ run-make/issue-37839/Makefile run-make/issue-40535/Makefile run-make/issue-47384/Makefile run-make/issue-47551/Makefile -run-make/issue-68794-textrel-on-minimal-lib/Makefile run-make/issue-69368/Makefile run-make/issue-83045/Makefile run-make/issue-83112-incr-test-moved-file/Makefile @@ -84,7 +80,6 @@ run-make/jobserver-error/Makefile run-make/libs-through-symlinks/Makefile run-make/libtest-json/Makefile run-make/libtest-junit/Makefile -run-make/libtest-padding/Makefile run-make/libtest-thread-limit/Makefile run-make/link-cfg/Makefile run-make/link-framework/Makefile @@ -94,18 +89,14 @@ run-make/llvm-ident/Makefile run-make/long-linker-command-lines-cmd-exe/Makefile run-make/long-linker-command-lines/Makefile run-make/longjmp-across-rust/Makefile -run-make/lto-dylib-dep/Makefile run-make/lto-linkage-used-attr/Makefile run-make/lto-no-link-whole-rlib/Makefile run-make/lto-smoke-c/Makefile run-make/macos-deployment-target/Makefile run-make/macos-fat-archive/Makefile run-make/manual-link/Makefile -run-make/many-crates-but-no-match/Makefile run-make/metadata-dep-info/Makefile run-make/min-global-align/Makefile -run-make/mingw-export-call-convention/Makefile -run-make/mismatching-target-triples/Makefile run-make/missing-crate-dependency/Makefile run-make/mixing-libs/Makefile run-make/msvc-opt-minsize/Makefile @@ -118,14 +109,11 @@ run-make/obey-crate-type-flag/Makefile run-make/optimization-remarks-dir-pgo/Makefile run-make/optimization-remarks-dir/Makefile run-make/output-type-permutations/Makefile -run-make/override-aliased-flags/Makefile -run-make/overwrite-input/Makefile run-make/panic-abort-eh_frame/Makefile run-make/pass-linker-flags-flavor/Makefile run-make/pass-linker-flags-from-dep/Makefile run-make/pass-linker-flags/Makefile run-make/pass-non-c-like-enum-to-c/Makefile -run-make/pdb-alt-path/Makefile run-make/pdb-buildinfo-cl-cmd/Makefile run-make/pgo-gen-lto/Makefile run-make/pgo-gen-no-imp-symbols/Makefile @@ -133,15 +121,12 @@ run-make/pgo-gen/Makefile run-make/pgo-indirect-call-promotion/Makefile run-make/pgo-use/Makefile run-make/pointer-auth-link-with-c/Makefile -run-make/pretty-print-to-file/Makefile -run-make/pretty-print-with-dep-file/Makefile run-make/print-calling-conventions/Makefile run-make/print-target-list/Makefile run-make/profile/Makefile run-make/prune-link-args/Makefile run-make/raw-dylib-alt-calling-convention/Makefile run-make/raw-dylib-c/Makefile -run-make/raw-dylib-cross-compilation/Makefile run-make/raw-dylib-custom-dlltool/Makefile run-make/raw-dylib-import-name-type/Makefile run-make/raw-dylib-inline-cross-dylib/Makefile @@ -149,11 +134,9 @@ run-make/raw-dylib-link-ordinal/Makefile run-make/raw-dylib-stdcall-ordinal/Makefile run-make/redundant-libs/Makefile run-make/remap-path-prefix-dwarf/Makefile -run-make/remap-path-prefix/Makefile run-make/reproducible-build-2/Makefile run-make/reproducible-build/Makefile run-make/return-non-c-like-enum-from-c/Makefile -run-make/return-non-c-like-enum/Makefile run-make/rlib-chain/Makefile run-make/rlib-format-packed-bundled-libs-2/Makefile run-make/rlib-format-packed-bundled-libs-3/Makefile @@ -191,10 +174,7 @@ run-make/track-path-dep-info/Makefile run-make/track-pgo-dep-info/Makefile run-make/translation/Makefile run-make/type-mismatch-same-crate-name/Makefile -run-make/unknown-mod-stdin/Makefile run-make/unstable-flag-required/Makefile -run-make/use-suggestions-rust-2018/Makefile -run-make/used-cdylib-macos/Makefile run-make/volatile-intrinsics/Makefile run-make/wasm-exceptions-nostd/Makefile run-make/wasm-override-linker/Makefile diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs index e9dd6c66f64..8ce44115ef3 100644 --- a/src/tools/tidy/src/ext_tool_checks.rs +++ b/src/tools/tidy/src/ext_tool_checks.rs @@ -73,6 +73,8 @@ fn check_impl( let python_fmt = lint_args.contains(&"py:fmt") || python_all; let shell_all = lint_args.contains(&"shell"); let shell_lint = lint_args.contains(&"shell:lint") || shell_all; + let cpp_all = lint_args.contains(&"cpp"); + let cpp_fmt = lint_args.contains(&"cpp:fmt") || cpp_all; let mut py_path = None; @@ -81,7 +83,7 @@ fn check_impl( .map(OsStr::new) .partition(|arg| arg.to_str().is_some_and(|s| s.starts_with('-'))); - if python_lint || python_fmt { + if python_lint || python_fmt || cpp_fmt { let venv_path = outdir.join("venv"); let mut reqs_path = root_path.to_owned(); reqs_path.extend(PIP_REQ_PATH); @@ -111,13 +113,13 @@ fn check_impl( let mut args = merge_args(&cfg_args_ruff, &file_args_ruff); args.insert(0, "check".as_ref()); - let res = py_runner(py_path.as_ref().unwrap(), "ruff", &args); + let res = py_runner(py_path.as_ref().unwrap(), true, None, "ruff", &args); if res.is_err() && show_diff { eprintln!("\npython linting failed! Printing diff suggestions:"); args.insert(1, "--diff".as_ref()); - let _ = py_runner(py_path.as_ref().unwrap(), "ruff", &args); + let _ = py_runner(py_path.as_ref().unwrap(), true, None, "ruff", &args); } // Rethrow error let _ = res?; @@ -144,13 +146,84 @@ fn check_impl( } let mut args = merge_args(&cfg_args_black, &file_args_black); - let res = py_runner(py_path.as_ref().unwrap(), "black", &args); + let res = py_runner(py_path.as_ref().unwrap(), true, None, "black", &args); if res.is_err() && show_diff { eprintln!("\npython formatting does not match! Printing diff:"); args.insert(0, "--diff".as_ref()); - let _ = py_runner(py_path.as_ref().unwrap(), "black", &args); + let _ = py_runner(py_path.as_ref().unwrap(), true, None, "black", &args); + } + // Rethrow error + let _ = res?; + } + + if cpp_fmt { + let mut cfg_args_clang_format = cfg_args.clone(); + let mut file_args_clang_format = file_args.clone(); + let config_path = root_path.join(".clang-format"); + let config_file_arg = format!("file:{}", config_path.display()); + cfg_args_clang_format.extend(&["--style".as_ref(), config_file_arg.as_ref()]); + if bless { + eprintln!("formatting C++ files"); + cfg_args_clang_format.push("-i".as_ref()); + } else { + eprintln!("checking C++ file formatting"); + cfg_args_clang_format.extend(&["--dry-run".as_ref(), "--Werror".as_ref()]); + } + let files; + if file_args_clang_format.is_empty() { + let llvm_wrapper = root_path.join("compiler/rustc_llvm/llvm-wrapper"); + files = find_with_extension( + root_path, + Some(llvm_wrapper.as_path()), + &[OsStr::new("h"), OsStr::new("cpp")], + )?; + file_args_clang_format.extend(files.iter().map(|p| p.as_os_str())); + } + let args = merge_args(&cfg_args_clang_format, &file_args_clang_format); + let res = py_runner(py_path.as_ref().unwrap(), false, None, "clang-format", &args); + + if res.is_err() && show_diff { + eprintln!("\nclang-format linting failed! Printing diff suggestions:"); + + let mut cfg_args_clang_format_diff = cfg_args.clone(); + cfg_args_clang_format_diff.extend(&["--style".as_ref(), config_file_arg.as_ref()]); + for file in file_args_clang_format { + let mut formatted = String::new(); + let mut diff_args = cfg_args_clang_format_diff.clone(); + diff_args.push(file); + let _ = py_runner( + py_path.as_ref().unwrap(), + false, + Some(&mut formatted), + "clang-format", + &diff_args, + ); + if formatted.is_empty() { + eprintln!( + "failed to obtain the formatted content for '{}'", + file.to_string_lossy() + ); + continue; + } + let actual = std::fs::read_to_string(file).unwrap_or_else(|e| { + panic!( + "failed to read the C++ file at '{}' due to '{e}'", + file.to_string_lossy() + ) + }); + if formatted != actual { + let diff = similar::TextDiff::from_lines(&actual, &formatted); + eprintln!( + "{}", + diff.unified_diff().context_radius(4).header( + &format!("{} (actual)", file.to_string_lossy()), + &format!("{} (formatted)", file.to_string_lossy()) + ) + ); + } + } } // Rethrow error let _ = res?; @@ -162,7 +235,7 @@ fn check_impl( let mut file_args_shc = file_args.clone(); let files; if file_args_shc.is_empty() { - files = find_with_extension(root_path, "sh")?; + files = find_with_extension(root_path, None, &[OsStr::new("sh")])?; file_args_shc.extend(files.iter().map(|p| p.as_os_str())); } @@ -181,8 +254,31 @@ fn merge_args<'a>(cfg_args: &[&'a OsStr], file_args: &[&'a OsStr]) -> Vec<&'a Os } /// Run a python command with given arguments. `py_path` should be a virtualenv. -fn py_runner(py_path: &Path, bin: &'static str, args: &[&OsStr]) -> Result<(), Error> { - let status = Command::new(py_path).arg("-m").arg(bin).args(args).status()?; +/// +/// Captures `stdout` to a string if provided, otherwise prints the output. +fn py_runner( + py_path: &Path, + as_module: bool, + stdout: Option<&mut String>, + bin: &'static str, + args: &[&OsStr], +) -> Result<(), Error> { + let mut cmd = Command::new(py_path); + if as_module { + cmd.arg("-m").arg(bin).args(args); + } else { + let bin_path = py_path.with_file_name(bin); + cmd.arg(bin_path).args(args); + } + let status = if let Some(stdout) = stdout { + let output = cmd.output()?; + if let Ok(s) = std::str::from_utf8(&output.stdout) { + stdout.push_str(s); + } + output.status + } else { + cmd.status()? + }; if status.success() { Ok(()) } else { Err(Error::FailedCheck(bin)) } } @@ -268,11 +364,10 @@ fn create_venv_at_path(path: &Path) -> Result<(), Error> { let stderr = String::from_utf8_lossy(&out.stderr); let err = if stderr.contains("No module named virtualenv") { - Error::Generic( + Error::Generic(format!( "virtualenv not found: you may need to install it \ - (`python3 -m pip install venv`)" - .to_owned(), - ) + (`{sys_py} -m pip install virtualenv`)" + )) } else { Error::Generic(format!( "failed to create venv at '{}' using {sys_py}: {stderr}", @@ -357,7 +452,11 @@ fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> { } /// Check git for tracked files matching an extension -fn find_with_extension(root_path: &Path, extension: &str) -> Result<Vec<PathBuf>, Error> { +fn find_with_extension( + root_path: &Path, + find_dir: Option<&Path>, + extensions: &[&OsStr], +) -> Result<Vec<PathBuf>, Error> { // Untracked files show up for short status and are indicated with a leading `?` // -C changes git to be as if run from that directory let stat_output = @@ -368,15 +467,25 @@ fn find_with_extension(root_path: &Path, extension: &str) -> Result<Vec<PathBuf> } let mut output = Vec::new(); - let binding = Command::new("git").arg("-C").arg(root_path).args(["ls-files"]).output()?; + let binding = { + let mut command = Command::new("git"); + command.arg("-C").arg(root_path).args(["ls-files"]); + if let Some(find_dir) = find_dir { + command.arg(find_dir); + } + command.output()? + }; let tracked = String::from_utf8_lossy(&binding.stdout); for line in tracked.lines() { let line = line.trim(); let path = Path::new(line); - if path.extension() == Some(OsStr::new(extension)) { - output.push(path.to_owned()); + let Some(ref extension) = path.extension() else { + continue; + }; + if extensions.contains(extension) { + output.push(root_path.join(path)); } } diff --git a/tests/codegen/patchable-function-entry/patchable-function-entry-both-flags.rs b/tests/codegen/patchable-function-entry/patchable-function-entry-both-flags.rs new file mode 100644 index 00000000000..72204c78a49 --- /dev/null +++ b/tests/codegen/patchable-function-entry/patchable-function-entry-both-flags.rs @@ -0,0 +1,64 @@ +//@ compile-flags: -Z patchable-function-entry=15,10 + +#![feature(patchable_function_entry)] +#![crate_type = "lib"] + +// This should have the default, as set by the compile flags +#[no_mangle] +pub fn fun0() {} + +// The attribute should override the compile flags +#[no_mangle] +#[patchable_function_entry(prefix_nops = 1, entry_nops = 2)] +pub fn fun1() {} + +// If we override an attribute to 0 or unset, the attribute should go away +#[no_mangle] +#[patchable_function_entry(entry_nops = 0)] +pub fn fun2() {} + +// The attribute should override the compile flags +#[no_mangle] +#[patchable_function_entry(prefix_nops = 20, entry_nops = 1)] +pub fn fun3() {} + +// The attribute should override the compile flags +#[no_mangle] +#[patchable_function_entry(prefix_nops = 2, entry_nops = 19)] +pub fn fun4() {} + +// The attribute should override patchable-function-entry to 3 and +// patchable-function-prefix to the default of 0, clearing it entirely +#[no_mangle] +#[patchable_function_entry(entry_nops = 3)] +pub fn fun5() {} + +// The attribute should override patchable-function-prefix to 4 +// and patchable-function-entry to the default of 0, clearing it entirely +#[no_mangle] +#[patchable_function_entry(prefix_nops = 4)] +pub fn fun6() {} + +// CHECK: @fun0() unnamed_addr #0 +// CHECK: @fun1() unnamed_addr #1 +// CHECK: @fun2() unnamed_addr #2 +// CHECK: @fun3() unnamed_addr #3 +// CHECK: @fun4() unnamed_addr #4 +// CHECK: @fun5() unnamed_addr #5 +// CHECK: @fun6() unnamed_addr #6 + +// CHECK: attributes #0 = { {{.*}}"patchable-function-entry"="5"{{.*}}"patchable-function-prefix"="10" {{.*}} } +// CHECK: attributes #1 = { {{.*}}"patchable-function-entry"="2"{{.*}}"patchable-function-prefix"="1" {{.*}} } + +// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-entry{{.*}} } +// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-prefix{{.*}} } +// CHECK: attributes #2 = { {{.*}} } + +// CHECK: attributes #3 = { {{.*}}"patchable-function-entry"="1"{{.*}}"patchable-function-prefix"="20" {{.*}} } +// CHECK: attributes #4 = { {{.*}}"patchable-function-entry"="19"{{.*}}"patchable-function-prefix"="2" {{.*}} } + +// CHECK: attributes #5 = { {{.*}}"patchable-function-entry"="3"{{.*}} } +// CHECK-NOT: attributes #5 = { {{.*}}patchable-function-prefix{{.*}} } + +// CHECK: attributes #6 = { {{.*}}"patchable-function-prefix"="4"{{.*}} } +// CHECK-NOT: attributes #6 = { {{.*}}patchable-function-entry{{.*}} } diff --git a/tests/codegen/patchable-function-entry/patchable-function-entry-no-flag.rs b/tests/codegen/patchable-function-entry/patchable-function-entry-no-flag.rs new file mode 100644 index 00000000000..3a7078fe551 --- /dev/null +++ b/tests/codegen/patchable-function-entry/patchable-function-entry-no-flag.rs @@ -0,0 +1,39 @@ +#![feature(patchable_function_entry)] +#![crate_type = "lib"] + +// No patchable function entry should be set +#[no_mangle] +pub fn fun0() {} + +// The attribute should work even without compiler flags +#[no_mangle] +#[patchable_function_entry(prefix_nops = 1, entry_nops = 2)] +pub fn fun1() {} + +// The attribute should work even without compiler flags +// and only set patchable-function-entry to 3. +#[no_mangle] +#[patchable_function_entry(entry_nops = 3)] +pub fn fun2() {} + +// The attribute should work even without compiler flags +// and only set patchable-function-prefix to 4. +#[no_mangle] +#[patchable_function_entry(prefix_nops = 4)] +pub fn fun3() {} + +// CHECK: @fun0() unnamed_addr #0 +// CHECK: @fun1() unnamed_addr #1 +// CHECK: @fun2() unnamed_addr #2 +// CHECK: @fun3() unnamed_addr #3 + +// CHECK-NOT: attributes #0 = { {{.*}}patchable-function-entry{{.*}} } +// CHECK-NOT: attributes #0 = { {{.*}}patchable-function-prefix{{.*}} } + +// CHECK: attributes #1 = { {{.*}}"patchable-function-entry"="2"{{.*}}"patchable-function-prefix"="1" {{.*}} } + +// CHECK: attributes #2 = { {{.*}}"patchable-function-entry"="3"{{.*}} } +// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-prefix{{.*}} } + +// CHECK: attributes #3 = { {{.*}}"patchable-function-prefix"="4"{{.*}} } +// CHECK-NOT: attributes #3 = { {{.*}}patchable-function-entry{{.*}} } diff --git a/tests/codegen/patchable-function-entry/patchable-function-entry-one-flag.rs b/tests/codegen/patchable-function-entry/patchable-function-entry-one-flag.rs new file mode 100644 index 00000000000..8bdd61e461b --- /dev/null +++ b/tests/codegen/patchable-function-entry/patchable-function-entry-one-flag.rs @@ -0,0 +1,66 @@ +//@ compile-flags: -Z patchable-function-entry=15 + +#![feature(patchable_function_entry)] +#![crate_type = "lib"] + +// This should have the default, as set by the compile flags +#[no_mangle] +pub fn fun0() {} + +// The attribute should override the compile flags +#[no_mangle] +#[patchable_function_entry(prefix_nops = 1, entry_nops = 2)] +pub fn fun1() {} + +// If we override an attribute to 0 or unset, the attribute should go away +#[no_mangle] +#[patchable_function_entry(entry_nops = 0)] +pub fn fun2() {} + +// The attribute should override the compile flags +#[no_mangle] +#[patchable_function_entry(prefix_nops = 20, entry_nops = 1)] +pub fn fun3() {} + +// The attribute should override the compile flags +#[no_mangle] +#[patchable_function_entry(prefix_nops = 2, entry_nops = 19)] +pub fn fun4() {} + +// The attribute should override patchable-function-entry to 3 +// and patchable-function-prefix to the default of 0, clearing it entirely +#[no_mangle] +#[patchable_function_entry(entry_nops = 3)] +pub fn fun5() {} + +// The attribute should override patchable-function-prefix to 4 +// and patchable-function-entry to the default of 0, clearing it entirely +#[no_mangle] +#[patchable_function_entry(prefix_nops = 4)] +pub fn fun6() {} + +// CHECK: @fun0() unnamed_addr #0 +// CHECK: @fun1() unnamed_addr #1 +// CHECK: @fun2() unnamed_addr #2 +// CHECK: @fun3() unnamed_addr #3 +// CHECK: @fun4() unnamed_addr #4 +// CHECK: @fun5() unnamed_addr #5 +// CHECK: @fun6() unnamed_addr #6 + +// CHECK: attributes #0 = { {{.*}}"patchable-function-entry"="15" {{.*}} } +// CHECK-NOT: attributes #0 = { {{.*}}patchable-function-prefix{{.*}} } + +// CHECK: attributes #1 = { {{.*}}"patchable-function-entry"="2"{{.*}}"patchable-function-prefix"="1" {{.*}} } + +// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-entry{{.*}} } +// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-prefix{{.*}} } +// CHECK: attributes #2 = { {{.*}} } + +// CHECK: attributes #3 = { {{.*}}"patchable-function-entry"="1"{{.*}}"patchable-function-prefix"="20" {{.*}} } +// CHECK: attributes #4 = { {{.*}}"patchable-function-entry"="19"{{.*}}"patchable-function-prefix"="2" {{.*}} } + +// CHECK: attributes #5 = { {{.*}}"patchable-function-entry"="3"{{.*}} } +// CHECK-NOT: attributes #5 = { {{.*}}patchable-function-prefix{{.*}} } + +// CHECK: attributes #6 = { {{.*}}"patchable-function-prefix"="4"{{.*}} } +// CHECK-NOT: attributes #6 = { {{.*}}patchable-function-entry{{.*}} } diff --git a/tests/coverage/attr/impl.cov-map b/tests/coverage/attr/impl.cov-map new file mode 100644 index 00000000000..9b0deed8b64 --- /dev/null +++ b/tests/coverage/attr/impl.cov-map @@ -0,0 +1,24 @@ +Function name: <impl::MyStruct>::off_on (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 0e, 05, 00, 13] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 14, 5) to (start + 0, 19) + +Function name: <impl::MyStruct>::on_inherit (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 16, 05, 00, 17] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 22, 5) to (start + 0, 23) + +Function name: <impl::MyStruct>::on_on (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 05, 00, 12] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 25, 5) to (start + 0, 18) + diff --git a/tests/coverage/attr/impl.coverage b/tests/coverage/attr/impl.coverage new file mode 100644 index 00000000000..560429fb5fe --- /dev/null +++ b/tests/coverage/attr/impl.coverage @@ -0,0 +1,42 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2021 + LL| | + LL| |// Checks that `#[coverage(..)]` can be applied to impl and impl-trait blocks, + LL| |// and is inherited by any enclosed functions. + LL| | + LL| |struct MyStruct; + LL| | + LL| |#[coverage(off)] + LL| |impl MyStruct { + LL| | fn off_inherit() {} + LL| | + LL| | #[coverage(on)] + LL| 0| fn off_on() {} + LL| | + LL| | #[coverage(off)] + LL| | fn off_off() {} + LL| |} + LL| | + LL| |#[coverage(on)] + LL| |impl MyStruct { + LL| 0| fn on_inherit() {} + LL| | + LL| | #[coverage(on)] + LL| 0| fn on_on() {} + LL| | + LL| | #[coverage(off)] + LL| | fn on_off() {} + LL| |} + LL| | + LL| |trait MyTrait { + LL| | fn method(); + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |impl MyTrait for MyStruct { + LL| | fn method() {} + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn main() {} + diff --git a/tests/coverage/attr/impl.rs b/tests/coverage/attr/impl.rs new file mode 100644 index 00000000000..d4d784a3502 --- /dev/null +++ b/tests/coverage/attr/impl.rs @@ -0,0 +1,41 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 + +// Checks that `#[coverage(..)]` can be applied to impl and impl-trait blocks, +// and is inherited by any enclosed functions. + +struct MyStruct; + +#[coverage(off)] +impl MyStruct { + fn off_inherit() {} + + #[coverage(on)] + fn off_on() {} + + #[coverage(off)] + fn off_off() {} +} + +#[coverage(on)] +impl MyStruct { + fn on_inherit() {} + + #[coverage(on)] + fn on_on() {} + + #[coverage(off)] + fn on_off() {} +} + +trait MyTrait { + fn method(); +} + +#[coverage(off)] +impl MyTrait for MyStruct { + fn method() {} +} + +#[coverage(off)] +fn main() {} diff --git a/tests/coverage/attr/module.cov-map b/tests/coverage/attr/module.cov-map new file mode 100644 index 00000000000..34898eb4ca8 --- /dev/null +++ b/tests/coverage/attr/module.cov-map @@ -0,0 +1,24 @@ +Function name: module::off::on (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 0c, 05, 00, 0f] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 12, 5) to (start + 0, 15) + +Function name: module::on::inherit (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 14, 05, 00, 14] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 20, 5) to (start + 0, 20) + +Function name: module::on::on (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 17, 05, 00, 0f] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 23, 5) to (start + 0, 15) + diff --git a/tests/coverage/attr/module.coverage b/tests/coverage/attr/module.coverage new file mode 100644 index 00000000000..c1b9f0e35c0 --- /dev/null +++ b/tests/coverage/attr/module.coverage @@ -0,0 +1,38 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2021 + LL| | + LL| |// Checks that `#[coverage(..)]` can be applied to modules, and is inherited + LL| |// by any enclosed functions. + LL| | + LL| |#[coverage(off)] + LL| |mod off { + LL| | fn inherit() {} + LL| | + LL| | #[coverage(on)] + LL| 0| fn on() {} + LL| | + LL| | #[coverage(off)] + LL| | fn off() {} + LL| |} + LL| | + LL| |#[coverage(on)] + LL| |mod on { + LL| 0| fn inherit() {} + LL| | + LL| | #[coverage(on)] + LL| 0| fn on() {} + LL| | + LL| | #[coverage(off)] + LL| | fn off() {} + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |mod nested_a { + LL| | mod nested_b { + LL| | fn inner() {} + LL| | } + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn main() {} + diff --git a/tests/coverage/attr/module.rs b/tests/coverage/attr/module.rs new file mode 100644 index 00000000000..4bfb1e7729b --- /dev/null +++ b/tests/coverage/attr/module.rs @@ -0,0 +1,37 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 + +// Checks that `#[coverage(..)]` can be applied to modules, and is inherited +// by any enclosed functions. + +#[coverage(off)] +mod off { + fn inherit() {} + + #[coverage(on)] + fn on() {} + + #[coverage(off)] + fn off() {} +} + +#[coverage(on)] +mod on { + fn inherit() {} + + #[coverage(on)] + fn on() {} + + #[coverage(off)] + fn off() {} +} + +#[coverage(off)] +mod nested_a { + mod nested_b { + fn inner() {} + } +} + +#[coverage(off)] +fn main() {} diff --git a/tests/coverage/attr/nested.cov-map b/tests/coverage/attr/nested.cov-map index a613bb7f8cd..0f2d5542f75 100644 --- a/tests/coverage/attr/nested.cov-map +++ b/tests/coverage/attr/nested.cov-map @@ -1,35 +1,3 @@ -Function name: <<<nested::MyOuter as nested::MyTrait>::trait_method::MyMiddle as nested::MyTrait>::trait_method::MyInner as nested::MyTrait>::trait_method (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 39, 15, 02, 16] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 57, 21) to (start + 2, 22) - -Function name: <<<nested::MyOuter>::outer_method::MyMiddle>::middle_method::MyInner>::inner_method (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 23, 15, 02, 16] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 35, 21) to (start + 2, 22) - -Function name: <<nested::MyOuter as nested::MyTrait>::trait_method::MyMiddle as nested::MyTrait>::trait_method (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 36, 0d, 08, 0e] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 54, 13) to (start + 8, 14) - -Function name: <<nested::MyOuter>::outer_method::MyMiddle>::middle_method (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 20, 0d, 08, 0e] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 32, 13) to (start + 8, 14) - Function name: nested::closure_expr Raw bytes (14): 0x[01, 01, 00, 02, 01, 44, 01, 01, 0f, 01, 0b, 05, 01, 02] Number of files: 1 @@ -39,23 +7,6 @@ Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 68, 1) to (start + 1, 15) - Code(Counter(0)) at (prev + 11, 5) to (start + 1, 2) -Function name: nested::closure_expr::{closure#0}::{closure#0} (unused) -Raw bytes (14): 0x[01, 01, 00, 02, 00, 47, 1a, 01, 17, 00, 04, 0d, 01, 0a] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Zero) at (prev + 71, 26) to (start + 1, 23) -- Code(Zero) at (prev + 4, 13) to (start + 1, 10) - -Function name: nested::closure_expr::{closure#0}::{closure#0}::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 48, 1d, 02, 0e] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 72, 29) to (start + 2, 14) - Function name: nested::closure_tail Raw bytes (14): 0x[01, 01, 00, 02, 01, 53, 01, 01, 0f, 01, 11, 05, 01, 02] Number of files: 1 @@ -65,36 +16,3 @@ Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 83, 1) to (start + 1, 15) - Code(Counter(0)) at (prev + 17, 5) to (start + 1, 2) -Function name: nested::closure_tail::{closure#0}::{closure#0} (unused) -Raw bytes (14): 0x[01, 01, 00, 02, 00, 58, 14, 01, 1f, 00, 06, 15, 01, 12] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Zero) at (prev + 88, 20) to (start + 1, 31) -- Code(Zero) at (prev + 6, 21) to (start + 1, 18) - -Function name: nested::closure_tail::{closure#0}::{closure#0}::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 5a, 1c, 02, 1a] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 90, 28) to (start + 2, 26) - -Function name: nested::outer_fn::middle_fn (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 11, 05, 05, 06] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 17, 5) to (start + 5, 6) - -Function name: nested::outer_fn::middle_fn::inner_fn (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 12, 09, 02, 0a] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 18, 9) to (start + 2, 10) - diff --git a/tests/coverage/attr/nested.coverage b/tests/coverage/attr/nested.coverage index 13129572aec..bdd117b7dfa 100644 --- a/tests/coverage/attr/nested.coverage +++ b/tests/coverage/attr/nested.coverage @@ -14,12 +14,12 @@ LL| | LL| |#[coverage(off)] LL| |fn outer_fn() { - LL| 0| fn middle_fn() { - LL| 0| fn inner_fn() { - LL| 0| do_stuff(); - LL| 0| } - LL| 0| do_stuff(); - LL| 0| } + LL| | fn middle_fn() { + LL| | fn inner_fn() { + LL| | do_stuff(); + LL| | } + LL| | do_stuff(); + LL| | } LL| | do_stuff(); LL| |} LL| | @@ -29,15 +29,15 @@ LL| | fn outer_method(&self) { LL| | struct MyMiddle; LL| | impl MyMiddle { - LL| 0| fn middle_method(&self) { - LL| 0| struct MyInner; - LL| 0| impl MyInner { - LL| 0| fn inner_method(&self) { - LL| 0| do_stuff(); - LL| 0| } - LL| 0| } - LL| 0| do_stuff(); - LL| 0| } + LL| | fn middle_method(&self) { + LL| | struct MyInner; + LL| | impl MyInner { + LL| | fn inner_method(&self) { + LL| | do_stuff(); + LL| | } + LL| | } + LL| | do_stuff(); + LL| | } LL| | } LL| | do_stuff(); LL| | } @@ -51,15 +51,15 @@ LL| | fn trait_method(&self) { LL| | struct MyMiddle; LL| | impl MyTrait for MyMiddle { - LL| 0| fn trait_method(&self) { - LL| 0| struct MyInner; - LL| 0| impl MyTrait for MyInner { - LL| 0| fn trait_method(&self) { - LL| 0| do_stuff(); - LL| 0| } - LL| 0| } - LL| 0| do_stuff(); - LL| 0| } + LL| | fn trait_method(&self) { + LL| | struct MyInner; + LL| | impl MyTrait for MyInner { + LL| | fn trait_method(&self) { + LL| | do_stuff(); + LL| | } + LL| | } + LL| | do_stuff(); + LL| | } LL| | } LL| | do_stuff(); LL| | } @@ -68,12 +68,12 @@ LL| 1|fn closure_expr() { LL| 1| let _outer = #[coverage(off)] LL| | || { - LL| 0| let _middle = || { - LL| 0| let _inner = || { - LL| 0| do_stuff(); - LL| 0| }; - LL| 0| do_stuff(); - LL| 0| }; + LL| | let _middle = || { + LL| | let _inner = || { + LL| | do_stuff(); + LL| | }; + LL| | do_stuff(); + LL| | }; LL| | do_stuff(); LL| | }; LL| 1| do_stuff(); @@ -85,14 +85,14 @@ LL| | #[coverage(off)] LL| | || { LL| | let _middle = { - LL| 0| || { - LL| 0| let _inner = { - LL| 0| || { - LL| 0| do_stuff(); - LL| 0| } + LL| | || { + LL| | let _inner = { + LL| | || { + LL| | do_stuff(); + LL| | } LL| | }; - LL| 0| do_stuff(); - LL| 0| } + LL| | do_stuff(); + LL| | } LL| | }; LL| | do_stuff(); LL| | } diff --git a/tests/coverage/attr/off-on-sandwich.cov-map b/tests/coverage/attr/off-on-sandwich.cov-map index 72b96420cb5..ed77d7d17e6 100644 --- a/tests/coverage/attr/off-on-sandwich.cov-map +++ b/tests/coverage/attr/off-on-sandwich.cov-map @@ -6,14 +6,6 @@ Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 20, 5) to (start + 7, 6) -Function name: off_on_sandwich::sparse_a::sparse_b -Raw bytes (9): 0x[01, 01, 00, 01, 01, 22, 05, 10, 06] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 34, 5) to (start + 16, 6) - Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c Raw bytes (9): 0x[01, 01, 00, 01, 01, 26, 09, 0b, 0a] Number of files: 1 diff --git a/tests/coverage/attr/off-on-sandwich.coverage b/tests/coverage/attr/off-on-sandwich.coverage index e831b0e926e..58c128b8342 100644 --- a/tests/coverage/attr/off-on-sandwich.coverage +++ b/tests/coverage/attr/off-on-sandwich.coverage @@ -31,10 +31,10 @@ LL| |fn sparse_a() { LL| | sparse_b(); LL| | sparse_b(); - LL| 2| fn sparse_b() { - LL| 2| sparse_c(); - LL| 2| sparse_c(); - LL| 2| #[coverage(on)] + LL| | fn sparse_b() { + LL| | sparse_c(); + LL| | sparse_c(); + LL| | #[coverage(on)] LL| 4| fn sparse_c() { LL| 4| sparse_d(); LL| 4| sparse_d(); @@ -47,7 +47,7 @@ LL| 8| } LL| 8| } LL| 4| } - LL| 2| } + LL| | } LL| |} LL| | LL| |#[coverage(off)] diff --git a/tests/coverage/issue-83601.cov-map b/tests/coverage/issue-83601.cov-map index ddb4407881a..f2447e3c92c 100644 --- a/tests/coverage/issue-83601.cov-map +++ b/tests/coverage/issue-83601.cov-map @@ -1,12 +1,12 @@ Function name: issue_83601::main -Raw bytes (21): 0x[01, 01, 01, 05, 00, 03, 01, 06, 01, 02, 1c, 05, 03, 09, 01, 1c, 02, 02, 05, 03, 02] +Raw bytes (21): 0x[01, 01, 01, 05, 09, 03, 01, 06, 01, 02, 1c, 05, 03, 09, 01, 1c, 02, 02, 05, 03, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 -- expression 0 operands: lhs = Counter(1), rhs = Zero +- expression 0 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 6, 1) to (start + 2, 28) - Code(Counter(1)) at (prev + 3, 9) to (start + 1, 28) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 3, 2) - = (c1 - Zero) + = (c1 - c2) diff --git a/tests/coverage/issue-84561.cov-map b/tests/coverage/issue-84561.cov-map index c4087d9369d..d3c4671e0ba 100644 --- a/tests/coverage/issue-84561.cov-map +++ b/tests/coverage/issue-84561.cov-map @@ -54,15 +54,15 @@ Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 167, 9) to (start + 2, 10) Function name: issue_84561::test3 -Raw bytes (375): 0x[01, 01, 31, 05, 00, 0d, 00, 15, 00, 12, 00, 15, 00, 21, 00, 1e, 00, 21, 00, 31, 00, 3d, 00, 2e, 45, 3d, 00, 42, 49, 45, 00, 3f, 51, 42, 49, 45, 00, 7a, 55, 51, 00, 7a, 55, 51, 00, 77, 5d, 7a, 55, 51, 00, 77, 61, 7a, 55, 51, 00, 72, 65, 77, 61, 7a, 55, 51, 00, 75, be, 01, c2, 01, 79, 69, 6d, 69, 6d, 69, 6d, c2, 01, 00, 69, 6d, c2, 01, 79, 69, 6d, bb, 01, 7d, 75, be, 01, c2, 01, 79, 69, 6d, b6, 01, 00, bb, 01, 7d, 75, be, 01, c2, 01, 79, 69, 6d, 33, 01, 08, 01, 03, 1c, 05, 04, 09, 01, 1c, 02, 02, 05, 04, 1f, 0d, 05, 05, 00, 1f, 06, 01, 05, 00, 1f, 15, 01, 09, 01, 1c, 12, 02, 05, 00, 1f, 0e, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 1e, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 1a, 04, 09, 05, 06, 31, 06, 05, 03, 06, 22, 04, 05, 03, 06, 3d, 04, 09, 04, 06, 2e, 05, 08, 00, 0f, 45, 01, 09, 03, 0a, 2a, 05, 09, 03, 0a, 3f, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 3a, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 77, 03, 05, 00, 0f, 77, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 56, 02, 0d, 00, 13, 72, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 6e, 02, 0d, 00, 13, bb, 01, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 03, 0e, 75, 04, 0d, 00, 13, c2, 01, 02, 0d, 00, 17, c2, 01, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 92, 01, 02, 15, 00, 1b, be, 01, 04, 0d, 00, 13, 7d, 03, 09, 00, 19, b6, 01, 02, 05, 00, 0f, b2, 01, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02] +Raw bytes (375): 0x[01, 01, 31, 05, 09, 0d, 00, 15, 19, 12, 00, 15, 19, 21, 00, 1e, 00, 21, 00, 31, 00, 3d, 00, 2e, 45, 3d, 00, 42, 49, 45, 00, 3f, 51, 42, 49, 45, 00, 7a, 55, 51, 00, 7a, 55, 51, 00, 77, 5d, 7a, 55, 51, 00, 77, 61, 7a, 55, 51, 00, 72, 65, 77, 61, 7a, 55, 51, 00, 75, be, 01, c2, 01, 79, 69, 6d, 69, 6d, 69, 6d, c2, 01, 00, 69, 6d, c2, 01, 79, 69, 6d, bb, 01, 7d, 75, be, 01, c2, 01, 79, 69, 6d, b6, 01, 00, bb, 01, 7d, 75, be, 01, c2, 01, 79, 69, 6d, 33, 01, 08, 01, 03, 1c, 05, 04, 09, 01, 1c, 02, 02, 05, 04, 1f, 0d, 05, 05, 00, 1f, 06, 01, 05, 00, 1f, 15, 01, 09, 01, 1c, 12, 02, 05, 00, 1f, 0e, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 1e, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 1a, 04, 09, 05, 06, 31, 06, 05, 03, 06, 22, 04, 05, 03, 06, 3d, 04, 09, 04, 06, 2e, 05, 08, 00, 0f, 45, 01, 09, 03, 0a, 2a, 05, 09, 03, 0a, 3f, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 3a, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 77, 03, 05, 00, 0f, 77, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 56, 02, 0d, 00, 13, 72, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 6e, 02, 0d, 00, 13, bb, 01, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 03, 0e, 75, 04, 0d, 00, 13, c2, 01, 02, 0d, 00, 17, c2, 01, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 92, 01, 02, 15, 00, 1b, be, 01, 04, 0d, 00, 13, 7d, 03, 09, 00, 19, b6, 01, 02, 05, 00, 0f, b2, 01, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 49 -- expression 0 operands: lhs = Counter(1), rhs = Zero +- expression 0 operands: lhs = Counter(1), rhs = Counter(2) - expression 1 operands: lhs = Counter(3), rhs = Zero -- expression 2 operands: lhs = Counter(5), rhs = Zero +- expression 2 operands: lhs = Counter(5), rhs = Counter(6) - expression 3 operands: lhs = Expression(4, Sub), rhs = Zero -- expression 4 operands: lhs = Counter(5), rhs = Zero +- expression 4 operands: lhs = Counter(5), rhs = Counter(6) - expression 5 operands: lhs = Counter(8), rhs = Zero - expression 6 operands: lhs = Expression(7, Sub), rhs = Zero - expression 7 operands: lhs = Counter(8), rhs = Zero @@ -111,15 +111,15 @@ Number of file 0 mappings: 51 - Code(Counter(0)) at (prev + 8, 1) to (start + 3, 28) - Code(Counter(1)) at (prev + 4, 9) to (start + 1, 28) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 4, 31) - = (c1 - Zero) + = (c1 - c2) - Code(Counter(3)) at (prev + 5, 5) to (start + 0, 31) - Code(Expression(1, Sub)) at (prev + 1, 5) to (start + 0, 31) = (c3 - Zero) - Code(Counter(5)) at (prev + 1, 9) to (start + 1, 28) - Code(Expression(4, Sub)) at (prev + 2, 5) to (start + 0, 31) - = (c5 - Zero) + = (c5 - c6) - Code(Expression(3, Sub)) at (prev + 1, 5) to (start + 0, 15) - = ((c5 - Zero) - Zero) + = ((c5 - c6) - Zero) - Code(Zero) at (prev + 0, 32) to (start + 0, 48) - Code(Counter(8)) at (prev + 1, 5) to (start + 3, 15) - Code(Zero) at (prev + 3, 32) to (start + 0, 48) diff --git a/tests/coverage/no_cov_crate.cov-map b/tests/coverage/no_cov_crate.cov-map index e623f6480b9..281efb6d00d 100644 --- a/tests/coverage/no_cov_crate.cov-map +++ b/tests/coverage/no_cov_crate.cov-map @@ -59,16 +59,3 @@ Number of file 0 mappings: 4 = (c0 - c1) - Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) -Function name: no_cov_crate::nested_fns::outer_not_covered::inner -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 26, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 1 -- expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 38, 9) to (start + 1, 23) -- Code(Counter(1)) at (prev + 1, 24) to (start + 2, 14) -- Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14) - = (c0 - c1) -- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) - diff --git a/tests/coverage/no_cov_crate.coverage b/tests/coverage/no_cov_crate.coverage index f5a0322bf3e..29ad1f979cf 100644 --- a/tests/coverage/no_cov_crate.coverage +++ b/tests/coverage/no_cov_crate.coverage @@ -35,13 +35,13 @@ LL| |mod nested_fns { LL| | #[coverage(off)] LL| | pub fn outer_not_covered(is_true: bool) { - LL| 1| fn inner(is_true: bool) { - LL| 1| if is_true { - LL| 1| println!("called and covered"); - LL| 1| } else { - LL| 0| println!("absolutely not covered"); - LL| 0| } - LL| 1| } + LL| | fn inner(is_true: bool) { + LL| | if is_true { + LL| | println!("called and covered"); + LL| | } else { + LL| | println!("absolutely not covered"); + LL| | } + LL| | } LL| | println!("called but not covered"); LL| | inner(is_true); LL| | } diff --git a/tests/crashes/119717.rs b/tests/crashes/119717.rs deleted file mode 100644 index 22746548e02..00000000000 --- a/tests/crashes/119717.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: #119717 -#![feature(const_trait_impl, effects)] - -use std::ops::{FromResidual, Try}; - -impl const FromResidual for T { - fn from_residual(t: T) -> _ { - t - } -} diff --git a/tests/crashes/123664.rs b/tests/crashes/123664.rs deleted file mode 100644 index 80c415fe07b..00000000000 --- a/tests/crashes/123664.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ known-bug: #123664 -#![feature(generic_const_exprs, effects)] -const fn with_positive<F: ~const Fn()>() {} -pub fn main() {} diff --git a/tests/crashes/124857.rs b/tests/crashes/124857.rs deleted file mode 100644 index 4b952fd64cc..00000000000 --- a/tests/crashes/124857.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: rust-lang/rust#124857 -//@ compile-flags: -Znext-solver=coherence - -#![feature(effects)] - -#[const_trait] -trait Foo {} - -impl const Foo for i32 {} - -impl<T> const Foo for T where T: ~const Foo {} diff --git a/tests/crashes/126148.rs b/tests/crashes/126148.rs deleted file mode 100644 index 79f8887b401..00000000000 --- a/tests/crashes/126148.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ known-bug: rust-lang/rust#126148 - -#![feature(effects)] -use std::ops::{FromResidual, Try}; - -struct TryMe; -struct Error; - -impl const FromResidual<Error> for TryMe {} - -impl const Try for TryMe { - type Output = (); - type Residual = Error; -} - -const fn t() -> TryMe { - TryMe?; - TryMe -} - -const _: () = { - t(); -}; diff --git a/tests/crashes/126646.rs b/tests/crashes/126646.rs new file mode 100644 index 00000000000..24e3530320a --- /dev/null +++ b/tests/crashes/126646.rs @@ -0,0 +1,18 @@ +//@ known-bug: rust-lang/rust#126646 +mod foo { + pub trait Callable { + type Output; + fn call() -> Self::Output; + } + + impl<'a, V: ?Sized> Callable for &'a () { + type Output = (); + } +} +use foo::*; + +fn test<'a>() -> impl Sized { + <&'a () as Callable>::call() +} + +fn main() {} diff --git a/tests/crashes/126648.rs b/tests/crashes/126648.rs new file mode 100644 index 00000000000..1cf3e44bba9 --- /dev/null +++ b/tests/crashes/126648.rs @@ -0,0 +1,8 @@ +//@ known-bug: rust-lang/rust#126648 +struct Outest(*const &'a ()); + +fn make() -> Outest {} + +fn main() { + if let Outest("foo") = make() {} +} diff --git a/tests/crashes/126666.rs b/tests/crashes/126666.rs new file mode 100644 index 00000000000..58526707c9a --- /dev/null +++ b/tests/crashes/126666.rs @@ -0,0 +1,18 @@ +//@ known-bug: rust-lang/rust#126666 +#![feature(const_mut_refs)] +#![feature(const_refs_to_static)] +#![feature(object_safe_for_dispatch)] + +struct Meh { + x: &'static dyn UnsafeCell, +} + +const MUH: Meh = Meh { + x: &mut *(&READONLY as *const _ as *mut _), +}; + +static READONLY: i32 = 0; + +trait UnsafeCell<'a> {} + +pub fn main() {} diff --git a/tests/crashes/126667.rs b/tests/crashes/126667.rs new file mode 100644 index 00000000000..27b170d6da5 --- /dev/null +++ b/tests/crashes/126667.rs @@ -0,0 +1,14 @@ +//@ known-bug: rust-lang/rust#126667 +#![warn(rust_2021_compatibility)] + +trait Static<'a> {} + +struct Foo((u32, u32)); + +fn main() { + type T = impl Static; + let foo: T = Foo((1u32, 2u32)); + let x = move || { + let Foo((a, b)) = foo; + }; +} diff --git a/tests/crashes/126680.rs b/tests/crashes/126680.rs new file mode 100644 index 00000000000..b1566d5e6be --- /dev/null +++ b/tests/crashes/126680.rs @@ -0,0 +1,21 @@ +//@ known-bug: rust-lang/rust#126680 +//@ compile-flags: -Zvalidate-mir +#![feature(type_alias_impl_trait)] +type Bar = impl std::fmt::Display; + +use std::path::Path; + +struct A { + pub func: fn(check: Bar, b: Option<&Path>), +} +const MY_A: A = A { + func: |check, b| { + if check { + () + } else if let Some(_) = b.and_then(|p| p.parent()) { + () + } + }, +}; + +fn main() {} diff --git a/tests/crashes/126696.rs b/tests/crashes/126696.rs new file mode 100644 index 00000000000..51dcf6cf294 --- /dev/null +++ b/tests/crashes/126696.rs @@ -0,0 +1,24 @@ +//@ known-bug: rust-lang/rust#126696 +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +fn can_double<const N: usize>(x: [(); N]) +where + [(); N * 2]:, +{ + x[0]; + unimplemented!() +} + +fn foo<const N: usize>() +where + [(); (N + 1) * 2]:, +{ + can_double([(); { N + 1 }]); + // Adding an explicit constant generic causes the ICE to go away + // can_double::<{N + 1}>([(); { N + 1 }]); +} + +fn main() { + foo::<1>(); +} diff --git a/tests/crashes/126725.rs b/tests/crashes/126725.rs new file mode 100644 index 00000000000..d7a7d21ae42 --- /dev/null +++ b/tests/crashes/126725.rs @@ -0,0 +1,20 @@ +//@ known-bug: rust-lang/rust#126725 +trait Foo { + fn foo<'a>(&'a self) -> <&'a impl Sized as Bar>::Output; +} + +trait Bar { + type Output; +} + +struct X(i32); + +impl<'a> Bar for &'a X { + type Output = &'a i32; +} + +impl Foo for X { + fn foo<'a>(&'a self) -> <&'a Self as Bar>::Output { + &self.0 + } +} diff --git a/tests/crashes/126744.rs b/tests/crashes/126744.rs new file mode 100644 index 00000000000..ed562c86e61 --- /dev/null +++ b/tests/crashes/126744.rs @@ -0,0 +1,8 @@ +//@ known-bug: rust-lang/rust#126744 +struct X {,} + +fn main() { + || { + if let X { x: 1,} = (X {}) {} + }; +} diff --git a/tests/crashes/126850.rs b/tests/crashes/126850.rs new file mode 100644 index 00000000000..0ddc24c8bb1 --- /dev/null +++ b/tests/crashes/126850.rs @@ -0,0 +1,11 @@ +//@ known-bug: rust-lang/rust#126850 +fn bug<T>() -> impl Iterator< + Item = [(); { + |found: &String| Some(false); + 4 + }], +> { + std::iter::empty() +} + +fn main() {} diff --git a/tests/mir-opt/building/issue_101867.main.built.after.mir b/tests/mir-opt/building/issue_101867.main.built.after.mir index 0f7917dbb5c..5c50b3db5ca 100644 --- a/tests/mir-opt/building/issue_101867.main.built.after.mir +++ b/tests/mir-opt/building/issue_101867.main.built.after.mir @@ -27,13 +27,13 @@ fn main() -> () { StorageLive(_5); PlaceMention(_1); _6 = discriminant(_1); - switchInt(move _6) -> [1: bb6, otherwise: bb4]; + switchInt(move _6) -> [1: bb4, otherwise: bb3]; } bb1: { StorageLive(_3); StorageLive(_4); - _4 = begin_panic::<&str>(const "explicit panic") -> bb10; + _4 = begin_panic::<&str>(const "explicit panic") -> bb8; } bb2: { @@ -43,12 +43,11 @@ fn main() -> () { } bb3: { - FakeRead(ForMatchedPlace(None), _1); - unreachable; + goto -> bb7; } bb4: { - goto -> bb9; + falseEdge -> [real: bb6, imaginary: bb3]; } bb5: { @@ -56,14 +55,6 @@ fn main() -> () { } bb6: { - falseEdge -> [real: bb8, imaginary: bb4]; - } - - bb7: { - goto -> bb4; - } - - bb8: { _5 = ((_1 as Some).0: u8); _0 = const (); StorageDead(_5); @@ -71,12 +62,12 @@ fn main() -> () { return; } - bb9: { + bb7: { StorageDead(_5); goto -> bb1; } - bb10 (cleanup): { + bb8 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir b/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir index fd8eb370ca9..3e16efe6980 100644 --- a/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir +++ b/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir @@ -19,22 +19,21 @@ fn test_complex() -> () { bb0: { StorageLive(_1); StorageLive(_2); - _2 = E::f() -> [return: bb1, unwind: bb38]; + _2 = E::f() -> [return: bb1, unwind: bb34]; } bb1: { PlaceMention(_2); _3 = discriminant(_2); - switchInt(move _3) -> [0: bb5, otherwise: bb3]; + switchInt(move _3) -> [0: bb3, otherwise: bb2]; } bb2: { - FakeRead(ForMatchedPlace(None), _2); - unreachable; + goto -> bb21; } bb3: { - goto -> bb23; + falseEdge -> [real: bb5, imaginary: bb2]; } bb4: { @@ -42,175 +41,158 @@ fn test_complex() -> () { } bb5: { - falseEdge -> [real: bb7, imaginary: bb3]; + StorageLive(_4); + _4 = always_true() -> [return: bb6, unwind: bb34]; } bb6: { - goto -> bb3; + switchInt(move _4) -> [0: bb8, otherwise: bb7]; } bb7: { - StorageLive(_4); - _4 = always_true() -> [return: bb8, unwind: bb38]; - } - - bb8: { - switchInt(move _4) -> [0: bb10, otherwise: bb9]; - } - - bb9: { StorageLive(_5); StorageLive(_6); StorageLive(_7); _7 = Droppy(const 0_u8); _6 = (_7.0: u8); _5 = Gt(move _6, const 0_u8); - switchInt(move _5) -> [0: bb12, otherwise: bb11]; + switchInt(move _5) -> [0: bb10, otherwise: bb9]; } - bb10: { - goto -> bb16; + bb8: { + goto -> bb14; } - bb11: { - drop(_7) -> [return: bb13, unwind: bb38]; + bb9: { + drop(_7) -> [return: bb11, unwind: bb34]; } - bb12: { - goto -> bb14; + bb10: { + goto -> bb12; } - bb13: { + bb11: { StorageDead(_7); StorageDead(_6); - goto -> bb20; + goto -> bb18; } - bb14: { - drop(_7) -> [return: bb15, unwind: bb38]; + bb12: { + drop(_7) -> [return: bb13, unwind: bb34]; } - bb15: { + bb13: { StorageDead(_7); StorageDead(_6); - goto -> bb16; + goto -> bb14; } - bb16: { + bb14: { StorageLive(_8); StorageLive(_9); StorageLive(_10); _10 = Droppy(const 1_u8); _9 = (_10.0: u8); _8 = Gt(move _9, const 1_u8); - switchInt(move _8) -> [0: bb18, otherwise: bb17]; + switchInt(move _8) -> [0: bb16, otherwise: bb15]; } - bb17: { - drop(_10) -> [return: bb19, unwind: bb38]; + bb15: { + drop(_10) -> [return: bb17, unwind: bb34]; } - bb18: { - goto -> bb21; + bb16: { + goto -> bb19; } - bb19: { + bb17: { StorageDead(_10); StorageDead(_9); - goto -> bb20; + goto -> bb18; } - bb20: { + bb18: { _1 = const (); - goto -> bb24; + goto -> bb22; } - bb21: { - drop(_10) -> [return: bb22, unwind: bb38]; + bb19: { + drop(_10) -> [return: bb20, unwind: bb34]; } - bb22: { + bb20: { StorageDead(_10); StorageDead(_9); - goto -> bb23; + goto -> bb21; } - bb23: { + bb21: { _1 = const (); - goto -> bb24; + goto -> bb22; } - bb24: { + bb22: { StorageDead(_8); StorageDead(_5); StorageDead(_4); StorageDead(_2); StorageDead(_1); StorageLive(_11); - _11 = always_true() -> [return: bb25, unwind: bb38]; + _11 = always_true() -> [return: bb23, unwind: bb34]; } - bb25: { - switchInt(move _11) -> [0: bb27, otherwise: bb26]; + bb23: { + switchInt(move _11) -> [0: bb25, otherwise: bb24]; } - bb26: { - goto -> bb36; + bb24: { + goto -> bb32; } - bb27: { - goto -> bb28; + bb25: { + goto -> bb26; } - bb28: { + bb26: { StorageLive(_12); - _12 = E::f() -> [return: bb29, unwind: bb38]; + _12 = E::f() -> [return: bb27, unwind: bb34]; } - bb29: { + bb27: { PlaceMention(_12); _13 = discriminant(_12); - switchInt(move _13) -> [1: bb33, otherwise: bb31]; - } - - bb30: { - FakeRead(ForMatchedPlace(None), _12); - unreachable; + switchInt(move _13) -> [1: bb29, otherwise: bb28]; } - bb31: { - goto -> bb36; - } - - bb32: { - goto -> bb30; + bb28: { + goto -> bb32; } - bb33: { - falseEdge -> [real: bb35, imaginary: bb31]; + bb29: { + falseEdge -> [real: bb31, imaginary: bb28]; } - bb34: { - goto -> bb31; + bb30: { + goto -> bb28; } - bb35: { + bb31: { _0 = const (); - goto -> bb37; + goto -> bb33; } - bb36: { + bb32: { _0 = const (); - goto -> bb37; + goto -> bb33; } - bb37: { + bb33: { StorageDead(_11); StorageDead(_12); return; } - bb38 (cleanup): { + bb34 (cleanup): { resume; } } diff --git a/tests/run-make/debug-assertions/Makefile b/tests/run-make/debug-assertions/Makefile deleted file mode 100644 index 4501459e9d1..00000000000 --- a/tests/run-make/debug-assertions/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -# ignore-cross-compile -# needs-unwind -include ../tools.mk - -all: - $(RUSTC) debug.rs -C debug-assertions=no - $(call RUN,debug) good - $(RUSTC) debug.rs -C opt-level=0 - $(call RUN,debug) bad - $(RUSTC) debug.rs -C opt-level=1 - $(call RUN,debug) good - $(RUSTC) debug.rs -C opt-level=2 - $(call RUN,debug) good - $(RUSTC) debug.rs -C opt-level=3 - $(call RUN,debug) good - $(RUSTC) debug.rs -C opt-level=s - $(call RUN,debug) good - $(RUSTC) debug.rs -C opt-level=z - $(call RUN,debug) good - $(RUSTC) debug.rs -O - $(call RUN,debug) good - $(RUSTC) debug.rs - $(call RUN,debug) bad - $(RUSTC) debug.rs -C debug-assertions=yes -O - $(call RUN,debug) bad - $(RUSTC) debug.rs -C debug-assertions=yes -C opt-level=1 - $(call RUN,debug) bad diff --git a/tests/run-make/debug-assertions/debug.rs b/tests/run-make/debug-assertions/debug.rs index 9eebf60ded0..1f27c04a16d 100644 --- a/tests/run-make/debug-assertions/debug.rs +++ b/tests/run-make/debug-assertions/debug.rs @@ -1,15 +1,13 @@ +#![allow(internal_features)] #![feature(rustc_attrs)] #![deny(warnings)] -use std::env; use std::thread; fn main() { - let should_fail = env::args().nth(1) == Some("bad".to_string()); - - assert_eq!(thread::spawn(debug_assert_eq).join().is_err(), should_fail); - assert_eq!(thread::spawn(debug_assert).join().is_err(), should_fail); - assert_eq!(thread::spawn(overflow).join().is_err(), should_fail); + assert!(thread::spawn(debug_assert_eq).join().is_ok()); + assert!(thread::spawn(debug_assert).join().is_ok()); + assert!(thread::spawn(overflow).join().is_ok()); } fn debug_assert_eq() { diff --git a/tests/run-make/debug-assertions/rmake.rs b/tests/run-make/debug-assertions/rmake.rs new file mode 100644 index 00000000000..ba8be9488a8 --- /dev/null +++ b/tests/run-make/debug-assertions/rmake.rs @@ -0,0 +1,37 @@ +// debug.rs contains some "debug assertion" statements which +// should only be enabled in either non-optimized builds or when +// `-C debug-assertions` is set to yes. These debug assertions +// are guaranteed to fail, so this test checks that the run command +// fails where debug assertions should be activated, and succeeds where +// debug assertions should be disabled. +// See https://github.com/rust-lang/rust/pull/22980 + +//@ ignore-cross-compile +//@ needs-unwind + +use run_make_support::{run, run_fail, rustc}; + +fn main() { + rustc().input("debug.rs").arg("-Cdebug-assertions=no").run(); + run("debug"); + rustc().input("debug.rs").opt_level("0").run(); + run_fail("debug"); + rustc().input("debug.rs").opt_level("1").run(); + run("debug"); + rustc().input("debug.rs").opt_level("2").run(); + run("debug"); + rustc().input("debug.rs").opt_level("3").run(); + run("debug"); + rustc().input("debug.rs").opt_level("s").run(); + run("debug"); + rustc().input("debug.rs").opt_level("z").run(); + run("debug"); + rustc().input("debug.rs").opt().run(); + run("debug"); + rustc().input("debug.rs").run(); + run_fail("debug"); + rustc().input("debug.rs").opt().arg("-Cdebug-assertions=yes").run(); + run_fail("debug"); + rustc().input("debug.rs").opt_level("1").arg("-Cdebug-assertions=yes").run(); + run_fail("debug"); +} diff --git a/tests/run-make/emit-stack-sizes/Makefile b/tests/run-make/emit-stack-sizes/Makefile deleted file mode 100644 index b546fcba512..00000000000 --- a/tests/run-make/emit-stack-sizes/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -include ../tools.mk - -# ignore-windows -# ignore-apple -# -# This feature only works when the output object format is ELF so we ignore -# Apple and Windows - -# check that the .stack_sizes section is generated -all: - $(RUSTC) -C opt-level=3 -Z emit-stack-sizes --emit=obj foo.rs - size -A $(TMPDIR)/foo.o | $(CGREP) .stack_sizes diff --git a/tests/run-make/emit-stack-sizes/rmake.rs b/tests/run-make/emit-stack-sizes/rmake.rs new file mode 100644 index 00000000000..53cc9ee5943 --- /dev/null +++ b/tests/run-make/emit-stack-sizes/rmake.rs @@ -0,0 +1,23 @@ +// Running rustc with the -Z emit-stack-sizes +// flag enables diagnostics to seek stack overflows +// at compile time. This test compiles a rust file +// with this flag, then checks that the output object +// file contains the section "stack_sizes", where +// this diagnostics information should be located. +// See https://github.com/rust-lang/rust/pull/51946 + +//@ ignore-windows +//@ ignore-apple +// Reason: this feature only works when the output object format is ELF. +// This won't be the case on Windows/OSX - for example, OSX produces a Mach-O binary. + +use run_make_support::{llvm_readobj, rustc}; + +fn main() { + rustc().opt_level("3").arg("-Zemit-stack-sizes").emit("obj").input("foo.rs").run(); + llvm_readobj() + .arg("--section-headers") + .input("foo.o") + .run() + .assert_stdout_contains(".stack_sizes"); +} diff --git a/tests/run-make/invalid-library/Makefile b/tests/run-make/invalid-library/Makefile deleted file mode 100644 index 910d9af7b05..00000000000 --- a/tests/run-make/invalid-library/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -include ../tools.mk - -all: - touch $(TMPDIR)/lib.rmeta - $(AR) crus $(TMPDIR)/libfoo-ffffffff-1.0.rlib $(TMPDIR)/lib.rmeta - $(RUSTC) foo.rs 2>&1 | $(CGREP) "found invalid metadata" diff --git a/tests/run-make/invalid-library/rmake.rs b/tests/run-make/invalid-library/rmake.rs new file mode 100644 index 00000000000..750fcd05c8a --- /dev/null +++ b/tests/run-make/invalid-library/rmake.rs @@ -0,0 +1,8 @@ +use run_make_support::fs_wrapper::create_file; +use run_make_support::{ar, rustc}; + +fn main() { + create_file("lib.rmeta"); + ar(&["lib.rmeta"], "libfoo-ffffffff-1.0.rlib"); + rustc().input("foo.rs").run_fail().assert_stderr_contains("found invalid metadata"); +} diff --git a/tests/run-make/issue-68794-textrel-on-minimal-lib/Makefile b/tests/run-make/issue-68794-textrel-on-minimal-lib/Makefile deleted file mode 100644 index 6140b39c0e2..00000000000 --- a/tests/run-make/issue-68794-textrel-on-minimal-lib/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# ignore-cross-compile -# Regression test for issue #68794 -# -# Verify that no text relocations are accidentally introduced by linking a -# minimal rust staticlib. -# -# The test links a rust static library into a shared library, and checks that -# the linker doesn't have to flag the resulting file as containing TEXTRELs. - -include ../tools.mk - -# only-linux - -all: - $(RUSTC) foo.rs - $(CC) bar.c $(call STATICLIB,foo) -fPIC -shared -o $(call DYLIB,bar) \ - $(EXTRACFLAGS) $(EXTRACXXFLAGS) - readelf -d $(call DYLIB,bar) | grep TEXTREL; test $$? -eq 1 diff --git a/tests/run-make/libtest-padding/Makefile b/tests/run-make/libtest-padding/Makefile deleted file mode 100644 index c8e2fc01f67..00000000000 --- a/tests/run-make/libtest-padding/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# ignore-cross-compile because we run the compiled code -# needs-unwind because #[bench] and -Cpanic=abort requires -Zpanic-abort-tests -include ../tools.mk - -NORMALIZE=sed 's%[0-9,\.]\{1,\} ns/iter (+/- [0-9,\.]\{1,\})%?? ns/iter (+/- ??)%' | sed 's%finished in [0-9\.]\{1,\}%finished in ??%' - -all: - $(RUSTC) --test tests.rs - - $(call RUN,tests) --test-threads=1 | $(NORMALIZE) > "$(TMPDIR)"/test.stdout - $(RUSTC_TEST_OP) "$(TMPDIR)"/test.stdout test.stdout - - $(call RUN,tests) --test-threads=1 --bench | $(NORMALIZE) > "$(TMPDIR)"/bench.stdout - $(RUSTC_TEST_OP) "$(TMPDIR)"/bench.stdout bench.stdout diff --git a/tests/run-make/libtest-padding/rmake.rs b/tests/run-make/libtest-padding/rmake.rs new file mode 100644 index 00000000000..4b17ba19bf7 --- /dev/null +++ b/tests/run-make/libtest-padding/rmake.rs @@ -0,0 +1,46 @@ +// Benchmarks, when ran as tests, would cause strange indentations +// to appear in the output. This was because padding formatting was +// applied before the conversion from bench to test, and not afterwards. +// Now that this bug has been fixed in #118548, this test checks that it +// does not make a resurgence by comparing the output of --bench with an +// example stdout file. +// See https://github.com/rust-lang/rust/issues/104092 + +//@ ignore-cross-compile +// Reason: the compiled code is ran +//@ needs-unwind +// Reason: #[bench] requires -Z panic-abort-tests + +use run_make_support::{diff, run_with_args, rustc}; + +fn main() { + rustc().arg("--test").input("tests.rs").run(); + let out = run_with_args("tests", &["--test-threads=1"]).stdout_utf8(); + diff() + .expected_file("test.stdout") + .actual_text("actual-test-stdout", out) + .normalize( + // Replace all instances of (arbitrary numbers) + // [1.2345 ns/iter (+/- 0.1234)] + // with + // [?? ns/iter (+/- ??)] + r#"(\d+(?:[.,]\d+)*)\s*ns/iter\s*\(\+/-\s*(\d+(?:[.,]\d+)*)\)"#, + "?? ns/iter (+/- ??)", + ) + // Replace all instances of (arbitrary numbers) + // finished in 8.0000 s + // with + // finished in ?? + .normalize(r#"finished\s+in\s+(\d+(?:\.\d+)*)"#, "finished in ??") + .run(); + let out = run_with_args("tests", &["--test-threads=1", "--bench"]).stdout_utf8(); + diff() + .expected_file("bench.stdout") + .actual_text("actual-bench-stdout", out) + .normalize( + r#"(\d+(?:[.,]\d+)*)\s*ns/iter\s*\(\+/-\s*(\d+(?:[.,]\d+)*)\)"#, + "?? ns/iter (+/- ??)", + ) + .normalize(r#"finished\s+in\s+(\d+(?:\.\d+)*)"#, "finished in ??") + .run(); +} diff --git a/tests/run-make/lto-dylib-dep/Makefile b/tests/run-make/lto-dylib-dep/Makefile deleted file mode 100644 index a9344597d08..00000000000 --- a/tests/run-make/lto-dylib-dep/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# Test that we don't run into an assertion when using a Rust dylib dependency -# while compiling with full LTO. -# See https://github.com/rust-lang/rust/issues/59137 - -all: - $(RUSTC) a_dylib.rs --crate-type=dylib -C prefer-dynamic - $(RUSTC) main.rs -C lto - $(call RUN,main) diff --git a/tests/run-make/lto-dylib-dep/rmake.rs b/tests/run-make/lto-dylib-dep/rmake.rs new file mode 100644 index 00000000000..842fce467d4 --- /dev/null +++ b/tests/run-make/lto-dylib-dep/rmake.rs @@ -0,0 +1,15 @@ +// Compiling with link-time-optimizations (LTO) would previously run into an internal +// compiler error (ICE) if a dylib was passed as a required library. This was due to a +// misplaced assert! call in the compiler, which is now removed. This test checks that +// this bug does not make a resurgence and that dylib+lto compilation succeeds. +// See https://github.com/rust-lang/rust/issues/59137 + +//@ ignore-cross-compile + +use run_make_support::{run, rustc}; + +fn main() { + rustc().input("a_dylib.rs").crate_type("dylib").arg("-Cprefer-dynamic").run(); + rustc().input("main.rs").arg("-Clto").run(); + run("main"); +} diff --git a/tests/run-make/many-crates-but-no-match/Makefile b/tests/run-make/many-crates-but-no-match/Makefile deleted file mode 100644 index ca0ab8e9e5f..00000000000 --- a/tests/run-make/many-crates-but-no-match/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -include ../tools.mk - -# Modelled after ui/changing-crates.rs test, but this one puts -# more than one (mismatching) candidate crate into the search path, -# which did not appear directly expressible in UI testing infrastructure. -# -# Note that we move the built libraries into target direcrtories rather than -# use the `--out-dir` option because the `../tools.mk` file already bakes a -# use of `--out-dir` into the definition of $(RUSTC). - -A1=$(TMPDIR)/a1 -A2=$(TMPDIR)/a2 -A3=$(TMPDIR)/a3 - -# A hack to match distinct lines of output from a single run. -LOG=$(TMPDIR)/log.txt - -all: - mkdir -p $(A1) $(A2) $(A3) - $(RUSTC) --crate-type=rlib crateA1.rs - mv $(TMPDIR)/$(call RLIB_GLOB,crateA) $(A1) - $(RUSTC) --crate-type=rlib -L $(A1) crateB.rs - $(RUSTC) --crate-type=rlib crateA2.rs - mv $(TMPDIR)/$(call RLIB_GLOB,crateA) $(A2) - $(RUSTC) --crate-type=rlib crateA3.rs - mv $(TMPDIR)/$(call RLIB_GLOB,crateA) $(A3) - # Ensure crateC fails to compile since A1 is "missing" and A2/A3 hashes do not match - $(RUSTC) -L $(A2) -L $(A3) crateC.rs >$(LOG) 2>&1 || true - $(CGREP) \ - 'found possibly newer version of crate `crateA` which `crateB` depends on' \ - 'note: perhaps that crate needs to be recompiled?' \ - 'crate `crateA`:' \ - 'crate `crateB`:' \ - < $(LOG) - # the 'crate `crateA`' will match two entries. diff --git a/tests/run-make/many-crates-but-no-match/rmake.rs b/tests/run-make/many-crates-but-no-match/rmake.rs new file mode 100644 index 00000000000..ea4f166b2bd --- /dev/null +++ b/tests/run-make/many-crates-but-no-match/rmake.rs @@ -0,0 +1,31 @@ +// An extended version of the ui/changing-crates.rs test, this test puts +// multiple mismatching crates into the search path of crateC (A2 and A3) +// and checks that the standard error contains helpful messages to indicate +// what should be done to fix the issue. +// See https://github.com/rust-lang/rust/issues/13266 + +use run_make_support::{fs_wrapper, rustc}; + +fn main() { + fs_wrapper::create_dir("a1"); + fs_wrapper::create_dir("a2"); + fs_wrapper::create_dir("a3"); + rustc().crate_type("rlib").out_dir("a1").input("crateA1.rs").run(); + rustc().crate_type("rlib").library_search_path("a1").input("crateB.rs").run(); + rustc().crate_type("rlib").out_dir("a2").input("crateA2.rs").run(); + rustc().crate_type("rlib").out_dir("a3").input("crateA3.rs").run(); + // Ensure crateC fails to compile since A1 is "missing" and A2/A3 hashes do not match + rustc() + .crate_type("rlib") + .library_search_path("a2") + .library_search_path("a3") + .input("crateC.rs") + .run_fail() + .assert_stderr_contains( + "found possibly newer version of crate `crateA` which `crateB` depends on", + ) + .assert_stderr_contains("note: perhaps that crate needs to be recompiled?") + .assert_stderr_contains("crate `crateA`:") + .assert_stderr_contains("crate `crateB`:"); + // the 'crate `crateA`' will match two entries. +} diff --git a/tests/run-make/mingw-export-call-convention/Makefile b/tests/run-make/mingw-export-call-convention/Makefile deleted file mode 100644 index 4a60059cc54..00000000000 --- a/tests/run-make/mingw-export-call-convention/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -include ../tools.mk - -# only-windows-gnu - -all: - $(RUSTC) foo.rs - # FIXME: we should make sure __stdcall calling convention is used here - # but that only works with LLD right now - nm -g "$(call IMPLIB,foo)" | $(CGREP) bar diff --git a/tests/run-make/mingw-export-call-convention/rmake.rs b/tests/run-make/mingw-export-call-convention/rmake.rs new file mode 100644 index 00000000000..d1fb745a64d --- /dev/null +++ b/tests/run-make/mingw-export-call-convention/rmake.rs @@ -0,0 +1,13 @@ +// On windows-gnu, symbol exporting used to fail to export names +// with no_mangle. #72049 brought this feature up to par with msvc, +// and this test checks that the symbol "bar" is successfully exported. +// See https://github.com/rust-lang/rust/issues/50176 + +//@ only-x86_64-pc-windows-gnu + +use run_make_support::{llvm_readobj, rustc}; + +fn main() { + rustc().input("foo.rs").run(); + llvm_readobj().arg("--all").input("libfoo.dll.a").run().assert_stdout_contains("bar"); +} diff --git a/tests/run-make/mismatching-target-triples/Makefile b/tests/run-make/mismatching-target-triples/Makefile deleted file mode 100644 index 409388e0414..00000000000 --- a/tests/run-make/mismatching-target-triples/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -include ../tools.mk - -# Issue #10814 -# -# these are no_std to avoid having to have the standard library or any -# linkers/assemblers for the relevant platform - -all: - $(RUSTC) foo.rs --target=i686-unknown-linux-gnu - $(RUSTC) bar.rs --target=x86_64-unknown-linux-gnu 2>&1 \ - | $(CGREP) 'couldn'"'"'t find crate `foo` with expected target triple x86_64-unknown-linux-gnu' diff --git a/tests/run-make/mismatching-target-triples/rmake.rs b/tests/run-make/mismatching-target-triples/rmake.rs new file mode 100644 index 00000000000..6f41eac8cda --- /dev/null +++ b/tests/run-make/mismatching-target-triples/rmake.rs @@ -0,0 +1,15 @@ +// In this test, foo links against 32-bit architecture, and then, bar, which depends +// on foo, links against 64-bit architecture, causing a metadata mismatch due to the +// differences in target architectures. This used to cause an internal compiler error, +// now replaced by a clearer normal error message. This test checks that this aforementioned +// error message is used. +// See https://github.com/rust-lang/rust/issues/10814 + +use run_make_support::rustc; + +fn main() { + rustc().input("foo.rs").target("i686-unknown-linux-gnu").run(); + rustc().input("bar.rs").target("x86_64-unknown-linux-gnu").run_fail().assert_stderr_contains( + r#"couldn't find crate `foo` with expected target triple x86_64-unknown-linux-gnu"#, + ); +} diff --git a/tests/run-make/override-aliased-flags/Makefile b/tests/run-make/override-aliased-flags/Makefile deleted file mode 100644 index db1ff1ff981..00000000000 --- a/tests/run-make/override-aliased-flags/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# FIXME: it would be good to check that it's actually the rightmost flags -# that are used when multiple flags are specified, but I can't think of a -# reliable way to check this. - -all: - # Test that `-O` and `-C opt-level` can be specified multiple times. - # The rightmost flag will be used over any previous flags. - $(RUSTC) -O -O main.rs - $(RUSTC) -O -C opt-level=0 main.rs - $(RUSTC) -C opt-level=0 -O main.rs - $(RUSTC) -C opt-level=0 -C opt-level=2 main.rs - $(RUSTC) -C opt-level=2 -C opt-level=0 main.rs - - # Test that `-g` and `-C debuginfo` can be specified multiple times. - # The rightmost flag will be used over any previous flags. - $(RUSTC) -g -g main.rs - $(RUSTC) -g -C debuginfo=0 main.rs - $(RUSTC) -C debuginfo=0 -g main.rs - $(RUSTC) -C debuginfo=0 -C debuginfo=2 main.rs - $(RUSTC) -C debuginfo=2 -C debuginfo=0 main.rs diff --git a/tests/run-make/override-aliased-flags/rmake.rs b/tests/run-make/override-aliased-flags/rmake.rs new file mode 100644 index 00000000000..e610c04651e --- /dev/null +++ b/tests/run-make/override-aliased-flags/rmake.rs @@ -0,0 +1,24 @@ +//@ ignore-cross-compile + +use run_make_support::rustc; + +// FIXME: it would be good to check that it's actually the rightmost flags +// that are used when multiple flags are specified, but I can't think of a +// reliable way to check this. +fn main() { + // Test that `-O` and `-C opt-level` can be specified multiple times. + // The rightmost flag will be used over any previous flags. + rustc().arg("-O").arg("-O").input("main.rs").run(); + rustc().arg("-O").arg("-C").arg("opt-level=0").input("main.rs").run(); + rustc().arg("-C").arg("opt-level=0").arg("-O").input("main.rs").run(); + rustc().arg("-C").arg("opt-level=0").arg("-C").arg("opt-level=2").input("main.rs").run(); + rustc().arg("-C").arg("opt-level=2").arg("-C").arg("opt-level=0").input("main.rs").run(); + + // Test that `-g` and `-C debuginfo` can be specified multiple times. + // The rightmost flag will be used over any previous flags. + rustc().arg("-g").arg("-g").input("main.rs").run(); + rustc().arg("-g").arg("-C").arg("debuginfo=0").input("main.rs").run(); + rustc().arg("-C").arg("debuginfo=0").arg("-g").input("main.rs").run(); + rustc().arg("-C").arg("debuginfo=0").arg("-C").arg("debuginfo=2").input("main.rs").run(); + rustc().arg("-C").arg("debuginfo=2").arg("-C").arg("debuginfo=0").input("main.rs").run(); +} diff --git a/tests/run-make/overwrite-input/Makefile b/tests/run-make/overwrite-input/Makefile deleted file mode 100644 index 721bf62b26b..00000000000 --- a/tests/run-make/overwrite-input/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) main.rs -o main.rs 2> $(TMPDIR)/file.stderr || echo "failed successfully" - $(RUSTC) main.rs -o . 2> $(TMPDIR)/folder.stderr || echo "failed successfully" - $(RUSTC_TEST_OP) "$(TMPDIR)"/file.stderr file.stderr - $(RUSTC_TEST_OP) "$(TMPDIR)"/folder.stderr folder.stderr diff --git a/tests/run-make/overwrite-input/file.stderr b/tests/run-make/overwrite-input/file.stderr index c13a270b067..3a741ae3852 100644 --- a/tests/run-make/overwrite-input/file.stderr +++ b/tests/run-make/overwrite-input/file.stderr @@ -1,6 +1,4 @@ -warning: ignoring --out-dir flag due to -o flag - error: the input file "main.rs" would be overwritten by the generated executable -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/run-make/overwrite-input/folder.stderr b/tests/run-make/overwrite-input/folder.stderr index 6e51cb812ce..30db08428fd 100644 --- a/tests/run-make/overwrite-input/folder.stderr +++ b/tests/run-make/overwrite-input/folder.stderr @@ -1,6 +1,4 @@ -warning: ignoring --out-dir flag due to -o flag - error: the generated executable for the input file "main.rs" conflicts with the existing directory "." -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/run-make/overwrite-input/main.stderr b/tests/run-make/overwrite-input/main.stderr deleted file mode 100644 index c13a270b067..00000000000 --- a/tests/run-make/overwrite-input/main.stderr +++ /dev/null @@ -1,6 +0,0 @@ -warning: ignoring --out-dir flag due to -o flag - -error: the input file "main.rs" would be overwritten by the generated executable - -error: aborting due to 1 previous error; 1 warning emitted - diff --git a/tests/run-make/overwrite-input/rmake.rs b/tests/run-make/overwrite-input/rmake.rs new file mode 100644 index 00000000000..b87a7c7e0a8 --- /dev/null +++ b/tests/run-make/overwrite-input/rmake.rs @@ -0,0 +1,13 @@ +// An attempt to set the output `-o` into a directory or a file we cannot write into should indeed +// be an error; but not an ICE (Internal Compiler Error). This test attempts both and checks +// that the standard error matches what is expected. +// See https://github.com/rust-lang/rust/issues/66530 + +use run_make_support::{diff, rustc}; + +fn main() { + let file_out = rustc().input("main.rs").output("main.rs").run_fail().stderr_utf8(); + let folder_out = rustc().input("main.rs").output(".").run_fail().stderr_utf8(); + diff().expected_file("file.stderr").actual_text("actual-file-stderr", file_out).run(); + diff().expected_file("folder.stderr").actual_text("actual-folder-stderr", folder_out).run(); +} diff --git a/tests/run-make/pdb-alt-path/Makefile b/tests/run-make/pdb-alt-path/Makefile deleted file mode 100644 index 7a0ae3bf2ef..00000000000 --- a/tests/run-make/pdb-alt-path/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -include ../tools.mk - -# only-windows-msvc - -all: - # Test that we don't have the full path to the PDB file in the binary - $(RUSTC) main.rs -g --crate-name my_crate_name --crate-type bin -Cforce-frame-pointers - $(CGREP) "my_crate_name.pdb" < $(TMPDIR)/my_crate_name.exe - $(CGREP) -v "\\my_crate_name.pdb" < $(TMPDIR)/my_crate_name.exe - - # Test that backtraces still can find debuginfo by checking that they contain symbol names and - # source locations. - $(TMPDIR)/my_crate_name.exe &> $(TMPDIR)/backtrace.txt - $(CGREP) "my_crate_name::fn_in_backtrace" < $(TMPDIR)/backtrace.txt - $(CGREP) "main.rs:15" < $(TMPDIR)/backtrace.txt - - # Test that explicitly passed `-Clink-arg=/PDBALTPATH:...` is respected - $(RUSTC) main.rs -g --crate-name my_crate_name --crate-type bin -Clink-arg=/PDBALTPATH:abcdefg.pdb -Cforce-frame-pointers - $(CGREP) "abcdefg.pdb" < $(TMPDIR)/my_crate_name.exe - $(CGREP) -v "my_crate_name.pdb" < $(TMPDIR)/my_crate_name.exe diff --git a/tests/run-make/pdb-alt-path/rmake.rs b/tests/run-make/pdb-alt-path/rmake.rs new file mode 100644 index 00000000000..6311d6d9ed7 --- /dev/null +++ b/tests/run-make/pdb-alt-path/rmake.rs @@ -0,0 +1,39 @@ +// The information inside a .exe file contains a string of the PDB file name. +// This could be a security concern if the full path was exposed, as it could +// reveal information about the filesystem where the bin was first compiled. +// This should only be overridden by `-Clink-arg=/PDBALTPATH:...` - this test +// checks that no full file paths are exposed and that the override flag is respected. +// See https://github.com/rust-lang/rust/pull/121297 + +//@ only-x86_64-pc-windows-msvc + +use run_make_support::{bin_name, invalid_utf8_contains, invalid_utf8_not_contains, run, rustc}; + +fn main() { + // Test that we don't have the full path to the PDB file in the binary + rustc() + .input("main.rs") + .arg("-g") + .crate_name("my_crate_name") + .crate_type("bin") + .arg("-Cforce-frame-pointers") + .run(); + invalid_utf8_contains(&bin_name("my_crate_name"), "my_crate_name.pdb"); + invalid_utf8_not_contains(&bin_name("my_crate_name"), r#"\my_crate_name.pdb"#); + // Test that backtraces still can find debuginfo by checking that they contain symbol names and + // source locations. + let out = run(&bin_name("my_crate_name")); + out.assert_stdout_contains("my_crate_name::fn_in_backtrace"); + out.assert_stdout_contains("main.rs:15"); + // Test that explicitly passed `-Clink-arg=/PDBALTPATH:...` is respected + rustc() + .input("main.rs") + .arg("-g") + .crate_name("my_crate_name") + .crate_type("bin") + .link_arg("/PDBALTPATH:abcdefg.pdb") + .arg("-Cforce-frame-pointers") + .run(); + invalid_utf8_contains(&bin_name("my_crate_name"), "abcdefg.pdb"); + invalid_utf8_not_contains(&bin_name("my_crate_name"), "my_crate_name.pdb"); +} diff --git a/tests/run-make/pretty-print-to-file/Makefile b/tests/run-make/pretty-print-to-file/Makefile deleted file mode 100644 index ca11b8c47f0..00000000000 --- a/tests/run-make/pretty-print-to-file/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) -o $(TMPDIR)/input.out -Zunpretty=normal input.rs - diff -u $(TMPDIR)/input.out input.pp diff --git a/tests/run-make/pretty-print-to-file/rmake.rs b/tests/run-make/pretty-print-to-file/rmake.rs new file mode 100644 index 00000000000..c23514ae849 --- /dev/null +++ b/tests/run-make/pretty-print-to-file/rmake.rs @@ -0,0 +1,12 @@ +// The "pretty-printer" of rustc translates source code into other formats, +// which is useful for debugging. This test checks the "normal" version of +// -Zunpretty, which should format the poorly formatted input.rs into a one-line +// function identical to the one in input.pp. +// See https://github.com/rust-lang/rust/commit/da25539c1ab295ec40261109557dd4526923928c + +use run_make_support::{diff, rustc}; + +fn main() { + rustc().output("input.out").arg("-Zunpretty=normal").input("input.rs").run(); + diff().expected_file("input.out").actual_file("input.pp").run(); +} diff --git a/tests/run-make/pretty-print-with-dep-file/Makefile b/tests/run-make/pretty-print-with-dep-file/Makefile deleted file mode 100644 index fa8089eb6a5..00000000000 --- a/tests/run-make/pretty-print-with-dep-file/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) --emit=dep-info -Zunpretty=expanded with-dep.rs - $(CGREP) "with-dep.rs" < $(TMPDIR)/with-dep.d - -rm $(TMPDIR)/with-dep.d - - $(RUSTC) --emit=dep-info -Zunpretty=normal with-dep.rs - ! test -f $(TMPDIR)/with-dep.d diff --git a/tests/run-make/pretty-print-with-dep-file/rmake.rs b/tests/run-make/pretty-print-with-dep-file/rmake.rs new file mode 100644 index 00000000000..859a9781bb6 --- /dev/null +++ b/tests/run-make/pretty-print-with-dep-file/rmake.rs @@ -0,0 +1,17 @@ +// Passing --emit=dep-info to the Rust compiler should create a .d file... +// but it failed to do so in Rust 1.69.0 when combined with -Z unpretty=expanded +// due to a bug. This test checks that -Z unpretty=expanded does not prevent the +// generation of the dep-info file, and that its -Z unpretty=normal counterpart +// does not get an unexpected dep-info file. +// See https://github.com/rust-lang/rust/issues/112898 + +use run_make_support::{fs_wrapper, invalid_utf8_contains, rustc}; +use std::path::Path; + +fn main() { + rustc().emit("dep-info").arg("-Zunpretty=expanded").input("with-dep.rs").run(); + invalid_utf8_contains("with-dep.d", "with-dep.rs"); + fs_wrapper::remove_file("with-dep.d"); + rustc().emit("dep-info").arg("-Zunpretty=normal").input("with-dep.rs").run(); + assert!(!Path::new("with-dep.d").exists()); +} diff --git a/tests/run-make/raw-dylib-cross-compilation/Makefile b/tests/run-make/raw-dylib-cross-compilation/Makefile deleted file mode 100644 index 2524f8500e1..00000000000 --- a/tests/run-make/raw-dylib-cross-compilation/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Tests that raw-dylib cross compilation works correctly - -# needs-dlltool - -# i686 dlltool.exe can't product x64 binaries. -# ignore-i686-pc-windows-gnu - -include ../tools.mk - -all: - # Build as x86 and make sure that we have x86 objects only. - $(RUSTC) --crate-type lib --crate-name i686_raw_dylib_test --target i686-pc-windows-gnu lib.rs - "$(LLVM_BIN_DIR)"/llvm-objdump -a $(TMPDIR)/libi686_raw_dylib_test.rlib > $(TMPDIR)/i686.objdump.txt - $(CGREP) "file format coff-i386" < $(TMPDIR)/i686.objdump.txt - $(CGREP) -v "file format coff-x86-64" < $(TMPDIR)/i686.objdump.txt - # Build as x64 and make sure that we have x64 objects only. - $(RUSTC) --crate-type lib --crate-name x64_raw_dylib_test --target x86_64-pc-windows-gnu lib.rs - "$(LLVM_BIN_DIR)"/llvm-objdump -a $(TMPDIR)/libx64_raw_dylib_test.rlib > $(TMPDIR)/x64.objdump.txt - $(CGREP) "file format coff-x86-64" < $(TMPDIR)/x64.objdump.txt - $(CGREP) -v "file format coff-i386" < $(TMPDIR)/x64.objdump.txt diff --git a/tests/run-make/raw-dylib-cross-compilation/rmake.rs b/tests/run-make/raw-dylib-cross-compilation/rmake.rs new file mode 100644 index 00000000000..3eb55546314 --- /dev/null +++ b/tests/run-make/raw-dylib-cross-compilation/rmake.rs @@ -0,0 +1,41 @@ +// When cross-compiling using `raw-dylib`, rustc would try to fetch some +// very specific `dlltool` to complete the cross-compilation (such as `i686-w64-mingw32-dlltool`) +// when Windows only calls it `dlltool`. This test performs some cross-compilation in a +// way that previously failed due to this bug, and checks that it succeeds. +// See https://github.com/rust-lang/rust/pull/108355 + +//@ ignore-i686-pc-windows-gnu +// Reason: dlltool on this distribution is unable to produce x64 binaries +//@ needs-dlltool +// Reason: this is the utility being checked by this test + +use run_make_support::{llvm_objdump, rust_lib_name, rustc}; + +fn main() { + // Build as x86 and make sure that we have x86 objects only. + rustc() + .crate_type("lib") + .crate_name("i686_raw_dylib_test") + .target("i686-pc-windows-gnu") + .input("lib.rs") + .run(); + llvm_objdump() + .arg("-a") + .input(rust_lib_name("i686_raw_dylib_test")) + .run() + .assert_stdout_contains("file format coff-i386") + .assert_stdout_not_contains("file format coff-x86-64"); + // Build as x64 and make sure that we have x64 objects only. + rustc() + .crate_type("lib") + .crate_name("x64_raw_dylib_test") + .target("x86_64-pc-windows-gnu") + .input("lib.rs") + .run(); + llvm_objdump() + .arg("-a") + .input(rust_lib_name("x64_raw_dylib_test")) + .run() + .assert_stdout_not_contains("file format coff-i386") + .assert_stdout_contains("file format coff-x86-64"); +} diff --git a/tests/run-make/remap-path-prefix/Makefile b/tests/run-make/remap-path-prefix/Makefile deleted file mode 100644 index 02423dea7d2..00000000000 --- a/tests/run-make/remap-path-prefix/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -include ../tools.mk - -# ignore-windows - -ifeq ($(UNAME),Darwin) - DEBUGINFOOPTS := -Csplit-debuginfo=off -else - DEBUGINFOOPTS := -endif - -all: remap remap-with-scope - -# Checks if remapping works if the remap-from string contains path to the working directory plus more -remap: - $(RUSTC) --remap-path-prefix $$PWD/auxiliary=/the/aux --crate-type=lib --emit=metadata auxiliary/lib.rs - grep "/the/aux/lib.rs" $(TMPDIR)/liblib.rmeta || exit 1 - ! grep "$$PWD/auxiliary" $(TMPDIR)/liblib.rmeta || exit 1 - -remap-with-scope: - $(RUSTC) --remap-path-prefix $$PWD/auxiliary=/the/aux -Zremap-path-scope=object $(DEBUGINFOOPTS) --crate-type=lib --emit=metadata auxiliary/lib.rs - grep "/the/aux/lib.rs" $(TMPDIR)/liblib.rmeta || exit 1 - ! grep "$$PWD/auxiliary" $(TMPDIR)/liblib.rmeta || exit 1 - - $(RUSTC) --remap-path-prefix $$PWD/auxiliary=/the/aux -Zremap-path-scope=macro $(DEBUGINFOOPTS) --crate-type=lib --emit=metadata auxiliary/lib.rs - grep "/the/aux/lib.rs" $(TMPDIR)/liblib.rmeta || exit 1 - ! grep "$$PWD/auxiliary" $(TMPDIR)/liblib.rmeta || exit 1 - - $(RUSTC) --remap-path-prefix $$PWD/auxiliary=/the/aux -Zremap-path-scope=diagnostics,object $(DEBUGINFOOPTS) --crate-type=lib --emit=metadata auxiliary/lib.rs - grep "/the/aux/lib.rs" $(TMPDIR)/liblib.rmeta || exit 1 - ! grep "$$PWD/auxiliary" $(TMPDIR)/liblib.rmeta || exit 1 diff --git a/tests/run-make/remap-path-prefix/rmake.rs b/tests/run-make/remap-path-prefix/rmake.rs new file mode 100644 index 00000000000..62c0368e4b3 --- /dev/null +++ b/tests/run-make/remap-path-prefix/rmake.rs @@ -0,0 +1,87 @@ +// Generating metadata alongside remap-path-prefix would fail to actually remap the path +// in the metadata. After this was fixed in #85344, this test checks that "auxiliary" is being +// successfully remapped to "/the/aux" in the rmeta files. +// See https://github.com/rust-lang/rust/pull/85344 + +use run_make_support::bstr::ByteSlice; +use run_make_support::{bstr, fs_wrapper, is_darwin, rustc}; + +fn main() { + let mut out_simple = rustc(); + let mut out_object = rustc(); + let mut out_macro = rustc(); + let mut out_diagobj = rustc(); + out_simple + .remap_path_prefix("auxiliary", "/the/aux") + .crate_type("lib") + .emit("metadata") + .input("auxiliary/lib.rs"); + out_object + .remap_path_prefix("auxiliary", "/the/aux") + .crate_type("lib") + .emit("metadata") + .input("auxiliary/lib.rs"); + out_macro + .remap_path_prefix("auxiliary", "/the/aux") + .crate_type("lib") + .emit("metadata") + .input("auxiliary/lib.rs"); + out_diagobj + .remap_path_prefix("auxiliary", "/the/aux") + .crate_type("lib") + .emit("metadata") + .input("auxiliary/lib.rs"); + + out_simple.run(); + rmeta_contains("/the/aux/lib.rs"); + rmeta_not_contains("auxiliary"); + + out_object.arg("-Zremap-path-scope=object"); + out_macro.arg("-Zremap-path-scope=macro"); + out_diagobj.arg("-Zremap-path-scope=diagnostics,object"); + if is_darwin() { + out_object.arg("-Csplit-debuginfo=off"); + out_macro.arg("-Csplit-debuginfo=off"); + out_diagobj.arg("-Csplit-debuginfo=off"); + } + + out_object.run(); + rmeta_contains("/the/aux/lib.rs"); + rmeta_not_contains("auxiliary"); + out_macro.run(); + rmeta_contains("/the/aux/lib.rs"); + rmeta_not_contains("auxiliary"); + out_diagobj.run(); + rmeta_contains("/the/aux/lib.rs"); + rmeta_not_contains("auxiliary"); +} + +//FIXME(Oneirical): These could be generalized into run_make_support +// helper functions. +fn rmeta_contains(expected: &str) { + // Normalize to account for path differences in Windows. + if !bstr::BString::from(fs_wrapper::read("liblib.rmeta")) + .replace(b"\\", b"/") + .contains_str(expected) + { + eprintln!("=== FILE CONTENTS (LOSSY) ==="); + eprintln!("{}", String::from_utf8_lossy(&fs_wrapper::read("liblib.rmeta"))); + eprintln!("=== SPECIFIED TEXT ==="); + eprintln!("{}", expected); + panic!("specified text was not found in file"); + } +} + +fn rmeta_not_contains(expected: &str) { + // Normalize to account for path differences in Windows. + if bstr::BString::from(fs_wrapper::read("liblib.rmeta")) + .replace(b"\\", b"/") + .contains_str(expected) + { + eprintln!("=== FILE CONTENTS (LOSSY) ==="); + eprintln!("{}", String::from_utf8_lossy(&fs_wrapper::read("liblib.rmeta"))); + eprintln!("=== SPECIFIED TEXT ==="); + eprintln!("{}", expected); + panic!("specified text was not found in file"); + } +} diff --git a/tests/run-make/return-non-c-like-enum/Makefile b/tests/run-make/return-non-c-like-enum/Makefile deleted file mode 100644 index 0c8d8bf3acc..00000000000 --- a/tests/run-make/return-non-c-like-enum/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) --crate-type=staticlib nonclike.rs - $(CC) test.c $(call STATICLIB,nonclike) $(call OUT_EXE,test) \ - $(EXTRACFLAGS) $(EXTRACXXFLAGS) - $(call RUN,test) diff --git a/tests/run-make/return-non-c-like-enum/rmake.rs b/tests/run-make/return-non-c-like-enum/rmake.rs new file mode 100644 index 00000000000..e698790b43c --- /dev/null +++ b/tests/run-make/return-non-c-like-enum/rmake.rs @@ -0,0 +1,18 @@ +// Check that we treat enum variants like union members in call ABIs. +// Added in #68443. +// Original issue: #68190. + +//@ ignore-cross-compile + +use run_make_support::{cc, extra_c_flags, extra_cxx_flags, run, rustc, static_lib_name}; + +fn main() { + rustc().crate_type("staticlib").input("nonclike.rs").run(); + cc().input("test.c") + .arg(&static_lib_name("nonclike")) + .out_exe("test") + .args(&extra_c_flags()) + .args(&extra_cxx_flags()) + .run(); + run("test"); +} diff --git a/tests/run-make/rust-lld-by-default-beta-stable/main.rs b/tests/run-make/rust-lld-by-default-beta-stable/main.rs new file mode 100644 index 00000000000..f328e4d9d04 --- /dev/null +++ b/tests/run-make/rust-lld-by-default-beta-stable/main.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/run-make/rust-lld-by-default-beta-stable/rmake.rs b/tests/run-make/rust-lld-by-default-beta-stable/rmake.rs new file mode 100644 index 00000000000..fc3dffdbaf4 --- /dev/null +++ b/tests/run-make/rust-lld-by-default-beta-stable/rmake.rs @@ -0,0 +1,29 @@ +// Ensure that rust-lld is *not* used as the default linker on `x86_64-unknown-linux-gnu` on stable +// or beta. + +//@ ignore-nightly +//@ only-x86_64-unknown-linux-gnu + +use run_make_support::regex::Regex; +use run_make_support::rustc; +use std::process::Output; + +fn main() { + // A regular compilation should not use rust-lld by default. We'll check that by asking the + // linker to display its version number with a link-arg. + let output = rustc() + .env("RUSTC_LOG", "rustc_codegen_ssa::back::link=info") + .link_arg("-Wl,-v") + .input("main.rs") + .run(); + assert!( + !find_lld_version_in_logs(output.stderr_utf8()), + "the LLD version string should not be present in the output logs:\n{}", + output.stderr_utf8() + ); +} + +fn find_lld_version_in_logs(stderr: String) -> bool { + let lld_version_re = Regex::new(r"^LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap(); + stderr.lines().any(|line| lld_version_re.is_match(line.trim())) +} diff --git a/tests/run-make/rust-lld-by-default/main.rs b/tests/run-make/rust-lld-by-default-nightly/main.rs index e9f655fc09e..e9f655fc09e 100644 --- a/tests/run-make/rust-lld-by-default/main.rs +++ b/tests/run-make/rust-lld-by-default-nightly/main.rs diff --git a/tests/run-make/rust-lld-by-default/rmake.rs b/tests/run-make/rust-lld-by-default-nightly/rmake.rs index 5b065f86f53..f3ce9ada157 100644 --- a/tests/run-make/rust-lld-by-default/rmake.rs +++ b/tests/run-make/rust-lld-by-default-nightly/rmake.rs @@ -1,7 +1,9 @@ -// Ensure that rust-lld is used as the default linker on `x86_64-unknown-linux-gnu`, and that it can -// also be turned off with a CLI flag. +// Ensure that rust-lld is used as the default linker on `x86_64-unknown-linux-gnu` on the nightly +// channel, and that it can also be turned off with a CLI flag. //@ needs-rust-lld +//@ ignore-beta +//@ ignore-stable //@ only-x86_64-unknown-linux-gnu use run_make_support::regex::Regex; diff --git a/tests/run-make/issue-68794-textrel-on-minimal-lib/bar.c b/tests/run-make/textrel-on-minimal-lib/bar.c index bb4036b06e1..bb4036b06e1 100644 --- a/tests/run-make/issue-68794-textrel-on-minimal-lib/bar.c +++ b/tests/run-make/textrel-on-minimal-lib/bar.c diff --git a/tests/run-make/issue-68794-textrel-on-minimal-lib/foo.rs b/tests/run-make/textrel-on-minimal-lib/foo.rs index a3e865b638e..a3e865b638e 100644 --- a/tests/run-make/issue-68794-textrel-on-minimal-lib/foo.rs +++ b/tests/run-make/textrel-on-minimal-lib/foo.rs diff --git a/tests/run-make/textrel-on-minimal-lib/rmake.rs b/tests/run-make/textrel-on-minimal-lib/rmake.rs new file mode 100644 index 00000000000..eba664479f1 --- /dev/null +++ b/tests/run-make/textrel-on-minimal-lib/rmake.rs @@ -0,0 +1,31 @@ +// Verify that no text relocations are accidentally introduced by linking a +// minimal rust staticlib. +// The test links a rust static library into a shared library, and checks that +// the linker doesn't have to flag the resulting file as containing TEXTRELs. +// This bug otherwise breaks Android builds, which forbid TEXTRELs. +// See https://github.com/rust-lang/rust/issues/68794 + +//@ ignore-cross-compile +//@ ignore-windows +// Reason: There is no `bar.dll` produced by CC to run readobj on + +use run_make_support::{ + cc, dynamic_lib_name, extra_c_flags, extra_cxx_flags, llvm_readobj, rustc, static_lib_name, +}; + +fn main() { + rustc().input("foo.rs").run(); + cc().input("bar.c") + .input(static_lib_name("foo")) + .out_exe(&dynamic_lib_name("bar")) + .arg("-fPIC") + .arg("-shared") + .args(&extra_c_flags()) + .args(&extra_cxx_flags()) + .run(); + llvm_readobj() + .input(dynamic_lib_name("bar")) + .arg("--dynamic") + .run() + .assert_stdout_not_contains("TEXTREL"); +} diff --git a/tests/run-make/unknown-mod-stdin/Makefile b/tests/run-make/unknown-mod-stdin/Makefile deleted file mode 100644 index 313b0ba837e..00000000000 --- a/tests/run-make/unknown-mod-stdin/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# ignore-windows - -include ../tools.mk - -all: - echo 'mod unknown;' | $(RUSTC) --crate-type rlib - >$(TMPDIR)/unknown-mod.stdout 2>$(TMPDIR)/unknown-mod.stderr || echo "failed successfully" - $(RUSTC_TEST_OP) "$(TMPDIR)"/unknown-mod.stdout unknown-mod.stdout - $(RUSTC_TEST_OP) "$(TMPDIR)"/unknown-mod.stderr unknown-mod.stderr diff --git a/tests/run-make/unknown-mod-stdin/rmake.rs b/tests/run-make/unknown-mod-stdin/rmake.rs new file mode 100644 index 00000000000..0fe5c78ed0f --- /dev/null +++ b/tests/run-make/unknown-mod-stdin/rmake.rs @@ -0,0 +1,25 @@ +// Rustc displays a compilation error when it finds a `mod` (module) +// statement referencing a file that does not exist. However, a bug from 2019 +// caused invalid `mod` statements to silently insert empty inline modules +// instead of showing an error if the invalid `mod` statement had been passed +// through standard input. This test checks that this bug does not make a resurgence. +// See https://github.com/rust-lang/rust/issues/65601 + +// NOTE: This is not a UI test, because the bug which this test +// is checking for is specifically tied to passing +// `mod unknown;` through standard input. + +use run_make_support::{diff, rustc}; + +fn main() { + let out = rustc().crate_type("rlib").stdin(b"mod unknown;").arg("-").run_fail(); + diff() + .actual_text("actual-stdout", out.stdout_utf8()) + .expected_file("unknown-mod.stdout") + .run(); + diff() + .actual_text("actual-stderr", out.stderr_utf8()) + .expected_file("unknown-mod.stderr") + .normalize(r#"\\"#, "/") + .run(); +} diff --git a/tests/run-make/use-suggestions-rust-2018/Makefile b/tests/run-make/use-suggestions-rust-2018/Makefile deleted file mode 100644 index 37cd6283c0a..00000000000 --- a/tests/run-make/use-suggestions-rust-2018/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) ep-nested-lib.rs - - $(RUSTC) use-suggestions.rs --edition=2018 --extern ep_nested_lib=$(TMPDIR)/libep_nested_lib.rlib 2>&1 | $(CGREP) "use ep_nested_lib::foo::bar::Baz" - diff --git a/tests/run-make/use-suggestions-rust-2018/rmake.rs b/tests/run-make/use-suggestions-rust-2018/rmake.rs new file mode 100644 index 00000000000..52c694da75e --- /dev/null +++ b/tests/run-make/use-suggestions-rust-2018/rmake.rs @@ -0,0 +1,18 @@ +// The compilation error caused by calling on an unimported crate +// should have a suggestion to write, say, crate::bar::Foo instead +// of just bar::Foo. However, this suggestion used to only appear for +// extern crate statements, not crate struct. After this was fixed in #51456, +// this test checks that the correct suggestion is printed no matter what. +// See https://github.com/rust-lang/rust/issues/51212 + +use run_make_support::{rust_lib_name, rustc}; + +fn main() { + rustc().input("ep-nested-lib.rs").run(); + rustc() + .input("use-suggestions.rs") + .edition("2018") + .extern_("ep_nested_lib", rust_lib_name("ep_nested_lib")) + .run_fail() + .assert_stderr_contains("use ep_nested_lib::foo::bar::Baz"); +} diff --git a/tests/run-make/used-cdylib-macos/Makefile b/tests/run-make/used-cdylib-macos/Makefile deleted file mode 100644 index bdf914a1ca9..00000000000 --- a/tests/run-make/used-cdylib-macos/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -include ../tools.mk - -# only-apple -# -# This checks that `#[used]` passes through to the linker on -# Apple targets. This is subject to change in the future, see -# https://github.com/rust-lang/rust/pull/93718 for discussion - -all: - $(RUSTC) -Copt-level=3 dylib_used.rs - nm $(TMPDIR)/libdylib_used.dylib | $(CGREP) VERY_IMPORTANT_SYMBOL diff --git a/tests/run-make/used-cdylib-macos/rmake.rs b/tests/run-make/used-cdylib-macos/rmake.rs new file mode 100644 index 00000000000..ad95ad640f0 --- /dev/null +++ b/tests/run-make/used-cdylib-macos/rmake.rs @@ -0,0 +1,16 @@ +// This checks that `#[used]` passes through to the linker on +// Apple targets. This is subject to change in the future. +// See https://github.com/rust-lang/rust/pull/93718 + +//@ only-apple + +use run_make_support::{dynamic_lib_name, llvm_readobj, rustc}; + +fn main() { + rustc().opt_level("3").input("dylib_used.rs").run(); + llvm_readobj() + .input(dynamic_lib_name("dylib_used")) + .arg("--all") + .run() + .assert_stdout_contains("VERY_IMPORTANT_SYMBOL"); +} diff --git a/tests/run-make/windows-safeseh/rmake.rs b/tests/run-make/windows-safeseh/rmake.rs index 10e6b38aa8d..c7c6ef7339d 100644 --- a/tests/run-make/windows-safeseh/rmake.rs +++ b/tests/run-make/windows-safeseh/rmake.rs @@ -1,4 +1,4 @@ -//@ only-windows +//@ only-x86_64-pc-windows-msvc //@ needs-rust-lld use run_make_support::rustc; diff --git a/tests/rustdoc-gui/label-next-to-symbol.goml b/tests/rustdoc-gui/label-next-to-symbol.goml index 9a7de60bf38..0582bd2cad3 100644 --- a/tests/rustdoc-gui/label-next-to-symbol.goml +++ b/tests/rustdoc-gui/label-next-to-symbol.goml @@ -1,7 +1,10 @@ // These tests verify that labels like "UNIX" and "Deprecated" stay on the same line as their symbol. // It also verifies the staggered layout on mobile. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +call-function: ("switch-theme", {"theme": "light"}) + // Desktop view set-window-size: (1080, 600) assert: (".stab.deprecated") diff --git a/tests/rustdoc-gui/sidebar-source-code-display.goml b/tests/rustdoc-gui/sidebar-source-code-display.goml index 7ce3be8a5b3..67152afbbaa 100644 --- a/tests/rustdoc-gui/sidebar-source-code-display.goml +++ b/tests/rustdoc-gui/sidebar-source-code-display.goml @@ -141,14 +141,15 @@ click: "#sidebar-button" wait-for-css: (".src .sidebar > *", {"visibility": "hidden"}) // We scroll to line 117 to change the scroll position. scroll-to: '//*[@id="117"]' -assert-window-property: {"pageYOffset": "2516"} +store-value: (y_offset, "2493") +assert-window-property: {"pageYOffset": |y_offset|} // Expanding the sidebar... click: "#sidebar-button" wait-for-css: (".sidebar", {"left": "0px"}) click: "#sidebar-button" wait-for-css: (".sidebar", {"left": "-1000px"}) // The "scrollTop" property should be the same. -assert-window-property: {"pageYOffset": "2516"} +assert-window-property: {"pageYOffset": |y_offset|} // We now check that opening the sidebar and clicking a link will close it. // The behavior here on mobile is different than the behavior on desktop, diff --git a/tests/rustdoc-ui/disambiguator-endswith-named-suffix.rs b/tests/rustdoc-ui/disambiguator-endswith-named-suffix.rs new file mode 100644 index 00000000000..c3da1fdd7cc --- /dev/null +++ b/tests/rustdoc-ui/disambiguator-endswith-named-suffix.rs @@ -0,0 +1,111 @@ +//@ check-pass +//@ normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL" + +//! [struct@m!()] //~ WARN: unmatched disambiguator `struct` and suffix `!()` +//! [struct@m!{}] +//! [struct@m![]] +//! [struct@f()] //~ WARN: unmatched disambiguator `struct` and suffix `()` +//! [struct@m!] //~ WARN: unmatched disambiguator `struct` and suffix `!` +//! +//! [enum@m!()] //~ WARN: unmatched disambiguator `enum` and suffix `!()` +//! [enum@m!{}] +//! [enum@m![]] +//! [enum@f()] //~ WARN: unmatched disambiguator `enum` and suffix `()` +//! [enum@m!] //~ WARN: unmatched disambiguator `enum` and suffix `!` +//! +//! [trait@m!()] //~ WARN: unmatched disambiguator `trait` and suffix `!()` +//! [trait@m!{}] +//! [trait@m![]] +//! [trait@f()] //~ WARN: unmatched disambiguator `trait` and suffix `()` +//! [trait@m!] //~ WARN: unmatched disambiguator `trait` and suffix `!` +//! +//! [module@m!()] //~ WARN: unmatched disambiguator `module` and suffix `!()` +//! [module@m!{}] +//! [module@m![]] +//! [module@f()] //~ WARN: unmatched disambiguator `module` and suffix `()` +//! [module@m!] //~ WARN: unmatched disambiguator `module` and suffix `!` +//! +//! [mod@m!()] //~ WARN: unmatched disambiguator `mod` and suffix `!()` +//! [mod@m!{}] +//! [mod@m![]] +//! [mod@f()] //~ WARN: unmatched disambiguator `mod` and suffix `()` +//! [mod@m!] //~ WARN: unmatched disambiguator `mod` and suffix `!` +//! +//! [const@m!()] //~ WARN: unmatched disambiguator `const` and suffix `!()` +//! [const@m!{}] +//! [const@m![]] +//! [const@f()] //~ WARN: incompatible link kind for `f` +//! [const@m!] //~ WARN: unmatched disambiguator `const` and suffix `!` +//! +//! [constant@m!()] //~ WARN: unmatched disambiguator `constant` and suffix `!()` +//! [constant@m!{}] +//! [constant@m![]] +//! [constant@f()] //~ WARN: incompatible link kind for `f` +//! [constant@m!] //~ WARN: unmatched disambiguator `constant` and suffix `!` +//! +//! [static@m!()] //~ WARN: unmatched disambiguator `static` and suffix `!()` +//! [static@m!{}] +//! [static@m![]] +//! [static@f()] //~ WARN: incompatible link kind for `f` +//! [static@m!] //~ WARN: unmatched disambiguator `static` and suffix `!` +//! +//! [function@m!()] //~ WARN: unmatched disambiguator `function` and suffix `!()` +//! [function@m!{}] +//! [function@m![]] +//! [function@f()] +//! [function@m!] //~ WARN: unmatched disambiguator `function` and suffix `!` +//! +//! [fn@m!()] //~ WARN: unmatched disambiguator `fn` and suffix `!()` +//! [fn@m!{}] +//! [fn@m![]] +//! [fn@f()] +//! [fn@m!] //~ WARN: unmatched disambiguator `fn` and suffix `!` +//! +//! [method@m!()] //~ WARN: unmatched disambiguator `method` and suffix `!()` +//! [method@m!{}] +//! [method@m![]] +//! [method@f()] +//! [method@m!] //~ WARN: unmatched disambiguator `method` and suffix `!` +//! +//! [derive@m!()] //~ WARN: incompatible link kind for `m` +//! [derive@m!{}] //~ WARN: incompatible link kind for `m` +//! [derive@m![]] +//! [derive@f()] //~ WARN: unmatched disambiguator `derive` and suffix `()` +//! [derive@m!] //~ WARN: incompatible link kind for `m` +//! +//! [type@m!()] //~ WARN: unmatched disambiguator `type` and suffix `!()` +//! [type@m!{}] +//! [type@m![]] +//! [type@f()] //~ WARN: unmatched disambiguator `type` and suffix `()` +//! [type@m!] //~ WARN: unmatched disambiguator `type` and suffix `!` +//! +//! [value@m!()] //~ WARN: unmatched disambiguator `value` and suffix `!()` +//! [value@m!{}] +//! [value@m![]] +//! [value@f()] +//! [value@m!] //~ WARN: unmatched disambiguator `value` and suffix `!` +//! +//! [macro@m!()] +//! [macro@m!{}] +//! [macro@m![]] +//! [macro@f()] //~ WARN: unmatched disambiguator `macro` and suffix `()` +//! [macro@m!] +//! +//! [prim@m!()] //~ WARN: unmatched disambiguator `prim` and suffix `!()` +//! [prim@m!{}] +//! [prim@m![]] +//! [prim@f()] //~ WARN: unmatched disambiguator `prim` and suffix `()` +//! [prim@m!] //~ WARN: unmatched disambiguator `prim` and suffix `!` +//! +//! [primitive@m!()] //~ WARN: unmatched disambiguator `primitive` and suffix `!()` +//! [primitive@m!{}] +//! [primitive@m![]] +//! [primitive@f()] //~ WARN: unmatched disambiguator `primitive` and suffix `()` +//! [primitive@m!] //~ WARN: unmatched disambiguator `primitive` and suffix `!` + +#[macro_export] +macro_rules! m { + () => {}; +} + +pub fn f() {} diff --git a/tests/rustdoc-ui/disambiguator-endswith-named-suffix.stderr b/tests/rustdoc-ui/disambiguator-endswith-named-suffix.stderr new file mode 100644 index 00000000000..f4e40a48873 --- /dev/null +++ b/tests/rustdoc-ui/disambiguator-endswith-named-suffix.stderr @@ -0,0 +1,395 @@ +warning: unmatched disambiguator `struct` and suffix `!()` + --> $DIR/disambiguator-endswith-named-suffix.rs:4:6 + | +LL | //! [struct@m!()] + | ^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default + +warning: unmatched disambiguator `struct` and suffix `()` + --> $DIR/disambiguator-endswith-named-suffix.rs:7:6 + | +LL | //! [struct@f()] + | ^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `struct` and suffix `!` + --> $DIR/disambiguator-endswith-named-suffix.rs:8:6 + | +LL | //! [struct@m!] + | ^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `enum` and suffix `!()` + --> $DIR/disambiguator-endswith-named-suffix.rs:10:6 + | +LL | //! [enum@m!()] + | ^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `enum` and suffix `()` + --> $DIR/disambiguator-endswith-named-suffix.rs:13:6 + | +LL | //! [enum@f()] + | ^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `enum` and suffix `!` + --> $DIR/disambiguator-endswith-named-suffix.rs:14:6 + | +LL | //! [enum@m!] + | ^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `trait` and suffix `!()` + --> $DIR/disambiguator-endswith-named-suffix.rs:16:6 + | +LL | //! [trait@m!()] + | ^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `trait` and suffix `()` + --> $DIR/disambiguator-endswith-named-suffix.rs:19:6 + | +LL | //! [trait@f()] + | ^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `trait` and suffix `!` + --> $DIR/disambiguator-endswith-named-suffix.rs:20:6 + | +LL | //! [trait@m!] + | ^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `module` and suffix `!()` + --> $DIR/disambiguator-endswith-named-suffix.rs:22:6 + | +LL | //! [module@m!()] + | ^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `module` and suffix `()` + --> $DIR/disambiguator-endswith-named-suffix.rs:25:6 + | +LL | //! [module@f()] + | ^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `module` and suffix `!` + --> $DIR/disambiguator-endswith-named-suffix.rs:26:6 + | +LL | //! [module@m!] + | ^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `mod` and suffix `!()` + --> $DIR/disambiguator-endswith-named-suffix.rs:28:6 + | +LL | //! [mod@m!()] + | ^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `mod` and suffix `()` + --> $DIR/disambiguator-endswith-named-suffix.rs:31:6 + | +LL | //! [mod@f()] + | ^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `mod` and suffix `!` + --> $DIR/disambiguator-endswith-named-suffix.rs:32:6 + | +LL | //! [mod@m!] + | ^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `const` and suffix `!()` + --> $DIR/disambiguator-endswith-named-suffix.rs:34:6 + | +LL | //! [const@m!()] + | ^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: incompatible link kind for `f` + --> $DIR/disambiguator-endswith-named-suffix.rs:37:6 + | +LL | //! [const@f()] + | ^^^^^^^^^ this link resolved to a function, which is not a constant + | +help: to link to the function, add parentheses + | +LL - //! [const@f()] +LL + //! [f()] + | + +warning: unmatched disambiguator `const` and suffix `!` + --> $DIR/disambiguator-endswith-named-suffix.rs:38:6 + | +LL | //! [const@m!] + | ^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `constant` and suffix `!()` + --> $DIR/disambiguator-endswith-named-suffix.rs:40:6 + | +LL | //! [constant@m!()] + | ^^^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: incompatible link kind for `f` + --> $DIR/disambiguator-endswith-named-suffix.rs:43:6 + | +LL | //! [constant@f()] + | ^^^^^^^^^^^^ this link resolved to a function, which is not a constant + | +help: to link to the function, add parentheses + | +LL - //! [constant@f()] +LL + //! [f()] + | + +warning: unmatched disambiguator `constant` and suffix `!` + --> $DIR/disambiguator-endswith-named-suffix.rs:44:6 + | +LL | //! [constant@m!] + | ^^^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `static` and suffix `!()` + --> $DIR/disambiguator-endswith-named-suffix.rs:46:6 + | +LL | //! [static@m!()] + | ^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: incompatible link kind for `f` + --> $DIR/disambiguator-endswith-named-suffix.rs:49:6 + | +LL | //! [static@f()] + | ^^^^^^^^^^ this link resolved to a function, which is not a static + | +help: to link to the function, add parentheses + | +LL - //! [static@f()] +LL + //! [f()] + | + +warning: unmatched disambiguator `static` and suffix `!` + --> $DIR/disambiguator-endswith-named-suffix.rs:50:6 + | +LL | //! [static@m!] + | ^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `function` and suffix `!()` + --> $DIR/disambiguator-endswith-named-suffix.rs:52:6 + | +LL | //! [function@m!()] + | ^^^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `function` and suffix `!` + --> $DIR/disambiguator-endswith-named-suffix.rs:56:6 + | +LL | //! [function@m!] + | ^^^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `fn` and suffix `!()` + --> $DIR/disambiguator-endswith-named-suffix.rs:58:6 + | +LL | //! [fn@m!()] + | ^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `fn` and suffix `!` + --> $DIR/disambiguator-endswith-named-suffix.rs:62:6 + | +LL | //! [fn@m!] + | ^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `method` and suffix `!()` + --> $DIR/disambiguator-endswith-named-suffix.rs:64:6 + | +LL | //! [method@m!()] + | ^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `method` and suffix `!` + --> $DIR/disambiguator-endswith-named-suffix.rs:68:6 + | +LL | //! [method@m!] + | ^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: incompatible link kind for `m` + --> $DIR/disambiguator-endswith-named-suffix.rs:70:6 + | +LL | //! [derive@m!()] + | ^^^^^^^^^^^ this link resolved to a macro, which is not a derive macro + | +help: to link to the macro, add an exclamation mark + | +LL - //! [derive@m!()] +LL + //! [m!!()] + | + +warning: incompatible link kind for `m` + --> $DIR/disambiguator-endswith-named-suffix.rs:71:6 + | +LL | //! [derive@m!{}] + | ^^^^^^^^^^^ this link resolved to a macro, which is not a derive macro + | +help: to link to the macro, add an exclamation mark + | +LL - //! [derive@m!{}] +LL + //! [m!!{}] + | + +warning: unmatched disambiguator `derive` and suffix `()` + --> $DIR/disambiguator-endswith-named-suffix.rs:73:6 + | +LL | //! [derive@f()] + | ^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: incompatible link kind for `m` + --> $DIR/disambiguator-endswith-named-suffix.rs:74:6 + | +LL | //! [derive@m!] + | ^^^^^^^^^ this link resolved to a macro, which is not a derive macro + | +help: to link to the macro, add an exclamation mark + | +LL - //! [derive@m!] +LL + //! [m!!] + | + +warning: unmatched disambiguator `type` and suffix `!()` + --> $DIR/disambiguator-endswith-named-suffix.rs:76:6 + | +LL | //! [type@m!()] + | ^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `type` and suffix `()` + --> $DIR/disambiguator-endswith-named-suffix.rs:79:6 + | +LL | //! [type@f()] + | ^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `type` and suffix `!` + --> $DIR/disambiguator-endswith-named-suffix.rs:80:6 + | +LL | //! [type@m!] + | ^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `value` and suffix `!()` + --> $DIR/disambiguator-endswith-named-suffix.rs:82:6 + | +LL | //! [value@m!()] + | ^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `value` and suffix `!` + --> $DIR/disambiguator-endswith-named-suffix.rs:86:6 + | +LL | //! [value@m!] + | ^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `macro` and suffix `()` + --> $DIR/disambiguator-endswith-named-suffix.rs:91:6 + | +LL | //! [macro@f()] + | ^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `prim` and suffix `!()` + --> $DIR/disambiguator-endswith-named-suffix.rs:94:6 + | +LL | //! [prim@m!()] + | ^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `prim` and suffix `()` + --> $DIR/disambiguator-endswith-named-suffix.rs:97:6 + | +LL | //! [prim@f()] + | ^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `prim` and suffix `!` + --> $DIR/disambiguator-endswith-named-suffix.rs:98:6 + | +LL | //! [prim@m!] + | ^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `primitive` and suffix `!()` + --> $DIR/disambiguator-endswith-named-suffix.rs:100:6 + | +LL | //! [primitive@m!()] + | ^^^^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `primitive` and suffix `()` + --> $DIR/disambiguator-endswith-named-suffix.rs:103:6 + | +LL | //! [primitive@f()] + | ^^^^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: unmatched disambiguator `primitive` and suffix `!` + --> $DIR/disambiguator-endswith-named-suffix.rs:104:6 + | +LL | //! [primitive@m!] + | ^^^^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +warning: 46 warnings emitted + diff --git a/tests/rustdoc-ui/disambiguator-macro-endswith-exclamatory.rs b/tests/rustdoc-ui/disambiguator-macro-endswith-exclamatory.rs new file mode 100644 index 00000000000..b955090e894 --- /dev/null +++ b/tests/rustdoc-ui/disambiguator-macro-endswith-exclamatory.rs @@ -0,0 +1,11 @@ +//@ check-pass + +//! [macro@m!] //~ WARN: unresolved link to `m` + +//issue#126986 + +macro_rules! m { + () => {}; +} + +fn main() {} diff --git a/tests/rustdoc-ui/disambiguator-macro-endswith-exclamatory.stderr b/tests/rustdoc-ui/disambiguator-macro-endswith-exclamatory.stderr new file mode 100644 index 00000000000..2ada7f1a4be --- /dev/null +++ b/tests/rustdoc-ui/disambiguator-macro-endswith-exclamatory.stderr @@ -0,0 +1,11 @@ +warning: unresolved link to `m` + --> $DIR/disambiguator-macro-endswith-exclamatory.rs:3:6 + | +LL | //! [macro@m!] + | ^^^^^^^^ no item named `m` in scope + | + = note: `macro_rules` named `m` exists in this crate, but it is not in scope at this link's location + = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default + +warning: 1 warning emitted + diff --git a/tests/rustdoc-ui/doctest/non_local_defs.rs b/tests/rustdoc-ui/doctest/non_local_defs.rs index aa166c343b2..d8cfe5637ae 100644 --- a/tests/rustdoc-ui/doctest/non_local_defs.rs +++ b/tests/rustdoc-ui/doctest/non_local_defs.rs @@ -4,6 +4,8 @@ //@ normalize-stderr-test: "tests/rustdoc-ui/doctest" -> "$$DIR" //@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +#![doc(test(attr(warn(non_local_definitions))))] + //! ``` //! #[macro_export] //! macro_rules! a_macro { () => {} } diff --git a/tests/rustdoc-ui/doctest/non_local_defs.stderr b/tests/rustdoc-ui/doctest/non_local_defs.stderr index 2b47e6b5bc4..13cd2558793 100644 --- a/tests/rustdoc-ui/doctest/non_local_defs.stderr +++ b/tests/rustdoc-ui/doctest/non_local_defs.stderr @@ -1,5 +1,5 @@ warning: non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module - --> $DIR/non_local_defs.rs:9:1 + --> $DIR/non_local_defs.rs:11:1 | LL | macro_rules! a_macro { () => {} } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,11 @@ LL | macro_rules! a_macro { () => {} } = help: remove the `#[macro_export]` or make this doc-test a standalone test with its own `fn main() { ... }` = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - = note: `#[warn(non_local_definitions)]` on by default +note: the lint level is defined here + --> $DIR/non_local_defs.rs:8:9 + | +LL | #![warn(non_local_definitions)] + | ^^^^^^^^^^^^^^^^^^^^^ warning: 1 warning emitted diff --git a/tests/rustdoc-ui/doctest/non_local_defs.stdout b/tests/rustdoc-ui/doctest/non_local_defs.stdout index bee195fcdd7..61b4074886e 100644 --- a/tests/rustdoc-ui/doctest/non_local_defs.stdout +++ b/tests/rustdoc-ui/doctest/non_local_defs.stdout @@ -1,6 +1,6 @@ running 1 test -test $DIR/non_local_defs.rs - (line 7) ... ok +test $DIR/non_local_defs.rs - (line 9) ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.rs b/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.rs index 169505b0406..87e6aa0c256 100644 --- a/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.rs +++ b/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.rs @@ -1,5 +1,4 @@ //@ check-pass -#![feature(lint_reasons)] //! This file tests the `#[expect]` attribute implementation for tool lints. The same //! file is used to test clippy and rustdoc. Any changes to this file should be synced diff --git a/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.stderr b/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.stderr index 5ae3c039d27..306496b6c85 100644 --- a/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.stderr +++ b/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.stderr @@ -1,5 +1,5 @@ warning: this lint expectation is unfulfilled - --> $DIR/expect-tool-lint-rfc-2383.rs:16:11 + --> $DIR/expect-tool-lint-rfc-2383.rs:15:11 | LL | #![expect(rustdoc::missing_crate_level_docs)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,19 +7,19 @@ LL | #![expect(rustdoc::missing_crate_level_docs)] = note: `#[warn(unfulfilled_lint_expectations)]` on by default warning: this lint expectation is unfulfilled - --> $DIR/expect-tool-lint-rfc-2383.rs:70:14 + --> $DIR/expect-tool-lint-rfc-2383.rs:69:14 | LL | #[expect(rustdoc::broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: this lint expectation is unfulfilled - --> $DIR/expect-tool-lint-rfc-2383.rs:75:14 + --> $DIR/expect-tool-lint-rfc-2383.rs:74:14 | LL | #[expect(rustdoc::invalid_html_tags)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: this lint expectation is unfulfilled - --> $DIR/expect-tool-lint-rfc-2383.rs:80:14 + --> $DIR/expect-tool-lint-rfc-2383.rs:79:14 | LL | #[expect(rustdoc::bare_urls)] | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/rustdoc/rfc-2632-const-trait-impl.rs b/tests/rustdoc/rfc-2632-const-trait-impl.rs index f6a5555dbad..eb3e00af3b0 100644 --- a/tests/rustdoc/rfc-2632-const-trait-impl.rs +++ b/tests/rustdoc/rfc-2632-const-trait-impl.rs @@ -8,7 +8,8 @@ // // FIXME(effects) add `const_trait` to `Fn` so we use `~const` // FIXME(effects) restore `const_trait` to `Destruct` -#![feature(const_trait_impl)] +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] #![crate_name = "foo"] use std::marker::Destruct; diff --git a/tests/ui-fulldeps/stable-mir/check_attribute.rs b/tests/ui-fulldeps/stable-mir/check_attribute.rs new file mode 100644 index 00000000000..be52853a479 --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/check_attribute.rs @@ -0,0 +1,155 @@ +//@ run-pass +//! Test information regarding type layout. + +//@ ignore-stage1 +//@ ignore-cross-compile +//@ ignore-remote +//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 + +#![feature(rustc_private)] +#![feature(control_flow_enum)] + +extern crate rustc_hir; +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate stable_mir; + +use rustc_smir::rustc_internal; +use stable_mir::{CrateDef, CrateItems}; +use std::io::Write; +use std::ops::ControlFlow; + +const CRATE_NAME: &str = "input"; + +/// This function uses the Stable MIR APIs to get information about the test crate. +fn test_stable_mir() -> ControlFlow<()> { + // Find items in the local crate. + let items = stable_mir::all_local_items(); + + test_builtins(&items); + test_derive(&items); + test_tool(&items); + test_all_attrs(&items); + + ControlFlow::Continue(()) +} + +// Test built-in attributes. +fn test_builtins(items: &CrateItems) { + let target_fn = *get_item(&items, "builtins_fn").unwrap(); + let allow_attrs = target_fn.attrs_by_path(&["allow".to_string()]); + assert_eq!(allow_attrs[0].as_str(), "#![allow(unused_variables)]"); + + let inline_attrs = target_fn.attrs_by_path(&["inline".to_string()]); + assert_eq!(inline_attrs[0].as_str(), "#[inline]"); + + let deprecated_attrs = target_fn.attrs_by_path(&["deprecated".to_string()]); + assert_eq!(deprecated_attrs[0].as_str(), "#[deprecated(since = \"5.2.0\")]"); +} + +// Test derive attribute. +fn test_derive(items: &CrateItems) { + let target_struct = *get_item(&items, "Foo").unwrap(); + let attrs = target_struct.attrs_by_path(&["derive".to_string()]); + // No `derive` attribute since it's expanded before MIR. + assert_eq!(attrs.len(), 0); + + // Check derived trait method's attributes. + let derived_fmt = *get_item(&items, "<Foo as std::fmt::Debug>::fmt").unwrap(); + // The Rust reference lies about this attribute. It doesn't show up in `clone` or `fmt` impl. + let _fmt_attrs = derived_fmt.attrs_by_path(&["automatically_derived".to_string()]); +} + +// Test tool attributes. +fn test_tool(items: &CrateItems) { + let rustfmt_fn = *get_item(&items, "do_not_format").unwrap(); + let rustfmt_attrs = rustfmt_fn.attrs_by_path(&["rustfmt".to_string(), "skip".to_string()]); + assert_eq!(rustfmt_attrs[0].as_str(), "#[rustfmt::skip]"); + + let clippy_fn = *get_item(&items, "complex_fn").unwrap(); + let clippy_attrs = clippy_fn.attrs_by_path(&["clippy".to_string(), + "cyclomatic_complexity".to_string()]); + assert_eq!(clippy_attrs[0].as_str(), "#[clippy::cyclomatic_complexity = \"100\"]"); +} + +fn test_all_attrs(items: &CrateItems) { + let target_fn = *get_item(&items, "many_attrs").unwrap(); + let all_attrs = target_fn.all_attrs(); + assert_eq!(all_attrs[0].as_str(), "#[inline]"); + assert_eq!(all_attrs[1].as_str(), "#[allow(unused_variables)]"); + assert_eq!(all_attrs[2].as_str(), "#[allow(dead_code)]"); + assert_eq!(all_attrs[3].as_str(), "#[allow(unused_imports)]"); + assert_eq!(all_attrs[4].as_str(), "#![allow(clippy::filter_map)]"); +} + + +fn get_item<'a>( + items: &'a CrateItems, + name: &str, +) -> Option<&'a stable_mir::CrateItem> { + items.iter().find(|crate_item| crate_item.name() == name) +} + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "attribute_input.rs"; + generate_input(&path).unwrap(); + let args = vec![ + "rustc".to_string(), + "--crate-type=lib".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + run!(args, test_stable_mir).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + // General metadata applied to the enclosing module or crate. + #![crate_type = "lib"] + + // Mixed inner and outer attributes. + #[inline] + #[deprecated(since = "5.2.0")] + fn builtins_fn() {{ + #![allow(unused_variables)] + + let x = (); + let y = (); + let z = (); + }} + + // A derive attribute to automatically implement a trait. + #[derive(Debug, Clone, Copy)] + struct Foo(u32); + + // A rustfmt tool attribute. + #[rustfmt::skip] + fn do_not_format() {{}} + + // A clippy tool attribute. + #[clippy::cyclomatic_complexity = "100"] + pub fn complex_fn() {{}} + + // A function with many attributes. + #[inline] + #[allow(unused_variables)] + #[allow(dead_code)] + #[allow(unused_imports)] + fn many_attrs() {{ + #![allow(clippy::filter_map)] + todo!() + }} + "# + )?; + Ok(()) +} diff --git a/tests/ui/async-await/async-block-control-flow-static-semantics.stderr b/tests/ui/async-await/async-block-control-flow-static-semantics.stderr index ce0d003f014..3bc467cc84d 100644 --- a/tests/ui/async-await/async-block-control-flow-static-semantics.stderr +++ b/tests/ui/async-await/async-block-control-flow-static-semantics.stderr @@ -1,20 +1,18 @@ error[E0267]: `break` inside `async` block --> $DIR/async-block-control-flow-static-semantics.rs:32:9 | -LL | / async { -LL | | break 0u8; - | | ^^^^^^^^^ cannot `break` inside `async` block -LL | | }; - | |_____- enclosing `async` block +LL | async { + | ----- enclosing `async` block +LL | break 0u8; + | ^^^^^^^^^ cannot `break` inside `async` block error[E0267]: `break` inside `async` block --> $DIR/async-block-control-flow-static-semantics.rs:39:13 | -LL | / async { -LL | | break 0u8; - | | ^^^^^^^^^ cannot `break` inside `async` block -LL | | }; - | |_________- enclosing `async` block +LL | async { + | ----- enclosing `async` block +LL | break 0u8; + | ^^^^^^^^^ cannot `break` inside `async` block error[E0308]: mismatched types --> $DIR/async-block-control-flow-static-semantics.rs:21:58 @@ -29,13 +27,13 @@ LL | | LL | | } | |_^ expected `u8`, found `()` -error[E0271]: expected `{async block@$DIR/async-block-control-flow-static-semantics.rs:23:17: 25:6}` to be a future that resolves to `()`, but it resolves to `u8` +error[E0271]: expected `{async block@$DIR/async-block-control-flow-static-semantics.rs:23:17: 23:22}` to be a future that resolves to `()`, but it resolves to `u8` --> $DIR/async-block-control-flow-static-semantics.rs:26:39 | LL | let _: &dyn Future<Output = ()> = █ | ^^^^^^ expected `()`, found `u8` | - = note: required for the cast from `&{async block@$DIR/async-block-control-flow-static-semantics.rs:23:17: 25:6}` to `&dyn Future<Output = ()>` + = note: required for the cast from `&{async block@$DIR/async-block-control-flow-static-semantics.rs:23:17: 23:22}` to `&dyn Future<Output = ()>` error[E0308]: mismatched types --> $DIR/async-block-control-flow-static-semantics.rs:12:43 @@ -45,13 +43,13 @@ LL | fn return_targets_async_block_not_fn() -> u8 { | | | implicitly returns `()` as its body has no tail or `return` expression -error[E0271]: expected `{async block@$DIR/async-block-control-flow-static-semantics.rs:14:17: 16:6}` to be a future that resolves to `()`, but it resolves to `u8` +error[E0271]: expected `{async block@$DIR/async-block-control-flow-static-semantics.rs:14:17: 14:22}` to be a future that resolves to `()`, but it resolves to `u8` --> $DIR/async-block-control-flow-static-semantics.rs:17:39 | LL | let _: &dyn Future<Output = ()> = █ | ^^^^^^ expected `()`, found `u8` | - = note: required for the cast from `&{async block@$DIR/async-block-control-flow-static-semantics.rs:14:17: 16:6}` to `&dyn Future<Output = ()>` + = note: required for the cast from `&{async block@$DIR/async-block-control-flow-static-semantics.rs:14:17: 14:22}` to `&dyn Future<Output = ()>` error[E0308]: mismatched types --> $DIR/async-block-control-flow-static-semantics.rs:49:44 diff --git a/tests/ui/async-await/async-borrowck-escaping-block-error.stderr b/tests/ui/async-await/async-borrowck-escaping-block-error.stderr index 190c59e32eb..8410e7eca57 100644 --- a/tests/ui/async-await/async-borrowck-escaping-block-error.stderr +++ b/tests/ui/async-await/async-borrowck-escaping-block-error.stderr @@ -2,9 +2,8 @@ error[E0373]: async block may outlive the current function, but it borrows `x`, --> $DIR/async-borrowck-escaping-block-error.rs:6:14 | LL | Box::new(async { x } ) - | ^^^^^^^^-^^ - | | | - | | `x` is borrowed here + | ^^^^^ - `x` is borrowed here + | | | may outlive borrowed value `x` | note: async block is returned here @@ -21,9 +20,8 @@ error[E0373]: async block may outlive the current function, but it borrows `x`, --> $DIR/async-borrowck-escaping-block-error.rs:11:5 | LL | async { *x } - | ^^^^^^^^--^^ - | | | - | | `x` is borrowed here + | ^^^^^ -- `x` is borrowed here + | | | may outlive borrowed value `x` | note: async block is returned here diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr index 6f07a6feed3..4b626c1bed6 100644 --- a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr +++ b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr @@ -22,20 +22,18 @@ LL | fn needs_async_fn(_: impl async Fn()) {} error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/wrong-fn-kind.rs:9:20 | -LL | fn needs_async_fn(_: impl async Fn()) {} - | --------------- change this to accept `FnMut` instead of `Fn` +LL | fn needs_async_fn(_: impl async Fn()) {} + | --------------- change this to accept `FnMut` instead of `Fn` ... -LL | needs_async_fn(async || { - | -------------- ^------- - | | | - | _____|______________in this closure - | | | - | | expects `Fn` instead of `FnMut` -LL | | -LL | | x += 1; - | | - mutable borrow occurs due to use of `x` in closure -LL | | }); - | |_____^ cannot borrow as mutable +LL | needs_async_fn(async || { + | -------------- ^^^^^^^^ + | | | + | | cannot borrow as mutable + | | in this closure + | expects `Fn` instead of `FnMut` +LL | +LL | x += 1; + | - mutable borrow occurs due to use of `x` in closure error: aborting due to 2 previous errors diff --git a/tests/ui/async-await/async-is-unwindsafe.stderr b/tests/ui/async-await/async-is-unwindsafe.stderr index 85fdcda3b8c..9c5e8f0252c 100644 --- a/tests/ui/async-await/async-is-unwindsafe.stderr +++ b/tests/ui/async-await/async-is-unwindsafe.stderr @@ -1,20 +1,19 @@ error[E0277]: the type `&mut Context<'_>` may not be safely transferred across an unwind boundary --> $DIR/async-is-unwindsafe.rs:12:5 | -LL | is_unwindsafe(async { - | ______^ - - | | ___________________| -LL | || -LL | || use std::ptr::null; -LL | || use std::task::{Context, RawWaker, RawWakerVTable, Waker}; -... || -LL | || drop(cx_ref); -LL | || }); - | ||_____-^ `&mut Context<'_>` may not be safely transferred across an unwind boundary - | |_____| - | within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}` +LL | is_unwindsafe(async { + | ^ ----- within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 12:24}` + | _____| + | | +LL | | +LL | | use std::ptr::null; +LL | | use std::task::{Context, RawWaker, RawWakerVTable, Waker}; +... | +LL | | drop(cx_ref); +LL | | }); + | |______^ `&mut Context<'_>` may not be safely transferred across an unwind boundary | - = help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>`, which is required by `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}: UnwindSafe` + = help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 12:24}`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>`, which is required by `{async block@$DIR/async-is-unwindsafe.rs:12:19: 12:24}: UnwindSafe` = note: `UnwindSafe` is implemented for `&Context<'_>`, but not for `&mut Context<'_>` note: future does not implement `UnwindSafe` as this value is used across an await --> $DIR/async-is-unwindsafe.rs:25:18 diff --git a/tests/ui/async-await/coroutine-desc.stderr b/tests/ui/async-await/coroutine-desc.stderr index 4c165ff619a..e1d7898478e 100644 --- a/tests/ui/async-await/coroutine-desc.stderr +++ b/tests/ui/async-await/coroutine-desc.stderr @@ -8,8 +8,8 @@ LL | fun(async {}, async {}); | | expected all arguments to be this `async` block type because they need to match the type of this parameter | arguments to this function are incorrect | - = note: expected `async` block `{async block@$DIR/coroutine-desc.rs:10:9: 10:17}` - found `async` block `{async block@$DIR/coroutine-desc.rs:10:19: 10:27}` + = note: expected `async` block `{async block@$DIR/coroutine-desc.rs:10:9: 10:14}` + found `async` block `{async block@$DIR/coroutine-desc.rs:10:19: 10:24}` = note: no two async blocks, even if identical, have the same type = help: consider pinning your async block and casting it to a trait object note: function defined here diff --git a/tests/ui/async-await/coroutine-not-future.stderr b/tests/ui/async-await/coroutine-not-future.stderr index 403e547a753..72921a72a95 100644 --- a/tests/ui/async-await/coroutine-not-future.stderr +++ b/tests/ui/async-await/coroutine-not-future.stderr @@ -26,11 +26,11 @@ note: required by a bound in `takes_coroutine` LL | fn takes_coroutine<ResumeTy>(_g: impl Coroutine<ResumeTy, Yield = (), Return = ()>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_coroutine` -error[E0277]: the trait bound `{async block@$DIR/coroutine-not-future.rs:39:21: 39:29}: Coroutine<_>` is not satisfied +error[E0277]: the trait bound `{async block@$DIR/coroutine-not-future.rs:39:21: 39:26}: Coroutine<_>` is not satisfied --> $DIR/coroutine-not-future.rs:39:21 | LL | takes_coroutine(async {}); - | --------------- ^^^^^^^^ the trait `Coroutine<_>` is not implemented for `{async block@$DIR/coroutine-not-future.rs:39:21: 39:29}` + | --------------- ^^^^^^^^ the trait `Coroutine<_>` is not implemented for `{async block@$DIR/coroutine-not-future.rs:39:21: 39:26}` | | | required by a bound introduced by this call | diff --git a/tests/ui/async-await/in-trait/async-example-desugared-extra.rs b/tests/ui/async-await/in-trait/async-example-desugared-extra.rs index b4fbcb78c13..d85ad869fd4 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-extra.rs +++ b/tests/ui/async-await/in-trait/async-example-desugared-extra.rs @@ -1,8 +1,6 @@ //@ check-pass //@ edition: 2021 -#![feature(lint_reasons)] - use std::future::Future; use std::pin::Pin; use std::task::Poll; diff --git a/tests/ui/async-await/issue-67252-unnamed-future.stderr b/tests/ui/async-await/issue-67252-unnamed-future.stderr index 51c06b9c8af..2ed40284702 100644 --- a/tests/ui/async-await/issue-67252-unnamed-future.stderr +++ b/tests/ui/async-await/issue-67252-unnamed-future.stderr @@ -8,7 +8,7 @@ LL | | let _a = a; LL | | }); | |______^ future created by async block is not `Send` | - = help: within `{async block@$DIR/issue-67252-unnamed-future.rs:18:11: 22:6}`, the trait `Send` is not implemented for `*mut ()`, which is required by `{async block@$DIR/issue-67252-unnamed-future.rs:18:11: 22:6}: Send` + = help: within `{async block@$DIR/issue-67252-unnamed-future.rs:18:11: 18:16}`, the trait `Send` is not implemented for `*mut ()`, which is required by `{async block@$DIR/issue-67252-unnamed-future.rs:18:11: 18:16}: Send` note: future is not `Send` as this value is used across an await --> $DIR/issue-67252-unnamed-future.rs:20:17 | diff --git a/tests/ui/async-await/issue-68112.stderr b/tests/ui/async-await/issue-68112.stderr index 96fc1633cc9..ca60079f3ef 100644 --- a/tests/ui/async-await/issue-68112.stderr +++ b/tests/ui/async-await/issue-68112.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | require_send(send_fut); | ^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` | - = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{async block@$DIR/issue-68112.rs:29:20: 33:6}: Send` + = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{async block@$DIR/issue-68112.rs:29:20: 29:25}: Send` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/issue-68112.rs:31:17 @@ -23,7 +23,7 @@ error: future cannot be sent between threads safely LL | require_send(send_fut); | ^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` | - = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{async block@$DIR/issue-68112.rs:39:20: 42:6}: Send` + = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{async block@$DIR/issue-68112.rs:39:20: 39:25}: Send` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/issue-68112.rs:40:17 @@ -42,7 +42,7 @@ error[E0277]: `RefCell<i32>` cannot be shared between threads safely LL | require_send(send_fut); | ^^^^^^^^^^^^^^^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{async block@$DIR/issue-68112.rs:57:20: 61:6}: Send` + = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{async block@$DIR/issue-68112.rs:57:20: 57:25}: Send` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc<RefCell<i32>>` to implement `Send` note: required because it's used within this `async` fn body @@ -61,13 +61,8 @@ LL | fn make_non_send_future2() -> impl Future<Output = Arc<RefCell<i32>>> { note: required because it's used within this `async` block --> $DIR/issue-68112.rs:57:20 | -LL | let send_fut = async { - | ____________________^ -LL | | let non_send_fut = make_non_send_future2(); -LL | | let _ = non_send_fut.await; -LL | | ready(0).await; -LL | | }; - | |_____^ +LL | let send_fut = async { + | ^^^^^ note: required by a bound in `require_send` --> $DIR/issue-68112.rs:11:25 | diff --git a/tests/ui/async-await/issue-70935-complex-spans.stderr b/tests/ui/async-await/issue-70935-complex-spans.stderr index 85c0c0c3088..1ca0b339c16 100644 --- a/tests/ui/async-await/issue-70935-complex-spans.stderr +++ b/tests/ui/async-await/issue-70935-complex-spans.stderr @@ -4,7 +4,7 @@ error[E0277]: `*mut ()` cannot be shared between threads safely LL | fn foo(x: NotSync) -> impl Future + Send { | ^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be shared between threads safely | - = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()`, which is required by `{async block@$DIR/issue-70935-complex-spans.rs:18:5: 22:6}: Send` + = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()`, which is required by `{async block@$DIR/issue-70935-complex-spans.rs:18:5: 18:15}: Send` note: required because it appears within the type `PhantomData<*mut ()>` --> $SRC_DIR/core/src/marker.rs:LL:COL note: required because it appears within the type `NotSync` @@ -28,12 +28,8 @@ LL | | } note: required because it's used within this `async` block --> $DIR/issue-70935-complex-spans.rs:18:5 | -LL | / async move { -LL | | baz(|| async { -LL | | foo(x.clone()); -LL | | }).await; -LL | | } - | |_____^ +LL | async move { + | ^^^^^^^^^^ error[E0277]: `*mut ()` cannot be shared between threads safely --> $DIR/issue-70935-complex-spans.rs:15:23 @@ -41,7 +37,7 @@ error[E0277]: `*mut ()` cannot be shared between threads safely LL | fn foo(x: NotSync) -> impl Future + Send { | ^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be shared between threads safely | - = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()`, which is required by `{async block@$DIR/issue-70935-complex-spans.rs:18:5: 22:6}: Send` + = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()`, which is required by `{async block@$DIR/issue-70935-complex-spans.rs:18:5: 18:15}: Send` note: required because it appears within the type `PhantomData<*mut ()>` --> $SRC_DIR/core/src/marker.rs:LL:COL note: required because it appears within the type `NotSync` @@ -65,12 +61,8 @@ LL | | } note: required because it's used within this `async` block --> $DIR/issue-70935-complex-spans.rs:18:5 | -LL | / async move { -LL | | baz(|| async { -LL | | foo(x.clone()); -LL | | }).await; -LL | | } - | |_____^ +LL | async move { + | ^^^^^^^^^^ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 2 previous errors diff --git a/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr b/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr index bdf2820887c..9d963686dea 100644 --- a/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr +++ b/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr @@ -13,14 +13,15 @@ LL | y error[E0506]: cannot assign to `*x` because it is borrowed --> $DIR/issue-74072-lifetime-name-annotations.rs:18:9 | +LL | (async move || { + | - return type of async closure is &'1 i32 +... LL | let y = &*x; | --- `*x` is borrowed here LL | *x += 1; | ^^^^^^^ `*x` is assigned to here but it was already borrowed LL | y | - returning this value requires that `*x` is borrowed for `'1` -LL | })() - | - return type of async closure is &'1 i32 error: lifetime may not live long enough --> $DIR/issue-74072-lifetime-name-annotations.rs:14:20 @@ -61,14 +62,15 @@ LL | } error[E0506]: cannot assign to `*x` because it is borrowed --> $DIR/issue-74072-lifetime-name-annotations.rs:28:9 | +LL | (async move || -> &i32 { + | - return type of async closure is &'1 i32 +... LL | let y = &*x; | --- `*x` is borrowed here LL | *x += 1; | ^^^^^^^ `*x` is assigned to here but it was already borrowed LL | y | - returning this value requires that `*x` is borrowed for `'1` -LL | })() - | - return type of async closure is &'1 i32 error: lifetime may not live long enough --> $DIR/issue-74072-lifetime-name-annotations.rs:24:28 @@ -109,14 +111,14 @@ LL | } error[E0506]: cannot assign to `*x` because it is borrowed --> $DIR/issue-74072-lifetime-name-annotations.rs:36:9 | +LL | async move { + | - return type of async block is &'1 i32 LL | let y = &*x; | --- `*x` is borrowed here LL | *x += 1; | ^^^^^^^ `*x` is assigned to here but it was already borrowed LL | y | - returning this value requires that `*x` is borrowed for `'1` -LL | } - | - return type of async block is &'1 i32 error: aborting due to 8 previous errors diff --git a/tests/ui/async-await/issue-86507.stderr b/tests/ui/async-await/issue-86507.stderr index 0398e57ef78..f4cd7c42706 100644 --- a/tests/ui/async-await/issue-86507.stderr +++ b/tests/ui/async-await/issue-86507.stderr @@ -13,7 +13,7 @@ note: captured value is not `Send` because `&` references cannot be sent unless | LL | let x = x; | ^ has type `&T` which is not `Send`, because `T` is not `Sync` - = note: required for the cast from `Pin<Box<{async block@$DIR/issue-86507.rs:18:17: 20:18}>>` to `Pin<Box<(dyn Future<Output = ()> + Send + 'async_trait)>>` + = note: required for the cast from `Pin<Box<{async block@$DIR/issue-86507.rs:18:17: 18:27}>>` to `Pin<Box<(dyn Future<Output = ()> + Send + 'async_trait)>>` help: consider further restricting this bound | LL | fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T) diff --git a/tests/ui/async-await/issues/issue-78938-async-block.stderr b/tests/ui/async-await/issues/issue-78938-async-block.stderr index dc373a24f6f..2974ff59ad2 100644 --- a/tests/ui/async-await/issues/issue-78938-async-block.stderr +++ b/tests/ui/async-await/issues/issue-78938-async-block.stderr @@ -1,12 +1,10 @@ error[E0373]: async block may outlive the current function, but it borrows `room_ref`, which is owned by the current function --> $DIR/issue-78938-async-block.rs:8:33 | -LL | let gameloop_handle = spawn(async { - | _________________________________^ -LL | | game_loop(Arc::clone(&room_ref)) - | | -------- `room_ref` is borrowed here -LL | | }); - | |_____^ may outlive borrowed value `room_ref` +LL | let gameloop_handle = spawn(async { + | ^^^^^ may outlive borrowed value `room_ref` +LL | game_loop(Arc::clone(&room_ref)) + | -------- `room_ref` is borrowed here | = note: async blocks are not executed immediately and must either take a reference or ownership of outside variables they use help: to force the async block to take ownership of `room_ref` (and any other referenced variables), use the `move` keyword diff --git a/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr b/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr index 640d946421a..8344b7a07dc 100644 --- a/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr +++ b/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr @@ -72,7 +72,7 @@ LL | | } | |_____^ expected `()`, found `async` block | = note: expected unit type `()` - found `async` block `{async block@$DIR/async-closure-gate.rs:27:5: 32:6}` + found `async` block `{async block@$DIR/async-closure-gate.rs:27:5: 27:10}` error[E0308]: mismatched types --> $DIR/async-closure-gate.rs:44:5 @@ -89,7 +89,7 @@ LL | | } | |_____^ expected `()`, found `async` block | = note: expected unit type `()` - found `async` block `{async block@$DIR/async-closure-gate.rs:44:5: 51:6}` + found `async` block `{async block@$DIR/async-closure-gate.rs:44:5: 44:10}` error: aborting due to 8 previous errors diff --git a/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr b/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr index 640d946421a..8344b7a07dc 100644 --- a/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr +++ b/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr @@ -72,7 +72,7 @@ LL | | } | |_____^ expected `()`, found `async` block | = note: expected unit type `()` - found `async` block `{async block@$DIR/async-closure-gate.rs:27:5: 32:6}` + found `async` block `{async block@$DIR/async-closure-gate.rs:27:5: 27:10}` error[E0308]: mismatched types --> $DIR/async-closure-gate.rs:44:5 @@ -89,7 +89,7 @@ LL | | } | |_____^ expected `()`, found `async` block | = note: expected unit type `()` - found `async` block `{async block@$DIR/async-closure-gate.rs:44:5: 51:6}` + found `async` block `{async block@$DIR/async-closure-gate.rs:44:5: 44:10}` error: aborting due to 8 previous errors diff --git a/tests/ui/async-await/try-on-option-in-async.stderr b/tests/ui/async-await/try-on-option-in-async.stderr index 4c7b4fa41fa..65f63093728 100644 --- a/tests/ui/async-await/try-on-option-in-async.stderr +++ b/tests/ui/async-await/try-on-option-in-async.stderr @@ -1,13 +1,11 @@ error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option-in-async.rs:8:10 | -LL | / async { -LL | | let x: Option<u32> = None; -LL | | x?; - | | ^ cannot use the `?` operator in an async block that returns `{integer}` -LL | | 22 -LL | | } - | |_____- this function should return `Result` or `Option` to accept `?` +LL | async { + | ----- this function should return `Result` or `Option` to accept `?` +LL | let x: Option<u32> = None; +LL | x?; + | ^ cannot use the `?` operator in an async block that returns `{integer}` | = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `{integer}` diff --git a/tests/ui/attributes/used-issue-126789.rs b/tests/ui/attributes/used-issue-126789.rs new file mode 100644 index 00000000000..90a1aa8d5cc --- /dev/null +++ b/tests/ui/attributes/used-issue-126789.rs @@ -0,0 +1,6 @@ +extern "C" { + #[used] //~ ERROR attribute must be applied to a `static` variable + static FOO: i32; +} + +fn main() {} diff --git a/tests/ui/attributes/used-issue-126789.stderr b/tests/ui/attributes/used-issue-126789.stderr new file mode 100644 index 00000000000..6014f7af95c --- /dev/null +++ b/tests/ui/attributes/used-issue-126789.stderr @@ -0,0 +1,10 @@ +error: attribute must be applied to a `static` variable + --> $DIR/used-issue-126789.rs:2:5 + | +LL | #[used] + | ^^^^^^^ +LL | static FOO: i32; + | ---------------- but this is a foreign static item + +error: aborting due to 1 previous error + diff --git a/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr b/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr index ebc3b6ebcac..79f18624c61 100644 --- a/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr +++ b/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr @@ -4,16 +4,10 @@ error[E0507]: cannot move out of `*x` which is behind a raw pointer LL | let y = *x; | ^^ move occurs because `*x` has type `Box<isize>`, which does not implement the `Copy` trait | -help: consider removing the dereference here - | -LL - let y = *x; -LL + let y = x; - | help: consider cloning the value if the performance cost is acceptable | -LL - let y = *x; -LL + let y = x.clone(); - | +LL | let y = (*x).clone(); + | + +++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/cloning-in-async-block-121547.stderr b/tests/ui/borrowck/cloning-in-async-block-121547.stderr index ae57e0018f8..0023644a1f5 100644 --- a/tests/ui/borrowck/cloning-in-async-block-121547.stderr +++ b/tests/ui/borrowck/cloning-in-async-block-121547.stderr @@ -1,16 +1,14 @@ error[E0382]: use of moved value: `value` --> $DIR/cloning-in-async-block-121547.rs:5:9 | -LL | async fn clone_async_block(value: String) { - | ----- move occurs because `value` has type `String`, which does not implement the `Copy` trait -LL | for _ in 0..10 { - | -------------- inside of this loop -LL | / async { -LL | | drop(value); - | | ----- use occurs due to use in coroutine -LL | | -LL | | }.await - | |_________^ value moved here, in previous iteration of loop +LL | async fn clone_async_block(value: String) { + | ----- move occurs because `value` has type `String`, which does not implement the `Copy` trait +LL | for _ in 0..10 { + | -------------- inside of this loop +LL | async { + | ^^^^^ value moved here, in previous iteration of loop +LL | drop(value); + | ----- use occurs due to use in coroutine | help: consider cloning the value if the performance cost is acceptable | diff --git a/tests/ui/borrowck/issue-20801.stderr b/tests/ui/borrowck/issue-20801.stderr index 20a4bd4e423..c1d06ac3e21 100644 --- a/tests/ui/borrowck/issue-20801.stderr +++ b/tests/ui/borrowck/issue-20801.stderr @@ -67,11 +67,6 @@ LL | struct T(u8); ... LL | let c = unsafe { *mut_ptr() }; | ---------- you could clone this value -help: consider removing the dereference here - | -LL - let c = unsafe { *mut_ptr() }; -LL + let c = unsafe { mut_ptr() }; - | error[E0507]: cannot move out of a raw pointer --> $DIR/issue-20801.rs:36:22 @@ -87,11 +82,6 @@ LL | struct T(u8); ... LL | let d = unsafe { *const_ptr() }; | ------------ you could clone this value -help: consider removing the dereference here - | -LL - let d = unsafe { *const_ptr() }; -LL + let d = unsafe { const_ptr() }; - | error: aborting due to 4 previous errors; 1 warning emitted diff --git a/tests/ui/borrowck/move-from-union-field-issue-66500.stderr b/tests/ui/borrowck/move-from-union-field-issue-66500.stderr index c951ce8e3cd..7f4593eefca 100644 --- a/tests/ui/borrowck/move-from-union-field-issue-66500.stderr +++ b/tests/ui/borrowck/move-from-union-field-issue-66500.stderr @@ -30,9 +30,8 @@ LL | *u.c | help: consider cloning the value if the performance cost is acceptable | -LL - *u.c -LL + u.c.clone() - | +LL | (*u.c).clone() + | + +++++++++ error[E0507]: cannot move out of `*u.d` which is behind a raw pointer --> $DIR/move-from-union-field-issue-66500.rs:24:5 @@ -42,9 +41,8 @@ LL | *u.d | help: consider cloning the value if the performance cost is acceptable | -LL - *u.d -LL + u.d.clone() - | +LL | (*u.d).clone() + | + +++++++++ error: aborting due to 4 previous errors diff --git a/tests/ui/cfg/diagnostics-not-a-def.rs b/tests/ui/cfg/diagnostics-not-a-def.rs index 1912cf9f616..3a7ca6240b1 100644 --- a/tests/ui/cfg/diagnostics-not-a-def.rs +++ b/tests/ui/cfg/diagnostics-not-a-def.rs @@ -1,5 +1,3 @@ -#![feature(lint_reasons)] - pub mod inner { #[expect(unexpected_cfgs)] pub fn i_am_here() { diff --git a/tests/ui/cfg/diagnostics-not-a-def.stderr b/tests/ui/cfg/diagnostics-not-a-def.stderr index 89bbf574871..51c1c03640f 100644 --- a/tests/ui/cfg/diagnostics-not-a-def.stderr +++ b/tests/ui/cfg/diagnostics-not-a-def.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find function `i_am_not` in module `inner` - --> $DIR/diagnostics-not-a-def.rs:14:12 + --> $DIR/diagnostics-not-a-def.rs:12:12 | LL | inner::i_am_not(); | ^^^^^^^^ not found in `inner` diff --git a/tests/ui/const-generics/const_trait_fn-issue-88433.rs b/tests/ui/const-generics/const_trait_fn-issue-88433.rs index cd008aa2c9f..5e0ea6fc168 100644 --- a/tests/ui/const-generics/const_trait_fn-issue-88433.rs +++ b/tests/ui/const-generics/const_trait_fn-issue-88433.rs @@ -1,6 +1,8 @@ //@ build-pass +//@ compile-flags: -Znext-solver -#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] #[const_trait] trait Func<T> { diff --git a/tests/ui/const-generics/const_trait_fn-issue-88433.stderr b/tests/ui/const-generics/const_trait_fn-issue-88433.stderr deleted file mode 100644 index 4e0d6370fbd..00000000000 --- a/tests/ui/const-generics/const_trait_fn-issue-88433.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/const_trait_fn-issue-88433.rs:3:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs b/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs index 2f903ea419e..bd9c08e5ad8 100644 --- a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs +++ b/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs @@ -1,6 +1,6 @@ //@ known-bug: #110395 -#![feature(generic_const_exprs, adt_const_params, const_trait_impl)] +#![feature(generic_const_exprs, adt_const_params, const_trait_impl, effects)] #![allow(incomplete_features)] // test `N + N` unifies with explicit function calls for non-builtin-types diff --git a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr b/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr index 335130c958f..cf03bb9ad76 100644 --- a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr +++ b/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr @@ -1,3 +1,12 @@ +error: const `impl` for trait `Add` which is not marked with `#[const_trait]` + --> $DIR/unify-op-with-fn-call.rs:10:12 + | +LL | impl const std::ops::Add for Foo { + | ^^^^^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + error[E0741]: `Foo` must implement `ConstParamTy` to be used as the type of a const generic parameter --> $DIR/unify-op-with-fn-call.rs:18:29 | @@ -45,48 +54,6 @@ help: try adding a `where` bound LL | fn foo2<const N: usize>(a: Evaluatable2<{ N + N }>) where [(); { std::ops::Add::add(N, N) }]: { | +++++++++++++++++++++++++++++++++++++++++ -error[E0015]: cannot call non-const operator in constants - --> $DIR/unify-op-with-fn-call.rs:20:39 - | -LL | fn foo<const N: Foo>(a: Evaluatable<{ N + N }>) { - | ^^^^^ - | -note: impl defined here, but it is not `const` - --> $DIR/unify-op-with-fn-call.rs:10:1 - | -LL | impl const std::ops::Add for Foo { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | - -error[E0015]: cannot call non-const fn `<Foo as Add>::add` in constants - --> $DIR/unify-op-with-fn-call.rs:21:13 - | -LL | bar::<{ std::ops::Add::add(N, N) }>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | - -error[E0015]: cannot call non-const fn `<usize as Add>::add` in constants - --> $DIR/unify-op-with-fn-call.rs:30:14 - | -LL | bar2::<{ std::ops::Add::add(N, N) }>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | - -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0015, E0741. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0741`. diff --git a/tests/ui/const-generics/issues/issue-88119.rs b/tests/ui/const-generics/issues/issue-88119.rs index bcbb26f0d8e..128e0b64a2b 100644 --- a/tests/ui/const-generics/issues/issue-88119.rs +++ b/tests/ui/const-generics/issues/issue-88119.rs @@ -1,7 +1,7 @@ //@ check-pass #![allow(incomplete_features)] -#![feature(const_trait_impl, generic_const_exprs)] +#![feature(const_trait_impl, effects, generic_const_exprs)] #[const_trait] trait ConstName { diff --git a/tests/ui/const-generics/polymorphic-drop-shim.rs b/tests/ui/const-generics/polymorphic-drop-shim.rs new file mode 100644 index 00000000000..4ca2e86cff9 --- /dev/null +++ b/tests/ui/const-generics/polymorphic-drop-shim.rs @@ -0,0 +1,18 @@ +//@ compile-flags: -Zinline-mir=yes --crate-type=lib +//@ build-pass + +use std::mem::ManuallyDrop; + +pub struct Foo<T, const N: usize>([T; N]); + +pub struct Dorp {} + +impl Drop for Dorp { + fn drop(&mut self) {} +} + +#[inline] +// SAFETY: call this with a valid allocation idk +pub unsafe fn drop<const M: usize>(x: *mut Foo<Dorp, M>) { + std::ptr::drop_in_place(x); +} diff --git a/tests/ui/consts/const-float-classify.rs b/tests/ui/consts/const-float-classify.rs index ae094003c89..acc8d00f83e 100644 --- a/tests/ui/consts/const-float-classify.rs +++ b/tests/ui/consts/const-float-classify.rs @@ -5,6 +5,7 @@ #![feature(const_float_bits_conv)] #![feature(const_float_classify)] #![feature(const_trait_impl, effects)] +#![allow(incomplete_features)] // Don't promote const fn nop<T>(x: T) -> T { x } diff --git a/tests/ui/consts/const-float-classify.stderr b/tests/ui/consts/const-float-classify.stderr index 1de27a072cf..38acb8a2281 100644 --- a/tests/ui/consts/const-float-classify.stderr +++ b/tests/ui/consts/const-float-classify.stderr @@ -1,14 +1,5 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/const-float-classify.rs:7:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information - = note: `#[warn(incomplete_features)]` on by default - error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` - --> $DIR/const-float-classify.rs:12:12 + --> $DIR/const-float-classify.rs:13:12 | LL | impl const PartialEq<NonDet> for bool { | ^^^^^^^^^^^^^^^^^ @@ -16,208 +7,5 @@ LL | impl const PartialEq<NonDet> for bool { = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates - --> $DIR/const-float-classify.rs:12:6 - | -LL | impl const PartialEq<NonDet> for bool { - | ^^^^^ unconstrained const parameter - | - = note: expressions using a const parameter must map each value to a distinct output value - = note: proving the result of expressions other than the parameter are unique is not supported - -error[E0284]: type annotations needed - --> $DIR/const-float-classify.rs:21:35 - | -LL | const _: () = assert!($a == $b); - | ^^ cannot infer the value of the constant `_` -... -LL | / suite! { -LL | | [is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative] -LL | | -0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] -LL | | 0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] -... | -LL | | -1.0 / 0.0 => [ false, true, false, false, false, true] -LL | | } - | |_- in this macro invocation - | -note: required for `bool` to implement `PartialEq<NonDet>` - --> $DIR/const-float-classify.rs:12:12 - | -LL | impl const PartialEq<NonDet> for bool { - | ----- ^^^^^^^^^^^^^^^^^ ^^^^ - | | - | unsatisfied trait bound introduced here - = note: this error originates in the macro `const_assert` which comes from the expansion of the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0284]: type annotations needed - --> $DIR/const-float-classify.rs:21:35 - | -LL | const _: () = assert!($a == $b); - | ^^ cannot infer the value of the constant `_` -... -LL | / suite! { -LL | | [is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative] -LL | | -0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] -LL | | 0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] -... | -LL | | -1.0 / 0.0 => [ false, true, false, false, false, true] -LL | | } - | |_- in this macro invocation - | -note: required for `bool` to implement `PartialEq<NonDet>` - --> $DIR/const-float-classify.rs:12:12 - | -LL | impl const PartialEq<NonDet> for bool { - | ----- ^^^^^^^^^^^^^^^^^ ^^^^ - | | - | unsatisfied trait bound introduced here - = note: this error originates in the macro `const_assert` which comes from the expansion of the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0284]: type annotations needed - --> $DIR/const-float-classify.rs:21:35 - | -LL | const _: () = assert!($a == $b); - | ^^ cannot infer the value of the constant `_` -... -LL | / suite! { -LL | | [is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative] -LL | | -0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] -LL | | 0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] -... | -LL | | -1.0 / 0.0 => [ false, true, false, false, false, true] -LL | | } - | |_- in this macro invocation - | -note: required for `bool` to implement `PartialEq<NonDet>` - --> $DIR/const-float-classify.rs:12:12 - | -LL | impl const PartialEq<NonDet> for bool { - | ----- ^^^^^^^^^^^^^^^^^ ^^^^ - | | - | unsatisfied trait bound introduced here - = note: this error originates in the macro `const_assert` which comes from the expansion of the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0284]: type annotations needed - --> $DIR/const-float-classify.rs:21:35 - | -LL | const _: () = assert!($a == $b); - | ^^ cannot infer the value of the constant `_` -... -LL | / suite! { -LL | | [is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative] -LL | | -0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] -LL | | 0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] -... | -LL | | -1.0 / 0.0 => [ false, true, false, false, false, true] -LL | | } - | |_- in this macro invocation - | -note: required for `bool` to implement `PartialEq<NonDet>` - --> $DIR/const-float-classify.rs:12:12 - | -LL | impl const PartialEq<NonDet> for bool { - | ----- ^^^^^^^^^^^^^^^^^ ^^^^ - | | - | unsatisfied trait bound introduced here - = note: this error originates in the macro `const_assert` which comes from the expansion of the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0284]: type annotations needed - --> $DIR/const-float-classify.rs:21:35 - | -LL | const _: () = assert!($a == $b); - | ^^ cannot infer the value of the constant `_` -... -LL | / suite! { -LL | | [is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative] -LL | | -0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] -LL | | 0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] -... | -LL | | -1.0 / 0.0 => [ false, true, false, false, false, true] -LL | | } - | |_- in this macro invocation - | -note: required for `bool` to implement `PartialEq<NonDet>` - --> $DIR/const-float-classify.rs:12:12 - | -LL | impl const PartialEq<NonDet> for bool { - | ----- ^^^^^^^^^^^^^^^^^ ^^^^ - | | - | unsatisfied trait bound introduced here - = note: this error originates in the macro `const_assert` which comes from the expansion of the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0284]: type annotations needed - --> $DIR/const-float-classify.rs:21:35 - | -LL | const _: () = assert!($a == $b); - | ^^ cannot infer the value of the constant `_` -... -LL | / suite! { -LL | | [is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative] -LL | | -0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] -LL | | 0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] -... | -LL | | -1.0 / 0.0 => [ false, true, false, false, false, true] -LL | | } - | |_- in this macro invocation - | -note: required for `bool` to implement `PartialEq<NonDet>` - --> $DIR/const-float-classify.rs:12:12 - | -LL | impl const PartialEq<NonDet> for bool { - | ----- ^^^^^^^^^^^^^^^^^ ^^^^ - | | - | unsatisfied trait bound introduced here - = note: this error originates in the macro `const_assert` which comes from the expansion of the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0284]: type annotations needed - --> $DIR/const-float-classify.rs:21:35 - | -LL | const _: () = assert!($a == $b); - | ^^ cannot infer the value of the constant `_` -... -LL | / suite! { -LL | | [is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative] -LL | | -0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] -LL | | 0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] -... | -LL | | -1.0 / 0.0 => [ false, true, false, false, false, true] -LL | | } - | |_- in this macro invocation - | -note: required for `bool` to implement `PartialEq<NonDet>` - --> $DIR/const-float-classify.rs:12:12 - | -LL | impl const PartialEq<NonDet> for bool { - | ----- ^^^^^^^^^^^^^^^^^ ^^^^ - | | - | unsatisfied trait bound introduced here - = note: this error originates in the macro `const_assert` which comes from the expansion of the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0284]: type annotations needed - --> $DIR/const-float-classify.rs:21:35 - | -LL | const _: () = assert!($a == $b); - | ^^ cannot infer the value of the constant `_` -... -LL | / suite! { -LL | | [is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative] -LL | | -0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] -LL | | 0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] -... | -LL | | -1.0 / 0.0 => [ false, true, false, false, false, true] -LL | | } - | |_- in this macro invocation - | -note: required for `bool` to implement `PartialEq<NonDet>` - --> $DIR/const-float-classify.rs:12:12 - | -LL | impl const PartialEq<NonDet> for bool { - | ----- ^^^^^^^^^^^^^^^^^ ^^^^ - | | - | unsatisfied trait bound introduced here - = note: this error originates in the macro `const_assert` which comes from the expansion of the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 10 previous errors; 1 warning emitted +error: aborting due to 1 previous error -Some errors have detailed explanations: E0207, E0284. -For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/consts/const-try.rs b/tests/ui/consts/const-try.rs index f2d3db9be9c..9089dd70a26 100644 --- a/tests/ui/consts/const-try.rs +++ b/tests/ui/consts/const-try.rs @@ -4,8 +4,9 @@ #![crate_type = "lib"] #![feature(try_trait_v2)] -#![feature(const_trait_impl)] +#![feature(const_trait_impl, effects)] #![feature(const_try)] +#![allow(incomplete_features)] use std::ops::{ControlFlow, FromResidual, Try}; diff --git a/tests/ui/consts/const-try.stderr b/tests/ui/consts/const-try.stderr index 2d91424c8d3..27eb1252d7b 100644 --- a/tests/ui/consts/const-try.stderr +++ b/tests/ui/consts/const-try.stderr @@ -1,37 +1,20 @@ -error[E0015]: `?` cannot determine the branch of `TryMe` in constant functions - --> $DIR/const-try.rs:33:5 +error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` + --> $DIR/const-try.rs:16:12 | -LL | TryMe?; - | ^^^^^^ - | -note: impl defined here, but it is not `const` - --> $DIR/const-try.rs:21:1 - | -LL | impl const Try for TryMe { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] +LL | impl const FromResidual<Error> for TryMe { + | ^^^^^^^^^^^^^^^^^^^ | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change -error[E0015]: `?` cannot convert from residual of `TryMe` in constant functions - --> $DIR/const-try.rs:33:5 +error: const `impl` for trait `Try` which is not marked with `#[const_trait]` + --> $DIR/const-try.rs:22:12 | -LL | TryMe?; - | ^^^^^^ - | -note: impl defined here, but it is not `const` - --> $DIR/const-try.rs:15:1 - | -LL | impl const FromResidual<Error> for TryMe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] +LL | impl const Try for TryMe { + | ^^^ | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/constifconst-call-in-const-position.rs b/tests/ui/consts/constifconst-call-in-const-position.rs index 29c967f38a7..757e35bbab2 100644 --- a/tests/ui/consts/constifconst-call-in-const-position.rs +++ b/tests/ui/consts/constifconst-call-in-const-position.rs @@ -1,6 +1,7 @@ //@ known-bug: #102498 -#![feature(const_trait_impl, generic_const_exprs)] +#![feature(const_trait_impl, effects, generic_const_exprs)] +#![allow(incomplete_features)] #[const_trait] pub trait Tr { diff --git a/tests/ui/consts/constifconst-call-in-const-position.stderr b/tests/ui/consts/constifconst-call-in-const-position.stderr index 09827f29baf..9096bd78682 100644 --- a/tests/ui/consts/constifconst-call-in-const-position.stderr +++ b/tests/ui/consts/constifconst-call-in-const-position.stderr @@ -1,36 +1,21 @@ -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/constifconst-call-in-const-position.rs:3:30 +error[E0308]: mismatched types + --> $DIR/constifconst-call-in-const-position.rs:17:38 | -LL | #![feature(const_trait_impl, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ +LL | const fn foo<T: ~const Tr>() -> [u8; T::a()] { + | ^^^^^^ expected `false`, found `host` | - = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information - = note: `#[warn(incomplete_features)]` on by default + = note: expected constant `false` + found constant `host` -error[E0015]: cannot call non-const fn `<T as Tr>::a` in constants - --> $DIR/constifconst-call-in-const-position.rs:17:9 +error[E0308]: mismatched types + --> $DIR/constifconst-call-in-const-position.rs:18:9 | LL | [0; T::a()] - | ^^^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | - -error[E0015]: cannot call non-const fn `<T as Tr>::a` in constants - --> $DIR/constifconst-call-in-const-position.rs:16:38 - | -LL | const fn foo<T: ~const Tr>() -> [u8; T::a()] { - | ^^^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] + | ^^^^^^ expected `false`, found `host` | + = note: expected constant `false` + found constant `host` -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/promoted-const-drop.rs b/tests/ui/consts/promoted-const-drop.rs index c896c011ab6..b7d92d6523a 100644 --- a/tests/ui/consts/promoted-const-drop.rs +++ b/tests/ui/consts/promoted-const-drop.rs @@ -4,6 +4,7 @@ struct A(); impl const Drop for A { + //~^ ERROR const `impl` for trait `Drop` which is not marked with `#[const_trait]` fn drop(&mut self) {} } diff --git a/tests/ui/consts/promoted-const-drop.stderr b/tests/ui/consts/promoted-const-drop.stderr index 4802834173f..1201f608232 100644 --- a/tests/ui/consts/promoted-const-drop.stderr +++ b/tests/ui/consts/promoted-const-drop.stderr @@ -1,5 +1,14 @@ +error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` + --> $DIR/promoted-const-drop.rs:6:12 + | +LL | impl const Drop for A { + | ^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted-const-drop.rs:13:26 + --> $DIR/promoted-const-drop.rs:14:26 | LL | let _: &'static A = &A(); | ---------- ^^^ creates a temporary value which is freed while still in use @@ -10,7 +19,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted-const-drop.rs:14:28 + --> $DIR/promoted-const-drop.rs:15:28 | LL | let _: &'static [A] = &[C]; | ------------ ^^^ creates a temporary value which is freed while still in use @@ -19,6 +28,6 @@ LL | let _: &'static [A] = &[C]; LL | } | - temporary value is freed at the end of this statement -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/promoted_const_call.stderr b/tests/ui/consts/promoted_const_call.stderr index ace449fae9c..64bf6bd73b0 100644 --- a/tests/ui/consts/promoted_const_call.stderr +++ b/tests/ui/consts/promoted_const_call.stderr @@ -1,10 +1,31 @@ -error[E0493]: destructor of `Panic` cannot be evaluated at compile-time +error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` + --> $DIR/promoted_const_call.rs:7:12 + | +LL | impl const Drop for Panic { fn drop(&mut self) { panic!(); } } + | ^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call.rs:11:26 + | +LL | let _: &'static _ = &id(&Panic); + | ---------- ^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | }; + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed --> $DIR/promoted_const_call.rs:11:30 | LL | let _: &'static _ = &id(&Panic); - | ^^^^^ - value is dropped here - | | - | the destructor for this type cannot be evaluated in constants + | ---------- ^^^^^ - temporary value is freed at the end of this statement + | | | + | | creates a temporary value which is freed while still in use + | type annotation requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed --> $DIR/promoted_const_call.rs:17:26 @@ -48,7 +69,6 @@ LL | let _: &'static _ = &&(Panic, 0).1; LL | } | - temporary value is freed at the end of this statement -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0493, E0716. -For more information about an error, try `rustc --explain E0493`. +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/rustc-impl-const-stability.stderr b/tests/ui/consts/rustc-impl-const-stability.stderr index 250d1c3fc05..84bd375ea40 100644 --- a/tests/ui/consts/rustc-impl-const-stability.stderr +++ b/tests/ui/consts/rustc-impl-const-stability.stderr @@ -16,15 +16,5 @@ LL | impl const Default for Data { = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates - --> $DIR/rustc-impl-const-stability.rs:15:6 - | -LL | impl const Default for Data { - | ^^^^^ unconstrained const parameter - | - = note: expressions using a const parameter must map each value to a distinct output value - = note: proving the result of expressions other than the parameter are unique is not supported - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 1 previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr b/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr index f030961b7ed..77dc214bcec 100644 --- a/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr +++ b/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr @@ -1,67 +1,57 @@ error[E0267]: `break` inside `async` function --> $DIR/break-inside-coroutine-issue-124495.rs:8:5 | -LL | async fn async_fn() { - | _____________________- -LL | | break; - | | ^^^^^ cannot `break` inside `async` function -LL | | } - | |_- enclosing `async` function +LL | async fn async_fn() { + | ------------------- enclosing `async` function +LL | break; + | ^^^^^ cannot `break` inside `async` function error[E0267]: `break` inside `gen` function --> $DIR/break-inside-coroutine-issue-124495.rs:12:5 | -LL | gen fn gen_fn() { - | _________________- -LL | | break; - | | ^^^^^ cannot `break` inside `gen` function -LL | | } - | |_- enclosing `gen` function +LL | gen fn gen_fn() { + | --------------- enclosing `gen` function +LL | break; + | ^^^^^ cannot `break` inside `gen` function error[E0267]: `break` inside `async gen` function --> $DIR/break-inside-coroutine-issue-124495.rs:16:5 | -LL | async gen fn async_gen_fn() { - | _____________________________- -LL | | break; - | | ^^^^^ cannot `break` inside `async gen` function -LL | | } - | |_- enclosing `async gen` function +LL | async gen fn async_gen_fn() { + | --------------------------- enclosing `async gen` function +LL | break; + | ^^^^^ cannot `break` inside `async gen` function error[E0267]: `break` inside `async` block --> $DIR/break-inside-coroutine-issue-124495.rs:20:21 | LL | let _ = async { break; }; - | --------^^^^^--- - | | | - | | cannot `break` inside `async` block + | ----- ^^^^^ cannot `break` inside `async` block + | | | enclosing `async` block error[E0267]: `break` inside `async` closure --> $DIR/break-inside-coroutine-issue-124495.rs:22:24 | LL | let _ = async || { break; }; - | -----------^^^^^--- - | | | - | | cannot `break` inside `async` closure + | -------- ^^^^^ cannot `break` inside `async` closure + | | | enclosing `async` closure error[E0267]: `break` inside `gen` block --> $DIR/break-inside-coroutine-issue-124495.rs:24:19 | LL | let _ = gen { break; }; - | ------^^^^^--- - | | | - | | cannot `break` inside `gen` block + | --- ^^^^^ cannot `break` inside `gen` block + | | | enclosing `gen` block error[E0267]: `break` inside `async gen` block --> $DIR/break-inside-coroutine-issue-124495.rs:26:25 | LL | let _ = async gen { break; }; - | ------------^^^^^--- - | | | - | | cannot `break` inside `async gen` block + | --------- ^^^^^ cannot `break` inside `async gen` block + | | | enclosing `async gen` block error: aborting due to 7 previous errors diff --git a/tests/ui/coroutine/clone-impl-async.stderr b/tests/ui/coroutine/clone-impl-async.stderr index d172dff3abd..b5074911aa9 100644 --- a/tests/ui/coroutine/clone-impl-async.stderr +++ b/tests/ui/coroutine/clone-impl-async.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:12:27: 16:6}: Copy` is not satisfied +error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:12:27: 12:32}: Copy` is not satisfied --> $DIR/clone-impl-async.rs:17:16 | LL | check_copy(&inner_non_clone); - | ---------- ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/clone-impl-async.rs:12:27: 16:6}` + | ---------- ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/clone-impl-async.rs:12:27: 12:32}` | | | required by a bound introduced by this call | @@ -12,11 +12,11 @@ note: required by a bound in `check_copy` LL | fn check_copy<T: Copy>(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:12:27: 16:6}: Clone` is not satisfied +error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:12:27: 12:32}: Clone` is not satisfied --> $DIR/clone-impl-async.rs:19:17 | LL | check_clone(&inner_non_clone); - | ----------- ^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `{async block@$DIR/clone-impl-async.rs:12:27: 16:6}` + | ----------- ^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `{async block@$DIR/clone-impl-async.rs:12:27: 12:32}` | | | required by a bound introduced by this call | @@ -26,11 +26,11 @@ note: required by a bound in `check_clone` LL | fn check_clone<T: Clone>(_x: &T) {} | ^^^^^ required by this bound in `check_clone` -error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:23:27: 25:6}: Copy` is not satisfied +error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:23:27: 23:37}: Copy` is not satisfied --> $DIR/clone-impl-async.rs:26:16 | LL | check_copy(&outer_non_clone); - | ---------- ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/clone-impl-async.rs:23:27: 25:6}` + | ---------- ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/clone-impl-async.rs:23:27: 23:37}` | | | required by a bound introduced by this call | @@ -40,11 +40,11 @@ note: required by a bound in `check_copy` LL | fn check_copy<T: Copy>(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:23:27: 25:6}: Clone` is not satisfied +error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:23:27: 23:37}: Clone` is not satisfied --> $DIR/clone-impl-async.rs:28:17 | LL | check_clone(&outer_non_clone); - | ----------- ^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `{async block@$DIR/clone-impl-async.rs:23:27: 25:6}` + | ----------- ^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `{async block@$DIR/clone-impl-async.rs:23:27: 23:37}` | | | required by a bound introduced by this call | @@ -54,11 +54,11 @@ note: required by a bound in `check_clone` LL | fn check_clone<T: Clone>(_x: &T) {} | ^^^^^ required by this bound in `check_clone` -error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:31:28: 31:41}: Copy` is not satisfied +error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:31:28: 31:38}: Copy` is not satisfied --> $DIR/clone-impl-async.rs:32:16 | LL | check_copy(&maybe_copy_clone); - | ---------- ^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/clone-impl-async.rs:31:28: 31:41}` + | ---------- ^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/clone-impl-async.rs:31:28: 31:38}` | | | required by a bound introduced by this call | @@ -68,11 +68,11 @@ note: required by a bound in `check_copy` LL | fn check_copy<T: Copy>(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:31:28: 31:41}: Clone` is not satisfied +error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:31:28: 31:38}: Clone` is not satisfied --> $DIR/clone-impl-async.rs:34:17 | LL | check_clone(&maybe_copy_clone); - | ----------- ^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `{async block@$DIR/clone-impl-async.rs:31:28: 31:41}` + | ----------- ^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `{async block@$DIR/clone-impl-async.rs:31:28: 31:38}` | | | required by a bound introduced by this call | diff --git a/tests/ui/coroutine/gen_block_is_coro.stderr b/tests/ui/coroutine/gen_block_is_coro.stderr index 83a674fa53c..afcdce1d58d 100644 --- a/tests/ui/coroutine/gen_block_is_coro.stderr +++ b/tests/ui/coroutine/gen_block_is_coro.stderr @@ -1,20 +1,20 @@ -error[E0277]: the trait bound `{gen block@$DIR/gen_block_is_coro.rs:7:5: 7:21}: Coroutine` is not satisfied +error[E0277]: the trait bound `{gen block@$DIR/gen_block_is_coro.rs:7:5: 7:8}: Coroutine` is not satisfied --> $DIR/gen_block_is_coro.rs:6:13 | LL | fn foo() -> impl Coroutine<Yield = u32, Return = ()> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:7:5: 7:21}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:7:5: 7:8}` -error[E0277]: the trait bound `{gen block@$DIR/gen_block_is_coro.rs:11:5: 11:21}: Coroutine` is not satisfied +error[E0277]: the trait bound `{gen block@$DIR/gen_block_is_coro.rs:11:5: 11:8}: Coroutine` is not satisfied --> $DIR/gen_block_is_coro.rs:10:13 | LL | fn bar() -> impl Coroutine<Yield = i64, Return = ()> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:11:5: 11:21}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:11:5: 11:8}` -error[E0277]: the trait bound `{gen block@$DIR/gen_block_is_coro.rs:15:5: 15:21}: Coroutine` is not satisfied +error[E0277]: the trait bound `{gen block@$DIR/gen_block_is_coro.rs:15:5: 15:8}: Coroutine` is not satisfied --> $DIR/gen_block_is_coro.rs:14:13 | LL | fn baz() -> impl Coroutine<Yield = i32, Return = ()> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:15:5: 15:21}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:15:5: 15:8}` error: aborting due to 3 previous errors diff --git a/tests/ui/coroutine/gen_block_is_no_future.stderr b/tests/ui/coroutine/gen_block_is_no_future.stderr index fb2f2ba5597..bf0985a76a2 100644 --- a/tests/ui/coroutine/gen_block_is_no_future.stderr +++ b/tests/ui/coroutine/gen_block_is_no_future.stderr @@ -1,10 +1,10 @@ -error[E0277]: `{gen block@$DIR/gen_block_is_no_future.rs:5:5: 5:21}` is not a future +error[E0277]: `{gen block@$DIR/gen_block_is_no_future.rs:5:5: 5:8}` is not a future --> $DIR/gen_block_is_no_future.rs:4:13 | LL | fn foo() -> impl std::future::Future { - | ^^^^^^^^^^^^^^^^^^^^^^^^ `{gen block@$DIR/gen_block_is_no_future.rs:5:5: 5:21}` is not a future + | ^^^^^^^^^^^^^^^^^^^^^^^^ `{gen block@$DIR/gen_block_is_no_future.rs:5:5: 5:8}` is not a future | - = help: the trait `Future` is not implemented for `{gen block@$DIR/gen_block_is_no_future.rs:5:5: 5:21}` + = help: the trait `Future` is not implemented for `{gen block@$DIR/gen_block_is_no_future.rs:5:5: 5:8}` error: aborting due to 1 previous error diff --git a/tests/ui/coroutine/gen_block_move.stderr b/tests/ui/coroutine/gen_block_move.stderr index b93f6a9a610..720b8d73322 100644 --- a/tests/ui/coroutine/gen_block_move.stderr +++ b/tests/ui/coroutine/gen_block_move.stderr @@ -1,14 +1,11 @@ error[E0373]: gen block may outlive the current function, but it borrows `x`, which is owned by the current function --> $DIR/gen_block_move.rs:7:5 | -LL | / gen { -LL | | yield 42; -LL | | if x == "foo" { return } -LL | | x.clear(); - | | - `x` is borrowed here -LL | | for x in 3..6 { yield x } -LL | | } - | |_____^ may outlive borrowed value `x` +LL | gen { + | ^^^ may outlive borrowed value `x` +... +LL | x.clear(); + | - `x` is borrowed here | note: gen block is returned here --> $DIR/gen_block_move.rs:7:5 diff --git a/tests/ui/coverage-attr/name-value.rs b/tests/ui/coverage-attr/name-value.rs index cfd78a03e43..24a0feb0710 100644 --- a/tests/ui/coverage-attr/name-value.rs +++ b/tests/ui/coverage-attr/name-value.rs @@ -10,13 +10,11 @@ #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input -//~| ERROR attribute should be applied to a function definition or closure mod my_mod {} mod my_mod_inner { #![coverage = "off"] //~^ ERROR malformed `coverage` attribute input - //~| ERROR attribute should be applied to a function definition or closure } #[coverage = "off"] @@ -26,7 +24,6 @@ struct MyStruct; #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input -//~| ERROR attribute should be applied to a function definition or closure impl MyStruct { #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input @@ -51,7 +48,6 @@ trait MyTrait { #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input -//~| ERROR attribute should be applied to a function definition or closure impl MyTrait for MyStruct { #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input diff --git a/tests/ui/coverage-attr/name-value.stderr b/tests/ui/coverage-attr/name-value.stderr index caac687c94d..986467dda69 100644 --- a/tests/ui/coverage-attr/name-value.stderr +++ b/tests/ui/coverage-attr/name-value.stderr @@ -12,7 +12,7 @@ LL | #[coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/name-value.rs:17:5 + --> $DIR/name-value.rs:16:5 | LL | #![coverage = "off"] | ^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | #![coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/name-value.rs:22:1 + --> $DIR/name-value.rs:20:1 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ @@ -38,7 +38,7 @@ LL | #[coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/name-value.rs:31:5 + --> $DIR/name-value.rs:28:5 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ @@ -51,7 +51,7 @@ LL | #[coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/name-value.rs:27:1 + --> $DIR/name-value.rs:25:1 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | #[coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/name-value.rs:41:5 + --> $DIR/name-value.rs:38:5 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ @@ -77,7 +77,7 @@ LL | #[coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/name-value.rs:46:5 + --> $DIR/name-value.rs:43:5 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | #[coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/name-value.rs:37:1 + --> $DIR/name-value.rs:34:1 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ @@ -103,7 +103,7 @@ LL | #[coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/name-value.rs:56:5 + --> $DIR/name-value.rs:52:5 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ @@ -116,7 +116,7 @@ LL | #[coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/name-value.rs:61:5 + --> $DIR/name-value.rs:57:5 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ @@ -129,7 +129,7 @@ LL | #[coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/name-value.rs:52:1 + --> $DIR/name-value.rs:49:1 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ @@ -142,7 +142,7 @@ LL | #[coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/name-value.rs:67:1 + --> $DIR/name-value.rs:63:1 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ @@ -155,27 +155,7 @@ LL | #[coverage(on)] | error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/name-value.rs:11:1 - | -LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ -... -LL | mod my_mod {} - | ------------- not a function or closure - -error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/name-value.rs:17:5 - | -LL | / mod my_mod_inner { -LL | | #![coverage = "off"] - | | ^^^^^^^^^^^^^^^^^^^^ -LL | | -LL | | -LL | | } - | |_- not a function or closure - -error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/name-value.rs:22:1 + --> $DIR/name-value.rs:20:1 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ @@ -184,21 +164,7 @@ LL | struct MyStruct; | ---------------- not a function or closure error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/name-value.rs:27:1 - | -LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ -... -LL | / impl MyStruct { -LL | | #[coverage = "off"] -LL | | -LL | | -LL | | const X: u32 = 7; -LL | | } - | |_- not a function or closure - -error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/name-value.rs:37:1 + --> $DIR/name-value.rs:34:1 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ @@ -213,22 +179,7 @@ LL | | } | |_- not a function or closure error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/name-value.rs:52:1 - | -LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ -... -LL | / impl MyTrait for MyStruct { -LL | | #[coverage = "off"] -LL | | -LL | | -... | -LL | | type T = (); -LL | | } - | |_- not a function or closure - -error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/name-value.rs:41:5 + --> $DIR/name-value.rs:38:5 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ @@ -237,7 +188,7 @@ LL | const X: u32; | ------------- not a function or closure error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/name-value.rs:46:5 + --> $DIR/name-value.rs:43:5 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ @@ -246,7 +197,7 @@ LL | type T; | ------- not a function or closure error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/name-value.rs:31:5 + --> $DIR/name-value.rs:28:5 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ @@ -255,7 +206,7 @@ LL | const X: u32 = 7; | ----------------- not a function or closure error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/name-value.rs:56:5 + --> $DIR/name-value.rs:52:5 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ @@ -264,7 +215,7 @@ LL | const X: u32 = 8; | ----------------- not a function or closure error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/name-value.rs:61:5 + --> $DIR/name-value.rs:57:5 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ @@ -272,6 +223,6 @@ LL | #[coverage = "off"] LL | type T = (); | ------------ not a function or closure -error: aborting due to 23 previous errors +error: aborting due to 19 previous errors For more information about this error, try `rustc --explain E0788`. diff --git a/tests/ui/coverage-attr/no-coverage.rs b/tests/ui/coverage-attr/no-coverage.rs index 5290fccca61..9545b0b55cf 100644 --- a/tests/ui/coverage-attr/no-coverage.rs +++ b/tests/ui/coverage-attr/no-coverage.rs @@ -2,7 +2,7 @@ #![feature(coverage_attribute)] #![feature(impl_trait_in_assoc_type)] #![warn(unused_attributes)] -#![coverage(off)] //~ ERROR attribute should be applied to a function definition or closure +#![coverage(off)] #[coverage(off)] //~ ERROR attribute should be applied to a function definition or closure trait Trait { @@ -15,7 +15,7 @@ trait Trait { type U; } -#[coverage(off)] //~ ERROR attribute should be applied to a function definition or closure +#[coverage(off)] impl Trait for () { const X: u32 = 0; diff --git a/tests/ui/coverage-attr/no-coverage.stderr b/tests/ui/coverage-attr/no-coverage.stderr index c5e3b0922cb..3897d295940 100644 --- a/tests/ui/coverage-attr/no-coverage.stderr +++ b/tests/ui/coverage-attr/no-coverage.stderr @@ -12,20 +12,6 @@ LL | | } | |_- not a function or closure error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/no-coverage.rs:18:1 - | -LL | #[coverage(off)] - | ^^^^^^^^^^^^^^^^ -LL | / impl Trait for () { -LL | | const X: u32 = 0; -LL | | -LL | | #[coverage(off)] -... | -LL | | type U = impl Trait; -LL | | } - | |_- not a function or closure - -error[E0788]: attribute should be applied to a function definition or closure --> $DIR/no-coverage.rs:39:5 | LL | #[coverage(off)] @@ -97,12 +83,6 @@ LL | #[coverage(off)] LL | type T; | ------- not a function or closure -error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/no-coverage.rs:5:1 - | -LL | #![coverage(off)] - | ^^^^^^^^^^^^^^^^^ not a function or closure - error: unconstrained opaque type --> $DIR/no-coverage.rs:26:14 | @@ -111,6 +91,6 @@ LL | type U = impl Trait; | = note: `U` must be used in combination with a concrete type within the same impl -error: aborting due to 13 previous errors +error: aborting due to 11 previous errors For more information about this error, try `rustc --explain E0788`. diff --git a/tests/ui/coverage-attr/word-only.rs b/tests/ui/coverage-attr/word-only.rs index 0a61d1e709f..ea12e7b19ee 100644 --- a/tests/ui/coverage-attr/word-only.rs +++ b/tests/ui/coverage-attr/word-only.rs @@ -10,13 +10,11 @@ #[coverage] //~^ ERROR malformed `coverage` attribute input -//~| ERROR attribute should be applied to a function definition or closure mod my_mod {} mod my_mod_inner { #![coverage] //~^ ERROR malformed `coverage` attribute input - //~| ERROR attribute should be applied to a function definition or closure } #[coverage] @@ -26,7 +24,6 @@ struct MyStruct; #[coverage] //~^ ERROR malformed `coverage` attribute input -//~| ERROR attribute should be applied to a function definition or closure impl MyStruct { #[coverage] //~^ ERROR malformed `coverage` attribute input @@ -51,7 +48,6 @@ trait MyTrait { #[coverage] //~^ ERROR malformed `coverage` attribute input -//~| ERROR attribute should be applied to a function definition or closure impl MyTrait for MyStruct { #[coverage] //~^ ERROR malformed `coverage` attribute input diff --git a/tests/ui/coverage-attr/word-only.stderr b/tests/ui/coverage-attr/word-only.stderr index 18b5fed7484..1ce149724c6 100644 --- a/tests/ui/coverage-attr/word-only.stderr +++ b/tests/ui/coverage-attr/word-only.stderr @@ -12,7 +12,7 @@ LL | #[coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/word-only.rs:17:5 + --> $DIR/word-only.rs:16:5 | LL | #![coverage] | ^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | #![coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/word-only.rs:22:1 + --> $DIR/word-only.rs:20:1 | LL | #[coverage] | ^^^^^^^^^^^ @@ -38,7 +38,7 @@ LL | #[coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/word-only.rs:31:5 + --> $DIR/word-only.rs:28:5 | LL | #[coverage] | ^^^^^^^^^^^ @@ -51,7 +51,7 @@ LL | #[coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/word-only.rs:27:1 + --> $DIR/word-only.rs:25:1 | LL | #[coverage] | ^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | #[coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/word-only.rs:41:5 + --> $DIR/word-only.rs:38:5 | LL | #[coverage] | ^^^^^^^^^^^ @@ -77,7 +77,7 @@ LL | #[coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/word-only.rs:46:5 + --> $DIR/word-only.rs:43:5 | LL | #[coverage] | ^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | #[coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/word-only.rs:37:1 + --> $DIR/word-only.rs:34:1 | LL | #[coverage] | ^^^^^^^^^^^ @@ -103,7 +103,7 @@ LL | #[coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/word-only.rs:56:5 + --> $DIR/word-only.rs:52:5 | LL | #[coverage] | ^^^^^^^^^^^ @@ -116,7 +116,7 @@ LL | #[coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/word-only.rs:61:5 + --> $DIR/word-only.rs:57:5 | LL | #[coverage] | ^^^^^^^^^^^ @@ -129,7 +129,7 @@ LL | #[coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/word-only.rs:52:1 + --> $DIR/word-only.rs:49:1 | LL | #[coverage] | ^^^^^^^^^^^ @@ -142,7 +142,7 @@ LL | #[coverage(on)] | error: malformed `coverage` attribute input - --> $DIR/word-only.rs:67:1 + --> $DIR/word-only.rs:63:1 | LL | #[coverage] | ^^^^^^^^^^^ @@ -155,27 +155,7 @@ LL | #[coverage(on)] | error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/word-only.rs:11:1 - | -LL | #[coverage] - | ^^^^^^^^^^^ -... -LL | mod my_mod {} - | ------------- not a function or closure - -error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/word-only.rs:17:5 - | -LL | / mod my_mod_inner { -LL | | #![coverage] - | | ^^^^^^^^^^^^ -LL | | -LL | | -LL | | } - | |_- not a function or closure - -error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/word-only.rs:22:1 + --> $DIR/word-only.rs:20:1 | LL | #[coverage] | ^^^^^^^^^^^ @@ -184,21 +164,7 @@ LL | struct MyStruct; | ---------------- not a function or closure error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/word-only.rs:27:1 - | -LL | #[coverage] - | ^^^^^^^^^^^ -... -LL | / impl MyStruct { -LL | | #[coverage] -LL | | -LL | | -LL | | const X: u32 = 7; -LL | | } - | |_- not a function or closure - -error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/word-only.rs:37:1 + --> $DIR/word-only.rs:34:1 | LL | #[coverage] | ^^^^^^^^^^^ @@ -213,22 +179,7 @@ LL | | } | |_- not a function or closure error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/word-only.rs:52:1 - | -LL | #[coverage] - | ^^^^^^^^^^^ -... -LL | / impl MyTrait for MyStruct { -LL | | #[coverage] -LL | | -LL | | -... | -LL | | type T = (); -LL | | } - | |_- not a function or closure - -error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/word-only.rs:41:5 + --> $DIR/word-only.rs:38:5 | LL | #[coverage] | ^^^^^^^^^^^ @@ -237,7 +188,7 @@ LL | const X: u32; | ------------- not a function or closure error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/word-only.rs:46:5 + --> $DIR/word-only.rs:43:5 | LL | #[coverage] | ^^^^^^^^^^^ @@ -246,7 +197,7 @@ LL | type T; | ------- not a function or closure error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/word-only.rs:31:5 + --> $DIR/word-only.rs:28:5 | LL | #[coverage] | ^^^^^^^^^^^ @@ -255,7 +206,7 @@ LL | const X: u32 = 7; | ----------------- not a function or closure error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/word-only.rs:56:5 + --> $DIR/word-only.rs:52:5 | LL | #[coverage] | ^^^^^^^^^^^ @@ -264,7 +215,7 @@ LL | const X: u32 = 8; | ----------------- not a function or closure error[E0788]: attribute should be applied to a function definition or closure - --> $DIR/word-only.rs:61:5 + --> $DIR/word-only.rs:57:5 | LL | #[coverage] | ^^^^^^^^^^^ @@ -272,6 +223,6 @@ LL | #[coverage] LL | type T = (); | ------------ not a function or closure -error: aborting due to 23 previous errors +error: aborting due to 19 previous errors For more information about this error, try `rustc --explain E0788`. diff --git a/tests/ui/empty/empty-attributes.rs b/tests/ui/empty/empty-attributes.rs index d319227b217..027d30cce17 100644 --- a/tests/ui/empty/empty-attributes.rs +++ b/tests/ui/empty/empty-attributes.rs @@ -1,5 +1,3 @@ -#![feature(lint_reasons)] - #![deny(unused_attributes)] #![allow()] //~ ERROR unused attribute #![expect()] //~ ERROR unused attribute diff --git a/tests/ui/empty/empty-attributes.stderr b/tests/ui/empty/empty-attributes.stderr index 01d0d5a6b48..e86dea10c70 100644 --- a/tests/ui/empty/empty-attributes.stderr +++ b/tests/ui/empty/empty-attributes.stderr @@ -1,18 +1,18 @@ error: unused attribute - --> $DIR/empty-attributes.rs:11:1 + --> $DIR/empty-attributes.rs:9:1 | LL | #[repr()] | ^^^^^^^^^ help: remove this attribute | = note: attribute `repr` with an empty list has no effect note: the lint level is defined here - --> $DIR/empty-attributes.rs:3:9 + --> $DIR/empty-attributes.rs:1:9 | LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/empty-attributes.rs:14:1 + --> $DIR/empty-attributes.rs:12:1 | LL | #[target_feature()] | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute @@ -20,7 +20,7 @@ LL | #[target_feature()] = note: attribute `target_feature` with an empty list has no effect error: unused attribute - --> $DIR/empty-attributes.rs:4:1 + --> $DIR/empty-attributes.rs:2:1 | LL | #![allow()] | ^^^^^^^^^^^ help: remove this attribute @@ -28,7 +28,7 @@ LL | #![allow()] = note: attribute `allow` with an empty list has no effect error: unused attribute - --> $DIR/empty-attributes.rs:5:1 + --> $DIR/empty-attributes.rs:3:1 | LL | #![expect()] | ^^^^^^^^^^^^ help: remove this attribute @@ -36,7 +36,7 @@ LL | #![expect()] = note: attribute `expect` with an empty list has no effect error: unused attribute - --> $DIR/empty-attributes.rs:6:1 + --> $DIR/empty-attributes.rs:4:1 | LL | #![warn()] | ^^^^^^^^^^ help: remove this attribute @@ -44,7 +44,7 @@ LL | #![warn()] = note: attribute `warn` with an empty list has no effect error: unused attribute - --> $DIR/empty-attributes.rs:7:1 + --> $DIR/empty-attributes.rs:5:1 | LL | #![deny()] | ^^^^^^^^^^ help: remove this attribute @@ -52,7 +52,7 @@ LL | #![deny()] = note: attribute `deny` with an empty list has no effect error: unused attribute - --> $DIR/empty-attributes.rs:8:1 + --> $DIR/empty-attributes.rs:6:1 | LL | #![forbid()] | ^^^^^^^^^^^^ help: remove this attribute @@ -60,7 +60,7 @@ LL | #![forbid()] = note: attribute `forbid` with an empty list has no effect error: unused attribute - --> $DIR/empty-attributes.rs:9:1 + --> $DIR/empty-attributes.rs:7:1 | LL | #![feature()] | ^^^^^^^^^^^^^ help: remove this attribute diff --git a/tests/ui/error-codes/E0602.stderr b/tests/ui/error-codes/E0602.stderr index b6b5cd5c3d3..b0b6033aadd 100644 --- a/tests/ui/error-codes/E0602.stderr +++ b/tests/ui/error-codes/E0602.stderr @@ -13,6 +13,11 @@ warning[E0602]: unknown lint: `bogus` = note: requested on the command line with `-D bogus` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -warning: 3 warnings emitted +warning[E0602]: unknown lint: `bogus` + | + = note: requested on the command line with `-D bogus` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: 4 warnings emitted For more information about this error, try `rustc --explain E0602`. diff --git a/tests/ui/feature-gates/feature-gate-lint-reasons.rs b/tests/ui/feature-gates/feature-gate-lint-reasons.rs deleted file mode 100644 index 7756074e235..00000000000 --- a/tests/ui/feature-gates/feature-gate-lint-reasons.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![warn(nonstandard_style, reason = "the standard should be respected")] -//~^ ERROR lint reasons are experimental -//~| ERROR lint reasons are experimental - -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-lint-reasons.stderr b/tests/ui/feature-gates/feature-gate-lint-reasons.stderr deleted file mode 100644 index efcb3a10f32..00000000000 --- a/tests/ui/feature-gates/feature-gate-lint-reasons.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error[E0658]: lint reasons are experimental - --> $DIR/feature-gate-lint-reasons.rs:1:28 - | -LL | #![warn(nonstandard_style, reason = "the standard should be respected")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #54503 <https://github.com/rust-lang/rust/issues/54503> for more information - = help: add `#![feature(lint_reasons)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: lint reasons are experimental - --> $DIR/feature-gate-lint-reasons.rs:1:28 - | -LL | #![warn(nonstandard_style, reason = "the standard should be respected")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #54503 <https://github.com/rust-lang/rust/issues/54503> for more information - = help: add `#![feature(lint_reasons)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-patchable-function-entry.rs b/tests/ui/feature-gates/feature-gate-patchable-function-entry.rs new file mode 100644 index 00000000000..b9642c7bfd4 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-patchable-function-entry.rs @@ -0,0 +1,3 @@ +#[patchable_function_entry(prefix_nops = 1, entry_nops = 1)] +//~^ ERROR: the `#[patchable_function_entry]` attribute is an experimental feature +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-patchable-function-entry.stderr b/tests/ui/feature-gates/feature-gate-patchable-function-entry.stderr new file mode 100644 index 00000000000..55fcdb4f729 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-patchable-function-entry.stderr @@ -0,0 +1,13 @@ +error[E0658]: the `#[patchable_function_entry]` attribute is an experimental feature + --> $DIR/feature-gate-patchable-function-entry.rs:1:1 + | +LL | #[patchable_function_entry(prefix_nops = 1, entry_nops = 1)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #123115 <https://github.com/rust-lang/rust/issues/123115> for more information + = help: add `#![feature(patchable_function_entry)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr b/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr index 84f00827c60..56534946308 100644 --- a/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr +++ b/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr @@ -3,6 +3,10 @@ error: extern block cannot be declared unsafe | LL | unsafe extern "C" { | ^^^^^^ + | + = note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information + = help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental --> $DIR/feature-gate-unsafe-extern-blocks.rs:9:5 diff --git a/tests/ui/fmt/send-sync.stderr b/tests/ui/fmt/send-sync.stderr index bebf575d9a7..dff9b23ba67 100644 --- a/tests/ui/fmt/send-sync.stderr +++ b/tests/ui/fmt/send-sync.stderr @@ -1,45 +1,27 @@ -error[E0277]: `core::fmt::rt::Opaque` cannot be shared between threads safely +error[E0277]: `Arguments<'_>` cannot be sent between threads safely --> $DIR/send-sync.rs:8:10 | LL | send(format_args!("{:?}", c)); - | ---- ^^^^^^^^^^^^^^^^^^^^^^^ `core::fmt::rt::Opaque` cannot be shared between threads safely + | ---- ^^^^^^^^^^^^^^^^^^^^^^^ `Arguments<'_>` cannot be sent between threads safely | | | required by a bound introduced by this call | - = help: within `[core::fmt::rt::Argument<'_>]`, the trait `Sync` is not implemented for `core::fmt::rt::Opaque`, which is required by `Arguments<'_>: Send` - = note: required because it appears within the type `&core::fmt::rt::Opaque` -note: required because it appears within the type `core::fmt::rt::ArgumentType<'_>` - --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL -note: required because it appears within the type `core::fmt::rt::Argument<'_>` - --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL - = note: required because it appears within the type `[core::fmt::rt::Argument<'_>]` - = note: required for `&[core::fmt::rt::Argument<'_>]` to implement `Send` -note: required because it appears within the type `Arguments<'_>` - --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL + = help: the trait `Send` is not implemented for `Arguments<'_>` note: required by a bound in `send` --> $DIR/send-sync.rs:1:12 | LL | fn send<T: Send>(_: T) {} | ^^^^ required by this bound in `send` -error[E0277]: `core::fmt::rt::Opaque` cannot be shared between threads safely +error[E0277]: `Arguments<'_>` cannot be shared between threads safely --> $DIR/send-sync.rs:9:10 | LL | sync(format_args!("{:?}", c)); - | ---- ^^^^^^^^^^^^^^^^^^^^^^^ `core::fmt::rt::Opaque` cannot be shared between threads safely + | ---- ^^^^^^^^^^^^^^^^^^^^^^^ `Arguments<'_>` cannot be shared between threads safely | | | required by a bound introduced by this call | - = help: within `Arguments<'_>`, the trait `Sync` is not implemented for `core::fmt::rt::Opaque`, which is required by `Arguments<'_>: Sync` - = note: required because it appears within the type `&core::fmt::rt::Opaque` -note: required because it appears within the type `core::fmt::rt::ArgumentType<'_>` - --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL -note: required because it appears within the type `core::fmt::rt::Argument<'_>` - --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL - = note: required because it appears within the type `[core::fmt::rt::Argument<'_>]` - = note: required because it appears within the type `&[core::fmt::rt::Argument<'_>]` -note: required because it appears within the type `Arguments<'_>` - --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL + = help: the trait `Sync` is not implemented for `Arguments<'_>` note: required by a bound in `sync` --> $DIR/send-sync.rs:2:12 | diff --git a/tests/ui/generic-associated-types/issue-90014-tait.stderr b/tests/ui/generic-associated-types/issue-90014-tait.stderr index e4bcc92bf6e..09c2903ab02 100644 --- a/tests/ui/generic-associated-types/issue-90014-tait.stderr +++ b/tests/ui/generic-associated-types/issue-90014-tait.stderr @@ -10,7 +10,7 @@ LL | async { () } | ^^^^^^^^^^^^ expected future, found `async` block | = note: expected opaque type `Foo<'_>::Fut<'a>` - found `async` block `{async block@$DIR/issue-90014-tait.rs:18:9: 18:21}` + found `async` block `{async block@$DIR/issue-90014-tait.rs:18:9: 18:14}` note: this item must have the opaque type in its signature in order to be able to register hidden types --> $DIR/issue-90014-tait.rs:17:8 | diff --git a/tests/ui/higher-ranked/erroneous-lifetime-bound.rs b/tests/ui/higher-ranked/erroneous-lifetime-bound.rs new file mode 100644 index 00000000000..b1720087b5f --- /dev/null +++ b/tests/ui/higher-ranked/erroneous-lifetime-bound.rs @@ -0,0 +1,5 @@ +fn foo<T>() where T: for<'a> 'a {} +//~^ ERROR `for<...>` may only modify trait bounds, not lifetime bounds +//~| ERROR use of undeclared lifetime name `'a` [E0261] + +fn main() {} diff --git a/tests/ui/higher-ranked/erroneous-lifetime-bound.stderr b/tests/ui/higher-ranked/erroneous-lifetime-bound.stderr new file mode 100644 index 00000000000..5b104f45d23 --- /dev/null +++ b/tests/ui/higher-ranked/erroneous-lifetime-bound.stderr @@ -0,0 +1,25 @@ +error: `for<...>` may only modify trait bounds, not lifetime bounds + --> $DIR/erroneous-lifetime-bound.rs:1:25 + | +LL | fn foo<T>() where T: for<'a> 'a {} + | ^^^^ + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/erroneous-lifetime-bound.rs:1:30 + | +LL | fn foo<T>() where T: for<'a> 'a {} + | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | fn foo<T>() where for<'a> T: for<'a> 'a {} + | +++++++ +help: consider introducing lifetime `'a` here + | +LL | fn foo<'a, T>() where T: for<'a> 'a {} + | +++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0261`. diff --git a/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs b/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs index a213994ff86..f6120b3fc70 100644 --- a/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs +++ b/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs @@ -1,5 +1,3 @@ -#![feature(lint_reasons)] - use std::ops::Deref; pub trait Foo { diff --git a/tests/ui/impl-trait/in-trait/deep-match-works.rs b/tests/ui/impl-trait/in-trait/deep-match-works.rs index 02fe5b0e19b..591429d6047 100644 --- a/tests/ui/impl-trait/in-trait/deep-match-works.rs +++ b/tests/ui/impl-trait/in-trait/deep-match-works.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(lint_reasons)] - pub struct Wrapper<T>(T); pub trait Foo { diff --git a/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr b/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr index 9cc4c4b2f9e..a0840699268 100644 --- a/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr +++ b/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr @@ -5,7 +5,7 @@ LL | let _: &dyn rpitit::Foo = todo!(); | ^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/auxiliary/rpitit.rs:6:21 + --> $DIR/auxiliary/rpitit.rs:4:21 | LL | fn bar(self) -> impl Deref<Target = impl Sized>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait cannot be made into an object because method `bar` references an `impl Trait` type in its return type diff --git a/tests/ui/impl-trait/in-trait/foreign.rs b/tests/ui/impl-trait/in-trait/foreign.rs index ca759afc2e6..3b6f79a4f52 100644 --- a/tests/ui/impl-trait/in-trait/foreign.rs +++ b/tests/ui/impl-trait/in-trait/foreign.rs @@ -1,8 +1,6 @@ //@ check-pass //@ aux-build: rpitit.rs -#![feature(lint_reasons)] - extern crate rpitit; use rpitit::{Foo, Foreign}; diff --git a/tests/ui/impl-trait/in-trait/foreign.stderr b/tests/ui/impl-trait/in-trait/foreign.stderr index 1a5a4f2432b..36114dcf02b 100644 --- a/tests/ui/impl-trait/in-trait/foreign.stderr +++ b/tests/ui/impl-trait/in-trait/foreign.stderr @@ -1,5 +1,5 @@ warning: impl trait in impl method signature does not match trait method signature - --> $DIR/foreign.rs:23:21 + --> $DIR/foreign.rs:21:21 | LL | fn bar(self) -> Arc<String> { | ^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | fn bar(self) -> Arc<String> { = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate = note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information note: the lint level is defined here - --> $DIR/foreign.rs:22:12 + --> $DIR/foreign.rs:20:12 | LL | #[warn(refining_impl_trait)] | ^^^^^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | fn bar(self) -> impl Deref<Target = impl Sized> { | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ warning: impl trait in impl method signature does not match trait method signature - --> $DIR/foreign.rs:33:21 + --> $DIR/foreign.rs:31:21 | LL | fn bar(self) -> Arc<String> { | ^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | fn bar(self) -> Arc<String> { = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate = note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information note: the lint level is defined here - --> $DIR/foreign.rs:31:12 + --> $DIR/foreign.rs:29:12 | LL | #[warn(refining_impl_trait)] | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/impl-trait/in-trait/nested-rpitit.rs b/tests/ui/impl-trait/in-trait/nested-rpitit.rs index 91fb5331f76..6e495458228 100644 --- a/tests/ui/impl-trait/in-trait/nested-rpitit.rs +++ b/tests/ui/impl-trait/in-trait/nested-rpitit.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(lint_reasons)] - use std::fmt::Display; use std::ops::Deref; diff --git a/tests/ui/impl-trait/in-trait/reveal.rs b/tests/ui/impl-trait/in-trait/reveal.rs index f949077a131..f6ce31e3837 100644 --- a/tests/ui/impl-trait/in-trait/reveal.rs +++ b/tests/ui/impl-trait/in-trait/reveal.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(lint_reasons)] - pub trait Foo { fn f() -> Box<impl Sized>; } diff --git a/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs b/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs index b9fe8d8bfc5..4e46b7114c1 100644 --- a/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs +++ b/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs @@ -1,7 +1,5 @@ // issue: 113903 -#![feature(lint_reasons)] - use std::ops::Deref; pub trait Tr { diff --git a/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.stderr b/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.stderr index 73ada8d7096..e7d38f22406 100644 --- a/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.stderr +++ b/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `Missing` in this scope - --> $DIR/rpitit-shadowed-by-missing-adt.rs:8:35 + --> $DIR/rpitit-shadowed-by-missing-adt.rs:6:35 | LL | fn w() -> impl Deref<Target = Missing<impl Sized>>; | ^^^^^^^ not found in this scope diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr b/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr index 0cd76815afa..56b83cbca77 100644 --- a/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr +++ b/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr @@ -1,5 +1,5 @@ error[E0623]: lifetime mismatch - --> $DIR/signature-mismatch.rs:79:10 + --> $DIR/signature-mismatch.rs:77:10 | LL | &'a self, | -------- this parameter and the return type are declared with different lifetimes... diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.rs b/tests/ui/impl-trait/in-trait/signature-mismatch.rs index 7a74281b1f2..55b9a0de5ff 100644 --- a/tests/ui/impl-trait/in-trait/signature-mismatch.rs +++ b/tests/ui/impl-trait/in-trait/signature-mismatch.rs @@ -2,8 +2,6 @@ //@ revisions: success failure //@[success] check-pass -#![feature(lint_reasons)] - use std::future::Future; pub trait Captures<'a> {} diff --git a/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs b/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs index 3ef6735de80..50bb61c9f02 100644 --- a/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs +++ b/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs @@ -1,7 +1,6 @@ //@ check-pass #![feature(specialization)] -#![feature(lint_reasons)] #![allow(incomplete_features)] pub trait Foo { diff --git a/tests/ui/impl-trait/in-trait/success.rs b/tests/ui/impl-trait/in-trait/success.rs index c99291def03..97a1ce80997 100644 --- a/tests/ui/impl-trait/in-trait/success.rs +++ b/tests/ui/impl-trait/in-trait/success.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(lint_reasons)] - use std::fmt::Display; pub trait Foo { diff --git a/tests/ui/impl-trait/issue-55872-3.stderr b/tests/ui/impl-trait/issue-55872-3.stderr index 9af0fad9cdb..f892da2a535 100644 --- a/tests/ui/impl-trait/issue-55872-3.stderr +++ b/tests/ui/impl-trait/issue-55872-3.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `{async block@$DIR/issue-55872-3.rs:15:9: 15:17}: Copy` is not satisfied +error[E0277]: the trait bound `{async block@$DIR/issue-55872-3.rs:15:9: 15:14}: Copy` is not satisfied --> $DIR/issue-55872-3.rs:13:20 | LL | fn foo<T>() -> Self::E { - | ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:15:9: 15:17}` + | ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:15:9: 15:14}` error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/issues/issue-78722-2.stderr b/tests/ui/impl-trait/issues/issue-78722-2.stderr index 91dad1b5e67..dc5579c1c82 100644 --- a/tests/ui/impl-trait/issues/issue-78722-2.stderr +++ b/tests/ui/impl-trait/issues/issue-78722-2.stderr @@ -1,4 +1,4 @@ -error[E0271]: expected `{async block@$DIR/issue-78722-2.rs:13:13: 13:21}` to be a future that resolves to `u8`, but it resolves to `()` +error[E0271]: expected `{async block@$DIR/issue-78722-2.rs:13:13: 13:18}` to be a future that resolves to `u8`, but it resolves to `()` --> $DIR/issue-78722-2.rs:11:30 | LL | fn concrete_use() -> F { @@ -16,7 +16,7 @@ LL | let f: F = async { 1 }; | expected due to this | = note: expected opaque type `F` - found `async` block `{async block@$DIR/issue-78722-2.rs:16:20: 16:31}` + found `async` block `{async block@$DIR/issue-78722-2.rs:16:20: 16:25}` error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/issues/issue-78722.stderr b/tests/ui/impl-trait/issues/issue-78722.stderr index 0bb24fae822..3642000597f 100644 --- a/tests/ui/impl-trait/issues/issue-78722.stderr +++ b/tests/ui/impl-trait/issues/issue-78722.stderr @@ -8,7 +8,7 @@ LL | let f: F = async { 1 }; = help: add `#![feature(const_async_blocks)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0271]: expected `{async block@$DIR/issue-78722.rs:10:13: 10:21}` to be a future that resolves to `u8`, but it resolves to `()` +error[E0271]: expected `{async block@$DIR/issue-78722.rs:10:13: 10:18}` to be a future that resolves to `u8`, but it resolves to `()` --> $DIR/issue-78722.rs:8:30 | LL | fn concrete_use() -> F { diff --git a/tests/ui/impl-trait/nested-return-type4.stderr b/tests/ui/impl-trait/nested-return-type4.stderr index 14d51a1b064..f1e3b97be02 100644 --- a/tests/ui/impl-trait/nested-return-type4.stderr +++ b/tests/ui/impl-trait/nested-return-type4.stderr @@ -4,7 +4,7 @@ error[E0700]: hidden type for `impl Future<Output = impl Sized>` captures lifeti LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> { | -- --------------------------------------------- opaque type defined here | | - | hidden type `{async block@$DIR/nested-return-type4.rs:4:5: 4:31}` captures the lifetime `'s` as defined here + | hidden type `{async block@$DIR/nested-return-type4.rs:4:5: 4:15}` captures the lifetime `'s` as defined here LL | async move { let _s = s; } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | diff --git a/tests/ui/impl-trait/precise-capturing/bound-modifiers.rs b/tests/ui/impl-trait/precise-capturing/bound-modifiers.rs new file mode 100644 index 00000000000..15f21882628 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/bound-modifiers.rs @@ -0,0 +1,25 @@ +//@ edition: 2021 + +#![feature(precise_capturing)] + +fn polarity() -> impl Sized + ?use<> {} +//~^ ERROR expected identifier, found keyword `use` +//~| ERROR cannot find trait `r#use` in this scope +//~| WARN relaxing a default bound only does something for `?Sized` +//~| WARN relaxing a default bound only does something for `?Sized` + +fn asyncness() -> impl Sized + async use<> {} +//~^ ERROR expected identifier, found keyword `use` +//~| ERROR cannot find trait `r#use` in this scope +//~| ERROR async closures are unstable + +fn constness() -> impl Sized + const use<> {} +//~^ ERROR expected identifier, found keyword `use` +//~| ERROR cannot find trait `r#use` in this scope +//~| ERROR const trait impls are experimental + +fn binder() -> impl Sized + for<'a> use<> {} +//~^ ERROR expected identifier, found keyword `use` +//~| ERROR cannot find trait `r#use` in this scope + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/bound-modifiers.stderr b/tests/ui/impl-trait/precise-capturing/bound-modifiers.stderr new file mode 100644 index 00000000000..4602225e7b9 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/bound-modifiers.stderr @@ -0,0 +1,87 @@ +error: expected identifier, found keyword `use` + --> $DIR/bound-modifiers.rs:5:32 + | +LL | fn polarity() -> impl Sized + ?use<> {} + | ^^^ expected identifier, found keyword + +error: expected identifier, found keyword `use` + --> $DIR/bound-modifiers.rs:11:38 + | +LL | fn asyncness() -> impl Sized + async use<> {} + | ^^^ expected identifier, found keyword + +error: expected identifier, found keyword `use` + --> $DIR/bound-modifiers.rs:16:38 + | +LL | fn constness() -> impl Sized + const use<> {} + | ^^^ expected identifier, found keyword + +error: expected identifier, found keyword `use` + --> $DIR/bound-modifiers.rs:21:37 + | +LL | fn binder() -> impl Sized + for<'a> use<> {} + | ^^^ expected identifier, found keyword + +error[E0405]: cannot find trait `r#use` in this scope + --> $DIR/bound-modifiers.rs:5:32 + | +LL | fn polarity() -> impl Sized + ?use<> {} + | ^^^ not found in this scope + +error[E0405]: cannot find trait `r#use` in this scope + --> $DIR/bound-modifiers.rs:11:38 + | +LL | fn asyncness() -> impl Sized + async use<> {} + | ^^^ not found in this scope + +error[E0405]: cannot find trait `r#use` in this scope + --> $DIR/bound-modifiers.rs:16:38 + | +LL | fn constness() -> impl Sized + const use<> {} + | ^^^ not found in this scope + +error[E0405]: cannot find trait `r#use` in this scope + --> $DIR/bound-modifiers.rs:21:37 + | +LL | fn binder() -> impl Sized + for<'a> use<> {} + | ^^^ not found in this scope + +error[E0658]: async closures are unstable + --> $DIR/bound-modifiers.rs:11:32 + | +LL | fn asyncness() -> impl Sized + async use<> {} + | ^^^^^ + | + = note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information + = help: add `#![feature(async_closure)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: to use an async block, remove the `||`: `async {` + +error[E0658]: const trait impls are experimental + --> $DIR/bound-modifiers.rs:16:32 + | +LL | fn constness() -> impl Sized + const use<> {} + | ^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default + --> $DIR/bound-modifiers.rs:5:31 + | +LL | fn polarity() -> impl Sized + ?use<> {} + | ^^^^^^ + +warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default + --> $DIR/bound-modifiers.rs:5:31 + | +LL | fn polarity() -> impl Sized + ?use<> {} + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 10 previous errors; 2 warnings emitted + +Some errors have detailed explanations: E0405, E0658. +For more information about an error, try `rustc --explain E0405`. diff --git a/tests/ui/linkage-attr/unreferenced-used-static-issue-127052.rs b/tests/ui/linkage-attr/unreferenced-used-static-issue-127052.rs new file mode 100644 index 00000000000..aa8236b7431 --- /dev/null +++ b/tests/ui/linkage-attr/unreferenced-used-static-issue-127052.rs @@ -0,0 +1,9 @@ +// This is a non-regression test for issue #127052 where unreferenced `#[used]` statics couldn't be +// removed by the MSVC linker, causing linking errors. + +//@ build-pass: needs linking +//@ only-msvc + +#[used] +static FOO: u32 = 0; +fn main() {} diff --git a/tests/ui/lint/cli-unknown-force-warn.stderr b/tests/ui/lint/cli-unknown-force-warn.stderr index 5084b4a4001..cfff190b54a 100644 --- a/tests/ui/lint/cli-unknown-force-warn.stderr +++ b/tests/ui/lint/cli-unknown-force-warn.stderr @@ -13,6 +13,11 @@ warning[E0602]: unknown lint: `foo_qux` = note: requested on the command line with `--force-warn foo_qux` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -warning: 3 warnings emitted +warning[E0602]: unknown lint: `foo_qux` + | + = note: requested on the command line with `--force-warn foo_qux` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: 4 warnings emitted For more information about this error, try `rustc --explain E0602`. diff --git a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs index 37c78bc68ed..20999df9844 100644 --- a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs +++ b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs @@ -7,7 +7,6 @@ // it also checks that the `dead_code` lint is also *NOT* emited // for `bar` as it's suppresed by the `#[expect]` on `bar` -#![feature(lint_reasons)] #![warn(dead_code)] // to override compiletest fn bar() {} diff --git a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.stderr b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.stderr index d5c4dabed01..a199859cb20 100644 --- a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.stderr +++ b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.stderr @@ -1,5 +1,5 @@ warning: this lint expectation is unfulfilled - --> $DIR/allow-or-expect-dead_code-114557-2.rs:15:10 + --> $DIR/allow-or-expect-dead_code-114557-2.rs:14:10 | LL | #[expect(dead_code)] | ^^^^^^^^^ diff --git a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs index d2ead24b57c..08103b23387 100644 --- a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs +++ b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs @@ -3,7 +3,6 @@ // this test makes sure that the `unfulfilled_lint_expectations` lint // is being emited for `foo` as foo is not dead code, it's pub -#![feature(lint_reasons)] #![warn(dead_code)] // to override compiletest #[expect(dead_code)] diff --git a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.stderr b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.stderr index c954a75b394..3169f0123e9 100644 --- a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.stderr +++ b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.stderr @@ -1,5 +1,5 @@ warning: this lint expectation is unfulfilled - --> $DIR/allow-or-expect-dead_code-114557-3.rs:9:10 + --> $DIR/allow-or-expect-dead_code-114557-3.rs:8:10 | LL | #[expect(dead_code)] | ^^^^^^^^^ diff --git a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs index 323bb06b681..f2625f0781f 100644 --- a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs +++ b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs @@ -4,7 +4,6 @@ // this test checks that no matter if we put #[allow(dead_code)] // or #[expect(dead_code)], no warning is being emited -#![feature(lint_reasons)] #![warn(dead_code)] // to override compiletest fn f() {} diff --git a/tests/ui/lint/empty-lint-attributes.rs b/tests/ui/lint/empty-lint-attributes.rs index b12b4064990..0193345e5c8 100644 --- a/tests/ui/lint/empty-lint-attributes.rs +++ b/tests/ui/lint/empty-lint-attributes.rs @@ -1,5 +1,3 @@ -#![feature(lint_reasons)] - //@ check-pass // Empty (and reason-only) lint attributes are legal—although we may want to diff --git a/tests/ui/lint/expect-future_breakage-crash-issue-126521.rs b/tests/ui/lint/expect-future_breakage-crash-issue-126521.rs index 0e622ff3aaf..19eb18fd17b 100644 --- a/tests/ui/lint/expect-future_breakage-crash-issue-126521.rs +++ b/tests/ui/lint/expect-future_breakage-crash-issue-126521.rs @@ -1,3 +1,5 @@ +//@ check-pass + // This test covers similar crashes from both #126521 and #126751. macro_rules! foo { @@ -12,12 +14,25 @@ macro_rules! bar { }; } -fn main() { +fn allow() { + #[allow(semicolon_in_expressions_from_macros)] + let _ = foo!(x); + + #[allow(semicolon_in_expressions_from_macros)] + let _ = bar!(x); +} + +// The `semicolon_in_expressions_from_macros` lint seems to be emitted even if the +// lint level is `allow` as shown in the function above. The behavior of `expect` +// should mirror this behavior. However, no `unfulfilled_lint_expectation` lint +// is emitted, since the expectation is theoretically fulfilled. +fn expect() { #[expect(semicolon_in_expressions_from_macros)] - //~^ ERROR the `#[expect]` attribute is an experimental feature let _ = foo!(x); #[expect(semicolon_in_expressions_from_macros)] - //~^ ERROR the `#[expect]` attribute is an experimental feature let _ = bar!(x); } + +fn main() { +} diff --git a/tests/ui/lint/expect-future_breakage-crash-issue-126521.stderr b/tests/ui/lint/expect-future_breakage-crash-issue-126521.stderr index 994630ec23b..72a74c1579d 100644 --- a/tests/ui/lint/expect-future_breakage-crash-issue-126521.stderr +++ b/tests/ui/lint/expect-future_breakage-crash-issue-126521.stderr @@ -1,23 +1,52 @@ -error[E0658]: the `#[expect]` attribute is an experimental feature - --> $DIR/expect-future_breakage-crash-issue-126521.rs:16:5 +Future incompatibility report: Future breakage diagnostic: +warning: trailing semicolon in macro used in expression position + --> $DIR/expect-future_breakage-crash-issue-126521.rs:7:13 | -LL | #[expect(semicolon_in_expressions_from_macros)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | true; + | ^ +... +LL | let _ = foo!(x); + | ------- in this macro invocation | - = note: see issue #54503 <https://github.com/rust-lang/rust/issues/54503> for more information - = help: add `#![feature(lint_reasons)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813> + = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0658]: the `#[expect]` attribute is an experimental feature - --> $DIR/expect-future_breakage-crash-issue-126521.rs:20:5 +Future breakage diagnostic: +warning: trailing semicolon in macro used in expression position + --> $DIR/expect-future_breakage-crash-issue-126521.rs:13:35 | -LL | #[expect(semicolon_in_expressions_from_macros)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | (5_i32.overflowing_sub(3)); + | ^ +... +LL | let _ = bar!(x); + | ------- in this macro invocation | - = note: see issue #54503 <https://github.com/rust-lang/rust/issues/54503> for more information - = help: add `#![feature(lint_reasons)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813> + = note: this warning originates in the macro `bar` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 2 previous errors +Future breakage diagnostic: +warning: trailing semicolon in macro used in expression position + --> $DIR/expect-future_breakage-crash-issue-126521.rs:7:13 + | +LL | true; + | ^ +... +LL | let _ = foo!(x); + | ------- in this macro invocation + | + = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: trailing semicolon in macro used in expression position + --> $DIR/expect-future_breakage-crash-issue-126521.rs:13:35 + | +LL | (5_i32.overflowing_sub(3)); + | ^ +... +LL | let _ = bar!(x); + | ------- in this macro invocation + | + = note: this warning originates in the macro `bar` (in Nightly builds, run with -Z macro-backtrace for more info) -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/lint/lint-removed-cmdline-deny.stderr b/tests/ui/lint/lint-removed-cmdline-deny.stderr index 3321afa7fcd..2a24e795f44 100644 --- a/tests/ui/lint/lint-removed-cmdline-deny.stderr +++ b/tests/ui/lint/lint-removed-cmdline-deny.stderr @@ -26,5 +26,10 @@ LL | #[deny(warnings)] | ^^^^^^^^ = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]` -error: aborting due to 4 previous errors +error: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok + | + = note: requested on the command line with `-D raw_pointer_derive` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 5 previous errors diff --git a/tests/ui/lint/lint-removed-cmdline.stderr b/tests/ui/lint/lint-removed-cmdline.stderr index fd63433c308..78ae2fd8fbf 100644 --- a/tests/ui/lint/lint-removed-cmdline.stderr +++ b/tests/ui/lint/lint-removed-cmdline.stderr @@ -26,5 +26,10 @@ LL | #[deny(warnings)] | ^^^^^^^^ = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]` -error: aborting due to 1 previous error; 3 warnings emitted +warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok + | + = note: requested on the command line with `-D raw_pointer_derive` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 1 previous error; 4 warnings emitted diff --git a/tests/ui/lint/lint-renamed-cmdline-deny.stderr b/tests/ui/lint/lint-renamed-cmdline-deny.stderr index 0e182a4e5de..3c1a59ec1e1 100644 --- a/tests/ui/lint/lint-renamed-cmdline-deny.stderr +++ b/tests/ui/lint/lint-renamed-cmdline-deny.stderr @@ -29,5 +29,11 @@ LL | #[deny(unused)] | ^^^^^^ = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]` -error: aborting due to 4 previous errors +error: lint `bare_trait_object` has been renamed to `bare_trait_objects` + | + = help: use the new name `bare_trait_objects` + = note: requested on the command line with `-D bare_trait_object` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 5 previous errors diff --git a/tests/ui/lint/lint-renamed-cmdline.stderr b/tests/ui/lint/lint-renamed-cmdline.stderr index d6bb72f34dc..6544416f611 100644 --- a/tests/ui/lint/lint-renamed-cmdline.stderr +++ b/tests/ui/lint/lint-renamed-cmdline.stderr @@ -29,5 +29,11 @@ LL | #[deny(unused)] | ^^^^^^ = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]` -error: aborting due to 1 previous error; 3 warnings emitted +warning: lint `bare_trait_object` has been renamed to `bare_trait_objects` + | + = help: use the new name `bare_trait_objects` + = note: requested on the command line with `-D bare_trait_object` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 1 previous error; 4 warnings emitted diff --git a/tests/ui/lint/lint-unexported-no-mangle.stderr b/tests/ui/lint/lint-unexported-no-mangle.stderr index 0efec51abaf..39377b6fe84 100644 --- a/tests/ui/lint/lint-unexported-no-mangle.stderr +++ b/tests/ui/lint/lint-unexported-no-mangle.stderr @@ -45,5 +45,15 @@ LL | pub const PUB_FOO: u64 = 1; | | | help: try a static value: `pub static` -error: aborting due to 2 previous errors; 6 warnings emitted +warning: lint `private_no_mangle_fns` has been removed: no longer a warning, `#[no_mangle]` functions always exported + | + = note: requested on the command line with `-F private_no_mangle_fns` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: lint `private_no_mangle_statics` has been removed: no longer a warning, `#[no_mangle]` statics always exported + | + = note: requested on the command line with `-F private_no_mangle_statics` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors; 8 warnings emitted diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr b/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr index f12ce03ddfc..1ce55706d76 100644 --- a/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr +++ b/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr @@ -30,6 +30,17 @@ error[E0602]: unknown lint: `dead_cod` = note: requested on the command line with `-D dead_cod` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 6 previous errors +error[E0602]: unknown lint: `bogus` + | + = note: requested on the command line with `-D bogus` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0602]: unknown lint: `dead_cod` + | + = help: did you mean: `dead_code` + = note: requested on the command line with `-D dead_cod` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0602`. diff --git a/tests/ui/lint/lint-unknown-lint-cmdline.stderr b/tests/ui/lint/lint-unknown-lint-cmdline.stderr index f452fc9eb94..4e0c5dbcb07 100644 --- a/tests/ui/lint/lint-unknown-lint-cmdline.stderr +++ b/tests/ui/lint/lint-unknown-lint-cmdline.stderr @@ -30,6 +30,17 @@ warning[E0602]: unknown lint: `dead_cod` = note: requested on the command line with `-D dead_cod` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -warning: 6 warnings emitted +warning[E0602]: unknown lint: `bogus` + | + = note: requested on the command line with `-D bogus` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning[E0602]: unknown lint: `dead_cod` + | + = help: did you mean: `dead_code` + = note: requested on the command line with `-D dead_cod` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: 8 warnings emitted For more information about this error, try `rustc --explain E0602`. diff --git a/tests/ui/lint/non-local-defs/cargo-update.rs b/tests/ui/lint/non-local-defs/cargo-update.rs index 8b8c15795d3..3c62a655a9f 100644 --- a/tests/ui/lint/non-local-defs/cargo-update.rs +++ b/tests/ui/lint/non-local-defs/cargo-update.rs @@ -10,6 +10,8 @@ // of the `cargo update` suggestion we assert it here. //@ error-pattern: `cargo update -p non_local_macro` +#![warn(non_local_definitions)] + extern crate non_local_macro; struct LocalStruct; diff --git a/tests/ui/lint/non-local-defs/cargo-update.stderr b/tests/ui/lint/non-local-defs/cargo-update.stderr index bccf8622bac..4dd41519455 100644 --- a/tests/ui/lint/non-local-defs/cargo-update.stderr +++ b/tests/ui/lint/non-local-defs/cargo-update.stderr @@ -1,5 +1,5 @@ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/cargo-update.rs:17:1 + --> $DIR/cargo-update.rs:19:1 | LL | non_local_macro::non_local_impl!(LocalStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -14,7 +14,11 @@ LL | non_local_macro::non_local_impl!(LocalStruct); = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - = note: `#[warn(non_local_definitions)]` on by default +note: the lint level is defined here + --> $DIR/cargo-update.rs:13:9 + | +LL | #![warn(non_local_definitions)] + | ^^^^^^^^^^^^^^^^^^^^^ = note: this warning originates in the macro `non_local_macro::non_local_impl` (in Nightly builds, run with -Z macro-backtrace for more info) warning: 1 warning emitted diff --git a/tests/ui/lint/non-local-defs/consts.rs b/tests/ui/lint/non-local-defs/consts.rs index d8a497e43e5..e7ee611529b 100644 --- a/tests/ui/lint/non-local-defs/consts.rs +++ b/tests/ui/lint/non-local-defs/consts.rs @@ -2,6 +2,8 @@ //@ edition:2021 //@ rustc-env:CARGO_CRATE_NAME=non_local_def +#![warn(non_local_definitions)] + struct Test; trait Uto {} diff --git a/tests/ui/lint/non-local-defs/consts.stderr b/tests/ui/lint/non-local-defs/consts.stderr index 9f70119e0f8..ed7bd56fe4a 100644 --- a/tests/ui/lint/non-local-defs/consts.stderr +++ b/tests/ui/lint/non-local-defs/consts.stderr @@ -1,5 +1,5 @@ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/consts.rs:13:5 + --> $DIR/consts.rs:15:5 | LL | const Z: () = { | ----------- @@ -17,10 +17,14 @@ LL | impl Uto for &Test {} = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - = note: `#[warn(non_local_definitions)]` on by default +note: the lint level is defined here + --> $DIR/consts.rs:5:9 + | +LL | #![warn(non_local_definitions)] + | ^^^^^^^^^^^^^^^^^^^^^ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/consts.rs:24:5 + --> $DIR/consts.rs:26:5 | LL | static A: u32 = { | ------------- move the `impl` block outside of this static `A` @@ -36,7 +40,7 @@ LL | impl Uto2 for Test {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/consts.rs:32:5 + --> $DIR/consts.rs:34:5 | LL | const B: u32 = { | ------------ move the `impl` block outside of this constant `B` @@ -52,7 +56,7 @@ LL | impl Uto3 for Test {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/consts.rs:43:5 + --> $DIR/consts.rs:45:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -65,7 +69,7 @@ LL | impl Test { = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/consts.rs:50:9 + --> $DIR/consts.rs:52:9 | LL | const { | ___________- @@ -84,7 +88,7 @@ LL | | }; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/consts.rs:59:9 + --> $DIR/consts.rs:61:9 | LL | const _: u32 = { | ------------ move the `impl` block outside of this constant `_` and up 2 bodies @@ -98,7 +102,7 @@ LL | impl Test { = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/consts.rs:72:9 + --> $DIR/consts.rs:74:9 | LL | let _a = || { | -- move the `impl` block outside of this closure `<unnameable>` and up 2 bodies @@ -113,7 +117,7 @@ LL | impl Uto9 for Test {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/consts.rs:79:9 + --> $DIR/consts.rs:81:9 | LL | type A = [u32; { | ____________________- diff --git a/tests/ui/lint/non-local-defs/exhaustive-trait.rs b/tests/ui/lint/non-local-defs/exhaustive-trait.rs index 40d2314460f..79f8cc4620b 100644 --- a/tests/ui/lint/non-local-defs/exhaustive-trait.rs +++ b/tests/ui/lint/non-local-defs/exhaustive-trait.rs @@ -1,6 +1,8 @@ //@ check-pass //@ edition:2021 +#![warn(non_local_definitions)] + struct Dog; fn main() { diff --git a/tests/ui/lint/non-local-defs/exhaustive-trait.stderr b/tests/ui/lint/non-local-defs/exhaustive-trait.stderr index 67df0e31d5b..24c9a6b4f01 100644 --- a/tests/ui/lint/non-local-defs/exhaustive-trait.stderr +++ b/tests/ui/lint/non-local-defs/exhaustive-trait.stderr @@ -1,5 +1,5 @@ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive-trait.rs:7:5 + --> $DIR/exhaustive-trait.rs:9:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -12,10 +12,14 @@ LL | impl PartialEq<()> for Dog { = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - = note: `#[warn(non_local_definitions)]` on by default +note: the lint level is defined here + --> $DIR/exhaustive-trait.rs:4:9 + | +LL | #![warn(non_local_definitions)] + | ^^^^^^^^^^^^^^^^^^^^^ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive-trait.rs:14:5 + --> $DIR/exhaustive-trait.rs:16:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -31,7 +35,7 @@ LL | impl PartialEq<()> for &Dog { = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive-trait.rs:21:5 + --> $DIR/exhaustive-trait.rs:23:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -47,7 +51,7 @@ LL | impl PartialEq<Dog> for () { = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive-trait.rs:28:5 + --> $DIR/exhaustive-trait.rs:30:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -63,7 +67,7 @@ LL | impl PartialEq<&Dog> for () { = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive-trait.rs:35:5 + --> $DIR/exhaustive-trait.rs:37:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -79,7 +83,7 @@ LL | impl PartialEq<Dog> for &Dog { = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive-trait.rs:42:5 + --> $DIR/exhaustive-trait.rs:44:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` diff --git a/tests/ui/lint/non-local-defs/exhaustive.rs b/tests/ui/lint/non-local-defs/exhaustive.rs index 2fb30f4344a..f59a85c7ed9 100644 --- a/tests/ui/lint/non-local-defs/exhaustive.rs +++ b/tests/ui/lint/non-local-defs/exhaustive.rs @@ -1,6 +1,8 @@ //@ check-pass //@ edition:2021 +#![warn(non_local_definitions)] + use std::fmt::Display; trait Trait {} diff --git a/tests/ui/lint/non-local-defs/exhaustive.stderr b/tests/ui/lint/non-local-defs/exhaustive.stderr index 1e0d5caec38..6d8c2ec0bc7 100644 --- a/tests/ui/lint/non-local-defs/exhaustive.stderr +++ b/tests/ui/lint/non-local-defs/exhaustive.stderr @@ -1,5 +1,5 @@ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:10:5 + --> $DIR/exhaustive.rs:12:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -10,10 +10,14 @@ LL | impl Test { | = note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - = note: `#[warn(non_local_definitions)]` on by default +note: the lint level is defined here + --> $DIR/exhaustive.rs:4:9 + | +LL | #![warn(non_local_definitions)] + | ^^^^^^^^^^^^^^^^^^^^^ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:15:5 + --> $DIR/exhaustive.rs:17:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -29,7 +33,7 @@ LL | impl Display for Test { = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:22:5 + --> $DIR/exhaustive.rs:24:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -43,7 +47,7 @@ LL | impl dyn Trait {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:25:5 + --> $DIR/exhaustive.rs:27:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -59,7 +63,7 @@ LL | impl<T: Trait> Trait for Vec<T> { } = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:28:5 + --> $DIR/exhaustive.rs:30:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -75,7 +79,7 @@ LL | impl Trait for &dyn Trait {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:31:5 + --> $DIR/exhaustive.rs:33:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -91,7 +95,7 @@ LL | impl Trait for *mut Test {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:34:5 + --> $DIR/exhaustive.rs:36:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -107,7 +111,7 @@ LL | impl Trait for *mut [Test] {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:37:5 + --> $DIR/exhaustive.rs:39:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -123,7 +127,7 @@ LL | impl Trait for [Test; 8] {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:40:5 + --> $DIR/exhaustive.rs:42:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -139,7 +143,7 @@ LL | impl Trait for (Test,) {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:43:5 + --> $DIR/exhaustive.rs:45:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -155,7 +159,7 @@ LL | impl Trait for fn(Test) -> () {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:46:5 + --> $DIR/exhaustive.rs:48:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -171,7 +175,7 @@ LL | impl Trait for fn() -> Test {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:50:9 + --> $DIR/exhaustive.rs:52:9 | LL | let _a = || { | -- move the `impl` block outside of this closure `<unnameable>` and up 2 bodies @@ -186,7 +190,7 @@ LL | impl Trait for Test {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:58:5 + --> $DIR/exhaustive.rs:60:5 | LL | impl Trait for *mut InsideMain {} | ^^^^^-----^^^^^--------------- @@ -198,7 +202,7 @@ LL | impl Trait for *mut InsideMain {} = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` help: move the `impl` block outside of this function `main` - --> $DIR/exhaustive.rs:9:1 + --> $DIR/exhaustive.rs:11:1 | LL | fn main() { | ^^^^^^^^^ @@ -208,7 +212,7 @@ LL | struct InsideMain; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:60:5 + --> $DIR/exhaustive.rs:62:5 | LL | impl Trait for *mut [InsideMain] {} | ^^^^^-----^^^^^----------------- @@ -219,7 +223,7 @@ LL | impl Trait for *mut [InsideMain] {} = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` help: move the `impl` block outside of this function `main` - --> $DIR/exhaustive.rs:9:1 + --> $DIR/exhaustive.rs:11:1 | LL | fn main() { | ^^^^^^^^^ @@ -229,7 +233,7 @@ LL | struct InsideMain; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:62:5 + --> $DIR/exhaustive.rs:64:5 | LL | impl Trait for [InsideMain; 8] {} | ^^^^^-----^^^^^--------------- @@ -240,7 +244,7 @@ LL | impl Trait for [InsideMain; 8] {} = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` help: move the `impl` block outside of this function `main` - --> $DIR/exhaustive.rs:9:1 + --> $DIR/exhaustive.rs:11:1 | LL | fn main() { | ^^^^^^^^^ @@ -250,7 +254,7 @@ LL | struct InsideMain; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:64:5 + --> $DIR/exhaustive.rs:66:5 | LL | impl Trait for (InsideMain,) {} | ^^^^^-----^^^^^------------- @@ -261,7 +265,7 @@ LL | impl Trait for (InsideMain,) {} = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` help: move the `impl` block outside of this function `main` - --> $DIR/exhaustive.rs:9:1 + --> $DIR/exhaustive.rs:11:1 | LL | fn main() { | ^^^^^^^^^ @@ -271,7 +275,7 @@ LL | struct InsideMain; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:66:5 + --> $DIR/exhaustive.rs:68:5 | LL | impl Trait for fn(InsideMain) -> () {} | ^^^^^-----^^^^^-------------------- @@ -282,7 +286,7 @@ LL | impl Trait for fn(InsideMain) -> () {} = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` help: move the `impl` block outside of this function `main` - --> $DIR/exhaustive.rs:9:1 + --> $DIR/exhaustive.rs:11:1 | LL | fn main() { | ^^^^^^^^^ @@ -292,7 +296,7 @@ LL | struct InsideMain; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:68:5 + --> $DIR/exhaustive.rs:70:5 | LL | impl Trait for fn() -> InsideMain {} | ^^^^^-----^^^^^------------------ @@ -303,7 +307,7 @@ LL | impl Trait for fn() -> InsideMain {} = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` help: move the `impl` block outside of this function `main` - --> $DIR/exhaustive.rs:9:1 + --> $DIR/exhaustive.rs:11:1 | LL | fn main() { | ^^^^^^^^^ @@ -313,7 +317,7 @@ LL | struct InsideMain; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:72:9 + --> $DIR/exhaustive.rs:74:9 | LL | fn inside_inside() { | ------------------ move the `impl` block outside of this function `inside_inside` and up 2 bodies @@ -328,7 +332,7 @@ LL | impl Display for InsideMain { = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:79:9 + --> $DIR/exhaustive.rs:81:9 | LL | fn inside_inside() { | ------------------ move the `impl` block outside of this function `inside_inside` and up 2 bodies diff --git a/tests/ui/lint/non-local-defs/from-local-for-global.rs b/tests/ui/lint/non-local-defs/from-local-for-global.rs index fea9679d737..1d8f4845c28 100644 --- a/tests/ui/lint/non-local-defs/from-local-for-global.rs +++ b/tests/ui/lint/non-local-defs/from-local-for-global.rs @@ -1,6 +1,8 @@ //@ check-pass //@ edition:2021 +#![warn(non_local_definitions)] + struct Cat; struct Wrap<T>(T); diff --git a/tests/ui/lint/non-local-defs/from-local-for-global.stderr b/tests/ui/lint/non-local-defs/from-local-for-global.stderr index 67fd937d134..04eba8435fc 100644 --- a/tests/ui/lint/non-local-defs/from-local-for-global.stderr +++ b/tests/ui/lint/non-local-defs/from-local-for-global.stderr @@ -1,5 +1,5 @@ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/from-local-for-global.rs:8:5 + --> $DIR/from-local-for-global.rs:10:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -12,10 +12,14 @@ LL | impl From<Cat> for () { = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - = note: `#[warn(non_local_definitions)]` on by default +note: the lint level is defined here + --> $DIR/from-local-for-global.rs:4:9 + | +LL | #![warn(non_local_definitions)] + | ^^^^^^^^^^^^^^^^^^^^^ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/from-local-for-global.rs:18:5 + --> $DIR/from-local-for-global.rs:20:5 | LL | impl From<Wrap<Wrap<Elephant>>> for () { | ^^^^^----^^^^^^^^^^^^^^^^^^^^^^^^^^^-- @@ -25,7 +29,7 @@ LL | impl From<Wrap<Wrap<Elephant>>> for () { = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` help: move the `impl` block outside of this function `main` - --> $DIR/from-local-for-global.rs:7:1 + --> $DIR/from-local-for-global.rs:9:1 | LL | fn main() { | ^^^^^^^^^ @@ -35,7 +39,7 @@ LL | struct Elephant; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/from-local-for-global.rs:32:5 + --> $DIR/from-local-for-global.rs:34:5 | LL | impl StillNonLocal for &Foo {} | ^^^^^-------------^^^^^---- @@ -47,7 +51,7 @@ LL | impl StillNonLocal for &Foo {} = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` help: move the `impl` block outside of this function `only_global` - --> $DIR/from-local-for-global.rs:30:1 + --> $DIR/from-local-for-global.rs:32:1 | LL | fn only_global() { | ^^^^^^^^^^^^^^^^ @@ -56,7 +60,7 @@ LL | struct Foo; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/from-local-for-global.rs:40:5 + --> $DIR/from-local-for-global.rs:42:5 | LL | impl From<Local1> for GlobalSameFunction { | ^^^^^----^^^^^^^^^^^^^------------------ @@ -67,7 +71,7 @@ LL | impl From<Local1> for GlobalSameFunction { = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` help: move the `impl` block outside of this function `same_function` - --> $DIR/from-local-for-global.rs:38:1 + --> $DIR/from-local-for-global.rs:40:1 | LL | fn same_function() { | ^^^^^^^^^^^^^^^^^^ @@ -76,7 +80,7 @@ LL | struct Local1(GlobalSameFunction); = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/from-local-for-global.rs:48:5 + --> $DIR/from-local-for-global.rs:50:5 | LL | impl From<Local2> for GlobalSameFunction { | ^^^^^----^^^^^^^^^^^^^------------------ @@ -87,7 +91,7 @@ LL | impl From<Local2> for GlobalSameFunction { = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` help: move the `impl` block outside of this function `same_function` - --> $DIR/from-local-for-global.rs:38:1 + --> $DIR/from-local-for-global.rs:40:1 | LL | fn same_function() { | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-local-defs/generics.rs b/tests/ui/lint/non-local-defs/generics.rs index 0f526526dba..13e392c510c 100644 --- a/tests/ui/lint/non-local-defs/generics.rs +++ b/tests/ui/lint/non-local-defs/generics.rs @@ -1,6 +1,8 @@ //@ check-pass //@ edition:2021 +#![warn(non_local_definitions)] + trait Global {} fn main() { diff --git a/tests/ui/lint/non-local-defs/generics.stderr b/tests/ui/lint/non-local-defs/generics.stderr index ed2f87a4ed2..35366ed8ecf 100644 --- a/tests/ui/lint/non-local-defs/generics.stderr +++ b/tests/ui/lint/non-local-defs/generics.stderr @@ -1,5 +1,5 @@ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/generics.rs:9:5 + --> $DIR/generics.rs:11:5 | LL | impl<T: Local> Global for Vec<T> { } | ^^^^^^^^^^^^^^^------^^^^^---^^^ @@ -10,17 +10,21 @@ LL | impl<T: Local> Global for Vec<T> { } = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` help: move the `impl` block outside of this function `main` - --> $DIR/generics.rs:6:1 + --> $DIR/generics.rs:8:1 | LL | fn main() { | ^^^^^^^^^ LL | trait Local {}; | ----------- may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - = note: `#[warn(non_local_definitions)]` on by default +note: the lint level is defined here + --> $DIR/generics.rs:4:9 + | +LL | #![warn(non_local_definitions)] + | ^^^^^^^^^^^^^^^^^^^^^ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/generics.rs:20:5 + --> $DIR/generics.rs:22:5 | LL | impl Uto7 for Test where Local: std::any::Any {} | ^^^^^----^^^^^---- @@ -31,7 +35,7 @@ LL | impl Uto7 for Test where Local: std::any::Any {} = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` help: move the `impl` block outside of this function `bad` - --> $DIR/generics.rs:18:1 + --> $DIR/generics.rs:20:1 | LL | fn bad() { | ^^^^^^^^ @@ -40,7 +44,7 @@ LL | struct Local; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/generics.rs:23:5 + --> $DIR/generics.rs:25:5 | LL | fn bad() { | -------- move the `impl` block outside of this function `bad` @@ -56,7 +60,7 @@ LL | impl<T> Uto8 for T {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/generics.rs:32:5 + --> $DIR/generics.rs:34:5 | LL | impl Default for UwU<OwO> { | ^^^^^-------^^^^^---^^^^^ @@ -67,7 +71,7 @@ LL | impl Default for UwU<OwO> { = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` help: move the `impl` block outside of this function `fun` - --> $DIR/generics.rs:29:1 + --> $DIR/generics.rs:31:1 | LL | fn fun() { | ^^^^^^^^ @@ -77,7 +81,7 @@ LL | struct OwO; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/generics.rs:43:5 + --> $DIR/generics.rs:45:5 | LL | impl AsRef<Cat> for () { | ^^^^^-----^^^^^^^^^^-- @@ -88,7 +92,7 @@ LL | impl AsRef<Cat> for () { = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` help: move the `impl` block outside of this function `meow` - --> $DIR/generics.rs:40:1 + --> $DIR/generics.rs:42:1 | LL | fn meow() { | ^^^^^^^^^ @@ -98,7 +102,7 @@ LL | struct Cat; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/generics.rs:54:5 + --> $DIR/generics.rs:56:5 | LL | impl PartialEq<B> for G { | ^^^^^---------^^^^^^^^- @@ -109,7 +113,7 @@ LL | impl PartialEq<B> for G { = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` help: move the `impl` block outside of this function `fun2` - --> $DIR/generics.rs:51:1 + --> $DIR/generics.rs:53:1 | LL | fn fun2() { | ^^^^^^^^^ @@ -119,7 +123,7 @@ LL | struct B; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/generics.rs:69:5 + --> $DIR/generics.rs:71:5 | LL | impl From<Wrap<Wrap<Lion>>> for () { | ^^^^^----^^^^^^^^^^^^^^^^^^^^^^^-- @@ -129,7 +133,7 @@ LL | impl From<Wrap<Wrap<Lion>>> for () { = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` help: move the `impl` block outside of this function `rawr` - --> $DIR/generics.rs:66:1 + --> $DIR/generics.rs:68:1 | LL | fn rawr() { | ^^^^^^^^^ @@ -138,7 +142,7 @@ LL | struct Lion; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/generics.rs:76:5 + --> $DIR/generics.rs:78:5 | LL | impl From<()> for Wrap<Lion> { | ^^^^^----^^^^^^^^^----^^^^^^ @@ -149,7 +153,7 @@ LL | impl From<()> for Wrap<Lion> { = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` help: move the `impl` block outside of this function `rawr` - --> $DIR/generics.rs:66:1 + --> $DIR/generics.rs:68:1 | LL | fn rawr() { | ^^^^^^^^^ diff --git a/tests/ui/lint/non-local-defs/inside-macro_rules.rs b/tests/ui/lint/non-local-defs/inside-macro_rules.rs index 9f21cc89852..744a1f7a6f1 100644 --- a/tests/ui/lint/non-local-defs/inside-macro_rules.rs +++ b/tests/ui/lint/non-local-defs/inside-macro_rules.rs @@ -1,6 +1,8 @@ //@ check-pass //@ edition:2021 +#![warn(non_local_definitions)] + macro_rules! m { () => { trait MacroTrait {} diff --git a/tests/ui/lint/non-local-defs/inside-macro_rules.stderr b/tests/ui/lint/non-local-defs/inside-macro_rules.stderr index fa9ba2cb785..89835372c8a 100644 --- a/tests/ui/lint/non-local-defs/inside-macro_rules.stderr +++ b/tests/ui/lint/non-local-defs/inside-macro_rules.stderr @@ -1,5 +1,5 @@ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/inside-macro_rules.rs:9:13 + --> $DIR/inside-macro_rules.rs:11:13 | LL | fn my_func() { | ------------ move the `impl` block outside of this function `my_func` @@ -16,7 +16,11 @@ LL | m!(); = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - = note: `#[warn(non_local_definitions)]` on by default +note: the lint level is defined here + --> $DIR/inside-macro_rules.rs:4:9 + | +LL | #![warn(non_local_definitions)] + | ^^^^^^^^^^^^^^^^^^^^^ = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) warning: 1 warning emitted diff --git a/tests/ui/lint/non-local-defs/local.rs b/tests/ui/lint/non-local-defs/local.rs index 166ee88c021..e9dbff1300f 100644 --- a/tests/ui/lint/non-local-defs/local.rs +++ b/tests/ui/lint/non-local-defs/local.rs @@ -1,6 +1,8 @@ //@ check-pass //@ edition:2021 +#![warn(non_local_definitions)] + use std::fmt::Debug; trait GlobalTrait {} diff --git a/tests/ui/lint/non-local-defs/macro_rules.rs b/tests/ui/lint/non-local-defs/macro_rules.rs index ed30a24903d..20672cf0a32 100644 --- a/tests/ui/lint/non-local-defs/macro_rules.rs +++ b/tests/ui/lint/non-local-defs/macro_rules.rs @@ -3,6 +3,8 @@ //@ aux-build:non_local_macro.rs //@ rustc-env:CARGO_CRATE_NAME=non_local_def +#![warn(non_local_definitions)] + extern crate non_local_macro; const B: u32 = { diff --git a/tests/ui/lint/non-local-defs/macro_rules.stderr b/tests/ui/lint/non-local-defs/macro_rules.stderr index 4e86fc7b987..f9995bf8218 100644 --- a/tests/ui/lint/non-local-defs/macro_rules.stderr +++ b/tests/ui/lint/non-local-defs/macro_rules.stderr @@ -1,5 +1,5 @@ warning: non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module - --> $DIR/macro_rules.rs:10:5 + --> $DIR/macro_rules.rs:12:5 | LL | macro_rules! m0 { () => { } }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,10 +7,14 @@ LL | macro_rules! m0 { () => { } }; = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current constant `B` = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - = note: `#[warn(non_local_definitions)]` on by default +note: the lint level is defined here + --> $DIR/macro_rules.rs:6:9 + | +LL | #![warn(non_local_definitions)] + | ^^^^^^^^^^^^^^^^^^^^^ warning: non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module - --> $DIR/macro_rules.rs:16:1 + --> $DIR/macro_rules.rs:18:1 | LL | non_local_macro::non_local_macro_rules!(my_macro); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -22,7 +26,7 @@ LL | non_local_macro::non_local_macro_rules!(my_macro); = note: this warning originates in the macro `non_local_macro::non_local_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info) warning: non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module - --> $DIR/macro_rules.rs:21:5 + --> $DIR/macro_rules.rs:23:5 | LL | macro_rules! m { () => { } }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +36,7 @@ LL | macro_rules! m { () => { } }; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module - --> $DIR/macro_rules.rs:29:13 + --> $DIR/macro_rules.rs:31:13 | LL | macro_rules! m2 { () => { } }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-local-defs/suggest-moving-inner.rs b/tests/ui/lint/non-local-defs/suggest-moving-inner.rs index 61b32e5bad9..9360ace4d80 100644 --- a/tests/ui/lint/non-local-defs/suggest-moving-inner.rs +++ b/tests/ui/lint/non-local-defs/suggest-moving-inner.rs @@ -1,5 +1,7 @@ //@ check-pass +#![warn(non_local_definitions)] + trait Trait<T> {} fn main() { diff --git a/tests/ui/lint/non-local-defs/suggest-moving-inner.stderr b/tests/ui/lint/non-local-defs/suggest-moving-inner.stderr index f0de0f72e74..a214415316f 100644 --- a/tests/ui/lint/non-local-defs/suggest-moving-inner.stderr +++ b/tests/ui/lint/non-local-defs/suggest-moving-inner.stderr @@ -1,5 +1,5 @@ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/suggest-moving-inner.rs:12:5 + --> $DIR/suggest-moving-inner.rs:14:5 | LL | impl<T> Trait<InsideMain> for &Vec<below::Type<(InsideMain, T)>> | ^^^^^^^^-----^^^^^^^^^^^^^^^^^---------------------------------- @@ -10,7 +10,7 @@ LL | impl<T> Trait<InsideMain> for &Vec<below::Type<(InsideMain, T)>> = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` help: move the `impl` block outside of this function `main` - --> $DIR/suggest-moving-inner.rs:5:1 + --> $DIR/suggest-moving-inner.rs:7:1 | LL | fn main() { | ^^^^^^^^^ @@ -23,7 +23,11 @@ LL | struct InsideMain; LL | trait HasFoo {} | ------------ may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - = note: `#[warn(non_local_definitions)]` on by default +note: the lint level is defined here + --> $DIR/suggest-moving-inner.rs:3:9 + | +LL | #![warn(non_local_definitions)] + | ^^^^^^^^^^^^^^^^^^^^^ warning: 1 warning emitted diff --git a/tests/ui/lint/non-local-defs/trait-solver-overflow-123573.rs b/tests/ui/lint/non-local-defs/trait-solver-overflow-123573.rs index 4291426e046..b726398bf9c 100644 --- a/tests/ui/lint/non-local-defs/trait-solver-overflow-123573.rs +++ b/tests/ui/lint/non-local-defs/trait-solver-overflow-123573.rs @@ -3,6 +3,8 @@ // https://github.com/rust-lang/rust/issues/123573#issue-2229428739 +#![warn(non_local_definitions)] + pub trait Test {} impl<'a, T: 'a> Test for &[T] where &'a T: Test {} diff --git a/tests/ui/lint/non-local-defs/trait-solver-overflow-123573.stderr b/tests/ui/lint/non-local-defs/trait-solver-overflow-123573.stderr index 80930ce1bcd..2eb71cecaca 100644 --- a/tests/ui/lint/non-local-defs/trait-solver-overflow-123573.stderr +++ b/tests/ui/lint/non-local-defs/trait-solver-overflow-123573.stderr @@ -1,5 +1,5 @@ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/trait-solver-overflow-123573.rs:12:5 + --> $DIR/trait-solver-overflow-123573.rs:14:5 | LL | impl Test for &Local {} | ^^^^^----^^^^^------ @@ -11,14 +11,18 @@ LL | impl Test for &Local {} = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` help: move the `impl` block outside of this function `main` - --> $DIR/trait-solver-overflow-123573.rs:10:1 + --> $DIR/trait-solver-overflow-123573.rs:12:1 | LL | fn main() { | ^^^^^^^^^ LL | struct Local {} | ------------ may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - = note: `#[warn(non_local_definitions)]` on by default +note: the lint level is defined here + --> $DIR/trait-solver-overflow-123573.rs:6:9 + | +LL | #![warn(non_local_definitions)] + | ^^^^^^^^^^^^^^^^^^^^^ warning: 1 warning emitted diff --git a/tests/ui/lint/non-local-defs/weird-exprs.rs b/tests/ui/lint/non-local-defs/weird-exprs.rs index 1d9cecea0c9..fbf1fd941ee 100644 --- a/tests/ui/lint/non-local-defs/weird-exprs.rs +++ b/tests/ui/lint/non-local-defs/weird-exprs.rs @@ -1,6 +1,8 @@ //@ check-pass //@ edition:2021 +#![warn(non_local_definitions)] + trait Uto {} struct Test; diff --git a/tests/ui/lint/non-local-defs/weird-exprs.stderr b/tests/ui/lint/non-local-defs/weird-exprs.stderr index cd414d636d3..49aba904ebb 100644 --- a/tests/ui/lint/non-local-defs/weird-exprs.stderr +++ b/tests/ui/lint/non-local-defs/weird-exprs.stderr @@ -1,5 +1,5 @@ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/weird-exprs.rs:8:5 + --> $DIR/weird-exprs.rs:10:5 | LL | type A = [u32; { | ________________- @@ -16,10 +16,14 @@ LL | | }]; = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - = note: `#[warn(non_local_definitions)]` on by default +note: the lint level is defined here + --> $DIR/weird-exprs.rs:4:9 + | +LL | #![warn(non_local_definitions)] + | ^^^^^^^^^^^^^^^^^^^^^ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/weird-exprs.rs:16:9 + --> $DIR/weird-exprs.rs:18:9 | LL | Discr = { | _____________- @@ -38,7 +42,7 @@ LL | | } = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/weird-exprs.rs:25:9 + --> $DIR/weird-exprs.rs:27:9 | LL | let _array = [0i32; { | _________________________- @@ -57,7 +61,7 @@ LL | | }]; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/weird-exprs.rs:34:9 + --> $DIR/weird-exprs.rs:36:9 | LL | type A = [u32; { | ____________________- @@ -76,7 +80,7 @@ LL | | }]; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/weird-exprs.rs:41:9 + --> $DIR/weird-exprs.rs:43:9 | LL | fn a(_: [u32; { | ___________________- @@ -95,7 +99,7 @@ LL | | }]) {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/weird-exprs.rs:48:9 + --> $DIR/weird-exprs.rs:50:9 | LL | fn b() -> [u32; { | _____________________- diff --git a/tests/ui/lint/reasons-erroneous.rs b/tests/ui/lint/reasons-erroneous.rs index 7366a03232f..244b376b60d 100644 --- a/tests/ui/lint/reasons-erroneous.rs +++ b/tests/ui/lint/reasons-erroneous.rs @@ -1,7 +1,5 @@ //@ compile-flags: -Zdeduplicate-diagnostics=yes -#![feature(lint_reasons)] - #![warn(absolute_paths_not_starting_with_crate, reason = 0)] //~^ ERROR malformed lint attribute //~| NOTE reason must be a string literal diff --git a/tests/ui/lint/reasons-erroneous.stderr b/tests/ui/lint/reasons-erroneous.stderr index 003da567370..adc97174b99 100644 --- a/tests/ui/lint/reasons-erroneous.stderr +++ b/tests/ui/lint/reasons-erroneous.stderr @@ -1,47 +1,47 @@ error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:5:58 + --> $DIR/reasons-erroneous.rs:3:58 | LL | #![warn(absolute_paths_not_starting_with_crate, reason = 0)] | ^ reason must be a string literal error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:8:40 + --> $DIR/reasons-erroneous.rs:6:40 | LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reason must be a string literal error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:11:29 + --> $DIR/reasons-erroneous.rs:9:29 | LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:14:23 + --> $DIR/reasons-erroneous.rs:12:23 | LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:17:36 + --> $DIR/reasons-erroneous.rs:15:36 | LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:20:44 + --> $DIR/reasons-erroneous.rs:18:44 | LL | #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")] | ^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:23:25 + --> $DIR/reasons-erroneous.rs:21:25 | LL | #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last warning: unknown lint: `reason` - --> $DIR/reasons-erroneous.rs:26:39 + --> $DIR/reasons-erroneous.rs:24:39 | LL | #![warn(missing_copy_implementations, reason)] | ^^^^^^ diff --git a/tests/ui/lint/reasons-forbidden.rs b/tests/ui/lint/reasons-forbidden.rs index 0b08e7571db..47a1454e714 100644 --- a/tests/ui/lint/reasons-forbidden.rs +++ b/tests/ui/lint/reasons-forbidden.rs @@ -1,5 +1,3 @@ -#![feature(lint_reasons)] - // If you turn off deduplicate diagnostics (which rustc turns on by default but // compiletest turns off when it runs ui tests), then the errors are // (unfortunately) repeated here because the checking is done as we read in the diff --git a/tests/ui/lint/reasons-forbidden.stderr b/tests/ui/lint/reasons-forbidden.stderr index ab6f19a019d..cecc8345079 100644 --- a/tests/ui/lint/reasons-forbidden.stderr +++ b/tests/ui/lint/reasons-forbidden.stderr @@ -1,5 +1,5 @@ error[E0453]: allow(unsafe_code) incompatible with previous forbid - --> $DIR/reasons-forbidden.rs:25:13 + --> $DIR/reasons-forbidden.rs:23:13 | LL | unsafe_code, | ----------- `forbid` level set here @@ -10,7 +10,7 @@ LL | #[allow(unsafe_code)] = note: our errors & omissions insurance policy doesn't cover unsafe Rust error: usage of an `unsafe` block - --> $DIR/reasons-forbidden.rs:29:5 + --> $DIR/reasons-forbidden.rs:27:5 | LL | / unsafe { LL | | @@ -21,7 +21,7 @@ LL | | } | = note: our errors & omissions insurance policy doesn't cover unsafe Rust note: the lint level is defined here - --> $DIR/reasons-forbidden.rs:14:5 + --> $DIR/reasons-forbidden.rs:12:5 | LL | unsafe_code, | ^^^^^^^^^^^ diff --git a/tests/ui/lint/reasons.rs b/tests/ui/lint/reasons.rs index 4c2f92af1c7..917e7539aae 100644 --- a/tests/ui/lint/reasons.rs +++ b/tests/ui/lint/reasons.rs @@ -1,6 +1,5 @@ //@ check-pass -#![feature(lint_reasons)] #![warn(elided_lifetimes_in_paths, //~^ NOTE the lint level is defined here reason = "explicit anonymous lifetimes aid reasoning about ownership")] diff --git a/tests/ui/lint/reasons.stderr b/tests/ui/lint/reasons.stderr index cd8412153f1..8028785ab94 100644 --- a/tests/ui/lint/reasons.stderr +++ b/tests/ui/lint/reasons.stderr @@ -1,5 +1,5 @@ warning: hidden lifetime parameters in types are deprecated - --> $DIR/reasons.rs:20:34 + --> $DIR/reasons.rs:19:34 | LL | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | -----^^^^^^^^^ @@ -8,7 +8,7 @@ LL | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | = note: explicit anonymous lifetimes aid reasoning about ownership note: the lint level is defined here - --> $DIR/reasons.rs:4:9 + --> $DIR/reasons.rs:3:9 | LL | #![warn(elided_lifetimes_in_paths, | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { | ++++ warning: variable `Social_exchange_psychology` should have a snake case name - --> $DIR/reasons.rs:30:9 + --> $DIR/reasons.rs:29:9 | LL | let Social_exchange_psychology = CheaterDetectionMechanism {}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case (notice the capitalization): `social_exchange_psychology` @@ -26,7 +26,7 @@ LL | let Social_exchange_psychology = CheaterDetectionMechanism {}; = note: people shouldn't have to change their usual style habits to contribute to our project note: the lint level is defined here - --> $DIR/reasons.rs:8:5 + --> $DIR/reasons.rs:7:5 | LL | nonstandard_style, | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/rfc-2383-lint-reason/avoid_delayed_good_path_ice.rs b/tests/ui/lint/rfc-2383-lint-reason/avoid_delayed_good_path_ice.rs index e94755618cf..1322d2d5e89 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/avoid_delayed_good_path_ice.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/avoid_delayed_good_path_ice.rs @@ -1,5 +1,4 @@ //@ check-pass -#![feature(lint_reasons)] #[expect(drop_bounds)] fn trigger_rustc_lints<T: Drop>() { diff --git a/tests/ui/lint/rfc-2383-lint-reason/catch_multiple_lint_triggers.rs b/tests/ui/lint/rfc-2383-lint-reason/catch_multiple_lint_triggers.rs index ce4b89f5d99..3b702dbd1cc 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/catch_multiple_lint_triggers.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/catch_multiple_lint_triggers.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(lint_reasons)] - #![warn(unused)] // This expect attribute should catch all lint triggers diff --git a/tests/ui/lint/rfc-2383-lint-reason/crate_level_expect.rs b/tests/ui/lint/rfc-2383-lint-reason/crate_level_expect.rs index 8f255065125..0a39674144c 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/crate_level_expect.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/crate_level_expect.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(lint_reasons)] - #![warn(unused)] #![expect(unused_mut)] diff --git a/tests/ui/lint/rfc-2383-lint-reason/crate_level_expect.stderr b/tests/ui/lint/rfc-2383-lint-reason/crate_level_expect.stderr index 7237f6fb6bb..90a2c54b582 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/crate_level_expect.stderr +++ b/tests/ui/lint/rfc-2383-lint-reason/crate_level_expect.stderr @@ -1,5 +1,5 @@ warning: this lint expectation is unfulfilled - --> $DIR/crate_level_expect.rs:7:11 + --> $DIR/crate_level_expect.rs:5:11 | LL | #![expect(unused_mut)] | ^^^^^^^^^^ diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_inside_macro.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_inside_macro.rs index 7bfb84c8826..3a3cef2d00d 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_inside_macro.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_inside_macro.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(lint_reasons)] - #![warn(unused)] macro_rules! expect_inside_macro { diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.rs index e6f7471b93c..549f031cbf6 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(lint_reasons)] - #![warn(unused_variables)] macro_rules! trigger_unused_variables_macro { diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.stderr b/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.stderr index 817e16fdcaa..49dba1c7ffe 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.stderr +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.stderr @@ -1,5 +1,5 @@ warning: unused variable: `x` - --> $DIR/expect_lint_from_macro.rs:9:13 + --> $DIR/expect_lint_from_macro.rs:7:13 | LL | let x = 0; | ^ help: if this is intentional, prefix it with an underscore: `_x` @@ -8,14 +8,14 @@ LL | trigger_unused_variables_macro!(); | --------------------------------- in this macro invocation | note: the lint level is defined here - --> $DIR/expect_lint_from_macro.rs:5:9 + --> $DIR/expect_lint_from_macro.rs:3:9 | LL | #![warn(unused_variables)] | ^^^^^^^^^^^^^^^^ = note: this warning originates in the macro `trigger_unused_variables_macro` (in Nightly builds, run with -Z macro-backtrace for more info) warning: unused variable: `x` - --> $DIR/expect_lint_from_macro.rs:9:13 + --> $DIR/expect_lint_from_macro.rs:7:13 | LL | let x = 0; | ^ help: if this is intentional, prefix it with an underscore: `_x` diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_missing_feature_gate.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_missing_feature_gate.rs deleted file mode 100644 index 928e1610614..00000000000 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_missing_feature_gate.rs +++ /dev/null @@ -1,9 +0,0 @@ -// should error due to missing feature gate. - -#![warn(unused)] - -#[expect(unused)] -//~^ ERROR: the `#[expect]` attribute is an experimental feature [E0658] -fn main() { - let x = 1; -} diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_missing_feature_gate.stderr b/tests/ui/lint/rfc-2383-lint-reason/expect_missing_feature_gate.stderr deleted file mode 100644 index 5d252fdcf5d..00000000000 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_missing_feature_gate.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: the `#[expect]` attribute is an experimental feature - --> $DIR/expect_missing_feature_gate.rs:5:1 - | -LL | #[expect(unused)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #54503 <https://github.com/rust-lang/rust/issues/54503> for more information - = help: add `#![feature(lint_reasons)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_multiple_lints.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_multiple_lints.rs index 1534d5f862c..5d80a7ca046 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_multiple_lints.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_multiple_lints.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(lint_reasons)] - #![warn(unused)] // The warnings are not double triggers, they identify different unfulfilled lint diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_multiple_lints.stderr b/tests/ui/lint/rfc-2383-lint-reason/expect_multiple_lints.stderr index 90ee744b26b..c551c55fbed 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_multiple_lints.stderr +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_multiple_lints.stderr @@ -1,5 +1,5 @@ warning: this lint expectation is unfulfilled - --> $DIR/expect_multiple_lints.rs:10:28 + --> $DIR/expect_multiple_lints.rs:8:28 | LL | #[expect(unused_variables, unused_mut, while_true)] | ^^^^^^^^^^ @@ -7,43 +7,43 @@ LL | #[expect(unused_variables, unused_mut, while_true)] = note: `#[warn(unfulfilled_lint_expectations)]` on by default warning: this lint expectation is unfulfilled - --> $DIR/expect_multiple_lints.rs:10:40 + --> $DIR/expect_multiple_lints.rs:8:40 | LL | #[expect(unused_variables, unused_mut, while_true)] | ^^^^^^^^^^ warning: this lint expectation is unfulfilled - --> $DIR/expect_multiple_lints.rs:19:10 + --> $DIR/expect_multiple_lints.rs:17:10 | LL | #[expect(unused_variables, unused_mut, while_true)] | ^^^^^^^^^^^^^^^^ warning: this lint expectation is unfulfilled - --> $DIR/expect_multiple_lints.rs:19:40 + --> $DIR/expect_multiple_lints.rs:17:40 | LL | #[expect(unused_variables, unused_mut, while_true)] | ^^^^^^^^^^ warning: this lint expectation is unfulfilled - --> $DIR/expect_multiple_lints.rs:28:10 + --> $DIR/expect_multiple_lints.rs:26:10 | LL | #[expect(unused_variables, unused_mut, while_true)] | ^^^^^^^^^^^^^^^^ warning: this lint expectation is unfulfilled - --> $DIR/expect_multiple_lints.rs:28:28 + --> $DIR/expect_multiple_lints.rs:26:28 | LL | #[expect(unused_variables, unused_mut, while_true)] | ^^^^^^^^^^ warning: this lint expectation is unfulfilled - --> $DIR/expect_multiple_lints.rs:36:18 + --> $DIR/expect_multiple_lints.rs:34:18 | LL | #[expect(unused, while_true)] | ^^^^^^^^^^ warning: this lint expectation is unfulfilled - --> $DIR/expect_multiple_lints.rs:45:10 + --> $DIR/expect_multiple_lints.rs:43:10 | LL | #[expect(unused, while_true)] | ^^^^^^ diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_nested_lint_levels.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_nested_lint_levels.rs index 8f94bd6ec6c..1d365363ceb 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_nested_lint_levels.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_nested_lint_levels.rs @@ -1,6 +1,5 @@ // ignore-tidy-linelength -#![feature(lint_reasons)] #![warn(unused_mut)] #[expect( diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_nested_lint_levels.stderr b/tests/ui/lint/rfc-2383-lint-reason/expect_nested_lint_levels.stderr index 0e445d2439b..02710d9f2af 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_nested_lint_levels.stderr +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_nested_lint_levels.stderr @@ -1,5 +1,5 @@ warning: variable does not need to be mutable - --> $DIR/expect_nested_lint_levels.rs:36:13 + --> $DIR/expect_nested_lint_levels.rs:35:13 | LL | let mut v = 0; | ----^ @@ -8,25 +8,25 @@ LL | let mut v = 0; | = note: this overrides the previous `expect` lint level and warns about the `unused_mut` lint here note: the lint level is defined here - --> $DIR/expect_nested_lint_levels.rs:31:9 + --> $DIR/expect_nested_lint_levels.rs:30:9 | LL | unused_mut, | ^^^^^^^^^^ error: unused variable: `this_is_my_function` - --> $DIR/expect_nested_lint_levels.rs:48:9 + --> $DIR/expect_nested_lint_levels.rs:47:9 | LL | let this_is_my_function = 3; | ^^^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_this_is_my_function` | note: the lint level is defined here - --> $DIR/expect_nested_lint_levels.rs:45:10 + --> $DIR/expect_nested_lint_levels.rs:44:10 | LL | #[forbid(unused_variables)] | ^^^^^^^^^^^^^^^^ warning: this lint expectation is unfulfilled - --> $DIR/expect_nested_lint_levels.rs:7:5 + --> $DIR/expect_nested_lint_levels.rs:6:5 | LL | unused_mut, | ^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | unused_mut, = note: `#[warn(unfulfilled_lint_expectations)]` on by default warning: this lint expectation is unfulfilled - --> $DIR/expect_nested_lint_levels.rs:24:5 + --> $DIR/expect_nested_lint_levels.rs:23:5 | LL | unused_mut, | ^^^^^^^^^^ @@ -43,7 +43,7 @@ LL | unused_mut, = note: this `expect` is overridden by a `warn` attribute before the `unused_mut` lint is triggered warning: this lint expectation is unfulfilled - --> $DIR/expect_nested_lint_levels.rs:43:10 + --> $DIR/expect_nested_lint_levels.rs:42:10 | LL | #[expect(unused_variables)] | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_on_fn_params.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_on_fn_params.rs index d066a2b6ba6..bdea0fa1ce0 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_on_fn_params.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_on_fn_params.rs @@ -1,5 +1,4 @@ //@ check-pass -#![feature(lint_reasons)] #[warn(unused_variables)] diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_on_fn_params.stderr b/tests/ui/lint/rfc-2383-lint-reason/expect_on_fn_params.stderr index 69f7cda08ef..14e78ddd305 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_on_fn_params.stderr +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_on_fn_params.stderr @@ -1,5 +1,5 @@ warning: this lint expectation is unfulfilled - --> $DIR/expect_on_fn_params.rs:9:43 + --> $DIR/expect_on_fn_params.rs:8:43 | LL | fn check_unfulfilled_expectation(#[expect(unused_variables)] used_value: u32) { | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs index 7a57ab0f981..c99317d6aa8 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs @@ -1,5 +1,4 @@ //@ check-pass -#![feature(lint_reasons)] //! This file tests the `#[expect]` attribute implementation for tool lints. The same //! file is used to test clippy and rustdoc. Any changes to this file should be synced diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr index efe1aa04e5e..cd6dae0d761 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr @@ -1,5 +1,5 @@ warning: this lint expectation is unfulfilled - --> $DIR/expect_tool_lint_rfc_2383.rs:33:14 + --> $DIR/expect_tool_lint_rfc_2383.rs:32:14 | LL | #[expect(dead_code)] | ^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[expect(dead_code)] = note: `#[warn(unfulfilled_lint_expectations)]` on by default warning: this lint expectation is unfulfilled - --> $DIR/expect_tool_lint_rfc_2383.rs:39:18 + --> $DIR/expect_tool_lint_rfc_2383.rs:38:18 | LL | #[expect(invalid_nan_comparisons)] | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.rs index 577c6855fbe..413833ba351 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.rs @@ -1,7 +1,6 @@ //@ check-pass // ignore-tidy-linelength -#![feature(lint_reasons)] #![warn(unused_mut)] #![expect(unfulfilled_lint_expectations, reason = "idk why you would expect this")] diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.stderr b/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.stderr index 9a1c3e442bb..bd2df362a77 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.stderr +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.stderr @@ -1,5 +1,5 @@ warning: this lint expectation is unfulfilled - --> $DIR/expect_unfulfilled_expectation.rs:7:11 + --> $DIR/expect_unfulfilled_expectation.rs:6:11 | LL | #![expect(unfulfilled_lint_expectations, reason = "idk why you would expect this")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | #![expect(unfulfilled_lint_expectations, reason = "idk why you would expect = note: `#[warn(unfulfilled_lint_expectations)]` on by default warning: this lint expectation is unfulfilled - --> $DIR/expect_unfulfilled_expectation.rs:13:10 + --> $DIR/expect_unfulfilled_expectation.rs:12:10 | LL | #[expect(unfulfilled_lint_expectations, reason = "a local: idk why you would expect this")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | #[expect(unfulfilled_lint_expectations, reason = "a local: idk why you woul = note: the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message warning: this lint expectation is unfulfilled - --> $DIR/expect_unfulfilled_expectation.rs:18:14 + --> $DIR/expect_unfulfilled_expectation.rs:17:14 | LL | #[expect(unused_mut, reason = "this expectation will create a diagnostic with the default lint level")] | ^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | #[expect(unused_mut, reason = "this expectation will create a diagnosti = note: this expectation will create a diagnostic with the default lint level warning: this lint expectation is unfulfilled - --> $DIR/expect_unfulfilled_expectation.rs:25:22 + --> $DIR/expect_unfulfilled_expectation.rs:24:22 | LL | #[expect(unused, unfulfilled_lint_expectations, reason = "the expectation for `unused` should be fulfilled")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_unused_inside_impl_block.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_unused_inside_impl_block.rs index 44a715e4cdc..0ba63aa7bf8 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_unused_inside_impl_block.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_unused_inside_impl_block.rs @@ -1,7 +1,6 @@ //@ check-pass //@ incremental -#![feature(lint_reasons)] #![warn(unused)] struct OneUnused; diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_with_forbid.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_with_forbid.rs index 7c0ecd19010..9e06140f80c 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_with_forbid.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_with_forbid.rs @@ -1,7 +1,5 @@ //@ compile-flags: -Zdeduplicate-diagnostics=yes -#![feature(lint_reasons)] - #[forbid(unused_variables)] //~^ NOTE `forbid` level set here #[expect(unused_variables)] diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_with_forbid.stderr b/tests/ui/lint/rfc-2383-lint-reason/expect_with_forbid.stderr index 0f42ffbdea3..e6d7896ddd4 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_with_forbid.stderr +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_with_forbid.stderr @@ -1,5 +1,5 @@ error[E0453]: expect(unused_variables) incompatible with previous forbid - --> $DIR/expect_with_forbid.rs:7:10 + --> $DIR/expect_with_forbid.rs:5:10 | LL | #[forbid(unused_variables)] | ---------------- `forbid` level set here @@ -8,7 +8,7 @@ LL | #[expect(unused_variables)] | ^^^^^^^^^^^^^^^^ overruled by previous forbid error[E0453]: expect(while_true) incompatible with previous forbid - --> $DIR/expect_with_forbid.rs:15:10 + --> $DIR/expect_with_forbid.rs:13:10 | LL | #[forbid(while_true)] | ---------- `forbid` level set here @@ -17,13 +17,13 @@ LL | #[expect(while_true)] | ^^^^^^^^^^ overruled by previous forbid error: denote infinite loops with `loop { ... }` - --> $DIR/expect_with_forbid.rs:22:5 + --> $DIR/expect_with_forbid.rs:20:5 | LL | while true {} | ^^^^^^^^^^ help: use `loop` | note: the lint level is defined here - --> $DIR/expect_with_forbid.rs:12:10 + --> $DIR/expect_with_forbid.rs:10:10 | LL | #[forbid(while_true)] | ^^^^^^^^^^ diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_with_reason.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_with_reason.rs index 29e60a265da..482c8134a83 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_with_reason.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_with_reason.rs @@ -1,6 +1,5 @@ //@ check-pass -#![feature(lint_reasons)] #![warn(unused)] #![expect(unused_variables, reason = "<This should fail and display this reason>")] diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_with_reason.stderr b/tests/ui/lint/rfc-2383-lint-reason/expect_with_reason.stderr index e349e4081f8..644f3fa7906 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_with_reason.stderr +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_with_reason.stderr @@ -1,5 +1,5 @@ warning: this lint expectation is unfulfilled - --> $DIR/expect_with_reason.rs:6:11 + --> $DIR/expect_with_reason.rs:5:11 | LL | #![expect(unused_variables, reason = "<This should fail and display this reason>")] | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.rs b/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.rs index efe921b76af..ad85a777ef9 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.rs @@ -3,8 +3,6 @@ //@ compile-flags: --force-warn unused_mut //@ check-pass -#![feature(lint_reasons)] - fn expect_early_pass_lint() { #[expect(while_true)] while true { diff --git a/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.stderr b/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.stderr index 169f03aed94..29e579464c8 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.stderr +++ b/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.stderr @@ -1,5 +1,5 @@ warning: unused variable: `x` - --> $DIR/force_warn_expected_lints_fulfilled.rs:20:9 + --> $DIR/force_warn_expected_lints_fulfilled.rs:18:9 | LL | let x = 2; | ^ help: if this is intentional, prefix it with an underscore: `_x` @@ -7,13 +7,13 @@ LL | let x = 2; = note: requested on the command line with `--force-warn unused-variables` warning: unused variable: `fox_name` - --> $DIR/force_warn_expected_lints_fulfilled.rs:28:9 + --> $DIR/force_warn_expected_lints_fulfilled.rs:26:9 | LL | let fox_name = "Sir Nibbles"; | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_fox_name` warning: variable does not need to be mutable - --> $DIR/force_warn_expected_lints_fulfilled.rs:32:9 + --> $DIR/force_warn_expected_lints_fulfilled.rs:30:9 | LL | let mut what_does_the_fox_say = "*ding* *deng* *dung*"; | ----^^^^^^^^^^^^^^^^^^^^^ @@ -23,13 +23,13 @@ LL | let mut what_does_the_fox_say = "*ding* *deng* *dung*"; = note: requested on the command line with `--force-warn unused-mut` warning: unused variable: `this_should_fulfill_the_expectation` - --> $DIR/force_warn_expected_lints_fulfilled.rs:43:9 + --> $DIR/force_warn_expected_lints_fulfilled.rs:41:9 | LL | let this_should_fulfill_the_expectation = "The `#[allow]` has no power here"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_this_should_fulfill_the_expectation` warning: denote infinite loops with `loop { ... }` - --> $DIR/force_warn_expected_lints_fulfilled.rs:10:5 + --> $DIR/force_warn_expected_lints_fulfilled.rs:8:5 | LL | while true { | ^^^^^^^^^^ help: use `loop` diff --git a/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.rs b/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.rs index 2751f5d8303..a43c75c3455 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.rs @@ -3,8 +3,6 @@ //@ compile-flags: --force-warn unused_mut //@ check-pass -#![feature(lint_reasons)] - fn expect_early_pass_lint(terminate: bool) { #[expect(while_true)] //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations] diff --git a/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.stderr b/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.stderr index c74fabe27dc..f5e66694b8e 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.stderr +++ b/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.stderr @@ -1,5 +1,5 @@ warning: unused variable: `this_should_not_fulfill_the_expectation` - --> $DIR/force_warn_expected_lints_unfulfilled.rs:40:9 + --> $DIR/force_warn_expected_lints_unfulfilled.rs:38:9 | LL | let this_should_not_fulfill_the_expectation = "maybe"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_this_should_not_fulfill_the_expectation` @@ -7,7 +7,7 @@ LL | let this_should_not_fulfill_the_expectation = "maybe"; = note: requested on the command line with `--force-warn unused-variables` warning: this lint expectation is unfulfilled - --> $DIR/force_warn_expected_lints_unfulfilled.rs:9:14 + --> $DIR/force_warn_expected_lints_unfulfilled.rs:7:14 | LL | #[expect(while_true)] | ^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | #[expect(while_true)] = note: `#[warn(unfulfilled_lint_expectations)]` on by default warning: this lint expectation is unfulfilled - --> $DIR/force_warn_expected_lints_unfulfilled.rs:17:10 + --> $DIR/force_warn_expected_lints_unfulfilled.rs:15:10 | LL | #[expect(unused_variables, reason="<this should fail and display this reason>")] | ^^^^^^^^^^^^^^^^ @@ -23,13 +23,13 @@ LL | #[expect(unused_variables, reason="<this should fail and display this reaso = note: <this should fail and display this reason> warning: this lint expectation is unfulfilled - --> $DIR/force_warn_expected_lints_unfulfilled.rs:24:10 + --> $DIR/force_warn_expected_lints_unfulfilled.rs:22:10 | LL | #[expect(unused)] | ^^^^^^ warning: this lint expectation is unfulfilled - --> $DIR/force_warn_expected_lints_unfulfilled.rs:36:10 + --> $DIR/force_warn_expected_lints_unfulfilled.rs:34:10 | LL | #[expect(unused)] | ^^^^^^ diff --git a/tests/ui/lint/rfc-2383-lint-reason/fulfilled_expectation_early_lints.rs b/tests/ui/lint/rfc-2383-lint-reason/fulfilled_expectation_early_lints.rs index 545939b1369..078c3a59eb3 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/fulfilled_expectation_early_lints.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/fulfilled_expectation_early_lints.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(lint_reasons)] - fn expect_early_pass_lints() { #[expect(while_true)] while true { diff --git a/tests/ui/lint/rfc-2383-lint-reason/fulfilled_expectation_late_lints.rs b/tests/ui/lint/rfc-2383-lint-reason/fulfilled_expectation_late_lints.rs index 9431655c41d..4e2377a2dc3 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/fulfilled_expectation_late_lints.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/fulfilled_expectation_late_lints.rs @@ -1,6 +1,5 @@ //@ check-pass -#![feature(lint_reasons)] #![warn(unused)] #[expect(unused_variables)] diff --git a/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.rs b/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.rs index bafdea96e08..a7767769344 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.rs @@ -1,5 +1,3 @@ -#![feature(lint_reasons)] - #![deny(unused_attributes)] #[allow(reason = "I want to allow something")]//~ ERROR unused attribute diff --git a/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr b/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr index 3e9d70821b5..7f01c2dc61b 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr +++ b/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr @@ -1,18 +1,18 @@ error: unused attribute - --> $DIR/lint-attribute-only-with-reason.rs:5:1 + --> $DIR/lint-attribute-only-with-reason.rs:3:1 | LL | #[allow(reason = "I want to allow something")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | = note: attribute `allow` without any lints has no effect note: the lint level is defined here - --> $DIR/lint-attribute-only-with-reason.rs:3:9 + --> $DIR/lint-attribute-only-with-reason.rs:1:9 | LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/lint-attribute-only-with-reason.rs:6:1 + --> $DIR/lint-attribute-only-with-reason.rs:4:1 | LL | #[expect(reason = "I don't know what I'm waiting for")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute @@ -20,7 +20,7 @@ LL | #[expect(reason = "I don't know what I'm waiting for")] = note: attribute `expect` without any lints has no effect error: unused attribute - --> $DIR/lint-attribute-only-with-reason.rs:7:1 + --> $DIR/lint-attribute-only-with-reason.rs:5:1 | LL | #[warn(reason = "This should be warn by default")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute @@ -28,7 +28,7 @@ LL | #[warn(reason = "This should be warn by default")] = note: attribute `warn` without any lints has no effect error: unused attribute - --> $DIR/lint-attribute-only-with-reason.rs:8:1 + --> $DIR/lint-attribute-only-with-reason.rs:6:1 | LL | #[deny(reason = "All listed lints are denied")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute @@ -36,7 +36,7 @@ LL | #[deny(reason = "All listed lints are denied")] = note: attribute `deny` without any lints has no effect error: unused attribute - --> $DIR/lint-attribute-only-with-reason.rs:9:1 + --> $DIR/lint-attribute-only-with-reason.rs:7:1 | LL | #[forbid(reason = "Just some reason")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute diff --git a/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.rs b/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.rs index f02dfdcea30..8930f1cd3b9 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.rs @@ -1,6 +1,5 @@ //@ check-pass -#![feature(lint_reasons)] #![warn(unused)] #[warn(unused_variables)] diff --git a/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.stderr b/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.stderr index df7d6584f99..31042c4bb6d 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.stderr +++ b/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.stderr @@ -1,5 +1,5 @@ warning: this lint expectation is unfulfilled - --> $DIR/multiple_expect_attrs.rs:7:10 + --> $DIR/multiple_expect_attrs.rs:6:10 | LL | #[expect(unused_variables)] | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.rs b/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.rs index 61333519384..9e38b94b76c 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.rs @@ -2,8 +2,6 @@ //@ check-pass //@ compile-flags: -Z unpretty=expanded -#![feature(lint_reasons)] - // This `expect` will create an expectation with an unstable expectation id #[expect(while_true)] fn create_early_lint_pass_expectation() { diff --git a/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout b/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout index 6a6b4dcff92..d804c1d2d20 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout +++ b/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout @@ -1,14 +1,12 @@ #![feature(prelude_import)] #![no_std] -// This ensures that ICEs like rust#94953 don't happen -//@ check-pass -//@ compile-flags: -Z unpretty=expanded - -#![feature(lint_reasons)] #[prelude_import] use ::std::prelude::rust_2015::*; #[macro_use] extern crate std; +// This ensures that ICEs like rust#94953 don't happen +//@ check-pass +//@ compile-flags: -Z unpretty=expanded // This `expect` will create an expectation with an unstable expectation id #[expect(while_true)] diff --git a/tests/ui/lint/rfc-2383-lint-reason/root-attribute-confusion.rs b/tests/ui/lint/rfc-2383-lint-reason/root-attribute-confusion.rs index 7b60b55eb61..f83066c138f 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/root-attribute-confusion.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/root-attribute-confusion.rs @@ -2,6 +2,5 @@ //@ compile-flags: -Dunused_attributes #![deny(unused_crate_dependencies)] -#![feature(lint_reasons)] fn main() {} diff --git a/tests/ui/macros/nonterminal-matching.rs b/tests/ui/macros/nonterminal-matching.rs index 84fffe44d6a..5f0d6b2f90e 100644 --- a/tests/ui/macros/nonterminal-matching.rs +++ b/tests/ui/macros/nonterminal-matching.rs @@ -23,4 +23,34 @@ simple_nonterminal!(a, 'a, (x, y, z)); // OK complex_nonterminal!(enum E {}); +// `ident`, `lifetime`, and `tt` all work. Other fragments do not. See +// https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment +macro_rules! foo { + (ident $x:ident) => { bar!(ident $x); }; + (lifetime $x:lifetime) => { bar!(lifetime $x); }; + (tt $x:tt) => { bar!(tt $x); }; + (expr $x:expr) => { bar!(expr $x); }; //~ ERROR: no rules expected the token `3` + (literal $x:literal) => { bar!(literal $x); }; //~ ERROR: no rules expected the token `4` + (path $x:path) => { bar!(path $x); }; //~ ERROR: no rules expected the token `a::b::c` + (stmt $x:stmt) => { bar!(stmt $x); }; //~ ERROR: no rules expected the token `let abc = 0` +} + +macro_rules! bar { + (ident abc) => {}; + (lifetime 'abc) => {}; + (tt 2) => {}; + (expr 3) => {}; + (literal 4) => {}; + (path a::b::c) => {}; + (stmt let abc = 0) => {}; +} + +foo!(ident abc); +foo!(lifetime 'abc); +foo!(tt 2); +foo!(expr 3); +foo!(literal 4); +foo!(path a::b::c); +foo!(stmt let abc = 0); + fn main() {} diff --git a/tests/ui/macros/nonterminal-matching.stderr b/tests/ui/macros/nonterminal-matching.stderr index d19141145fa..3ee88b5f52e 100644 --- a/tests/ui/macros/nonterminal-matching.stderr +++ b/tests/ui/macros/nonterminal-matching.stderr @@ -23,5 +23,93 @@ LL | complex_nonterminal!(enum E {}); = help: try using `:tt` instead in the macro definition = note: this error originates in the macro `complex_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 1 previous error +error: no rules expected the token `3` + --> $DIR/nonterminal-matching.rs:32:35 + | +LL | (expr $x:expr) => { bar!(expr $x); }; + | ^^ no rules expected this token in macro call +... +LL | macro_rules! bar { + | ---------------- when calling this macro +... +LL | foo!(expr 3); + | ------------ in this macro invocation + | +note: while trying to match `3` + --> $DIR/nonterminal-matching.rs:42:11 + | +LL | (expr 3) => {}; + | ^ + = note: captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens + = note: see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information + = help: try using `:tt` instead in the macro definition + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: no rules expected the token `4` + --> $DIR/nonterminal-matching.rs:33:44 + | +LL | (literal $x:literal) => { bar!(literal $x); }; + | ^^ no rules expected this token in macro call +... +LL | macro_rules! bar { + | ---------------- when calling this macro +... +LL | foo!(literal 4); + | --------------- in this macro invocation + | +note: while trying to match `4` + --> $DIR/nonterminal-matching.rs:43:14 + | +LL | (literal 4) => {}; + | ^ + = note: captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens + = note: see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information + = help: try using `:tt` instead in the macro definition + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: no rules expected the token `a::b::c` + --> $DIR/nonterminal-matching.rs:34:35 + | +LL | (path $x:path) => { bar!(path $x); }; + | ^^ no rules expected this token in macro call +... +LL | macro_rules! bar { + | ---------------- when calling this macro +... +LL | foo!(path a::b::c); + | ------------------ in this macro invocation + | +note: while trying to match `a` + --> $DIR/nonterminal-matching.rs:44:11 + | +LL | (path a::b::c) => {}; + | ^ + = note: captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens + = note: see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information + = help: try using `:tt` instead in the macro definition + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: no rules expected the token `let abc = 0` + --> $DIR/nonterminal-matching.rs:35:35 + | +LL | (stmt $x:stmt) => { bar!(stmt $x); }; + | ^^ no rules expected this token in macro call +... +LL | macro_rules! bar { + | ---------------- when calling this macro +... +LL | foo!(stmt let abc = 0); + | ---------------------- in this macro invocation + | +note: while trying to match `let` + --> $DIR/nonterminal-matching.rs:45:11 + | +LL | (stmt let abc = 0) => {}; + | ^^^ + = note: captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens + = note: see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information + = help: try using `:tt` instead in the macro definition + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 5 previous errors diff --git a/tests/ui/macros/vec-macro-in-pattern.rs b/tests/ui/macros/vec-macro-in-pattern.rs index ce4298b8bb3..26d7d4280fa 100644 --- a/tests/ui/macros/vec-macro-in-pattern.rs +++ b/tests/ui/macros/vec-macro-in-pattern.rs @@ -4,7 +4,7 @@ fn main() { match Some(vec![42]) { - Some(vec![43]) => {} //~ ERROR arbitrary expressions aren't allowed in patterns + Some(vec![43]) => {} //~ ERROR expected pattern, found `#` _ => {} } } diff --git a/tests/ui/macros/vec-macro-in-pattern.stderr b/tests/ui/macros/vec-macro-in-pattern.stderr index 1a446b8c3ed..f32a2cf8e43 100644 --- a/tests/ui/macros/vec-macro-in-pattern.stderr +++ b/tests/ui/macros/vec-macro-in-pattern.stderr @@ -1,10 +1,13 @@ -error: arbitrary expressions aren't allowed in patterns +error: expected pattern, found `#` --> $DIR/vec-macro-in-pattern.rs:7:14 | LL | Some(vec![43]) => {} | ^^^^^^^^ + | | + | expected pattern + | in this macro invocation + | this macro call doesn't expand to a pattern | - = note: the `expr` fragment specifier forces the metavariable's content to be an expression = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/mir/auxiliary/static_fnptr.rs b/tests/ui/mir/auxiliary/static_fnptr.rs new file mode 100644 index 00000000000..8c7347175f4 --- /dev/null +++ b/tests/ui/mir/auxiliary/static_fnptr.rs @@ -0,0 +1,11 @@ +//@ compile-flags:-O + +#[inline] +fn foo() {} + +pub static ADDR: fn() = foo; + +#[inline(always)] +pub fn bar(x: fn()) -> bool { + x == ADDR +} diff --git a/tests/ui/mir/static_fnptr.rs b/tests/ui/mir/static_fnptr.rs new file mode 100644 index 00000000000..6b1ec021629 --- /dev/null +++ b/tests/ui/mir/static_fnptr.rs @@ -0,0 +1,21 @@ +//! Verify that we correctly handle fn pointer provenance in MIR optimizations. +//! By asking to inline `static_fnptr::bar`, we have two copies of `static_fnptr::foo`, one in the +//! auxiliary crate and one in the local crate CGU. +//! `baz` must only consider the versions from upstream crate, and not try to compare with the +//! address of the CGU-local copy. +//! Related issue: #123670 + +//@ run-pass +//@ compile-flags:-Cno-prepopulate-passes -Copt-level=0 +//@ aux-build:static_fnptr.rs + +extern crate static_fnptr; +use static_fnptr::{ADDR, bar}; + +fn baz() -> bool { + bar(ADDR) +} + +fn main() { + assert!(baz()) +} diff --git a/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.stderr b/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.stderr index 1baf95d2bf7..225d7503a02 100644 --- a/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.stderr +++ b/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.stderr @@ -52,13 +52,13 @@ error[E0308]: mismatched types --> $DIR/mismatch-sugg-for-shorthand-field.rs:57:20 | LL | let a = async { 42 }; - | ------------ the found `async` block + | ----- the found `async` block ... LL | let s = Demo { a }; | ^ expected `Pin<Box<...>>`, found `async` block | = note: expected struct `Pin<Box<(dyn Future<Output = i32> + Send + 'static)>>` - found `async` block `{async block@$DIR/mismatch-sugg-for-shorthand-field.rs:53:13: 53:25}` + found `async` block `{async block@$DIR/mismatch-sugg-for-shorthand-field.rs:53:13: 53:18}` help: you need to pin and box this expression | LL | let s = Demo { a: Box::pin(a) }; diff --git a/tests/ui/parser/unsafe-foreign-mod-2.stderr b/tests/ui/parser/unsafe-foreign-mod-2.stderr index 77a383d5efa..8bd592b5d43 100644 --- a/tests/ui/parser/unsafe-foreign-mod-2.stderr +++ b/tests/ui/parser/unsafe-foreign-mod-2.stderr @@ -9,17 +9,16 @@ error: extern block cannot be declared unsafe | LL | extern "C" unsafe { | ^^^^^^ + | + = note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information + = help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: items in unadorned `extern` blocks cannot have safety qualifiers --> $DIR/unsafe-foreign-mod-2.rs:4:5 | LL | unsafe fn foo(); | ^^^^^^^^^^^^^^^^ - | -help: add unsafe to this `extern` block - | -LL | unsafe extern "C" unsafe { - | ++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/parser/unsafe-foreign-mod.stderr b/tests/ui/parser/unsafe-foreign-mod.stderr index 77f6e93be10..60b918a89b3 100644 --- a/tests/ui/parser/unsafe-foreign-mod.stderr +++ b/tests/ui/parser/unsafe-foreign-mod.stderr @@ -3,6 +3,10 @@ error: extern block cannot be declared unsafe | LL | unsafe extern "C" { | ^^^^^^ + | + = note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information + = help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 1 previous error diff --git a/tests/ui/patchable-function-entry/patchable-function-entry-attribute.rs b/tests/ui/patchable-function-entry/patchable-function-entry-attribute.rs new file mode 100644 index 00000000000..1e376c9ff3c --- /dev/null +++ b/tests/ui/patchable-function-entry/patchable-function-entry-attribute.rs @@ -0,0 +1,17 @@ +#![feature(patchable_function_entry)] +fn main() {} + +#[patchable_function_entry(prefix_nops = 256, entry_nops = 0)]//~error: integer value out of range +pub fn too_high_pnops() {} + +#[patchable_function_entry(prefix_nops = "stringvalue", entry_nops = 0)]//~error: invalid literal value +pub fn non_int_nop() {} + +#[patchable_function_entry]//~error: malformed `patchable_function_entry` attribute input +pub fn malformed_attribute() {} + +#[patchable_function_entry(prefix_nops = 10, something = 0)]//~error: unexpected parameter name +pub fn unexpected_parameter_name() {} + +#[patchable_function_entry()]//~error: must specify at least one parameter +pub fn no_parameters_given() {} diff --git a/tests/ui/patchable-function-entry/patchable-function-entry-attribute.stderr b/tests/ui/patchable-function-entry/patchable-function-entry-attribute.stderr new file mode 100644 index 00000000000..d9710c6e6a2 --- /dev/null +++ b/tests/ui/patchable-function-entry/patchable-function-entry-attribute.stderr @@ -0,0 +1,32 @@ +error: malformed `patchable_function_entry` attribute input + --> $DIR/patchable-function-entry-attribute.rs:10:1 + | +LL | #[patchable_function_entry] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` + +error: integer value out of range + --> $DIR/patchable-function-entry-attribute.rs:4:42 + | +LL | #[patchable_function_entry(prefix_nops = 256, entry_nops = 0)] + | ^^^ value must be between `0` and `255` + +error: invalid literal value + --> $DIR/patchable-function-entry-attribute.rs:7:42 + | +LL | #[patchable_function_entry(prefix_nops = "stringvalue", entry_nops = 0)] + | ^^^^^^^^^^^^^ value must be an integer between `0` and `255` + +error: unexpected parameter name + --> $DIR/patchable-function-entry-attribute.rs:13:46 + | +LL | #[patchable_function_entry(prefix_nops = 10, something = 0)] + | ^^^^^^^^^^^^^ expected prefix_nops or entry_nops + +error: must specify at least one parameter + --> $DIR/patchable-function-entry-attribute.rs:16:1 + | +LL | #[patchable_function_entry()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/patchable-function-entry/patchable-function-entry-flags.rs b/tests/ui/patchable-function-entry/patchable-function-entry-flags.rs new file mode 100644 index 00000000000..cb5bc62b6b3 --- /dev/null +++ b/tests/ui/patchable-function-entry/patchable-function-entry-flags.rs @@ -0,0 +1,2 @@ +//@ compile-flags: -Z patchable-function-entry=1,2 +fn main() {} diff --git a/tests/ui/patchable-function-entry/patchable-function-entry-flags.stderr b/tests/ui/patchable-function-entry/patchable-function-entry-flags.stderr new file mode 100644 index 00000000000..b09af94a615 --- /dev/null +++ b/tests/ui/patchable-function-entry/patchable-function-entry-flags.stderr @@ -0,0 +1,2 @@ +error: incorrect value `1,2` for unstable option `patchable-function-entry` - either two comma separated integers (total_nops,prefix_nops), with prefix_nops <= total_nops, or one integer (total_nops) was expected + diff --git a/tests/ui/pattern/non-structural-match-types.stderr b/tests/ui/pattern/non-structural-match-types.stderr index f3e0665fef5..9075cf40dda 100644 --- a/tests/ui/pattern/non-structural-match-types.stderr +++ b/tests/ui/pattern/non-structural-match-types.stderr @@ -4,7 +4,7 @@ error: `{closure@$DIR/non-structural-match-types.rs:9:17: 9:19}` cannot be used LL | const { || {} } => {} | ^^^^^^^^^^^^^^^ -error: `{async block@$DIR/non-structural-match-types.rs:12:17: 12:25}` cannot be used in patterns +error: `{async block@$DIR/non-structural-match-types.rs:12:17: 12:22}` cannot be used in patterns --> $DIR/non-structural-match-types.rs:12:9 | LL | const { async {} } => {} diff --git a/tests/ui/return/infer-return-ty-for-fn-sig-issue-125488.fixed b/tests/ui/return/infer-return-ty-for-fn-sig-issue-125488.fixed new file mode 100644 index 00000000000..442ade6abf1 --- /dev/null +++ b/tests/ui/return/infer-return-ty-for-fn-sig-issue-125488.fixed @@ -0,0 +1,33 @@ +//@ run-rustfix + +#[allow(dead_code)] + +fn main() { + struct S<'a>(&'a ()); + + fn f1(s: S<'_>) -> S<'_> { + //~^ ERROR the placeholder `_` is not allowed + s + } + + fn f2(s: S<'_>) -> S<'_> { + //~^ ERROR the placeholder `_` is not allowed + let x = true; + if x { + s + } else { + s + } + } + + fn f3(s: S<'_>) -> S<'_> { + //~^ ERROR the placeholder `_` is not allowed + return s; + } + + fn f4(s: S<'_>) -> S<'_> { + //~^ ERROR the placeholder `_` is not allowed + let _x = 1; + return s; + } +} diff --git a/tests/ui/return/infer-return-ty-for-fn-sig-issue-125488.rs b/tests/ui/return/infer-return-ty-for-fn-sig-issue-125488.rs new file mode 100644 index 00000000000..04ea3a28add --- /dev/null +++ b/tests/ui/return/infer-return-ty-for-fn-sig-issue-125488.rs @@ -0,0 +1,33 @@ +//@ run-rustfix + +#[allow(dead_code)] + +fn main() { + struct S<'a>(&'a ()); + + fn f1(s: S<'_>) -> _ { + //~^ ERROR the placeholder `_` is not allowed + s + } + + fn f2(s: S<'_>) -> _ { + //~^ ERROR the placeholder `_` is not allowed + let x = true; + if x { + s + } else { + s + } + } + + fn f3(s: S<'_>) -> _ { + //~^ ERROR the placeholder `_` is not allowed + return s; + } + + fn f4(s: S<'_>) -> _ { + //~^ ERROR the placeholder `_` is not allowed + let _x = 1; + return s; + } +} diff --git a/tests/ui/return/infer-return-ty-for-fn-sig-issue-125488.stderr b/tests/ui/return/infer-return-ty-for-fn-sig-issue-125488.stderr new file mode 100644 index 00000000000..8b7c5e1681a --- /dev/null +++ b/tests/ui/return/infer-return-ty-for-fn-sig-issue-125488.stderr @@ -0,0 +1,39 @@ +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/infer-return-ty-for-fn-sig-issue-125488.rs:8:24 + | +LL | fn f1(s: S<'_>) -> _ { + | ^ + | | + | not allowed in type signatures + | help: replace with the correct return type: `S<'_>` + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/infer-return-ty-for-fn-sig-issue-125488.rs:13:24 + | +LL | fn f2(s: S<'_>) -> _ { + | ^ + | | + | not allowed in type signatures + | help: replace with the correct return type: `S<'_>` + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/infer-return-ty-for-fn-sig-issue-125488.rs:23:24 + | +LL | fn f3(s: S<'_>) -> _ { + | ^ + | | + | not allowed in type signatures + | help: replace with the correct return type: `S<'_>` + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/infer-return-ty-for-fn-sig-issue-125488.rs:28:24 + | +LL | fn f4(s: S<'_>) -> _ { + | ^ + | | + | not allowed in type signatures + | help: replace with the correct return type: `S<'_>` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0121`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.qualified.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.qualified.stderr deleted file mode 100644 index 3aec4383eab..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.qualified.stderr +++ /dev/null @@ -1,23 +0,0 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/assoc-type-const-bound-usage-0.rs:6:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information - = note: `#[warn(incomplete_features)]` on by default - -error[E0277]: the trait bound `T: Trait` is not satisfied - --> $DIR/assoc-type-const-bound-usage-0.rs:21:6 - | -LL | <T as /* FIXME: ~const */ Trait>::Assoc::func() - | ^ the trait `Trait` is not implemented for `T` - | -help: consider further restricting this bound - | -LL | const fn qualified<T: ~const Trait + Trait>() -> i32 { - | +++++++ - -error: aborting due to 1 previous error; 1 warning emitted - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.rs index eecd6e6109c..4399ae2d1be 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.rs @@ -1,9 +1,7 @@ -// FIXME(effects): Collapse the revisions into one once we support `<Ty as ~const Trait>::Proj`. -//@ revisions: unqualified qualified -//@[unqualified] check-pass -//@[qualified] known-bug: unknown +//@ known-bug: unknown -#![feature(const_trait_impl, effects)] //[unqualified]~ WARN the feature `effects` is incomplete +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] #[const_trait] trait Trait { @@ -11,14 +9,12 @@ trait Trait { fn func() -> i32; } -#[cfg(unqualified)] const fn unqualified<T: ~const Trait>() -> i32 { T::Assoc::func() } -#[cfg(qualified)] const fn qualified<T: ~const Trait>() -> i32 { - <T as /* FIXME: ~const */ Trait>::Assoc::func() + <T as Trait>::Assoc::func() } fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.stderr new file mode 100644 index 00000000000..919b5b6cd91 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.stderr @@ -0,0 +1,33 @@ +error[E0277]: the trait bound `Trait::{synthetic#0}: Compat` is not satisfied + --> $DIR/assoc-type-const-bound-usage-0.rs:13:5 + | +LL | T::Assoc::func() + | ^^^^^^^^ the trait `Compat` is not implemented for `Trait::{synthetic#0}` + | +note: required by a bound in `Trait::func` + --> $DIR/assoc-type-const-bound-usage-0.rs:6:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ required by this bound in `Trait::func` +... +LL | fn func() -> i32; + | ---- required by a bound in this associated function + +error[E0277]: the trait bound `Trait::{synthetic#0}: Compat` is not satisfied + --> $DIR/assoc-type-const-bound-usage-0.rs:17:5 + | +LL | <T as Trait>::Assoc::func() + | ^^^^^^^^^^^^^^^^^^^ the trait `Compat` is not implemented for `Trait::{synthetic#0}` + | +note: required by a bound in `Trait::func` + --> $DIR/assoc-type-const-bound-usage-0.rs:6:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ required by this bound in `Trait::func` +... +LL | fn func() -> i32; + | ---- required by a bound in this associated function + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.unqualified.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.unqualified.stderr deleted file mode 100644 index 3d592834600..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.unqualified.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/assoc-type-const-bound-usage-0.rs:6:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.qualified.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.qualified.stderr deleted file mode 100644 index 10e467da952..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.qualified.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0277]: the trait bound `T: Trait` is not satisfied - --> $DIR/assoc-type-const-bound-usage-1.rs:23:43 - | -LL | fn qualified<T: const Trait>() -> Type<{ <T as /* FIXME: const */ Trait>::Assoc::func() }> { - | ^ the trait `Trait` is not implemented for `T` - | -help: consider further restricting this bound - | -LL | fn qualified<T: const Trait + Trait>() -> Type<{ <T as /* FIXME: const */ Trait>::Assoc::func() }> { - | +++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.rs index 8213dae1369..8a1bf75f87e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.rs @@ -1,7 +1,5 @@ -// FIXME(effects): Collapse the revisions into one once we support `<Ty as const Trait>::Proj`. -//@ revisions: unqualified qualified -//@[unqualified] check-pass -//@[qualified] known-bug: unknown +//@ known-bug: unknown +// FIXME(effects) #![feature(const_trait_impl, effects, generic_const_exprs)] #![allow(incomplete_features)] @@ -14,13 +12,11 @@ trait Trait { struct Type<const N: i32>; -#[cfg(unqualified)] fn unqualified<T: const Trait>() -> Type<{ T::Assoc::func() }> { Type } -#[cfg(qualified)] -fn qualified<T: const Trait>() -> Type<{ <T as /* FIXME: const */ Trait>::Assoc::func() }> { +fn qualified<T: const Trait>() -> Type<{ <T as Trait>::Assoc::func() }> { Type } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.stderr new file mode 100644 index 00000000000..48855d64b58 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.stderr @@ -0,0 +1,33 @@ +error[E0277]: the trait bound `Trait::{synthetic#0}: Compat` is not satisfied + --> $DIR/assoc-type-const-bound-usage-1.rs:15:44 + | +LL | fn unqualified<T: const Trait>() -> Type<{ T::Assoc::func() }> { + | ^^^^^^^^ the trait `Compat` is not implemented for `Trait::{synthetic#0}` + | +note: required by a bound in `Trait::func` + --> $DIR/assoc-type-const-bound-usage-1.rs:7:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ required by this bound in `Trait::func` +... +LL | fn func() -> i32; + | ---- required by a bound in this associated function + +error[E0277]: the trait bound `Trait::{synthetic#0}: Compat` is not satisfied + --> $DIR/assoc-type-const-bound-usage-1.rs:19:42 + | +LL | fn qualified<T: const Trait>() -> Type<{ <T as Trait>::Assoc::func() }> { + | ^^^^^^^^^^^^^^^^^^^ the trait `Compat` is not implemented for `Trait::{synthetic#0}` + | +note: required by a bound in `Trait::func` + --> $DIR/assoc-type-const-bound-usage-1.rs:7:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ required by this bound in `Trait::func` +... +LL | fn func() -> i32; + | ---- required by a bound in this associated function + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs index 645fff4e014..348bf839b69 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs @@ -32,12 +32,14 @@ trait Foo { } impl const Foo for NonConstAdd { - type Bar = NonConstAdd; //~ ERROR the trait bound `NonConstAdd: ~const Add` is not satisfied + type Bar = NonConstAdd; + // FIXME(effects) ERROR the trait bound `NonConstAdd: ~const Add` is not satisfied } #[const_trait] trait Baz { type Qux: Add; + //~^ ERROR the trait bound } impl const Baz for NonConstAdd { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr index cc3abea25eb..1862339cddc 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr @@ -7,18 +7,16 @@ LL | #![feature(const_trait_impl, effects)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error[E0277]: the trait bound `NonConstAdd: ~const Add` is not satisfied - --> $DIR/assoc-type.rs:35:16 +error[E0277]: the trait bound `Add::{synthetic#0}: Compat` is not satisfied + --> $DIR/assoc-type.rs:41:15 | -LL | type Bar = NonConstAdd; - | ^^^^^^^^^^^ the trait `~const Add` is not implemented for `NonConstAdd` +LL | type Qux: Add; + | ^^^ the trait `Compat` is not implemented for `Add::{synthetic#0}` | - = help: the trait `Add` is implemented for `NonConstAdd` -note: required by a bound in `Foo::Bar` - --> $DIR/assoc-type.rs:31:15 +help: consider further restricting the associated type | -LL | type Bar: ~const Add; - | ^^^^^^^^^^ required by this bound in `Foo::Bar` +LL | trait Baz where Add::{synthetic#0}: Compat { + | ++++++++++++++++++++++++++++++++ error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs index 62609384cff..78e41ca6b75 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs @@ -1,4 +1,5 @@ -#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] #[const_trait] pub trait MyTrait { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr index 0e4dcf0f302..336ee01dc8d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr @@ -7,13 +7,21 @@ LL | #![feature(const_trait_impl, effects)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error[E0277]: the trait bound `u32: ~const Plus` is not satisfied +error[E0277]: the trait bound `Runtime: ~const Compat` is not satisfied --> $DIR/call-const-trait-method-fail.rs:25:5 | LL | a.plus(b) - | ^ the trait `~const Plus` is not implemented for `u32` + | ^ the trait `~const Compat` is not implemented for `Runtime` | - = help: the trait `Plus` is implemented for `u32` + = help: the trait `Compat` is implemented for `Runtime` +note: required by a bound in `Plus::plus` + --> $DIR/call-const-trait-method-fail.rs:3:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ required by this bound in `Plus::plus` +LL | pub trait Plus { +LL | fn plus(self, rhs: Self) -> Self; + | ---- required by a bound in this associated function error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr index 22e8e692752..bf455a714a3 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr @@ -1,14 +1,36 @@ +error: const `impl` for trait `Add` which is not marked with `#[const_trait]` + --> $DIR/call-const-trait-method-pass.rs:7:12 + | +LL | impl const std::ops::Add for Int { + | ^^^^^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` + --> $DIR/call-const-trait-method-pass.rs:15:12 + | +LL | impl const PartialEq for Int { + | ^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error[E0049]: method `plus` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/call-const-trait-method-pass.rs:24:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | pub trait Plus { +LL | fn plus(self, rhs: Self) -> Self; + | - expected 0 const parameters + error[E0015]: cannot call non-const operator in constants --> $DIR/call-const-trait-method-pass.rs:39:22 | LL | const ADD_INT: Int = Int(1i32) + Int(2i32); | ^^^^^^^^^^^^^^^^^^^^^ | -note: impl defined here, but it is not `const` - --> $DIR/call-const-trait-method-pass.rs:7:1 - | -LL | impl const std::ops::Add for Int { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: calls in constants are limited to constant functions, tuple structs and tuple variants help: add `#![feature(effects)]` to the crate attributes to enable | @@ -16,6 +38,30 @@ LL + #![feature(effects)] | error[E0015]: cannot call non-const fn `<i32 as Plus>::plus` in constant functions + --> $DIR/call-const-trait-method-pass.rs:11:20 + | +LL | Int(self.0.plus(rhs.0)) + | ^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: add `#![feature(effects)]` to the crate attributes to enable + | +LL + #![feature(effects)] + | + +error[E0015]: cannot call non-const fn `<Int as PartialEq>::eq` in constant functions + --> $DIR/call-const-trait-method-pass.rs:20:15 + | +LL | !self.eq(other) + | ^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: add `#![feature(effects)]` to the crate attributes to enable + | +LL + #![feature(effects)] + | + +error[E0015]: cannot call non-const fn `<i32 as Plus>::plus` in constant functions --> $DIR/call-const-trait-method-pass.rs:36:7 | LL | a.plus(b) @@ -27,6 +73,7 @@ help: add `#![feature(effects)]` to the crate attributes to enable LL + #![feature(effects)] | -error: aborting due to 2 previous errors +error: aborting due to 7 previous errors -For more information about this error, try `rustc --explain E0015`. +Some errors have detailed explanations: E0015, E0049. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.stderr index 12027c4d713..5cd274c6c5a 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.stderr @@ -4,5 +4,28 @@ error: `~const` can only be applied to `#[const_trait]` traits LL | impl<T: ~const PartialEq> const MyPartialEq for T { | ^^^^^^^^^ -error: aborting due to 1 previous error +error[E0049]: method `eq` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/call-generic-in-impl.rs:5:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | trait MyPartialEq { +LL | fn eq(&self, other: &Self) -> bool; + | - expected 0 const parameters + +error[E0015]: cannot call non-const fn `<T as PartialEq>::eq` in constant functions + --> $DIR/call-generic-in-impl.rs:12:9 + | +LL | PartialEq::eq(self, other) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: add `#![feature(effects)]` to the crate attributes to enable + | +LL + #![feature(effects)] + | + +error: aborting due to 3 previous errors +Some errors have detailed explanations: E0015, E0049. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.stderr index 36c7a654430..2e1feccd0f3 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.stderr @@ -16,15 +16,6 @@ LL | impl const PartialEq for S { = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates - --> $DIR/call-generic-method-chain.rs:10:6 - | -LL | impl const PartialEq for S { - | ^^^^^ unconstrained const parameter - | - = note: expressions using a const parameter must map each value to a distinct output value - = note: proving the result of expressions other than the parameter are unique is not supported - error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/call-generic-method-chain.rs:19:32 | @@ -37,35 +28,5 @@ error: `~const` can only be applied to `#[const_trait]` traits LL | const fn equals_self_wrapper<T: ~const PartialEq>(t: &T) -> bool { | ^^^^^^^^^ -error[E0284]: type annotations needed - --> $DIR/call-generic-method-chain.rs:27:22 - | -LL | pub const EQ: bool = equals_self_wrapper(&S); - | ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the constant `_` - | -note: required for `S` to implement `PartialEq` - --> $DIR/call-generic-method-chain.rs:10:12 - | -LL | impl const PartialEq for S { - | ----- ^^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here - -error[E0284]: type annotations needed - --> $DIR/call-generic-method-chain.rs:15:10 - | -LL | !self.eq(other) - | ^^^^^^^^^^^^^^ cannot infer the value of the constant `_` - | -note: required for `S` to implement `PartialEq` - --> $DIR/call-generic-method-chain.rs:10:12 - | -LL | impl const PartialEq for S { - | ----- ^^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here - -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 3 previous errors; 1 warning emitted -Some errors have detailed explanations: E0207, E0284. -For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.stderr index 320e420b80a..d3b00963686 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.stderr @@ -16,15 +16,6 @@ LL | impl const PartialEq for S { = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates - --> $DIR/call-generic-method-dup-bound.rs:8:6 - | -LL | impl const PartialEq for S { - | ^^^^^ unconstrained const parameter - | - = note: expressions using a const parameter must map each value to a distinct output value - = note: proving the result of expressions other than the parameter are unique is not supported - error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/call-generic-method-dup-bound.rs:19:44 | @@ -37,49 +28,5 @@ error: `~const` can only be applied to `#[const_trait]` traits LL | const fn equals_self2<T: A + ~const PartialEq>(t: &T) -> bool { | ^^^^^^^^^ -error[E0284]: type annotations needed - --> $DIR/call-generic-method-dup-bound.rs:30:22 - | -LL | pub const EQ: bool = equals_self(&S) && equals_self2(&S); - | ^^^^^^^^^^^^^^^ cannot infer the value of the constant `_` - | -note: required for `S` to implement `PartialEq` - --> $DIR/call-generic-method-dup-bound.rs:8:12 - | -LL | impl const PartialEq for S { - | ----- ^^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here - -error[E0284]: type annotations needed - --> $DIR/call-generic-method-dup-bound.rs:30:41 - | -LL | pub const EQ: bool = equals_self(&S) && equals_self2(&S); - | ^^^^^^^^^^^^^^^^ cannot infer the value of the constant `_` - | -note: required for `S` to implement `PartialEq` - --> $DIR/call-generic-method-dup-bound.rs:8:12 - | -LL | impl const PartialEq for S { - | ----- ^^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here - -error[E0284]: type annotations needed - --> $DIR/call-generic-method-dup-bound.rs:13:10 - | -LL | !self.eq(other) - | ^^^^^^^^^^^^^^ cannot infer the value of the constant `_` - | -note: required for `S` to implement `PartialEq` - --> $DIR/call-generic-method-dup-bound.rs:8:12 - | -LL | impl const PartialEq for S { - | ----- ^^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here - -error: aborting due to 7 previous errors; 1 warning emitted +error: aborting due to 3 previous errors; 1 warning emitted -Some errors have detailed explanations: E0207, E0284. -For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs index 222bff2db88..74e33ca72ff 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs @@ -21,6 +21,7 @@ const fn equals_self<T: ~const Foo>(t: &T) -> bool { // it not using the impl. pub const EQ: bool = equals_self(&S); -//~^ ERROR: the trait bound `S: const Foo` is not satisfied +//~^ ERROR: the trait bound `Runtime: const Compat` is not satisfied +// FIXME(effects) diagnostic fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr index fa59e5ee03d..d48ee9c95f5 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr @@ -7,15 +7,15 @@ LL | #![feature(const_trait_impl, effects)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error[E0277]: the trait bound `S: const Foo` is not satisfied +error[E0277]: the trait bound `Runtime: const Compat` is not satisfied --> $DIR/call-generic-method-nonconst.rs:23:34 | LL | pub const EQ: bool = equals_self(&S); - | ----------- ^^ the trait `const Foo` is not implemented for `S` + | ----------- ^^ the trait `const Compat` is not implemented for `Runtime` | | | required by a bound introduced by this call | - = help: the trait `Foo` is implemented for `S` + = help: the trait `Compat` is implemented for `Runtime` note: required by a bound in `equals_self` --> $DIR/call-generic-method-nonconst.rs:16:25 | diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.stderr index 6b9d290839e..cab8d6d7611 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.stderr @@ -16,50 +16,11 @@ LL | impl const PartialEq for S { = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates - --> $DIR/call-generic-method-pass.rs:10:6 - | -LL | impl const PartialEq for S { - | ^^^^^ unconstrained const parameter - | - = note: expressions using a const parameter must map each value to a distinct output value - = note: proving the result of expressions other than the parameter are unique is not supported - error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/call-generic-method-pass.rs:19:32 | LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool { | ^^^^^^^^^ -error[E0284]: type annotations needed - --> $DIR/call-generic-method-pass.rs:23:22 - | -LL | pub const EQ: bool = equals_self(&S); - | ^^^^^^^^^^^^^^^ cannot infer the value of the constant `_` - | -note: required for `S` to implement `PartialEq` - --> $DIR/call-generic-method-pass.rs:10:12 - | -LL | impl const PartialEq for S { - | ----- ^^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here - -error[E0284]: type annotations needed - --> $DIR/call-generic-method-pass.rs:15:10 - | -LL | !self.eq(other) - | ^^^^^^^^^^^^^^ cannot infer the value of the constant `_` - | -note: required for `S` to implement `PartialEq` - --> $DIR/call-generic-method-pass.rs:10:12 - | -LL | impl const PartialEq for S { - | ----- ^^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here - -error: aborting due to 5 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted -Some errors have detailed explanations: E0207, E0284. -For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr index 8916450df2d..9c1c8df8da4 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr @@ -1,3 +1,21 @@ +error: const `impl` for trait `Add` which is not marked with `#[const_trait]` + --> $DIR/const-and-non-const-impl.rs:7:12 + | +LL | impl const std::ops::Add for i32 { + | ^^^^^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: const `impl` for trait `Add` which is not marked with `#[const_trait]` + --> $DIR/const-and-non-const-impl.rs:23:12 + | +LL | impl const std::ops::Add for Int { + | ^^^^^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + error[E0119]: conflicting implementations of trait `Add` for type `Int` --> $DIR/const-and-non-const-impl.rs:23:1 | @@ -19,7 +37,7 @@ LL | impl const std::ops::Add for i32 { | = note: define and implement a trait or new type instead -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0117, E0119. For more information about an error, try `rustc --explain E0117`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bound-on-not-const-associated-fn.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bound-on-not-const-associated-fn.rs index 0025449c492..099cf0b00d3 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bound-on-not-const-associated-fn.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bound-on-not-const-associated-fn.rs @@ -1,4 +1,5 @@ -#![feature(const_trait_impl)] +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] #[const_trait] trait MyTrait { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bound-on-not-const-associated-fn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bound-on-not-const-associated-fn.stderr index db48c170d1c..42964b9774e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bound-on-not-const-associated-fn.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bound-on-not-const-associated-fn.stderr @@ -1,23 +1,23 @@ error: `~const` is not allowed here - --> $DIR/const-bound-on-not-const-associated-fn.rs:9:40 + --> $DIR/const-bound-on-not-const-associated-fn.rs:10:40 | LL | fn do_something_else() where Self: ~const MyTrait; | ^^^^^^ | note: this function is not `const`, so it cannot have `~const` trait bounds - --> $DIR/const-bound-on-not-const-associated-fn.rs:9:8 + --> $DIR/const-bound-on-not-const-associated-fn.rs:10:8 | LL | fn do_something_else() where Self: ~const MyTrait; | ^^^^^^^^^^^^^^^^^ error: `~const` is not allowed here - --> $DIR/const-bound-on-not-const-associated-fn.rs:20:32 + --> $DIR/const-bound-on-not-const-associated-fn.rs:21:32 | LL | pub fn foo(&self) where T: ~const MyTrait { | ^^^^^^ | note: this function is not `const`, so it cannot have `~const` trait bounds - --> $DIR/const-bound-on-not-const-associated-fn.rs:20:12 + --> $DIR/const-bound-on-not-const-associated-fn.rs:21:12 | LL | pub fn foo(&self) where T: ~const MyTrait { | ^^^ diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr index fb2e66db1d4..507ceaae2ea 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr @@ -1,3 +1,12 @@ +error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/const-closure-trait-method-fail.rs:5:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | trait Tr { +LL | fn a(self) -> i32; + | - expected 0 const parameters + error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closure-trait-method-fail.rs:14:39 | @@ -20,6 +29,7 @@ help: add `#![feature(effects)]` to the crate attributes to enable LL + #![feature(effects)] | -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0015`. +Some errors have detailed explanations: E0015, E0049. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr index dede411e69c..2a54cd5d7f6 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr @@ -1,3 +1,12 @@ +error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/const-closure-trait-method.rs:5:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | trait Tr { +LL | fn a(self) -> i32; + | - expected 0 const parameters + error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closure-trait-method.rs:14:39 | @@ -20,6 +29,7 @@ help: add `#![feature(effects)]` to the crate attributes to enable LL + #![feature(effects)] | -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0015`. +Some errors have detailed explanations: E0015, E0049. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr index 8e04d0bd20d..32bc0093347 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr @@ -7,13 +7,21 @@ LL | #![feature(const_trait_impl, effects)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied +error[E0277]: the trait bound `Runtime: ~const Compat` is not satisfied --> $DIR/const-default-method-bodies.rs:24:18 | LL | NonConstImpl.a(); - | ^ the trait `~const ConstDefaultFn` is not implemented for `NonConstImpl` + | ^ the trait `~const Compat` is not implemented for `Runtime` | - = help: the trait `ConstDefaultFn` is implemented for `NonConstImpl` + = help: the trait `Compat` is implemented for `Runtime` +note: required by a bound in `ConstDefaultFn::a` + --> $DIR/const-default-method-bodies.rs:3:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ required by this bound in `ConstDefaultFn::a` +... +LL | fn a(self) { + | - required by a bound in this associated function error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr index 085d9e71012..1d56d015dfc 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr @@ -1,3 +1,12 @@ +error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` + --> $DIR/const-drop-fail-2.rs:40:25 + | +LL | impl<T: ~const A> const Drop for ConstDropImplWithNonConstBounds<T> { + | ^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-drop-fail-2.rs:21:26 | @@ -12,6 +21,19 @@ LL | const fn check<T: ~const Destruct>(_: T) {} | | | the destructor for this type cannot be evaluated in constant functions -error: aborting due to 2 previous errors +error[E0015]: cannot call non-const fn `<T as A>::a` in constant functions + --> $DIR/const-drop-fail-2.rs:42:9 + | +LL | T::a(); + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: add `#![feature(effects)]` to the crate attributes to enable + | +LL + #![feature(effects)] + | + +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0493`. +Some errors have detailed explanations: E0015, E0493. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr index e95215d4715..b251d84a967 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr @@ -1,3 +1,12 @@ +error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` + --> $DIR/const-drop-fail.rs:20:12 + | +LL | impl const Drop for ConstImplWithDropGlue { + | ^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-drop-fail.rs:24:26 | @@ -38,8 +47,10 @@ LL | | } error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | - = note: calling non-const function `<ConstImplWithDropGlue as Drop>::drop` + = note: calling non-const function `<NonTrivialDrop as Drop>::drop` | +note: inside `std::ptr::drop_in_place::<NonTrivialDrop> - shim(Some(NonTrivialDrop))` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL note: inside `std::ptr::drop_in_place::<ConstImplWithDropGlue> - shim(Some(ConstImplWithDropGlue))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL note: inside `check::<ConstImplWithDropGlue>` @@ -60,7 +71,7 @@ LL | | } | |_- in this macro invocation = note: this error originates in the macro `check_all` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0080, E0493. For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr index f9bd9953fcf..912700f2a83 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr @@ -1,3 +1,12 @@ +error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` + --> $DIR/const-drop-fail.rs:20:12 + | +LL | impl const Drop for ConstImplWithDropGlue { + | ^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-drop-fail.rs:24:26 | @@ -12,6 +21,6 @@ LL | const fn check<T: ~const Destruct>(_: T) {} | | | the destructor for this type cannot be evaluated in constant functions -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr index 6aace105896..9d1ca5dbf2c 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr @@ -1,32 +1,64 @@ +error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` + --> $DIR/const-drop.rs:13:16 + | +LL | impl<'a> const Drop for S<'a> { + | ^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` + --> $DIR/const-drop.rs:47:16 + | +LL | impl const Drop for ConstDrop { + | ^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` + --> $DIR/const-drop.rs:68:37 + | +LL | impl<T: ~const SomeTrait> const Drop for ConstDropWithBound<T> { + | ^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` + --> $DIR/const-drop.rs:76:30 + | +LL | impl<T: SomeTrait> const Drop for ConstDropWithNonconstBound<T> { + | ^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-drop.rs:19:22 | LL | const fn a<T: ~const Destruct>(_: T) {} | ^^^^^^^^ -error[E0493]: destructor of `S<'_>` cannot be evaluated at compile-time - --> $DIR/const-drop.rs:24:13 +error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/const-drop.rs:54:5 | -LL | let _ = S(&mut c); - | ^^^^^^^^^ the destructor for this type cannot be evaluated in constant functions +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | pub trait SomeTrait { +LL | fn foo(); + | - expected 0 const parameters -error[E0080]: evaluation of constant value failed - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL - | - = note: calling non-const function `<S<'_> as Drop>::drop` +error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/const-drop.rs:54:5 | -note: inside `std::ptr::drop_in_place::<S<'_>> - shim(Some(S<'_>))` - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `b` - --> $DIR/const-drop.rs:24:22 +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | pub trait SomeTrait { +LL | fn foo(); + | - expected 0 const parameters | -LL | let _ = S(&mut c); - | ^ -note: inside `C` - --> $DIR/const-drop.rs:30:15 - | -LL | const C: u8 = b(); - | ^^^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/const-drop.rs:19:32 @@ -34,65 +66,19 @@ error[E0493]: destructor of `T` cannot be evaluated at compile-time LL | const fn a<T: ~const Destruct>(_: T) {} | ^ the destructor for this type cannot be evaluated in constant functions -error[E0080]: evaluation of constant value failed - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +error[E0015]: cannot call non-const fn `<T as SomeTrait>::foo` in constant functions + --> $DIR/const-drop.rs:70:13 | - = note: calling non-const function `<t::ConstDrop as Drop>::drop` +LL | T::foo(); + | ^^^^^^^^ | -note: inside `std::ptr::drop_in_place::<t::ConstDrop> - shim(Some(t::ConstDrop))` - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `a::<t::ConstDrop>` - --> $DIR/const-drop.rs:19:39 + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: add `#![feature(effects)]` to the crate attributes to enable | -LL | const fn a<T: ~const Destruct>(_: T) {} - | ^ -note: inside `_` - --> $DIR/const-drop.rs:35:27 - | -LL | const _: () = a($exp); - | ^^^^^^^ -... -LL | / implements_const_drop! { -LL | | 1u8, -LL | | 2, -LL | | 3.0, -... | -LL | | Result::<i32, !>::Ok(1), -LL | | } - | |_- in this macro invocation - = note: this error originates in the macro `implements_const_drop` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0080]: evaluation of constant value failed - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL - | - = note: calling non-const function `<t::ConstDrop as Drop>::drop` +LL + #![feature(effects)] | -note: inside `std::ptr::drop_in_place::<t::ConstDrop> - shim(Some(t::ConstDrop))` - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `std::ptr::drop_in_place::<t::HasConstDrop> - shim(Some(t::HasConstDrop))` - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `a::<t::HasConstDrop>` - --> $DIR/const-drop.rs:19:39 - | -LL | const fn a<T: ~const Destruct>(_: T) {} - | ^ -note: inside `_` - --> $DIR/const-drop.rs:35:27 - | -LL | const _: () = a($exp); - | ^^^^^^^ -... -LL | / implements_const_drop! { -LL | | 1u8, -LL | | 2, -LL | | 3.0, -... | -LL | | Result::<i32, !>::Ok(1), -LL | | } - | |_- in this macro invocation - = note: this error originates in the macro `implements_const_drop` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 6 previous errors +error: aborting due to 9 previous errors -Some errors have detailed explanations: E0080, E0493. -For more information about an error, try `rustc --explain E0080`. +Some errors have detailed explanations: E0015, E0049, E0493. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr index 18dd4543c3d..2f93f9a6743 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr @@ -1,16 +1,64 @@ +error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` + --> $DIR/const-drop.rs:13:16 + | +LL | impl<'a> const Drop for S<'a> { + | ^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` + --> $DIR/const-drop.rs:47:16 + | +LL | impl const Drop for ConstDrop { + | ^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` + --> $DIR/const-drop.rs:68:37 + | +LL | impl<T: ~const SomeTrait> const Drop for ConstDropWithBound<T> { + | ^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` + --> $DIR/const-drop.rs:76:30 + | +LL | impl<T: SomeTrait> const Drop for ConstDropWithNonconstBound<T> { + | ^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-drop.rs:19:22 | LL | const fn a<T: ~const Destruct>(_: T) {} | ^^^^^^^^ -error[E0493]: destructor of `S<'_>` cannot be evaluated at compile-time - --> $DIR/const-drop.rs:24:13 +error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/const-drop.rs:54:5 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | pub trait SomeTrait { +LL | fn foo(); + | - expected 0 const parameters + +error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/const-drop.rs:54:5 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | pub trait SomeTrait { +LL | fn foo(); + | - expected 0 const parameters | -LL | let _ = S(&mut c); - | ^^^^^^^^^- value is dropped here - | | - | the destructor for this type cannot be evaluated in constant functions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/const-drop.rs:19:32 @@ -20,6 +68,19 @@ LL | const fn a<T: ~const Destruct>(_: T) {} | | | the destructor for this type cannot be evaluated in constant functions -error: aborting due to 3 previous errors +error[E0015]: cannot call non-const fn `<T as SomeTrait>::foo` in constant functions + --> $DIR/const-drop.rs:70:13 + | +LL | T::foo(); + | ^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: add `#![feature(effects)]` to the crate attributes to enable + | +LL + #![feature(effects)] + | + +error: aborting due to 9 previous errors -For more information about this error, try `rustc --explain E0493`. +Some errors have detailed explanations: E0015, E0049, E0493. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs index faa913c7598..b3087349e4d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs @@ -1,17 +1,21 @@ -//@ check-pass +//@ known-bug: #110395 +// FIXME(effects) check-pass +//@ compile-flags: -Znext-solver #![crate_type = "lib"] -#![allow(internal_features)] +#![allow(internal_features, incomplete_features)] #![no_std] #![no_core] #![feature( auto_traits, const_trait_impl, - effects, //~ WARN the feature `effects` is incomplete + effects, lang_items, no_core, staged_api, - unboxed_closures + unboxed_closures, + rustc_attrs, + marker_trait_attr, )] #![stable(feature = "minicore", since = "1.0.0")] @@ -84,3 +88,49 @@ trait Receiver {} impl<T: ?Sized> Receiver for &T {} impl<T: ?Sized> Receiver for &mut T {} + +#[stable(feature = "minicore", since = "1.0.0")] +pub mod effects { + use super::Sized; + + #[lang = "EffectsNoRuntime"] + #[stable(feature = "minicore", since = "1.0.0")] + pub struct NoRuntime; + #[lang = "EffectsMaybe"] + #[stable(feature = "minicore", since = "1.0.0")] + pub struct Maybe; + #[lang = "EffectsRuntime"] + #[stable(feature = "minicore", since = "1.0.0")] + pub struct Runtime; + + #[lang = "EffectsCompat"] + #[stable(feature = "minicore", since = "1.0.0")] + pub trait Compat<#[rustc_runtime] const RUNTIME: bool> {} + + #[stable(feature = "minicore", since = "1.0.0")] + impl Compat<false> for NoRuntime {} + #[stable(feature = "minicore", since = "1.0.0")] + impl Compat<true> for Runtime {} + #[stable(feature = "minicore", since = "1.0.0")] + impl<#[rustc_runtime] const RUNTIME: bool> Compat<RUNTIME> for Maybe {} + + #[lang = "EffectsTyCompat"] + #[marker] + #[stable(feature = "minicore", since = "1.0.0")] + pub trait TyCompat<T: ?Sized> {} + + #[stable(feature = "minicore", since = "1.0.0")] + impl<T: ?Sized> TyCompat<T> for T {} + #[stable(feature = "minicore", since = "1.0.0")] + impl<T: ?Sized> TyCompat<T> for Maybe {} + #[stable(feature = "minicore", since = "1.0.0")] + impl<T: ?Sized> TyCompat<Maybe> for T {} + + #[lang = "EffectsIntersection"] + #[stable(feature = "minicore", since = "1.0.0")] + pub trait Intersection { + #[lang = "EffectsIntersectionOutput"] + #[stable(feature = "minicore", since = "1.0.0")] + type Output: ?Sized; + } +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr index 42b19fce28e..7aa3aa8c6bb 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr @@ -1,11 +1,20 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/const-fns-are-early-bound.rs:10:5 +error[E0277]: the trait bound `FnOnce<()>::{synthetic#0}: const Compat` is not satisfied + --> $DIR/const-fns-are-early-bound.rs:31:17 | -LL | effects, - | ^^^^^^^ +LL | is_const_fn(foo); + | ----------- ^^^ the trait `const Compat` is not implemented for `FnOnce<()>::{synthetic#0}` + | | + | required by a bound introduced by this call | - = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information - = note: `#[warn(incomplete_features)]` on by default +note: required by a bound in `is_const_fn` + --> $DIR/const-fns-are-early-bound.rs:25:12 + | +LL | fn is_const_fn<F>(_: F) + | ----------- required by a bound in this function +LL | where +LL | F: const FnOnce<()>, + | ^^^^^^^^^^^^^^^^ required by this bound in `is_const_fn` -warning: 1 warning emitted +error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr index fb282d9ee2b..7925cf53f42 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr @@ -19,15 +19,5 @@ LL | impl const A for () {} = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates - --> $DIR/const-impl-requires-const-trait.rs:8:6 - | -LL | impl const A for () {} - | ^^^^^ unconstrained const parameter - | - = note: expressions using a const parameter must map each value to a distinct output value - = note: proving the result of expressions other than the parameter are unique is not supported - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 1 previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.rs index 8e71fa4d519..691bce19dc2 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.rs @@ -1,4 +1,5 @@ -#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete +#![feature(const_trait_impl)] +// FIXME(effects) add effects //@ edition: 2021 #[const_trait] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.stderr index 7d774bef0e9..bd29b4b860b 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.stderr @@ -1,11 +1,11 @@ error: const trait bounds are not allowed in trait object types - --> $DIR/const-trait-bounds-trait-objects.rs:8:17 + --> $DIR/const-trait-bounds-trait-objects.rs:9:17 | LL | let _: &dyn const Trait; | ^^^^^^^^^^^ error: `~const` is not allowed here - --> $DIR/const-trait-bounds-trait-objects.rs:9:17 + --> $DIR/const-trait-bounds-trait-objects.rs:10:17 | LL | let _: &dyn ~const Trait; | ^^^^^^ @@ -13,27 +13,18 @@ LL | let _: &dyn ~const Trait; = note: trait objects cannot have `~const` trait bounds error: const trait bounds are not allowed in trait object types - --> $DIR/const-trait-bounds-trait-objects.rs:14:25 + --> $DIR/const-trait-bounds-trait-objects.rs:15:25 | LL | const fn handle(_: &dyn const NonConst) {} | ^^^^^^^^^^^^^^ error: `~const` is not allowed here - --> $DIR/const-trait-bounds-trait-objects.rs:16:23 + --> $DIR/const-trait-bounds-trait-objects.rs:17:23 | LL | const fn take(_: &dyn ~const NonConst) {} | ^^^^^^ | = note: trait objects cannot have `~const` trait bounds -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/const-trait-bounds-trait-objects.rs:1:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information - = note: `#[warn(incomplete_features)]` on by default - -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs index 348ca0ab190..a772d69c9e2 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs @@ -1,4 +1,5 @@ #[derive_const(Default)] //~ ERROR use of unstable library feature +//~^ ERROR const `impl` for trait `Default` which is not marked with `#[const_trait]` pub struct S; fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr index 9ec2ac93381..3ccae5a83e6 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr @@ -7,6 +7,16 @@ LL | #[derive_const(Default)] = help: add `#![feature(derive_const)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 1 previous error +error: const `impl` for trait `Default` which is not marked with `#[const_trait]` + --> $DIR/derive-const-gate.rs:1:16 + | +LL | #[derive_const(Default)] + | ^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr index 1e091283510..78e5b70d41c 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr @@ -17,11 +17,5 @@ LL | #[derive_const(Default)] = note: adding a non-const method body in the future would be a breaking change = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates - | - = note: expressions using a const parameter must map each value to a distinct output value - = note: proving the result of expressions other than the parameter are unique is not supported - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 1 previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.stderr index 925b2c58ed7..da6b77f623c 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.stderr @@ -28,33 +28,6 @@ LL | impl const Default for A { = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates - --> $DIR/derive-const-use.rs:7:6 - | -LL | impl const Default for A { - | ^^^^^ unconstrained const parameter - | - = note: expressions using a const parameter must map each value to a distinct output value - = note: proving the result of expressions other than the parameter are unique is not supported - -error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` - --> $DIR/derive-const-use.rs:11:12 - | -LL | impl const PartialEq for A { - | ^^^^^^^^^ - | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` - = note: adding a non-const method body in the future would be a breaking change - -error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates - --> $DIR/derive-const-use.rs:11:6 - | -LL | impl const PartialEq for A { - | ^^^^^ unconstrained const parameter - | - = note: expressions using a const parameter must map each value to a distinct output value - = note: proving the result of expressions other than the parameter are unique is not supported - error: const `impl` for trait `Default` which is not marked with `#[const_trait]` --> $DIR/derive-const-use.rs:15:16 | @@ -65,10 +38,14 @@ LL | #[derive_const(Default, PartialEq)] = note: adding a non-const method body in the future would be a breaking change = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates +error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` + --> $DIR/derive-const-use.rs:11:12 + | +LL | impl const PartialEq for A { + | ^^^^^^^^^ | - = note: expressions using a const parameter must map each value to a distinct output value - = note: proving the result of expressions other than the parameter are unique is not supported + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` --> $DIR/derive-const-use.rs:15:25 @@ -80,73 +57,29 @@ LL | #[derive_const(Default, PartialEq)] = note: adding a non-const method body in the future would be a breaking change = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates - | - = note: expressions using a const parameter must map each value to a distinct output value - = note: proving the result of expressions other than the parameter are unique is not supported - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0284]: type annotations needed - --> $DIR/derive-const-use.rs:18:35 - | -LL | const _: () = assert!(S((), A) == S::default()); - | ^^^^^^^^^^^^ cannot infer the value of the constant `_` - | -note: required for `S` to implement `Default` - --> $DIR/derive-const-use.rs:15:16 - | -LL | #[derive_const(Default, PartialEq)] - | ^^^^^^^ unsatisfied trait bound introduced in this `derive` macro - = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0284]: type annotations needed - --> $DIR/derive-const-use.rs:18:23 - | -LL | const _: () = assert!(S((), A) == S::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the constant `_` - | -note: required for `S` to implement `PartialEq` - --> $DIR/derive-const-use.rs:15:25 - | -LL | #[derive_const(Default, PartialEq)] - | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro - = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0284]: type annotations needed - --> $DIR/derive-const-use.rs:16:18 +error[E0080]: evaluation of constant value failed + --> $DIR/derive-const-use.rs:16:14 | LL | #[derive_const(Default, PartialEq)] | ------- in this derive macro expansion LL | pub struct S((), A); - | ^ cannot infer the value of the constant `_` + | ^^ calling non-const function `<() as Default>::default` | -note: required for `A` to implement `Default` - --> $DIR/derive-const-use.rs:7:12 - | -LL | impl const Default for A { - | ----- ^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here - = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0284]: type annotations needed - --> $DIR/derive-const-use.rs:16:18 +note: inside `<S as Default>::default` + --> $DIR/derive-const-use.rs:16:14 | LL | #[derive_const(Default, PartialEq)] - | --------- in this derive macro expansion + | ------- in this derive macro expansion LL | pub struct S((), A); - | ^ cannot infer the value of the constant `_` - | -note: required for `A` to implement `PartialEq` - --> $DIR/derive-const-use.rs:11:12 + | ^^ +note: inside `_` + --> $DIR/derive-const-use.rs:18:35 | -LL | impl const PartialEq for A { - | ----- ^^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here - = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +LL | const _: () = assert!(S((), A) == S::default()); + | ^^^^^^^^^^^^ + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 14 previous errors; 1 warning emitted +error: aborting due to 7 previous errors; 1 warning emitted -Some errors have detailed explanations: E0207, E0284, E0635. -For more information about an error, try `rustc --explain E0207`. +Some errors have detailed explanations: E0080, E0635. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.stderr index 5d3aa250d18..102458450fb 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.stderr @@ -25,25 +25,5 @@ LL | #[derive_const(PartialEq)] | = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates - | - = note: expressions using a const parameter must map each value to a distinct output value - = note: proving the result of expressions other than the parameter are unique is not supported - -error[E0284]: type annotations needed - --> $DIR/derive-const-with-params.rs:11:5 - | -LL | a == b - | ^^^^^^ cannot infer the value of the constant `_` - | -note: required for `Reverse<i32>` to implement `PartialEq` - --> $DIR/derive-const-with-params.rs:7:16 - | -LL | #[derive_const(PartialEq)] - | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro - = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted -Some errors have detailed explanations: E0207, E0284. -For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr index ddb5b3c7c50..af042ecff95 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr @@ -7,13 +7,21 @@ LL | #![cfg_attr(any(gated, gatednc), feature(const_trait_impl, effects))] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied +error[E0277]: the trait bound `Runtime: ~const Compat` is not satisfied --> $DIR/cross-crate.rs:18:14 | LL | NonConst.func(); - | ^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst` + | ^^^^ the trait `~const Compat` is not implemented for `Runtime` | - = help: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst` + = help: the trait `Compat` is implemented for `Runtime` +note: required by a bound in `func` + --> $DIR/auxiliary/cross-crate.rs:4:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ required by this bound in `MyTrait::func` +... +LL | fn func(self); + | ---- required by a bound in this associated function error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr index 67a936d0882..8b422d62578 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr @@ -7,13 +7,21 @@ LL | #![feature(const_trait_impl, effects)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error[E0277]: the trait bound `(): ~const Tr` is not satisfied +error[E0277]: the trait bound `Runtime: ~const Compat` is not satisfied --> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12 | LL | ().a() - | ^ the trait `~const Tr` is not implemented for `()` + | ^ the trait `~const Compat` is not implemented for `Runtime` | - = help: the trait `Tr` is implemented for `()` + = help: the trait `Compat` is implemented for `Runtime` +note: required by a bound in `Tr::a` + --> $DIR/default-method-body-is-const-same-trait-ck.rs:3:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ required by this bound in `Tr::a` +LL | pub trait Tr { +LL | fn a(&self) {} + | - required by a bound in this associated function error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/group-traits.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/group-traits.rs new file mode 100644 index 00000000000..2c5b6cc40e6 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/group-traits.rs @@ -0,0 +1,14 @@ +//@ check-pass +use std::ops::Add; + +pub trait GroupOpsOwned<Rhs = Self, Output = Self>: for<'r> Add<&'r Rhs, Output = Output> {} + +pub trait Curve: Sized + GroupOpsOwned<Self::AffineRepr> { + type AffineRepr; +} + +pub trait CofactorCurve: Curve<AffineRepr = <Self as CofactorCurve>::Affine> { + type Affine; +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr index e4a5f368608..1963332b856 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr @@ -7,12 +7,11 @@ LL | #![feature(const_trait_impl, effects, const_mut_refs)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error[E0094]: intrinsic has wrong number of const parameters: found 1, expected 0 - --> $DIR/minicore.rs:517:27 +error: requires `EffectsCompat` lang_item + --> $DIR/minicore.rs:455:9 | -LL | const fn const_eval_select<ARG: Tuple, F, G, RET>( - | ^^^^^^^^^^^^^^^^^^^^^^^ expected 0 const parameters +LL | impl<T: Clone> Clone for RefCell<T> { + | ^^^^^ error: aborting due to 1 previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0094`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr index cc870ad336c..34732ac4f2e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr @@ -16,15 +16,17 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/no-explicit-const-params-cross-crate.rs:16:12 | LL | <() as Bar<false>>::bar(); - | ^^^------- help: remove these generics - | | - | expected 0 generic arguments + | ^^^ expected 0 generic arguments | note: trait defined here, with 0 generic parameters --> $DIR/auxiliary/cross-crate.rs:6:11 | LL | pub trait Bar { | ^^^ +help: replace the generic bound with the associated type + | +LL | <() as Bar< = false>>::bar(); + | + error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied --> $DIR/no-explicit-const-params-cross-crate.rs:7:5 @@ -44,15 +46,17 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/no-explicit-const-params-cross-crate.rs:9:12 | LL | <() as Bar<true>>::bar(); - | ^^^------ help: remove these generics - | | - | expected 0 generic arguments + | ^^^ expected 0 generic arguments | note: trait defined here, with 0 generic parameters --> $DIR/auxiliary/cross-crate.rs:6:11 | LL | pub trait Bar { | ^^^ +help: replace the generic bound with the associated type + | +LL | <() as Bar< = true>>::bar(); + | + error: aborting due to 4 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr index 39aa5825611..c3ff30d2d79 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr @@ -25,15 +25,17 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/no-explicit-const-params.rs:24:12 | LL | <() as Bar<false>>::bar(); - | ^^^------- help: remove these generics - | | - | expected 0 generic arguments + | ^^^ expected 0 generic arguments | note: trait defined here, with 0 generic parameters --> $DIR/no-explicit-const-params.rs:6:7 | LL | trait Bar { | ^^^ +help: replace the generic bound with the associated type + | +LL | <() as Bar< = false>>::bar(); + | + error[E0308]: mismatched types --> $DIR/no-explicit-const-params.rs:24:5 @@ -62,15 +64,17 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/no-explicit-const-params.rs:17:12 | LL | <() as Bar<true>>::bar(); - | ^^^------ help: remove these generics - | | - | expected 0 generic arguments + | ^^^ expected 0 generic arguments | note: trait defined here, with 0 generic parameters --> $DIR/no-explicit-const-params.rs:6:7 | LL | trait Bar { | ^^^ +help: replace the generic bound with the associated type + | +LL | <() as Bar< = true>>::bar(); + | + error: aborting due to 5 previous errors; 1 warning emitted diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs index 0592ac2e0e7..373a4393713 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs @@ -1,12 +1,10 @@ -//@ known-bug: #110395 -// FIXME: effects +//@ check-pass #![feature(const_trait_impl, effects)] +#![allow(incomplete_features)] -// This fails because `~const Uwu` doesn't imply (non-const) `Uwu`. - -// FIXME: #[const_trait] -pub trait Owo<X = <Self as /* FIXME: ~const */ Uwu>::T> {} +#[const_trait] +pub trait Owo<X = <Self as Uwu>::T> {} #[const_trait] pub trait Uwu: Owo { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.stderr deleted file mode 100644 index ab5f7b55a4e..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.stderr +++ /dev/null @@ -1,74 +0,0 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/project.rs:4:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information - = note: `#[warn(incomplete_features)]` on by default - -error[E0277]: the trait bound `Self: Uwu` is not satisfied - --> $DIR/project.rs:12:1 - | -LL | pub trait Uwu: Owo { - | ^^^^^^^^^^^^^^^^^^ the trait `Uwu` is not implemented for `Self` - | -help: consider further restricting `Self` - | -LL | pub trait Uwu: Owo + Uwu { - | +++++ - -error[E0277]: the trait bound `Self: Uwu` is not satisfied - --> $DIR/project.rs:12:1 - | -LL | / pub trait Uwu: Owo { -LL | | type T; -LL | | } - | |_^ the trait `Uwu` is not implemented for `Self` - | -help: consider further restricting `Self` - | -LL | pub trait Uwu: Owo + Uwu { - | +++++ - -error[E0277]: the trait bound `Self: Uwu` is not satisfied - --> $DIR/project.rs:12:16 - | -LL | pub trait Uwu: Owo { - | ^^^ the trait `Uwu` is not implemented for `Self` - | -note: required by a bound in `Owo` - --> $DIR/project.rs:9:15 - | -LL | pub trait Owo<X = <Self as /* FIXME: ~const */ Uwu>::T> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Owo` -help: consider further restricting `Self` - | -LL | pub trait Uwu: Owo + Uwu { - | +++++ - -error[E0277]: the trait bound `Self: Uwu` is not satisfied - --> $DIR/project.rs:13:5 - | -LL | type T; - | ^^^^^^ the trait `Uwu` is not implemented for `Self` - | -help: consider further restricting `Self` - | -LL | pub trait Uwu: Owo + Uwu { - | +++++ - -error[E0277]: the trait bound `Self: Uwu` is not satisfied - --> $DIR/project.rs:13:5 - | -LL | type T; - | ^^^^^^^ the trait `Uwu` is not implemented for `Self` - | -help: consider further restricting `Self` - | -LL | pub trait Uwu: Owo + Uwu { - | +++++ - -error: aborting due to 5 previous errors; 1 warning emitted - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.rs index 987a162cd6c..e6e41c472bd 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.rs @@ -6,7 +6,6 @@ trait T {} impl const dyn T { //~^ ERROR inherent impls cannot be `const` - //~| ERROR the const parameter `host` is not constrained by the impl trait, self type, or pub const fn new() -> std::sync::Mutex<dyn T> {} //~^ ERROR mismatched types //~| ERROR cannot be known at compilation time diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.stderr index f24d7c7a160..313ba4fc956 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.stderr @@ -17,17 +17,8 @@ LL | #![feature(effects)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates - --> $DIR/span-bug-issue-121418.rs:7:6 - | -LL | impl const dyn T { - | ^^^^^ unconstrained const parameter - | - = note: expressions using a const parameter must map each value to a distinct output value - = note: proving the result of expressions other than the parameter are unique is not supported - error[E0308]: mismatched types - --> $DIR/span-bug-issue-121418.rs:10:27 + --> $DIR/span-bug-issue-121418.rs:9:27 | LL | pub const fn new() -> std::sync::Mutex<dyn T> {} | --- ^^^^^^^^^^^^^^^^^^^^^^^ expected `Mutex<dyn T>`, found `()` @@ -38,7 +29,7 @@ LL | pub const fn new() -> std::sync::Mutex<dyn T> {} found unit type `()` error[E0277]: the size for values of type `(dyn T + 'static)` cannot be known at compilation time - --> $DIR/span-bug-issue-121418.rs:10:27 + --> $DIR/span-bug-issue-121418.rs:9:27 | LL | pub const fn new() -> std::sync::Mutex<dyn T> {} | ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -48,7 +39,7 @@ note: required because it appears within the type `Mutex<(dyn T + 'static)>` --> $SRC_DIR/std/src/sync/mutex.rs:LL:COL = note: the return type of a function must have a statically known size -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 3 previous errors; 1 warning emitted -Some errors have detailed explanations: E0207, E0277, E0308. -For more information about an error, try `rustc --explain E0207`. +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.rs index 00465b0f53d..0508b1c5e26 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.rs @@ -11,12 +11,11 @@ trait Foo {} impl<T> const Foo for T {} //~^ error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` -//~| error: the const parameter `host` is not constrained by the impl trait, self type, or predicates [E0207] impl<T> const Foo for T where T: const Specialize {} //~^ error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` //~| error: `const` can only be applied to `#[const_trait]` traits -//~| error: the const parameter `host` is not constrained by the impl trait, self type, or predicates [E0207] -//~| error: conflicting implementations of trait `Foo` +//~| error: specialization impl does not specialize any associated items +//~| error: cannot specialize on trait `Specialize` fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.stderr index 8d69151bf74..047549bca75 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.stderr @@ -20,7 +20,7 @@ LL | impl<T> const Foo for T {} = note: adding a non-const method body in the future would be a breaking change error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` - --> $DIR/spec-effectvar-ice.rs:16:15 + --> $DIR/spec-effectvar-ice.rs:15:15 | LL | trait Foo {} | - help: mark `Foo` as const: `#[const_trait]` @@ -32,39 +32,28 @@ LL | impl<T> const Foo for T where T: const Specialize {} = note: adding a non-const method body in the future would be a breaking change error: `const` can only be applied to `#[const_trait]` traits - --> $DIR/spec-effectvar-ice.rs:16:40 + --> $DIR/spec-effectvar-ice.rs:15:40 | LL | impl<T> const Foo for T where T: const Specialize {} | ^^^^^^^^^^ -error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates - --> $DIR/spec-effectvar-ice.rs:12:9 +error: specialization impl does not specialize any associated items + --> $DIR/spec-effectvar-ice.rs:15:1 | -LL | impl<T> const Foo for T {} - | ^^^^^ unconstrained const parameter +LL | impl<T> const Foo for T where T: const Specialize {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expressions using a const parameter must map each value to a distinct output value - = note: proving the result of expressions other than the parameter are unique is not supported - -error[E0119]: conflicting implementations of trait `Foo` - --> $DIR/spec-effectvar-ice.rs:16:1 +note: impl is a specialization of this impl + --> $DIR/spec-effectvar-ice.rs:12:1 | LL | impl<T> const Foo for T {} - | ----------------------- first implementation here -... -LL | impl<T> const Foo for T where T: const Specialize {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation + | ^^^^^^^^^^^^^^^^^^^^^^^ -error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates - --> $DIR/spec-effectvar-ice.rs:16:9 +error: cannot specialize on trait `Specialize` + --> $DIR/spec-effectvar-ice.rs:15:34 | LL | impl<T> const Foo for T where T: const Specialize {} - | ^^^^^ unconstrained const parameter - | - = note: expressions using a const parameter must map each value to a distinct output value - = note: proving the result of expressions other than the parameter are unique is not supported + | ^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 5 previous errors; 1 warning emitted -Some errors have detailed explanations: E0119, E0207. -For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.stderr index 7905abfa40e..2baac1d2a16 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.stderr @@ -1,20 +1,24 @@ +error: const `impl` for trait `Add` which is not marked with `#[const_trait]` + --> $DIR/generic-bound.rs:16:15 + | +LL | impl<T> const std::ops::Add for S<T> { + | ^^^^^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + error[E0015]: cannot call non-const operator in constant functions --> $DIR/generic-bound.rs:25:5 | LL | arg + arg | ^^^^^^^^^ | -note: impl defined here, but it is not `const` - --> $DIR/generic-bound.rs:16:1 - | -LL | impl<T> const std::ops::Add for S<T> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants help: add `#![feature(effects)]` to the crate attributes to enable | LL + #![feature(effects)] | -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-119717-constant-lifetime.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-119717-constant-lifetime.rs new file mode 100644 index 00000000000..c2f452a9925 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-119717-constant-lifetime.rs @@ -0,0 +1,15 @@ +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects, try_trait_v2)] + +use std::ops::FromResidual; + +impl<T> const FromResidual for T { + //~^ ERROR const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` + //~| type parameter `T` must be used as the type parameter for some local type + fn from_residual(t: T) -> _ { + //~^ the placeholder `_` is not allowed + t + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-119717-constant-lifetime.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-119717-constant-lifetime.stderr new file mode 100644 index 00000000000..9e22422ad3b --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-119717-constant-lifetime.stderr @@ -0,0 +1,33 @@ +error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` + --> $DIR/ice-119717-constant-lifetime.rs:6:15 + | +LL | impl<T> const FromResidual for T { + | ^^^^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`) + --> $DIR/ice-119717-constant-lifetime.rs:6:6 + | +LL | impl<T> const FromResidual for T { + | ^ type parameter `T` must be used as the type parameter for some local type + | + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/ice-119717-constant-lifetime.rs:9:31 + | +LL | fn from_residual(t: T) -> _ { + | ^ not allowed in type signatures + | +help: try replacing `_` with the type in the corresponding trait method signature + | +LL | fn from_residual(t: T) -> T { + | ~ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0121, E0210. +For more information about an error, try `rustc --explain E0121`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-123664-unexpected-bound-var.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-123664-unexpected-bound-var.rs new file mode 100644 index 00000000000..64634e7b7ac --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-123664-unexpected-bound-var.rs @@ -0,0 +1,7 @@ +#![allow(incomplete_features)] +#![feature(generic_const_exprs, const_trait_impl, effects)] + +const fn with_positive<F: ~const Fn()>() {} +//~^ ERROR `~const` can only be applied to `#[const_trait]` traits + +pub fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-123664-unexpected-bound-var.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-123664-unexpected-bound-var.stderr new file mode 100644 index 00000000000..19369e38964 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-123664-unexpected-bound-var.stderr @@ -0,0 +1,8 @@ +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/ice-123664-unexpected-bound-var.rs:4:34 + | +LL | const fn with_positive<F: ~const Fn()>() {} + | ^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-124857-combine-effect-const-infer-vars.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-124857-combine-effect-const-infer-vars.rs new file mode 100644 index 00000000000..d4fcbfb1b83 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-124857-combine-effect-const-infer-vars.rs @@ -0,0 +1,14 @@ +//@ compile-flags: -Znext-solver=coherence + +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] + +#[const_trait] +trait Foo {} + +impl const Foo for i32 {} + +impl<T> const Foo for T where T: ~const Foo {} +//~^ ERROR conflicting implementations of trait `Foo` for type `i32` + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-124857-combine-effect-const-infer-vars.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-124857-combine-effect-const-infer-vars.stderr new file mode 100644 index 00000000000..0b1f8b40898 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-124857-combine-effect-const-infer-vars.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Foo` for type `i32` + --> $DIR/ice-124857-combine-effect-const-infer-vars.rs:11:1 + | +LL | impl const Foo for i32 {} + | ---------------------- first implementation here +LL | +LL | impl<T> const Foo for T where T: ~const Foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-126148-failed-to-normalize.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-126148-failed-to-normalize.rs new file mode 100644 index 00000000000..717c0e7c088 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-126148-failed-to-normalize.rs @@ -0,0 +1,28 @@ +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects, try_trait_v2, const_try)] +use std::ops::{FromResidual, Try}; + +struct TryMe; +struct Error; + +impl const FromResidual<Error> for TryMe {} +//~^ ERROR const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` +//~| ERROR not all trait items implemented + +impl const Try for TryMe { + //~^ ERROR const `impl` for trait `Try` which is not marked with `#[const_trait]` + //~| ERROR not all trait items implemented + type Output = (); + type Residual = Error; +} + +const fn t() -> TryMe { + TryMe?; + TryMe +} + +const _: () = { + t(); +}; + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-126148-failed-to-normalize.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-126148-failed-to-normalize.stderr new file mode 100644 index 00000000000..e641b457ef9 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-126148-failed-to-normalize.stderr @@ -0,0 +1,38 @@ +error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` + --> $DIR/ice-126148-failed-to-normalize.rs:8:12 + | +LL | impl const FromResidual<Error> for TryMe {} + | ^^^^^^^^^^^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error[E0046]: not all trait items implemented, missing: `from_residual` + --> $DIR/ice-126148-failed-to-normalize.rs:8:1 + | +LL | impl const FromResidual<Error> for TryMe {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `from_residual` in implementation + | + = help: implement the missing item: `fn from_residual(_: Error) -> Self { todo!() }` + +error: const `impl` for trait `Try` which is not marked with `#[const_trait]` + --> $DIR/ice-126148-failed-to-normalize.rs:12:12 + | +LL | impl const Try for TryMe { + | ^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error[E0046]: not all trait items implemented, missing: `from_output`, `branch` + --> $DIR/ice-126148-failed-to-normalize.rs:12:1 + | +LL | impl const Try for TryMe { + | ^^^^^^^^^^^^^^^^^^^^^^^^ missing `from_output`, `branch` in implementation + | + = help: implement the missing item: `fn from_output(_: <Self as Try>::Output) -> Self { todo!() }` + = help: implement the missing item: `fn branch(self) -> ControlFlow<<Self as Try>::Residual, <Self as Try>::Output> { todo!() }` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0046`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs index 6df9696f2cb..49741ca24c7 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs @@ -1,4 +1,5 @@ -#![feature(const_trait_impl)] +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] #[const_trait] trait Tr { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr index 36c8163f1c5..0135296526f 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr @@ -1,5 +1,5 @@ error[E0046]: not all trait items implemented, missing: `req` - --> $DIR/impl-with-default-fn-fail.rs:12:1 + --> $DIR/impl-with-default-fn-fail.rs:13:1 | LL | fn req(&self); | -------------- `req` from trait diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs index c6fab4aabb6..0a1d2355a75 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs @@ -1,6 +1,6 @@ //@ check-pass - -#![feature(const_trait_impl)] +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] #[const_trait] trait Tr { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs index 2a40a1b86ca..10d7a3942e4 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs @@ -1,6 +1,7 @@ //@ revisions: nn ny yn yy //@ check-pass -#![feature(const_trait_impl, associated_type_defaults, const_mut_refs)] +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects, associated_type_defaults, const_mut_refs)] #[cfg_attr(any(yn, yy), const_trait)] pub trait Index { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs index 825ddb6a5cd..e666355db6f 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs @@ -1,8 +1,10 @@ // Regression test for #92230. // //@ check-pass +//@ compile-flags: -Znext-solver -#![feature(const_trait_impl)] +#![feature(const_trait_impl, effects)] +#![allow(incomplete_features)] #[const_trait] pub trait Super {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr index ae76cab2f2e..de4783bdb3f 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr @@ -4,5 +4,28 @@ error: `~const` can only be applied to `#[const_trait]` traits LL | impl<A, B> const Convert<B> for A where B: ~const From<A> { | ^^^^^^^ -error: aborting due to 1 previous error +error[E0049]: method `to` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/non-const-op-in-closure-in-const.rs:5:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | trait Convert<T> { +LL | fn to(self) -> T; + | - expected 0 const parameters + +error[E0015]: cannot call non-const fn `<B as From<A>>::from` in constant functions + --> $DIR/non-const-op-in-closure-in-const.rs:12:9 + | +LL | B::from(self) + | ^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: add `#![feature(effects)]` to the crate attributes to enable + | +LL + #![feature(effects)] + | + +error: aborting due to 3 previous errors +Some errors have detailed explanations: E0015, E0049. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs index fe4df09342f..69dcb403aa9 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs @@ -1,6 +1,6 @@ // Tests that trait bounds on specializing trait impls must be `~const` if the // same bound is present on the default impl and is `~const` there. -//@ check-pass +//@ known-bug: #110395 // FIXME(effects) ^ should error #![feature(const_trait_impl)] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr new file mode 100644 index 00000000000..b4c4cf0a890 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr @@ -0,0 +1,41 @@ +error[E0049]: method `bar` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/const-default-bound-non-const-specialized-bound.rs:16:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | trait Bar { +LL | fn bar(); + | - expected 0 const parameters + +error: cannot specialize on const impl with non-const impl + --> $DIR/const-default-bound-non-const-specialized-bound.rs:28:1 + | +LL | / impl<T> Bar for T +LL | | where +LL | | T: Foo, //FIXME ~ ERROR missing `~const` qualifier +LL | | T: Specialize, + | |__________________^ + +error[E0049]: method `baz` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/const-default-bound-non-const-specialized-bound.rs:36:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | trait Baz { +LL | fn baz(); + | - expected 0 const parameters + +error[E0049]: method `baz` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/const-default-bound-non-const-specialized-bound.rs:36:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | trait Baz { +LL | fn baz(); + | - expected 0 const parameters + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0049`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs index c653e62032e..a48a50b9e5c 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs @@ -1,9 +1,10 @@ // Tests that a const default trait impl can be specialized by another const // trait impl and that the specializing impl will be used during const-eval. -//@ run-pass +//@ known-bug: #110395 +// FIXME(effects) run-pass -#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete +#![feature(const_trait_impl)] #![feature(min_specialization)] #[const_trait] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr index f533fb61aad..cabf201405f 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr @@ -1,11 +1,36 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/const-default-const-specialized.rs:6:30 +error[E0049]: method `value` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/const-default-const-specialized.rs:10:1 | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | trait Value { +LL | fn value() -> u32; + | - expected 0 const parameters + +error[E0049]: method `value` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/const-default-const-specialized.rs:10:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | trait Value { +LL | fn value() -> u32; + | - expected 0 const parameters + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0015]: cannot call non-const fn `<T as Value>::value` in constant functions + --> $DIR/const-default-const-specialized.rs:16:5 + | +LL | T::value() + | ^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: add `#![feature(effects)]` to the crate attributes to enable + | +LL + #![feature(effects)] | - = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information - = note: `#[warn(incomplete_features)]` on by default -warning: 1 warning emitted +error: aborting due to 3 previous errors +Some errors have detailed explanations: E0015, E0049. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.rs index bc45a70777c..d9ffd237dce 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.rs @@ -1,4 +1,5 @@ -//@ check-pass +//@ known-bug: #110395 +// FIXME check-pass #![feature(const_trait_impl)] #![feature(min_specialization)] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.stderr new file mode 100644 index 00000000000..52c8708f2c8 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.stderr @@ -0,0 +1,12 @@ +error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/default-keyword.rs:7:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | trait Foo { +LL | fn foo(); + | - expected 0 const parameters + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0049`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs index d80370aee82..219e5f3a600 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs @@ -1,6 +1,7 @@ // Tests that `~const` trait bounds can be used to specialize const trait impls. -//@ check-pass +//@ known-bug: #110395 +// FIXME check-pass #![feature(const_trait_impl)] #![feature(rustc_attrs)] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.stderr new file mode 100644 index 00000000000..1aa34637ca4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.stderr @@ -0,0 +1,43 @@ +error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/issue-95186-specialize-on-tilde-const.rs:14:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | trait Foo { +LL | fn foo(); + | - expected 0 const parameters + +error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/issue-95186-specialize-on-tilde-const.rs:14:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | trait Foo { +LL | fn foo(); + | - expected 0 const parameters + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0049]: method `bar` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/issue-95186-specialize-on-tilde-const.rs:30:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | trait Bar { +LL | fn bar() {} + | - expected 0 const parameters + +error[E0049]: method `bar` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/issue-95186-specialize-on-tilde-const.rs:30:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | trait Bar { +LL | fn bar() {} + | - expected 0 const parameters + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0049`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs index d97469edaf9..7514baa2fd5 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs @@ -2,7 +2,8 @@ // `T: Foo` in the default impl for the purposes of specialization (i.e., it // does not think that the user is attempting to specialize on trait `Foo`). -//@ check-pass +//@ known-bug: #110395 +// FIXME check-pass #![feature(rustc_attrs)] #![feature(min_specialization)] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.stderr new file mode 100644 index 00000000000..0e0f391b086 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.stderr @@ -0,0 +1,43 @@ +error[E0049]: method `bar` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/issue-95187-same-trait-bound-different-constness.rs:18:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | trait Bar { +LL | fn bar(); + | - expected 0 const parameters + +error[E0049]: method `bar` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/issue-95187-same-trait-bound-different-constness.rs:18:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | trait Bar { +LL | fn bar(); + | - expected 0 const parameters + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0049]: method `baz` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/issue-95187-same-trait-bound-different-constness.rs:38:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | trait Baz { +LL | fn baz(); + | - expected 0 const parameters + +error[E0049]: method `baz` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/issue-95187-same-trait-bound-different-constness.rs:38:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | trait Baz { +LL | fn baz(); + | - expected 0 const parameters + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0049`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs index fc8fc3f2a1d..912b35095f9 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs @@ -1,9 +1,9 @@ // Tests that a non-const default impl can be specialized by a const trait impl, // but that the default impl cannot be used in a const context. //@ known-bug: #110395 -// FIXME run-pass +// FIXME(effects) run-pass -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl)] #![feature(min_specialization)] #[const_trait] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr index bcccc855aab..d49beb93259 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr @@ -1,21 +1,36 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/non-const-default-const-specialized.rs:6:30 +error[E0049]: method `value` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/non-const-default-const-specialized.rs:9:1 | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | trait Value { +LL | fn value() -> u32; + | - expected 0 const parameters + +error[E0049]: method `value` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/non-const-default-const-specialized.rs:9:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | trait Value { +LL | fn value() -> u32; + | - expected 0 const parameters | - = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information - = note: `#[warn(incomplete_features)]` on by default + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0119]: conflicting implementations of trait `Value` for type `FortyTwo` - --> $DIR/non-const-default-const-specialized.rs:27:1 +error[E0015]: cannot call non-const fn `<T as Value>::value` in constant functions + --> $DIR/non-const-default-const-specialized.rs:15:5 + | +LL | T::value() + | ^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: add `#![feature(effects)]` to the crate attributes to enable + | +LL + #![feature(effects)] | -LL | impl<T> Value for T { - | ------------------- first implementation here -... -LL | impl const Value for FortyTwo { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `FortyTwo` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0119`. +Some errors have detailed explanations: E0015, E0049. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.rs index 5218ea92566..c1fe42b9751 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl, effects, min_specialization, rustc_attrs)] +#![feature(const_trait_impl, min_specialization, rustc_attrs)] //@ known-bug: #110395 #[rustc_specialization_trait] #[const_trait] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr index 7404b6a8b11..d082cd6de60 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr @@ -1,31 +1,36 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specializing-constness-2.rs:1:30 +error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/specializing-constness-2.rs:9:1 | -LL | #![feature(const_trait_impl, effects, min_specialization, rustc_attrs)] - | ^^^^^^^ - | - = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information - = note: `#[warn(incomplete_features)]` on by default +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | pub trait A { +LL | fn a() -> u32; + | - expected 0 const parameters -error[E0119]: conflicting implementations of trait `A` - --> $DIR/specializing-constness-2.rs:20:1 +error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/specializing-constness-2.rs:9:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | pub trait A { +LL | fn a() -> u32; + | - expected 0 const parameters | -LL | impl<T: Default> A for T { - | ------------------------ first implementation here -... -LL | impl<T: Default + ~const Sup> const A for T { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0308]: mismatched types +error[E0015]: cannot call non-const fn `<T as A>::a` in constant functions --> $DIR/specializing-constness-2.rs:27:5 | LL | <T as A>::a(); - | ^^^^^^^^^^^^^ expected `host`, found `true` + | ^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: add `#![feature(effects)]` to the crate attributes to enable + | +LL + #![feature(effects)] | - = note: expected constant `host` - found constant `true` -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0119, E0308. -For more information about an error, try `rustc --explain E0119`. +Some errors have detailed explanations: E0015, E0049. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs index 3aabaf137d5..4501a218ad7 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs @@ -22,6 +22,8 @@ impl<T: ~const Spec> const A for T { impl<T: Spec + Sup> A for T { //~^ ERROR: cannot specialize +//~| ERROR: cannot specialize +//~| ERROR: cannot specialize //FIXME(effects) ~| ERROR: missing `~const` qualifier fn a() -> u32 { 3 diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr index 226295bf949..272cb26ff42 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr @@ -13,5 +13,17 @@ error: cannot specialize on const impl with non-const impl LL | impl<T: Spec + Sup> A for T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error; 1 warning emitted +error: cannot specialize on trait `Compat` + --> $DIR/specializing-constness.rs:23:16 + | +LL | impl<T: Spec + Sup> A for T { + | ^^^ + +error: cannot specialize on trait `Compat` + --> $DIR/specializing-constness.rs:23:9 + | +LL | impl<T: Spec + Sup> A for T { + | ^^^^ + +error: aborting due to 3 previous errors; 1 warning emitted diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs index 2f26eebbe32..ba20a79a4df 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs @@ -15,7 +15,7 @@ trait Bar: ~const Foo {} const fn foo<T: Bar>(x: &T) { x.a(); - //[yy,yn]~^ ERROR mismatched types + //[yy,yn]~^ ERROR the trait bound // FIXME(effects) diagnostic } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr index f96e6fb4ae4..a4f1c94bca0 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr @@ -19,15 +19,25 @@ LL | #![feature(const_trait_impl, effects)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error[E0308]: mismatched types - --> $DIR/super-traits-fail-2.rs:17:5 +error[E0277]: the trait bound `Foo::{synthetic#0}: ~const Compat` is not satisfied + --> $DIR/super-traits-fail-2.rs:17:7 | LL | x.a(); - | ^^^^^ expected `host`, found `true` + | ^ the trait `~const Compat` is not implemented for `Foo::{synthetic#0}` | - = note: expected constant `host` - found constant `true` +note: required by a bound in `Foo::a` + --> $DIR/super-traits-fail-2.rs:4:25 + | +LL | #[cfg_attr(any(yy, yn), const_trait)] + | ^^^^^^^^^^^ required by this bound in `Foo::a` +LL | trait Foo { +LL | fn a(&self); + | - required by a bound in this associated function +help: consider further restricting the associated type + | +LL | const fn foo<T: Bar>(x: &T) where Foo::{synthetic#0}: ~const Compat { + | +++++++++++++++++++++++++++++++++++++++ error: aborting due to 2 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr index ffc259e590e..4e27ebc5e9e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr @@ -7,15 +7,25 @@ LL | #![feature(const_trait_impl, effects)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error[E0308]: mismatched types - --> $DIR/super-traits-fail-2.rs:17:5 +error[E0277]: the trait bound `Foo::{synthetic#0}: ~const Compat` is not satisfied + --> $DIR/super-traits-fail-2.rs:17:7 | LL | x.a(); - | ^^^^^ expected `host`, found `true` + | ^ the trait `~const Compat` is not implemented for `Foo::{synthetic#0}` | - = note: expected constant `host` - found constant `true` +note: required by a bound in `Foo::a` + --> $DIR/super-traits-fail-2.rs:4:25 + | +LL | #[cfg_attr(any(yy, yn), const_trait)] + | ^^^^^^^^^^^ required by this bound in `Foo::a` +LL | trait Foo { +LL | fn a(&self); + | - required by a bound in this associated function +help: consider further restricting the associated type + | +LL | const fn foo<T: Bar>(x: &T) where Foo::{synthetic#0}: ~const Compat { + | +++++++++++++++++++++++++++++++++++++++ error: aborting due to 1 previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr index cde4b1ff77f..a9bf2687cb8 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr @@ -1,32 +1,23 @@ error: `~const` is not allowed here - --> $DIR/super-traits-fail-3.rs:12:12 + --> $DIR/super-traits-fail-3.rs:13:12 | LL | trait Bar: ~const Foo {} | ^^^^^^ | note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds - --> $DIR/super-traits-fail-3.rs:12:1 + --> $DIR/super-traits-fail-3.rs:13:1 | LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/super-traits-fail-3.rs:1:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information - = note: `#[warn(incomplete_features)]` on by default - error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:12:19 + --> $DIR/super-traits-fail-3.rs:13:19 | LL | trait Bar: ~const Foo {} | ^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:12:19 + --> $DIR/super-traits-fail-3.rs:13:19 | LL | trait Bar: ~const Foo {} | ^^^ @@ -34,7 +25,7 @@ LL | trait Bar: ~const Foo {} = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:12:19 + --> $DIR/super-traits-fail-3.rs:13:19 | LL | trait Bar: ~const Foo {} | ^^^ @@ -42,10 +33,10 @@ LL | trait Bar: ~const Foo {} = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:18:24 + --> $DIR/super-traits-fail-3.rs:19:24 | LL | const fn foo<T: ~const Bar>(x: &T) { | ^^^ -error: aborting due to 5 previous errors; 1 warning emitted +error: aborting due to 5 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr index 6f184018148..c3811623c1c 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr @@ -1,20 +1,11 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/super-traits-fail-3.rs:1:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information - = note: `#[warn(incomplete_features)]` on by default - error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:12:19 + --> $DIR/super-traits-fail-3.rs:13:19 | LL | trait Bar: ~const Foo {} | ^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:12:19 + --> $DIR/super-traits-fail-3.rs:13:19 | LL | trait Bar: ~const Foo {} | ^^^ @@ -22,12 +13,12 @@ LL | trait Bar: ~const Foo {} = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:12:19 + --> $DIR/super-traits-fail-3.rs:13:19 | LL | trait Bar: ~const Foo {} | ^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 3 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs index f7e85902a41..24661f078b0 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs @@ -1,7 +1,8 @@ -#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] //@ revisions: yy yn ny nn -//@[yy] check-pass +//@[yy] known-bug: #110395 #[cfg_attr(any(yy, yn), const_trait)] trait Foo { @@ -18,7 +19,7 @@ trait Bar: ~const Foo {} const fn foo<T: ~const Bar>(x: &T) { //[yn,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]` x.a(); - //[yn]~^ ERROR: mismatched types + //[yn]~^ ERROR: the trait bound } fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr index b0a3b39631d..34a60329eb5 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr @@ -1,39 +1,40 @@ error: `~const` is not allowed here - --> $DIR/super-traits-fail-3.rs:12:12 + --> $DIR/super-traits-fail-3.rs:13:12 | LL | trait Bar: ~const Foo {} | ^^^^^^ | note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds - --> $DIR/super-traits-fail-3.rs:12:1 + --> $DIR/super-traits-fail-3.rs:13:1 | LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/super-traits-fail-3.rs:1:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information - = note: `#[warn(incomplete_features)]` on by default - error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:18:24 + --> $DIR/super-traits-fail-3.rs:19:24 | LL | const fn foo<T: ~const Bar>(x: &T) { | ^^^ -error[E0308]: mismatched types - --> $DIR/super-traits-fail-3.rs:20:5 +error[E0277]: the trait bound `Foo::{synthetic#0}: ~const Compat` is not satisfied + --> $DIR/super-traits-fail-3.rs:21:7 | LL | x.a(); - | ^^^^^ expected `host`, found `true` + | ^ the trait `~const Compat` is not implemented for `Foo::{synthetic#0}` + | +note: required by a bound in `Foo::a` + --> $DIR/super-traits-fail-3.rs:7:25 + | +LL | #[cfg_attr(any(yy, yn), const_trait)] + | ^^^^^^^^^^^ required by this bound in `Foo::a` +LL | trait Foo { +LL | fn a(&self); + | - required by a bound in this associated function +help: consider further restricting the associated type | - = note: expected constant `host` - found constant `true` +LL | const fn foo<T: ~const Bar>(x: &T) where Foo::{synthetic#0}: ~const Compat { + | +++++++++++++++++++++++++++++++++++++++ -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr index e354c66919e..8ac20b3e068 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr @@ -1,11 +1,22 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/super-traits-fail-3.rs:1:30 +error[E0277]: the trait bound `Foo::{synthetic#0}: ~const Compat` is not satisfied + --> $DIR/super-traits-fail-3.rs:21:7 | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ +LL | x.a(); + | ^ the trait `~const Compat` is not implemented for `Foo::{synthetic#0}` | - = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information - = note: `#[warn(incomplete_features)]` on by default +note: required by a bound in `Foo::a` + --> $DIR/super-traits-fail-3.rs:7:25 + | +LL | #[cfg_attr(any(yy, yn), const_trait)] + | ^^^^^^^^^^^ required by this bound in `Foo::a` +LL | trait Foo { +LL | fn a(&self); + | - required by a bound in this associated function +help: consider further restricting the associated type + | +LL | const fn foo<T: ~const Bar>(x: &T) where Foo::{synthetic#0}: ~const Compat { + | +++++++++++++++++++++++++++++++++++++++ -warning: 1 warning emitted +error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs index 0bbf2dabffe..637a24f53bc 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs @@ -1,7 +1,8 @@ //@ check-pass -//@ known-bug: #110395 +//@ compile-flags: -Znext-solver -#![feature(const_trait_impl)] +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] #[const_trait] trait Foo { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs index cfbb8e9f6be..fbe89b00b97 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs @@ -1,5 +1,8 @@ -//@ check-pass -#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete +// FIXME(effects) check-pass +//@ known-bug: #110395 +//@ compile-flags: -Znext-solver +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] #[const_trait] trait Foo { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr index 2ff1a880d84..5b6b39ee05e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr @@ -1,11 +1,22 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/super-traits.rs:2:30 +error[E0277]: the trait bound `Foo::{synthetic#0}: ~const Compat` is not satisfied + --> $DIR/super-traits.rs:23:7 | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ +LL | t.a(); + | ^ the trait `~const Compat` is not implemented for `Foo::{synthetic#0}` | - = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information - = note: `#[warn(incomplete_features)]` on by default +note: required by a bound in `Foo::a` + --> $DIR/super-traits.rs:7:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ required by this bound in `Foo::a` +LL | trait Foo { +LL | fn a(&self); + | - required by a bound in this associated function +help: consider further restricting the associated type + | +LL | const fn foo<T: ~const Bar>(t: &T) where Foo::{synthetic#0}: ~const Compat { + | +++++++++++++++++++++++++++++++++++++++ -warning: 1 warning emitted +error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr index adb1b01f087..d0c2f88005d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr @@ -25,112 +25,5 @@ LL | impl const FromResidual for T { = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates - --> $DIR/trait-default-body-stability.rs:18:6 - | -LL | impl const Try for T { - | ^^^^^ unconstrained const parameter - | - = note: expressions using a const parameter must map each value to a distinct output value - = note: proving the result of expressions other than the parameter are unique is not supported - -error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates - --> $DIR/trait-default-body-stability.rs:33:6 - | -LL | impl const FromResidual for T { - | ^^^^^ unconstrained const parameter - | - = note: expressions using a const parameter must map each value to a distinct output value - = note: proving the result of expressions other than the parameter are unique is not supported - -error[E0284]: type annotations needed - --> $DIR/trait-default-body-stability.rs:33:6 - | -LL | impl const FromResidual for T { - | ^^^^^ cannot infer the value of the constant `_` - | -note: required for `T` to implement `Try` - --> $DIR/trait-default-body-stability.rs:18:12 - | -LL | impl const Try for T { - | ----- ^^^ ^ - | | - | unsatisfied trait bound introduced here - -error[E0284]: type annotations needed - --> $DIR/trait-default-body-stability.rs:44:9 - | -LL | T? - | ^^ cannot infer the value of the constant `_` - | -note: required for `T` to implement `Try` - --> $DIR/trait-default-body-stability.rs:18:12 - | -LL | impl const Try for T { - | ----- ^^^ ^ - | | - | unsatisfied trait bound introduced here - -error[E0284]: type annotations needed - --> $DIR/trait-default-body-stability.rs:44:9 - | -LL | T? - | ^^ cannot infer the value of the constant `_` - | -note: required for `T` to implement `FromResidual<T>` - --> $DIR/trait-default-body-stability.rs:33:12 - | -LL | impl const FromResidual for T { - | ----- ^^^^^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here - -error[E0284]: type annotations needed - --> $DIR/trait-default-body-stability.rs:44:9 - | -LL | T? - | ^^ cannot infer the value of the constant `_` - | -note: required for `T` to implement `Try` - --> $DIR/trait-default-body-stability.rs:18:12 - | -LL | impl const Try for T { - | ----- ^^^ ^ - | | - | unsatisfied trait bound introduced here - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0284]: type annotations needed - --> $DIR/trait-default-body-stability.rs:44:9 - | -LL | T? - | ^^ cannot infer the value of the constant `_` - | -note: required for `T` to implement `FromResidual<T>` - --> $DIR/trait-default-body-stability.rs:33:12 - | -LL | impl const FromResidual for T { - | ----- ^^^^^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0284]: type annotations needed - --> $DIR/trait-default-body-stability.rs:44:9 - | -LL | T? - | ^^ cannot infer the value of the constant `_` - | -note: required for `T` to implement `Try` - --> $DIR/trait-default-body-stability.rs:18:12 - | -LL | impl const Try for T { - | ----- ^^^ ^ - | | - | unsatisfied trait bound introduced here - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 10 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted -Some errors have detailed explanations: E0207, E0284. -For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.rs index 364ddfcc8dd..dd5de62aff5 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.rs @@ -2,9 +2,9 @@ // Checking the validity of traits' where clauses happen at a later stage. // (`rustc_const_eval` instead of `rustc_hir_analysis`) Therefore one file as a // test is not enough. -//@ known-bug: #110395 -// FIXME check-pass + #![feature(const_trait_impl, effects)] +#![allow(incomplete_features)] #[const_trait] trait Bar {} @@ -19,9 +19,11 @@ trait Foo { const fn test1<T: ~const Foo + Bar>() { T::a(); T::b(); - //FIXME ~^ ERROR the trait bound + //~^ ERROR mismatched types + //~| ERROR the trait bound T::c::<T>(); - //FIXME ~^ ERROR the trait bound + //~^ ERROR mismatched types + //~| ERROR the trait bound } const fn test2<T: ~const Foo + ~const Bar>() { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr index 95c32b12241..877152472c1 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr @@ -1,44 +1,60 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/trait-where-clause-const.rs:7:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information - = note: `#[warn(incomplete_features)]` on by default - -error[E0277]: the trait bound `T: ~const Bar` is not satisfied +error[E0277]: the trait bound `Foo::{synthetic#0}: Compat` is not satisfied --> $DIR/trait-where-clause-const.rs:21:5 | LL | T::b(); - | ^ the trait `~const Bar` is not implemented for `T` + | ^ the trait `Compat` is not implemented for `Foo::{synthetic#0}` | note: required by a bound in `Foo::b` - --> $DIR/trait-where-clause-const.rs:15:24 + --> $DIR/trait-where-clause-const.rs:12:1 | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ required by this bound in `Foo::b` +... LL | fn b() where Self: ~const Bar; - | ^^^^^^^^^^ required by this bound in `Foo::b` -help: consider further restricting this bound + | - required by a bound in this associated function +help: consider further restricting the associated type + | +LL | const fn test1<T: ~const Foo + Bar>() where Foo::{synthetic#0}: Compat { + | ++++++++++++++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/trait-where-clause-const.rs:21:5 | -LL | const fn test1<T: ~const Foo + Bar + ~const Bar>() { - | ++++++++++++ +LL | T::b(); + | ^^^^^^ expected `host`, found `true` + | + = note: expected constant `host` + found constant `true` -error[E0277]: the trait bound `T: ~const Bar` is not satisfied - --> $DIR/trait-where-clause-const.rs:23:12 +error[E0277]: the trait bound `Foo::{synthetic#0}: Compat` is not satisfied + --> $DIR/trait-where-clause-const.rs:24:5 | LL | T::c::<T>(); - | ^ the trait `~const Bar` is not implemented for `T` + | ^ the trait `Compat` is not implemented for `Foo::{synthetic#0}` | note: required by a bound in `Foo::c` - --> $DIR/trait-where-clause-const.rs:16:13 + --> $DIR/trait-where-clause-const.rs:12:1 | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ required by this bound in `Foo::c` +... LL | fn c<T: ~const Bar>(); - | ^^^^^^^^^^ required by this bound in `Foo::c` -help: consider further restricting this bound + | - required by a bound in this associated function +help: consider further restricting the associated type + | +LL | const fn test1<T: ~const Foo + Bar>() where Foo::{synthetic#0}: Compat { + | ++++++++++++++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/trait-where-clause-const.rs:24:5 + | +LL | T::c::<T>(); + | ^^^^^^^^^^^ expected `host`, found `true` | -LL | const fn test1<T: ~const Foo + Bar + ~const Bar>() { - | ++++++++++++ + = note: expected constant `host` + found constant `true` -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs index afc5b1c8369..2837c835429 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs @@ -1,6 +1,8 @@ //@ run-pass +//@ compile-flags: -Znext-solver -#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete +#![feature(const_trait_impl, effects)] +#![allow(incomplete_features)] #[const_trait] trait Bar { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.stderr deleted file mode 100644 index aef4f569d5e..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/trait-where-clause-run.rs:3:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs index 8f441410c17..c50c755f667 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs @@ -1,4 +1,5 @@ // Ensure that we print unsatisfied always-const trait bounds as `const Trait` in diagnostics. +//@ compile-flags: -Znext-solver #![feature(const_trait_impl, effects, generic_const_exprs)] #![allow(incomplete_features)] @@ -17,7 +18,8 @@ impl Trait for Ty { } fn main() { - require::<Ty>(); //~ ERROR the trait bound `Ty: const Trait` is not satisfied + // FIXME(effects): improve diagnostics on this + require::<Ty>(); //~ ERROR the trait bound `Trait::{synthetic#0}: const Compat` is not satisfied } struct Container<const N: u32>; diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr index 258f95b5c4a..b9f6c9e8835 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/unsatisfied-const-trait-bound.rs:27:37 + --> $DIR/unsatisfied-const-trait-bound.rs:29:37 | LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {} | ^^^^^^^^^ expected `false`, found `true` @@ -8,7 +8,7 @@ LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {} found constant `true` error[E0308]: mismatched types - --> $DIR/unsatisfied-const-trait-bound.rs:32:50 + --> $DIR/unsatisfied-const-trait-bound.rs:34:50 | LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {} | ^^^^^^^^^ expected `false`, found `host` @@ -16,15 +16,14 @@ LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {} = note: expected constant `false` found constant `host` -error[E0277]: the trait bound `Ty: const Trait` is not satisfied - --> $DIR/unsatisfied-const-trait-bound.rs:20:15 +error[E0277]: the trait bound `Trait::{synthetic#0}: const Compat` is not satisfied + --> $DIR/unsatisfied-const-trait-bound.rs:22:15 | LL | require::<Ty>(); - | ^^ the trait `const Trait` is not implemented for `Ty` + | ^^ the trait `const Compat` is not implemented for `Trait::{synthetic#0}` | - = help: the trait `Trait` is implemented for `Ty` note: required by a bound in `require` - --> $DIR/unsatisfied-const-trait-bound.rs:6:15 + --> $DIR/unsatisfied-const-trait-bound.rs:7:15 | LL | fn require<T: const Trait>() {} | ^^^^^^^^^^^ required by this bound in `require` diff --git a/tests/ui/specialization/const_trait_impl.stderr b/tests/ui/specialization/const_trait_impl.stderr index fc02f6f8f74..e39138983c6 100644 --- a/tests/ui/specialization/const_trait_impl.stderr +++ b/tests/ui/specialization/const_trait_impl.stderr @@ -1,3 +1,23 @@ +error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/const_trait_impl.rs:6:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | pub unsafe trait Sup { +LL | fn foo() -> u32; + | - expected 0 const parameters + +error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/const_trait_impl.rs:6:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | pub unsafe trait Sup { +LL | fn foo() -> u32; + | - expected 0 const parameters + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const_trait_impl.rs:34:16 | @@ -16,6 +36,37 @@ error: `~const` can only be applied to `#[const_trait]` traits LL | impl<T: ~const Default + ~const Sub> const A for T { | ^^^^^^^ +error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/const_trait_impl.rs:29:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | pub trait A { +LL | fn a() -> u32; + | - expected 0 const parameters + +error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/const_trait_impl.rs:29:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | pub trait A { +LL | fn a() -> u32; + | - expected 0 const parameters + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters + --> $DIR/const_trait_impl.rs:29:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ found 1 const parameter +LL | pub trait A { +LL | fn a() -> u32; + | - expected 0 const parameters + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error[E0015]: cannot call non-const fn `<() as A>::a` in constants --> $DIR/const_trait_impl.rs:52:23 | @@ -52,6 +103,19 @@ help: add `#![feature(effects)]` to the crate attributes to enable LL + #![feature(effects)] | -error: aborting due to 6 previous errors +error[E0015]: cannot call non-const fn `<T as Sup>::foo` in constant functions + --> $DIR/const_trait_impl.rs:48:9 + | +LL | T::foo() + | ^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: add `#![feature(effects)]` to the crate attributes to enable + | +LL + #![feature(effects)] + | + +error: aborting due to 12 previous errors -For more information about this error, try `rustc --explain E0015`. +Some errors have detailed explanations: E0015, E0049. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/sse2.rs b/tests/ui/sse2.rs index 9ed6f6fefbd..a1894cc03db 100644 --- a/tests/ui/sse2.rs +++ b/tests/ui/sse2.rs @@ -2,7 +2,6 @@ #![allow(stable_features)] #![feature(cfg_target_feature)] -#![feature(lint_reasons)] use std::env; diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr index a3d0d47d407..a7a612a8a9e 100644 --- a/tests/ui/stats/hir-stats.stderr +++ b/tests/ui/stats/hir-stats.stderr @@ -13,13 +13,13 @@ ast-stats-1 - DocComment 32 ( 0.5%) 1 ast-stats-1 Local 80 ( 1.2%) 1 80 ast-stats-1 ForeignItem 88 ( 1.3%) 1 88 ast-stats-1 - Fn 88 ( 1.3%) 1 -ast-stats-1 Arm 96 ( 1.5%) 2 48 +ast-stats-1 Arm 96 ( 1.4%) 2 48 ast-stats-1 FnDecl 120 ( 1.8%) 5 24 ast-stats-1 FieldDef 160 ( 2.4%) 2 80 ast-stats-1 Stmt 160 ( 2.4%) 5 32 ast-stats-1 - Let 32 ( 0.5%) 1 ast-stats-1 - MacCall 32 ( 0.5%) 1 -ast-stats-1 - Expr 96 ( 1.5%) 3 +ast-stats-1 - Expr 96 ( 1.4%) 3 ast-stats-1 Param 160 ( 2.4%) 4 40 ast-stats-1 Block 192 ( 2.9%) 6 32 ast-stats-1 Variant 208 ( 3.1%) 2 104 @@ -28,7 +28,7 @@ ast-stats-1 - Trait 352 ( 5.3%) 4 ast-stats-1 AssocItem 352 ( 5.3%) 4 88 ast-stats-1 - Type 176 ( 2.7%) 2 ast-stats-1 - Fn 176 ( 2.7%) 2 -ast-stats-1 GenericParam 480 ( 7.3%) 5 96 +ast-stats-1 GenericParam 480 ( 7.2%) 5 96 ast-stats-1 Pat 504 ( 7.6%) 7 72 ast-stats-1 - Struct 72 ( 1.1%) 1 ast-stats-1 - Wild 72 ( 1.1%) 1 @@ -39,28 +39,28 @@ ast-stats-1 - Match 72 ( 1.1%) 1 ast-stats-1 - Struct 72 ( 1.1%) 1 ast-stats-1 - Lit 144 ( 2.2%) 2 ast-stats-1 - Block 216 ( 3.3%) 3 -ast-stats-1 PathSegment 720 (10.9%) 30 24 +ast-stats-1 PathSegment 744 (11.2%) 31 24 ast-stats-1 Ty 896 (13.5%) 14 64 ast-stats-1 - Ptr 64 ( 1.0%) 1 ast-stats-1 - Ref 64 ( 1.0%) 1 ast-stats-1 - ImplicitSelf 128 ( 1.9%) 2 -ast-stats-1 - Path 640 ( 9.7%) 10 -ast-stats-1 Item 1_224 (18.5%) 9 136 -ast-stats-1 - Trait 136 ( 2.1%) 1 -ast-stats-1 - Enum 136 ( 2.1%) 1 -ast-stats-1 - ForeignMod 136 ( 2.1%) 1 -ast-stats-1 - Impl 136 ( 2.1%) 1 +ast-stats-1 - Path 640 ( 9.6%) 10 +ast-stats-1 Item 1_224 (18.4%) 9 136 +ast-stats-1 - Trait 136 ( 2.0%) 1 +ast-stats-1 - Enum 136 ( 2.0%) 1 +ast-stats-1 - ForeignMod 136 ( 2.0%) 1 +ast-stats-1 - Impl 136 ( 2.0%) 1 ast-stats-1 - Fn 272 ( 4.1%) 2 -ast-stats-1 - Use 408 ( 6.2%) 3 +ast-stats-1 - Use 408 ( 6.1%) 3 ast-stats-1 ---------------------------------------------------------------- -ast-stats-1 Total 6_616 +ast-stats-1 Total 6_640 ast-stats-1 ast-stats-2 POST EXPANSION AST STATS ast-stats-2 Name Accumulated Size Count Item Size ast-stats-2 ---------------------------------------------------------------- -ast-stats-2 GenericArgs 40 ( 0.6%) 1 40 -ast-stats-2 - AngleBracketed 40 ( 0.6%) 1 -ast-stats-2 Crate 40 ( 0.6%) 1 40 +ast-stats-2 GenericArgs 40 ( 0.5%) 1 40 +ast-stats-2 - AngleBracketed 40 ( 0.5%) 1 +ast-stats-2 Crate 40 ( 0.5%) 1 40 ast-stats-2 ExprField 48 ( 0.7%) 1 48 ast-stats-2 WherePredicate 56 ( 0.8%) 1 56 ast-stats-2 - BoundPredicate 56 ( 0.8%) 1 @@ -68,8 +68,8 @@ ast-stats-2 Local 80 ( 1.1%) 1 80 ast-stats-2 ForeignItem 88 ( 1.2%) 1 88 ast-stats-2 - Fn 88 ( 1.2%) 1 ast-stats-2 Arm 96 ( 1.3%) 2 48 -ast-stats-2 InlineAsm 120 ( 1.7%) 1 120 -ast-stats-2 FnDecl 120 ( 1.7%) 5 24 +ast-stats-2 InlineAsm 120 ( 1.6%) 1 120 +ast-stats-2 FnDecl 120 ( 1.6%) 5 24 ast-stats-2 Attribute 128 ( 1.8%) 4 32 ast-stats-2 - DocComment 32 ( 0.4%) 1 ast-stats-2 - Normal 96 ( 1.3%) 3 @@ -79,41 +79,41 @@ ast-stats-2 - Let 32 ( 0.4%) 1 ast-stats-2 - Semi 32 ( 0.4%) 1 ast-stats-2 - Expr 96 ( 1.3%) 3 ast-stats-2 Param 160 ( 2.2%) 4 40 -ast-stats-2 Block 192 ( 2.7%) 6 32 +ast-stats-2 Block 192 ( 2.6%) 6 32 ast-stats-2 Variant 208 ( 2.9%) 2 104 -ast-stats-2 GenericBound 352 ( 4.9%) 4 88 -ast-stats-2 - Trait 352 ( 4.9%) 4 -ast-stats-2 AssocItem 352 ( 4.9%) 4 88 +ast-stats-2 GenericBound 352 ( 4.8%) 4 88 +ast-stats-2 - Trait 352 ( 4.8%) 4 +ast-stats-2 AssocItem 352 ( 4.8%) 4 88 ast-stats-2 - Type 176 ( 2.4%) 2 ast-stats-2 - Fn 176 ( 2.4%) 2 -ast-stats-2 GenericParam 480 ( 6.7%) 5 96 -ast-stats-2 Pat 504 ( 7.0%) 7 72 +ast-stats-2 GenericParam 480 ( 6.6%) 5 96 +ast-stats-2 Pat 504 ( 6.9%) 7 72 ast-stats-2 - Struct 72 ( 1.0%) 1 ast-stats-2 - Wild 72 ( 1.0%) 1 -ast-stats-2 - Ident 360 ( 5.0%) 5 -ast-stats-2 Expr 648 ( 9.0%) 9 72 +ast-stats-2 - Ident 360 ( 4.9%) 5 +ast-stats-2 Expr 648 ( 8.9%) 9 72 ast-stats-2 - Path 72 ( 1.0%) 1 ast-stats-2 - Match 72 ( 1.0%) 1 ast-stats-2 - Struct 72 ( 1.0%) 1 ast-stats-2 - InlineAsm 72 ( 1.0%) 1 ast-stats-2 - Lit 144 ( 2.0%) 2 ast-stats-2 - Block 216 ( 3.0%) 3 -ast-stats-2 PathSegment 792 (11.0%) 33 24 -ast-stats-2 Ty 896 (12.4%) 14 64 +ast-stats-2 PathSegment 864 (11.9%) 36 24 +ast-stats-2 Ty 896 (12.3%) 14 64 ast-stats-2 - Ptr 64 ( 0.9%) 1 ast-stats-2 - Ref 64 ( 0.9%) 1 ast-stats-2 - ImplicitSelf 128 ( 1.8%) 2 -ast-stats-2 - Path 640 ( 8.9%) 10 -ast-stats-2 Item 1_496 (20.7%) 11 136 +ast-stats-2 - Path 640 ( 8.8%) 10 +ast-stats-2 Item 1_496 (20.5%) 11 136 ast-stats-2 - Trait 136 ( 1.9%) 1 ast-stats-2 - Enum 136 ( 1.9%) 1 ast-stats-2 - ExternCrate 136 ( 1.9%) 1 ast-stats-2 - ForeignMod 136 ( 1.9%) 1 ast-stats-2 - Impl 136 ( 1.9%) 1 -ast-stats-2 - Fn 272 ( 3.8%) 2 +ast-stats-2 - Fn 272 ( 3.7%) 2 ast-stats-2 - Use 544 ( 7.5%) 4 ast-stats-2 ---------------------------------------------------------------- -ast-stats-2 Total 7_216 +ast-stats-2 Total 7_288 ast-stats-2 hir-stats HIR STATS hir-stats Name Accumulated Size Count Item Size diff --git a/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr b/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr index 60ab392f55d..42bc094859a 100644 --- a/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr +++ b/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr @@ -79,7 +79,7 @@ LL | | } | |_____^ expected `Pin<Box<...>>`, found `async` block | = note: expected struct `Pin<Box<(dyn Future<Output = i32> + Send + 'static)>>` - found `async` block `{async block@$DIR/expected-boxed-future-isnt-pinned.rs:28:5: 30:6}` + found `async` block `{async block@$DIR/expected-boxed-future-isnt-pinned.rs:28:5: 28:10}` help: you need to pin and box this expression | LL ~ Box::pin(async { diff --git a/tests/ui/target-feature/no-llvm-leaks.rs b/tests/ui/target-feature/no-llvm-leaks.rs index 73cec0a4496..9f5dec4447f 100644 --- a/tests/ui/target-feature/no-llvm-leaks.rs +++ b/tests/ui/target-feature/no-llvm-leaks.rs @@ -6,7 +6,7 @@ //@ build-pass #![no_core] #![crate_type = "rlib"] -#![feature(intrinsics, rustc_attrs, no_core, lang_items, staged_api, lint_reasons)] +#![feature(intrinsics, rustc_attrs, no_core, lang_items, staged_api)] #![stable(feature = "test", since = "1.0.0")] // Supporting minimal rust core code diff --git a/tests/ui/traits/next-solver/async.fail.stderr b/tests/ui/traits/next-solver/async.fail.stderr index ebd0ada2604..83d520341bc 100644 --- a/tests/ui/traits/next-solver/async.fail.stderr +++ b/tests/ui/traits/next-solver/async.fail.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<{async block@$DIR/async.rs:12:17: 12:25} as Future>::Output == i32` +error[E0271]: type mismatch resolving `<{async block@$DIR/async.rs:12:17: 12:22} as Future>::Output == i32` --> $DIR/async.rs:12:17 | LL | needs_async(async {}); diff --git a/tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.stderr b/tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.stderr index b62186103c7..6cbffaaed4d 100644 --- a/tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.stderr +++ b/tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.stderr @@ -2,9 +2,7 @@ error[E0733]: recursion in an async block requires boxing --> $DIR/indirect-recursion-issue-112047.rs:22:9 | LL | async move { recur(self).await; } - | ^^^^^^^^^^^^^-----------------^^^ - | | - | recursive call here + | ^^^^^^^^^^ ----------------- recursive call here | note: which leads to this async fn --> $DIR/indirect-recursion-issue-112047.rs:14:1 diff --git a/tests/ui/typeck/typeck_type_placeholder_item.rs b/tests/ui/typeck/typeck_type_placeholder_item.rs index a95b44e807c..29a21a1f45f 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.rs +++ b/tests/ui/typeck/typeck_type_placeholder_item.rs @@ -47,7 +47,7 @@ impl Test9 { fn test11(x: &usize) -> &_ { //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types - &x //~ ERROR cannot return reference to function parameter + &x } unsafe fn test12(x: *const usize) -> *const *const _ { diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr index 7977504dae1..9d295f88da5 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.stderr +++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr @@ -158,7 +158,7 @@ LL | fn test11(x: &usize) -> &_ { | -^ | || | |not allowed in type signatures - | help: replace with the correct return type: `&'static &'static usize` + | help: replace with the correct return type: `&&usize` error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:53:52 @@ -687,13 +687,7 @@ help: add `#![feature(const_trait_impl)]` to the crate attributes to enable LL + #![feature(const_trait_impl)] | -error[E0515]: cannot return reference to function parameter `x` - --> $DIR/typeck_type_placeholder_item.rs:50:5 - | -LL | &x - | ^^ returns a reference to data owned by the current function - -error: aborting due to 75 previous errors +error: aborting due to 74 previous errors -Some errors have detailed explanations: E0015, E0046, E0121, E0282, E0403, E0515. +Some errors have detailed explanations: E0015, E0046, E0121, E0282, E0403. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/used.stderr b/tests/ui/used.stderr index ea77f129d8e..c586dc72293 100644 --- a/tests/ui/used.stderr +++ b/tests/ui/used.stderr @@ -3,24 +3,32 @@ error: attribute must be applied to a `static` variable | LL | #[used] | ^^^^^^^ +LL | fn foo() {} + | ----------- but this is a function error: attribute must be applied to a `static` variable --> $DIR/used.rs:7:1 | LL | #[used] | ^^^^^^^ +LL | struct Foo {} + | ------------- but this is a struct error: attribute must be applied to a `static` variable --> $DIR/used.rs:10:1 | LL | #[used] | ^^^^^^^ +LL | trait Bar {} + | ------------ but this is a trait error: attribute must be applied to a `static` variable --> $DIR/used.rs:13:1 | LL | #[used] | ^^^^^^^ +LL | impl Bar for Foo {} + | ------------------- but this is a implementation block error: aborting due to 4 previous errors diff --git a/triagebot.toml b/triagebot.toml index 62e0917efab..8ae454d412a 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -331,6 +331,7 @@ trigger_files = [ "src/tools/tidy", "src/tools/rustdoc-gui-test", "src/tools/libcxx-version", + "src/tools/rustc-perf-wrapper", ] [autolabel."T-infra"] |
