diff options
750 files changed, 9666 insertions, 4858 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d8980fcd1a..b12a0b855e2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -201,6 +201,9 @@ jobs: - name: dist-i686-linux os: ubuntu-20.04-8core-32gb env: {} + - name: dist-loongarch64-linux + os: ubuntu-20.04-8core-32gb + env: {} - name: dist-mips-linux os: ubuntu-20.04-8core-32gb env: {} diff --git a/Cargo.lock b/Cargo.lock index be95e63eb76..d5840513083 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -154,11 +154,11 @@ checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" [[package]] name = "ar_archive_writer" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0639441fd17a3197d1cbca8dc8768cc172a63b64b4bb6c372e8f41ed0acc9bb" +checksum = "74cfb39880a59e122232cb5fb06b20b4382d58c12fa9747d16f846d38a7b094c" dependencies = [ - "object", + "object 0.31.1", ] [[package]] @@ -233,7 +233,7 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object", + "object 0.30.1", "rustc-demangle", ] @@ -247,6 +247,15 @@ dependencies = [ ] [[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -332,6 +341,12 @@ dependencies = [ ] [[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] name = "bytes" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -629,7 +644,7 @@ dependencies = [ "itertools", "pulldown-cmark", "quine-mc_cluskey", - "regex-syntax", + "regex-syntax 0.7.1", "rustc-semver", "semver", "serde", @@ -723,6 +738,7 @@ dependencies = [ name = "compiletest" version = "0.0.0" dependencies = [ + "anyhow", "build_helper", "colored", "diff", @@ -888,6 +904,16 @@ dependencies = [ ] [[package]] +name = "ctrlc" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7394a21d012ce5c850497fb774b167d81b99f060025fbf06ee92b9848bd97eb2" +dependencies = [ + "nix", + "windows-sys 0.48.0", +] + +[[package]] name = "curl" version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2288,6 +2314,7 @@ name = "miri" version = "0.1.0" dependencies = [ "colored", + "ctrlc", "env_logger 0.9.0", "getrandom", "lazy_static", @@ -2318,6 +2345,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" [[package]] +name = "nix" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +dependencies = [ + "bitflags", + "cfg-if", + "libc", + "static_assertions", +] + +[[package]] name = "nom" version = "7.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2364,13 +2403,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d864c91689fdc196779b98dba0aceac6118594c2df6ee5d943eb6a8df4d107a" dependencies = [ "compiler_builtins", + "memchr", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + +[[package]] +name = "object" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +dependencies = [ "crc32fast", "flate2", "hashbrown 0.13.1", "indexmap", "memchr", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", + "ruzstd", ] [[package]] @@ -2695,9 +2744,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.53" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] @@ -2865,7 +2914,7 @@ checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.6.26", ] [[package]] @@ -2874,7 +2923,7 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "regex-syntax", + "regex-syntax 0.6.26", ] [[package]] @@ -2893,6 +2942,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" [[package]] +name = "regex-syntax" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" + +[[package]] name = "remote-test-client" version = "0.1.0" @@ -3222,7 +3277,7 @@ dependencies = [ "cstr", "libc", "measureme", - "object", + "object 0.31.1", "rustc-demangle", "rustc_ast", "rustc_attr", @@ -3258,7 +3313,7 @@ dependencies = [ "itertools", "jobserver", "libc", - "object", + "object 0.31.1", "pathdiff", "regex", "rustc_arena", @@ -4328,6 +4383,7 @@ dependencies = [ name = "rustdoc-json-types" version = "0.1.0" dependencies = [ + "bincode", "rustc-hash", "serde", "serde_json", @@ -4418,6 +4474,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" [[package]] +name = "ruzstd" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a15e661f0f9dac21f3494fe5d23a6338c0ac116a2d22c2b63010acd89467ffe" +dependencies = [ + "byteorder", + "thiserror", + "twox-hash", +] + +[[package]] name = "ryu" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4477,18 +4544,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.159" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.159" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", @@ -4653,7 +4720,7 @@ dependencies = [ "hermit-abi 0.3.0", "libc", "miniz_oxide", - "object", + "object 0.30.1", "panic_abort", "panic_unwind", "profiler_builtins", @@ -4925,13 +4992,13 @@ dependencies = [ [[package]] name = "thorin-dwp" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da8fbf660a019b6bf11ea95762041464aa9099cc293b6a66d77cea5107619671" +checksum = "98c040e1340b889d4180c64e1d787efa9c32cb1617757e101480b61238b0d927" dependencies = [ "gimli 0.26.2", "hashbrown 0.12.3", - "object", + "object 0.31.1", "tracing", ] diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 3d97d9b4895..f11c1c77f9c 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -12,7 +12,7 @@ use tracing::debug; pub trait LayoutCalculator { type TargetDataLayoutRef: Borrow<TargetDataLayout>; - fn delay_bug(&self, txt: &str); + fn delay_bug(&self, txt: String); fn current_data_layout(&self) -> Self::TargetDataLayoutRef; fn scalar_pair(&self, a: Scalar, b: Scalar) -> LayoutS { @@ -969,7 +969,7 @@ fn univariant( for &i in &inverse_memory_index { let field = &fields[i]; if !sized { - this.delay_bug(&format!( + this.delay_bug(format!( "univariant: field #{} comes after unsized field", offsets.len(), )); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index cd6614a54a4..211f5cb0a2a 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -58,7 +58,7 @@ use rustc_errors::{ use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; -use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; +use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::DefPathData; use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate}; use rustc_index::{Idx, IndexSlice, IndexVec}; @@ -435,6 +435,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> { // Queries that borrow `resolver_for_lowering`. tcx.ensure_with_value().output_filenames(()); tcx.ensure_with_value().early_lint_checks(()); + tcx.ensure_with_value().debugger_visualizers(LOCAL_CRATE); let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal(); let ast_index = index_crate(&resolver.node_id_to_def_id, &krate); diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 2a3092d3c7b..372a58857f3 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -23,8 +23,7 @@ use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause}; pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION"; pub fn rust_version_symbol() -> Symbol { - let version = option_env!("CFG_VERSION").unwrap_or("<current>"); - let version = version.split(' ').next().unwrap(); + let version = option_env!("CFG_RELEASE").unwrap_or("<current>"); Symbol::intern(&version) } diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index a4394ddc01c..b6ccf924a5c 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -430,7 +430,7 @@ pub(super) fn dump_annotation<'tcx>( fn for_each_region_constraint<'tcx>( tcx: TyCtxt<'tcx>, closure_region_requirements: &ClosureRegionRequirements<'tcx>, - with_msg: &mut dyn FnMut(&str) -> io::Result<()>, + with_msg: &mut dyn FnMut(String) -> io::Result<()>, ) -> io::Result<()> { for req in &closure_region_requirements.outlives_requirements { let subject = match req.subject { @@ -439,7 +439,7 @@ fn for_each_region_constraint<'tcx>( format!("{:?}", ty.instantiate(tcx, |vid| tcx.mk_re_var(vid))) } }; - with_msg(&format!("where {}: {:?}", subject, req.outlived_free_region,))?; + with_msg(format!("where {}: {:?}", subject, req.outlived_free_region,))?; } Ok(()) } diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 309f23d9226..e9b5c47ce23 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -152,8 +152,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { let guar = ty.error_reported().err().unwrap_or_else(|| { prev.report_mismatch( &OpaqueHiddenType { ty, span: concrete_type.span }, + opaque_type_key.def_id, infcx.tcx, ) + .emit() }); prev.ty = infcx.tcx.ty_error(guar); } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 33b24b68f7c..fa4bc926f27 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -71,7 +71,7 @@ macro_rules! span_mirbug { $crate::type_check::mirbug( $context.tcx(), $context.last_span, - &format!( + format!( "broken MIR in {:?} ({:?}): {}", $context.body().source.def_id(), $elem, @@ -274,7 +274,7 @@ fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) { } #[track_caller] -fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: &str) { +fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: String) { // We sometimes see MIR failures (notably predicate failures) due to // the fact that we check rvalue sized predicates here. So use `delay_span_bug` // to avoid reporting bugs in those cases. diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index bb059a120df..5217e317adf 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -550,7 +550,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl if !parser.errors.is_empty() { let err = parser.errors.remove(0); let err_sp = template_span.from_inner(InnerSpan::new(err.span.start, err.span.end)); - let msg = &format!("invalid asm template string: {}", err.description); + let msg = format!("invalid asm template string: {}", err.description); let mut e = ecx.struct_span_err(err_sp, msg); e.span_label(err_sp, err.label + " in asm template string"); if let Some(note) = err.note { @@ -585,7 +585,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl || args.reg_args.contains(idx) { let msg = format!("invalid reference to argument at index {}", idx); - let mut err = ecx.struct_span_err(span, &msg); + let mut err = ecx.struct_span_err(span, msg); err.span_label(span, "from here"); let positional_args = args.operands.len() @@ -638,7 +638,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl ecx.struct_span_err( template_span .from_inner(InnerSpan::new(span.start, span.end)), - &msg, + msg, ) .emit(); None diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 750f1fe121f..ed91cea4ae2 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -166,7 +166,9 @@ impl CfgEval<'_, '_> { )) }, Annotatable::Stmt(_) => |parser| { - Ok(Annotatable::Stmt(P(parser.parse_stmt(ForceCollect::Yes)?.unwrap()))) + Ok(Annotatable::Stmt(P(parser + .parse_stmt_without_recovery(false, ForceCollect::Yes)? + .unwrap()))) }, Annotatable::Expr(_) => { |parser| Ok(Annotatable::Expr(parser.parse_expr_force_collect()?)) diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index 0481a118906..2c8e6f99c67 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -27,3 +27,26 @@ pub fn expand_deriving_copy( trait_def.expand(cx, mitem, item, push); } + +pub fn expand_deriving_const_param_ty( + cx: &mut ExtCtxt<'_>, + span: Span, + mitem: &MetaItem, + item: &Annotatable, + push: &mut dyn FnMut(Annotatable), + is_const: bool, +) { + let trait_def = TraitDef { + span, + path: path_std!(marker::ConstParamTy), + skip_path_as_bound: false, + needs_copy_as_bound_if_packed: false, + additional_bounds: Vec::new(), + supports_unions: false, + methods: Vec::new(), + associated_types: Vec::new(), + is_const, + }; + + trait_def.expand(cx, mitem, item, push); +} diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index dfee2d3ce77..9883563746e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -145,7 +145,7 @@ fn cs_clone_simple( } _ => cx.span_bug( trait_span, - &format!("unexpected substructure in simple `derive({})`", name), + format!("unexpected substructure in simple `derive({})`", name), ), } } @@ -179,10 +179,10 @@ fn cs_clone( vdata = &variant.data; } EnumTag(..) | AllFieldlessEnum(..) => { - cx.span_bug(trait_span, &format!("enum tags in `derive({})`", name,)) + cx.span_bug(trait_span, format!("enum tags in `derive({})`", name,)) } StaticEnum(..) | StaticStruct(..) => { - cx.span_bug(trait_span, &format!("associated function in `derive({})`", name)) + cx.span_bug(trait_span, format!("associated function in `derive({})`", name)) } } @@ -194,7 +194,7 @@ fn cs_clone( let Some(ident) = field.name else { cx.span_bug( trait_span, - &format!("unnamed field in normal struct in `derive({})`", name,), + format!("unnamed field in normal struct in `derive({})`", name,), ); }; let call = subcall(cx, field); diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index caced3d6447..4ba09335cb7 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -1591,7 +1591,7 @@ impl<'a> TraitDef<'a> { BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, sp, ast::CRATE_NODE_ID, - &format!( + format!( "{} slice in a packed struct that derives a built-in trait", ty ), diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index adc12ec84f5..c59a733c055 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -814,7 +814,7 @@ fn report_invalid_references( }; e = ecx.struct_span_err( span, - &format!("invalid reference to positional {} ({})", arg_list, num_args_desc), + format!("invalid reference to positional {} ({})", arg_list, num_args_desc), ); e.note("positional arguments are zero-based"); } diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 4e5edb4d6b1..ebf1448f55c 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -115,6 +115,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { register_derive! { Clone: clone::expand_deriving_clone, Copy: bounds::expand_deriving_copy, + ConstParamTy: bounds::expand_deriving_const_param_ty, Debug: debug::expand_deriving_debug, Default: default::expand_deriving_default, Eq: eq::expand_deriving_eq, diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index b8a24f1102d..e613b904d2e 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -188,12 +188,12 @@ pub fn expand_include_str( base::MacEager::expr(cx.expr_str(sp, interned_src)) } Err(_) => { - cx.span_err(sp, &format!("{} wasn't a utf-8 file", file.display())); + cx.span_err(sp, format!("{} wasn't a utf-8 file", file.display())); DummyResult::any(sp) } }, Err(e) => { - cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e)); + cx.span_err(sp, format!("couldn't read {}: {}", file.display(), e)); DummyResult::any(sp) } } @@ -221,7 +221,7 @@ pub fn expand_include_bytes( base::MacEager::expr(expr) } Err(e) => { - cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e)); + cx.span_err(sp, format!("couldn't read {}: {}", file.display(), e)); DummyResult::any(sp) } } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index e9dbea1be67..25fd5ca3ae8 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -966,11 +966,7 @@ fn codegen_panic_inner<'tcx>( args: &[Value], span: Span, ) { - let def_id = fx - .tcx - .lang_items() - .require(lang_item) - .unwrap_or_else(|e| fx.tcx.sess.span_fatal(span, e.to_string())); + let def_id = fx.tcx.require_lang_item(lang_item, Some(span)); let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx); let symbol_name = fx.tcx.symbol_name(instance).name; diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs index 27e21183c55..1007b33eca4 100644 --- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs +++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs @@ -227,7 +227,7 @@ pub(crate) fn write_ir_file( // Using early_warn as no Session is available here rustc_session::early_warn( rustc_session::config::ErrorOutputType::default(), - &format!("error writing ir file: {}", err), + format!("error writing ir file: {}", err), ); } } diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 5e750d91b82..ad51f2d0958 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -11,7 +11,7 @@ bitflags = "1.0" cstr = "0.2" libc = "0.2" measureme = "10.0.0" -object = { version = "0.30.1", default-features = false, features = [ +object = { version = "0.31.1", default-features = false, features = [ "std", "read", ] } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index d2e01708a37..604f68eb6a4 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -25,7 +25,6 @@ use std::fs::File; use std::io; use std::iter; use std::path::Path; -use std::ptr; use std::slice; use std::sync::Arc; @@ -709,17 +708,6 @@ pub unsafe fn optimize_thin_module( let llmod = module.module_llvm.llmod(); save_temp_bitcode(cgcx, &module, "thin-lto-input"); - // Before we do much else find the "main" `DICompileUnit` that we'll be - // using below. If we find more than one though then rustc has changed - // in a way we're not ready for, so generate an ICE by returning - // an error. - let mut cu1 = ptr::null_mut(); - let mut cu2 = ptr::null_mut(); - llvm::LLVMRustThinLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2); - if !cu2.is_null() { - return Err(write::llvm_err(&diag_handler, LlvmError::MultipleSourceDiCompileUnit)); - } - // Up next comes the per-module local analyses that we do for Thin LTO. // Each of these functions is basically copied from the LLVM // implementation and then tailored to suit this implementation. Ideally @@ -766,43 +754,6 @@ pub unsafe fn optimize_thin_module( save_temp_bitcode(cgcx, &module, "thin-lto-after-import"); } - // Ok now this is a bit unfortunate. This is also something you won't - // find upstream in LLVM's ThinLTO passes! This is a hack for now to - // work around bugs in LLVM. - // - // First discovered in #45511 it was found that as part of ThinLTO - // importing passes LLVM will import `DICompileUnit` metadata - // information across modules. This means that we'll be working with one - // LLVM module that has multiple `DICompileUnit` instances in it (a - // bunch of `llvm.dbg.cu` members). Unfortunately there's a number of - // bugs in LLVM's backend which generates invalid DWARF in a situation - // like this: - // - // https://bugs.llvm.org/show_bug.cgi?id=35212 - // https://bugs.llvm.org/show_bug.cgi?id=35562 - // - // While the first bug there is fixed the second ended up causing #46346 - // which was basically a resurgence of #45511 after LLVM's bug 35212 was - // fixed. - // - // This function below is a huge hack around this problem. The function - // below is defined in `PassWrapper.cpp` and will basically "merge" - // all `DICompileUnit` instances in a module. Basically it'll take all - // the objects, rewrite all pointers of `DISubprogram` to point to the - // first `DICompileUnit`, and then delete all the other units. - // - // This is probably mangling to the debug info slightly (but hopefully - // not too much) but for now at least gets LLVM to emit valid DWARF (or - // so it appears). Hopefully we can remove this once upstream bugs are - // fixed in LLVM. - { - let _timer = cgcx - .prof - .generic_activity_with_arg("LLVM_thin_lto_patch_debuginfo", thin_module.name()); - llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1); - save_temp_bitcode(cgcx, &module, "thin-lto-after-patch"); - } - // Alright now that we've done everything related to the ThinLTO // analysis it's time to run some optimizations! Here we use the same // `run_pass_manager` as the "fat" LTO above except that we tell it to diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index aaf5dbd9930..37f30917609 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -9,10 +9,9 @@ use rustc_ast::attr; use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive; use rustc_codegen_ssa::traits::*; use rustc_hir::def_id::LOCAL_CRATE; -use rustc_middle::bug; +use rustc_middle::{bug, middle::debugger_visualizer::DebuggerVisualizerType}; use rustc_session::config::{CrateType, DebugInfo}; use rustc_span::symbol::sym; -use rustc_span::DebuggerVisualizerType; /// Inserts a side-effect free instruction sequence that makes sure that the /// .debug_gdb_scripts global is referenced, so it isn't removed by the linker. diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 25fe3cb265d..bd2fba12602 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -806,8 +806,7 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>( name_in_debuginfo.push(codegen_unit_name); debug!("build_compile_unit_di_node: {:?}", name_in_debuginfo); - let rustc_producer = - format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION"),); + let rustc_producer = format!("rustc version {}", tcx.sess.cfg_version); // FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice. let producer = format!("clang LLVM ({})", rustc_producer); diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 6a86237d79e..805843e5863 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -10,6 +10,7 @@ #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(never_type)] +#![feature(impl_trait_in_assoc_type)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index aefd5b2a13c..de93a64c0d6 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2484,12 +2484,6 @@ extern "C" { len: usize, out_len: &mut usize, ) -> *const u8; - pub fn LLVMRustThinLTOGetDICompileUnit( - M: &Module, - CU1: &mut *mut c_void, - CU2: &mut *mut c_void, - ); - pub fn LLVMRustThinLTOPatchDICompileUnit(M: &Module, CU: *mut c_void); pub fn LLVMRustLinkerNew(M: &Module) -> &mut Linker<'_>; pub fn LLVMRustLinkerAdd( diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 994addf12eb..03be0654b50 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -16,7 +16,6 @@ use rustc_session::config::PrintRequest; use rustc_session::Session; use rustc_span::symbol::Symbol; use rustc_target::spec::{MergeFunctions, PanicStrategy}; -use smallvec::{smallvec, SmallVec}; use std::ffi::{CStr, CString}; use std::path::Path; @@ -132,6 +131,60 @@ pub fn time_trace_profiler_finish(file_name: &Path) { } } +pub enum TargetFeatureFoldStrength<'a> { + // The feature is only tied when enabling the feature, disabling + // this feature shouldn't disable the tied feature. + EnableOnly(&'a str), + // The feature is tied for both enabling and disabling this feature. + Both(&'a str), +} + +impl<'a> TargetFeatureFoldStrength<'a> { + fn as_str(&self) -> &'a str { + match self { + TargetFeatureFoldStrength::EnableOnly(feat) => feat, + TargetFeatureFoldStrength::Both(feat) => feat, + } + } +} + +pub struct LLVMFeature<'a> { + pub llvm_feature_name: &'a str, + pub dependency: Option<TargetFeatureFoldStrength<'a>>, +} + +impl<'a> LLVMFeature<'a> { + pub fn new(llvm_feature_name: &'a str) -> Self { + Self { llvm_feature_name, dependency: None } + } + + pub fn with_dependency( + llvm_feature_name: &'a str, + dependency: TargetFeatureFoldStrength<'a>, + ) -> Self { + Self { llvm_feature_name, dependency: Some(dependency) } + } + + pub fn contains(&self, feat: &str) -> bool { + self.iter().any(|dep| dep == feat) + } + + pub fn iter(&'a self) -> impl Iterator<Item = &'a str> { + let dependencies = self.dependency.iter().map(|feat| feat.as_str()); + std::iter::once(self.llvm_feature_name).chain(dependencies) + } +} + +impl<'a> IntoIterator for LLVMFeature<'a> { + type Item = &'a str; + type IntoIter = impl Iterator<Item = &'a str>; + + fn into_iter(self) -> Self::IntoIter { + let dependencies = self.dependency.into_iter().map(|feat| feat.as_str()); + std::iter::once(self.llvm_feature_name).chain(dependencies) + } +} + // WARNING: the features after applying `to_llvm_features` must be known // to LLVM or the feature detection code will walk past the end of the feature // array, leading to crashes. @@ -147,36 +200,65 @@ pub fn time_trace_profiler_finish(file_name: &Path) { // Though note that Rust can also be build with an external precompiled version of LLVM // which might lead to failures if the oldest tested / supported LLVM version // doesn't yet support the relevant intrinsics -pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> { +pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a> { let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch }; match (arch, s) { - ("x86", "sse4.2") => smallvec!["sse4.2", "crc32"], - ("x86", "pclmulqdq") => smallvec!["pclmul"], - ("x86", "rdrand") => smallvec!["rdrnd"], - ("x86", "bmi1") => smallvec!["bmi"], - ("x86", "cmpxchg16b") => smallvec!["cx16"], - ("aarch64", "rcpc2") => smallvec!["rcpc-immo"], - ("aarch64", "dpb") => smallvec!["ccpp"], - ("aarch64", "dpb2") => smallvec!["ccdp"], - ("aarch64", "frintts") => smallvec!["fptoint"], - ("aarch64", "fcma") => smallvec!["complxnum"], - ("aarch64", "pmuv3") => smallvec!["perfmon"], - ("aarch64", "paca") => smallvec!["pauth"], - ("aarch64", "pacg") => smallvec!["pauth"], - // Rust ties fp and neon together. In LLVM neon implicitly enables fp, - // but we manually enable neon when a feature only implicitly enables fp - ("aarch64", "f32mm") => smallvec!["f32mm", "neon"], - ("aarch64", "f64mm") => smallvec!["f64mm", "neon"], - ("aarch64", "fhm") => smallvec!["fp16fml", "neon"], - ("aarch64", "fp16") => smallvec!["fullfp16", "neon"], - ("aarch64", "jsconv") => smallvec!["jsconv", "neon"], - ("aarch64", "sve") => smallvec!["sve", "neon"], - ("aarch64", "sve2") => smallvec!["sve2", "neon"], - ("aarch64", "sve2-aes") => smallvec!["sve2-aes", "neon"], - ("aarch64", "sve2-sm4") => smallvec!["sve2-sm4", "neon"], - ("aarch64", "sve2-sha3") => smallvec!["sve2-sha3", "neon"], - ("aarch64", "sve2-bitperm") => smallvec!["sve2-bitperm", "neon"], - (_, s) => smallvec![s], + ("x86", "sse4.2") => { + LLVMFeature::with_dependency("sse4.2", TargetFeatureFoldStrength::EnableOnly("crc32")) + } + ("x86", "pclmulqdq") => LLVMFeature::new("pclmul"), + ("x86", "rdrand") => LLVMFeature::new("rdrnd"), + ("x86", "bmi1") => LLVMFeature::new("bmi"), + ("x86", "cmpxchg16b") => LLVMFeature::new("cx16"), + ("aarch64", "rcpc2") => LLVMFeature::new("rcpc-immo"), + ("aarch64", "dpb") => LLVMFeature::new("ccpp"), + ("aarch64", "dpb2") => LLVMFeature::new("ccdp"), + ("aarch64", "frintts") => LLVMFeature::new("fptoint"), + ("aarch64", "fcma") => LLVMFeature::new("complxnum"), + ("aarch64", "pmuv3") => LLVMFeature::new("perfmon"), + ("aarch64", "paca") => LLVMFeature::new("pauth"), + ("aarch64", "pacg") => LLVMFeature::new("pauth"), + // Rust ties fp and neon together. + ("aarch64", "neon") => { + LLVMFeature::with_dependency("neon", TargetFeatureFoldStrength::Both("fp-armv8")) + } + // In LLVM neon implicitly enables fp, but we manually enable + // neon when a feature only implicitly enables fp + ("aarch64", "f32mm") => { + LLVMFeature::with_dependency("f32mm", TargetFeatureFoldStrength::EnableOnly("neon")) + } + ("aarch64", "f64mm") => { + LLVMFeature::with_dependency("f64mm", TargetFeatureFoldStrength::EnableOnly("neon")) + } + ("aarch64", "fhm") => { + LLVMFeature::with_dependency("fp16fml", TargetFeatureFoldStrength::EnableOnly("neon")) + } + ("aarch64", "fp16") => { + LLVMFeature::with_dependency("fullfp16", TargetFeatureFoldStrength::EnableOnly("neon")) + } + ("aarch64", "jsconv") => { + LLVMFeature::with_dependency("jsconv", TargetFeatureFoldStrength::EnableOnly("neon")) + } + ("aarch64", "sve") => { + LLVMFeature::with_dependency("sve", TargetFeatureFoldStrength::EnableOnly("neon")) + } + ("aarch64", "sve2") => { + LLVMFeature::with_dependency("sve2", TargetFeatureFoldStrength::EnableOnly("neon")) + } + ("aarch64", "sve2-aes") => { + LLVMFeature::with_dependency("sve2-aes", TargetFeatureFoldStrength::EnableOnly("neon")) + } + ("aarch64", "sve2-sm4") => { + LLVMFeature::with_dependency("sve2-sm4", TargetFeatureFoldStrength::EnableOnly("neon")) + } + ("aarch64", "sve2-sha3") => { + LLVMFeature::with_dependency("sve2-sha3", TargetFeatureFoldStrength::EnableOnly("neon")) + } + ("aarch64", "sve2-bitperm") => LLVMFeature::with_dependency( + "sve2-bitperm", + TargetFeatureFoldStrength::EnableOnly("neon"), + ), + (_, s) => LLVMFeature::new(s), } } @@ -274,18 +356,17 @@ fn print_target_features(sess: &Session, tm: &llvm::TargetMachine) { let mut rustc_target_features = supported_target_features(sess) .iter() .map(|(feature, _gate)| { - let desc = if let Some(llvm_feature) = to_llvm_features(sess, *feature).first() { - // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings. + // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings. + let llvm_feature = to_llvm_features(sess, *feature).llvm_feature_name; + let desc = match llvm_target_features.binary_search_by_key(&llvm_feature, |(f, _d)| f).ok() { Some(index) => { known_llvm_target_features.insert(llvm_feature); llvm_target_features[index].1 } None => "", - } - } else { - "" - }; + }; + (*feature, desc) }) .collect::<Vec<_>>(); @@ -469,10 +550,19 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str // passing requests down to LLVM. This means that all in-language // features also work on the command line instead of having two // different names when the LLVM name and the Rust name differ. + let llvm_feature = to_llvm_features(sess, feature); + Some( - to_llvm_features(sess, feature) - .into_iter() - .map(move |f| format!("{}{}", enable_disable, f)), + std::iter::once(format!("{}{}", enable_disable, llvm_feature.llvm_feature_name)) + .chain(llvm_feature.dependency.into_iter().filter_map(move |feat| { + match (enable_disable, feat) { + ('-' | '+', TargetFeatureFoldStrength::Both(f)) + | ('+', TargetFeatureFoldStrength::EnableOnly(f)) => { + Some(format!("{}{}", enable_disable, f)) + } + _ => None, + } + })), ) }) .flatten(); diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 02be88df103..0ac12d32be5 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -14,7 +14,7 @@ itertools = "0.10.1" tracing = "0.1" jobserver = "0.1.22" tempfile = "3.2" -thorin-dwp = "0.4" +thorin-dwp = "0.6" pathdiff = "0.2.0" serde_json = "1.0.59" snap = "1" @@ -46,7 +46,7 @@ rustc_session = { path = "../rustc_session" } libc = "0.2.50" [dependencies.object] -version = "0.30.1" +version = "0.31.1" default-features = false features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"] diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index ea06cb02d8b..8a00c42a0e8 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -9,6 +9,7 @@ use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_metadata::find_native_static_library; use rustc_metadata::fs::{emit_wrapper_file, METADATA_FILENAME}; +use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip}; @@ -21,7 +22,6 @@ use rustc_session::utils::NativeLibKind; /// need out of the shared crate context before we get rid of it. use rustc_session::{filesearch, Session}; use rustc_span::symbol::Symbol; -use rustc_span::DebuggerVisualizerFile; use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault}; use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy}; use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo}; @@ -574,6 +574,8 @@ fn link_staticlib<'a>( } } + all_native_libs.extend_from_slice(&codegen_results.crate_info.used_libraries); + if sess.opts.prints.contains(&PrintRequest::NativeStaticLibs) { print_native_static_libs(sess, &all_native_libs, &all_rust_dylibs); } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 1e57f4248d2..cd56f85cccd 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -144,7 +144,7 @@ pub fn get_linker<'a>( cmd, sess, target_cpu, - hinted_static: false, + hinted_static: None, is_ld: cc == Cc::No, is_gnu: flavor.is_gnu(), }) as Box<dyn Linker>, @@ -214,7 +214,7 @@ pub struct GccLinker<'a> { cmd: Command, sess: &'a Session, target_cpu: &'a str, - hinted_static: bool, // Keeps track of the current hinting mode. + hinted_static: Option<bool>, // Keeps track of the current hinting mode. // Link as ld is_ld: bool, is_gnu: bool, @@ -275,9 +275,9 @@ impl<'a> GccLinker<'a> { if !self.takes_hints() { return; } - if !self.hinted_static { + if self.hinted_static != Some(true) { self.linker_arg("-Bstatic"); - self.hinted_static = true; + self.hinted_static = Some(true); } } @@ -285,9 +285,9 @@ impl<'a> GccLinker<'a> { if !self.takes_hints() { return; } - if self.hinted_static { + if self.hinted_static != Some(false) { self.linker_arg("-Bdynamic"); - self.hinted_static = false; + self.hinted_static = Some(false); } } @@ -1484,25 +1484,25 @@ impl<'a> L4Bender<'a> { pub struct AixLinker<'a> { cmd: Command, sess: &'a Session, - hinted_static: bool, + hinted_static: Option<bool>, } impl<'a> AixLinker<'a> { pub fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> { - AixLinker { cmd: cmd, sess: sess, hinted_static: false } + AixLinker { cmd: cmd, sess: sess, hinted_static: None } } fn hint_static(&mut self) { - if !self.hinted_static { + if self.hinted_static != Some(true) { self.cmd.arg("-bstatic"); - self.hinted_static = true; + self.hinted_static = Some(true); } } fn hint_dynamic(&mut self) { - if self.hinted_static { + if self.hinted_static != Some(false) { self.cmd.arg("-bdynamic"); - self.hinted_static = false; + self.hinted_static = Some(false); } } diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 8968133bac5..8bf84772f08 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -14,8 +14,7 @@ use snap::write::FrameEncoder; use object::elf::NT_GNU_PROPERTY_TYPE_0; use rustc_data_structures::memmap::Mmap; -use rustc_data_structures::owned_slice::try_slice_owned; -use rustc_data_structures::sync::MetadataRef; +use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice}; use rustc_metadata::fs::METADATA_FILENAME; use rustc_metadata::EncodedMetadata; use rustc_session::cstore::MetadataLoader; @@ -39,7 +38,7 @@ pub struct DefaultMetadataLoader; fn load_metadata_with( path: &Path, f: impl for<'a> FnOnce(&'a [u8]) -> Result<&'a [u8], String>, -) -> Result<MetadataRef, String> { +) -> Result<OwnedSlice, String> { let file = File::open(path).map_err(|e| format!("failed to open file '{}': {}", path.display(), e))?; @@ -49,7 +48,7 @@ fn load_metadata_with( } impl MetadataLoader for DefaultMetadataLoader { - fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> { + fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result<OwnedSlice, String> { load_metadata_with(path, |data| { let archive = object::read::archive::ArchiveFile::parse(&*data) .map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?; @@ -69,7 +68,7 @@ impl MetadataLoader for DefaultMetadataLoader { }) } - fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> { + fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<OwnedSlice, String> { load_metadata_with(path, |data| search_for_section(path, data, ".rustc")) } } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index d9b0a152594..15c7847155d 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -23,6 +23,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; use rustc_metadata::EncodedMetadata; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; +use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}; use rustc_middle::middle::exported_symbols; use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_middle::middle::lang_items; @@ -35,7 +36,6 @@ use rustc_session::config::{self, CrateType, EntryFnType, OutputType}; use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::Symbol; -use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType}; use rustc_target::abi::{Align, FIRST_VARIANT}; use std::collections::BTreeSet; diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index f4b9d1dea58..31854c7f4c4 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -28,6 +28,7 @@ use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_hir::def_id::CrateNum; use rustc_middle::dep_graph::WorkProduct; +use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::dependency_format::Dependencies; use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_middle::query::{ExternProviders, Providers}; @@ -36,8 +37,8 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT}; use rustc_session::cstore::{self, CrateSource}; use rustc_session::utils::NativeLibKind; +use rustc_session::Session; use rustc_span::symbol::Symbol; -use rustc_span::DebuggerVisualizerFile; use std::collections::BTreeSet; use std::io; use std::path::{Path, PathBuf}; @@ -175,11 +176,11 @@ pub struct CodegenResults { pub crate_info: CrateInfo, } -pub enum CodegenErrors<'a> { +pub enum CodegenErrors { WrongFileType, EmptyVersionNumber, EncodingVersionMismatch { version_array: String, rlink_version: u32 }, - RustcVersionMismatch { rustc_version: String, current_version: &'a str }, + RustcVersionMismatch { rustc_version: String }, } pub fn provide(providers: &mut Providers) { @@ -213,10 +214,9 @@ pub fn looks_like_rust_object_file(filename: &str) -> bool { const RLINK_VERSION: u32 = 1; const RLINK_MAGIC: &[u8] = b"rustlink"; -const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION"); - impl CodegenResults { pub fn serialize_rlink( + sess: &Session, rlink_file: &Path, codegen_results: &CodegenResults, ) -> Result<usize, io::Error> { @@ -225,12 +225,12 @@ impl CodegenResults { // `emit_raw_bytes` is used to make sure that the version representation does not depend on // Encoder's inner representation of `u32`. encoder.emit_raw_bytes(&RLINK_VERSION.to_be_bytes()); - encoder.emit_str(RUSTC_VERSION.unwrap()); + encoder.emit_str(sess.cfg_version); Encodable::encode(codegen_results, &mut encoder); encoder.finish() } - pub fn deserialize_rlink<'a>(data: Vec<u8>) -> Result<Self, CodegenErrors<'a>> { + pub fn deserialize_rlink(sess: &Session, data: Vec<u8>) -> Result<Self, CodegenErrors> { // The Decodable machinery is not used here because it panics if the input data is invalid // and because its internal representation may change. if !data.starts_with(RLINK_MAGIC) { @@ -252,11 +252,9 @@ impl CodegenResults { let mut decoder = MemDecoder::new(&data[4..], 0); let rustc_version = decoder.read_str(); - let current_version = RUSTC_VERSION.unwrap(); - if rustc_version != current_version { + if rustc_version != sess.cfg_version { return Err(CodegenErrors::RustcVersionMismatch { rustc_version: rustc_version.to_string(), - current_version, }); } diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 3719283cccc..c5976a65411 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -250,6 +250,7 @@ const RISCV_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ ("f", Some(sym::riscv_target_feature)), ("m", Some(sym::riscv_target_feature)), ("relax", Some(sym::riscv_target_feature)), + ("unaligned-scalar-mem", Some(sym::riscv_target_feature)), ("v", Some(sym::riscv_target_feature)), ("zba", Some(sym::riscv_target_feature)), ("zbb", Some(sym::riscv_target_feature)), diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 5c88368bc87..d83bfc74082 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -1,3 +1,5 @@ +use std::any::Any; + use super::write::WriteBackendMethods; use super::CodegenObject; use crate::back::write::TargetMachineFactoryFn; @@ -5,6 +7,7 @@ use crate::{CodegenResults, ModuleCodegen}; use rustc_ast::expand::allocator::AllocatorKind; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_errors::ErrorGuaranteed; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; @@ -20,11 +23,6 @@ use rustc_span::symbol::Symbol; use rustc_target::abi::call::FnAbi; use rustc_target::spec::Target; -pub use rustc_data_structures::sync::MetadataRef; - -use rustc_data_structures::sync::{DynSend, DynSync}; -use std::any::Any; - pub trait BackendTypes { type Value: CodegenObject; type Function: CodegenObject; diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 5037c210e7d..c591ff75ab8 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -3,7 +3,8 @@ use std::fmt; use rustc_errors::Diagnostic; use rustc_middle::mir::AssertKind; -use rustc_middle::ty::{layout::LayoutError, query::TyCtxtAt, ConstInt}; +use rustc_middle::query::TyCtxtAt; +use rustc_middle::ty::{layout::LayoutError, ConstInt}; use rustc_span::{Span, Symbol}; use super::InterpCx; diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 2fa63dc8c93..040eba10eb4 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -8,13 +8,12 @@ use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; use rustc_index::IndexVec; use rustc_middle::mir; use rustc_middle::mir::interpret::{ErrorHandled, InterpError, ReportedErrorInfo}; +use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{ self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout, }; -use rustc_middle::ty::{ - self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, -}; +use rustc_middle::ty::{self, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable}; use rustc_mir_dataflow::storage::always_storage_live_locals; use rustc_session::Limit; use rustc_span::Span; diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index 4e80a285186..11ad5b49df2 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -58,11 +58,12 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { // Types with identity (print the module path). ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs) | ty::FnDef(def_id, substs) - | ty::Alias(_, ty::AliasTy { def_id, substs, .. }) + | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. }) | ty::Closure(def_id, substs) | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs), ty::Foreign(def_id) => self.print_def_path(def_id, &[]), + ty::Alias(ty::Inherent, _) => bug!("type_name: unexpected inherent projection"), ty::GeneratorWitness(_) => bug!("type_name: unexpected `GeneratorWitness`"), ty::GeneratorWitnessMIR(..) => bug!("type_name: unexpected `GeneratorWitnessMIR`"), } diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index 4868f49d8d5..a5db14d9102 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -109,28 +109,27 @@ pub fn dominators<G: ControlFlowGraph>(graph: &G) -> Dominators<G::Node> { // they have been placed in the bucket. // // We compute a partial set of immediate dominators here. - let z = parent[w]; - for &v in bucket[z].iter() { + for &v in bucket[w].iter() { // This uses the result of Lemma 5 from section 2 from the original // 1979 paper, to compute either the immediate or relative dominator // for a given vertex v. // // eval returns a vertex y, for which semi[y] is minimum among - // vertices semi[v] +> y *> v. Note that semi[v] = z as we're in the - // z bucket. + // vertices semi[v] +> y *> v. Note that semi[v] = w as we're in the + // w bucket. // // Given such a vertex y, semi[y] <= semi[v] and idom[y] = idom[v]. // If semi[y] = semi[v], though, idom[v] = semi[v]. // // Using this, we can either set idom[v] to be: - // * semi[v] (i.e. z), if semi[y] is z + // * semi[v] (i.e. w), if semi[y] is w // * idom[y], otherwise // // We don't directly set to idom[y] though as it's not necessarily // known yet. The second preorder traversal will cleanup by updating // the idom for any that were missed in this pass. let y = eval(&mut parent, lastlinked, &semi, &mut label, v); - idom[v] = if semi[y] < z { y } else { z }; + idom[v] = if semi[y] < w { y } else { w }; } // This loop computes the semi[w] for w. @@ -213,10 +212,11 @@ pub fn dominators<G: ControlFlowGraph>(graph: &G) -> Dominators<G::Node> { // If we don't yet know the idom directly, then push this vertex into // our semidominator's bucket, where it will get processed at a later // stage to compute its immediate dominator. - if parent[w] != semi[w] { + let z = parent[w]; + if z != semi[w] { bucket[semi[w]].push(w); } else { - idom[w] = parent[w]; + idom[w] = z; } // Optimization: We share the parent array between processed and not diff --git a/compiler/rustc_data_structures/src/graph/dominators/tests.rs b/compiler/rustc_data_structures/src/graph/dominators/tests.rs index 8b124516623..5472bb8087e 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/tests.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/tests.rs @@ -53,3 +53,30 @@ fn immediate_dominator() { assert_eq!(dominators.immediate_dominator(2), Some(1)); assert_eq!(dominators.immediate_dominator(3), Some(2)); } + +#[test] +fn transitive_dominator() { + let graph = TestGraph::new( + 0, + &[ + // First tree branch. + (0, 1), + (1, 2), + (2, 3), + (3, 4), + // Second tree branch. + (1, 5), + (5, 6), + // Third tree branch. + (0, 7), + // These links make 0 the dominator for 2 and 3. + (7, 2), + (5, 3), + ], + ); + + let dom_tree = dominators(&graph); + let immediate_dominators = &dom_tree.immediate_dominators; + assert_eq!(immediate_dominators[2], Some(0)); + assert_eq!(immediate_dominators[3], Some(0)); // This used to return Some(1). +} diff --git a/compiler/rustc_data_structures/src/owned_slice.rs b/compiler/rustc_data_structures/src/owned_slice.rs index 311a42aa42a..cbb3047d884 100644 --- a/compiler/rustc_data_structures/src/owned_slice.rs +++ b/compiler/rustc_data_structures/src/owned_slice.rs @@ -1,5 +1,6 @@ use std::{borrow::Borrow, ops::Deref}; +use crate::sync::Lrc; // Use our fake Send/Sync traits when on not parallel compiler, // so that `OwnedSlice` only implements/requires Send/Sync // for parallel compiler builds. @@ -7,7 +8,7 @@ use crate::sync::{Send, Sync}; /// An owned slice. /// -/// This is similar to `Box<[u8]>` but allows slicing and using anything as the +/// This is similar to `Lrc<[u8]>` but allows slicing and using anything as the /// backing buffer. /// /// See [`slice_owned`] for `OwnedSlice` construction and examples. @@ -16,6 +17,7 @@ use crate::sync::{Send, Sync}; /// /// This is essentially a replacement for `owning_ref` which is a lot simpler /// and even sound! 🌸 +#[derive(Clone)] pub struct OwnedSlice { /// This is conceptually a `&'self.owner [u8]`. bytes: *const [u8], @@ -31,7 +33,7 @@ pub struct OwnedSlice { // \/ // ⊂(´・◡・⊂ )∘˚˳° (I am the phantom remnant of #97770) #[expect(dead_code)] - owner: Box<dyn Send + Sync>, + owner: Lrc<dyn Send + Sync>, } /// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function. @@ -72,10 +74,10 @@ where O: Send + Sync + 'static, F: FnOnce(&O) -> Result<&[u8], E>, { - // We box the owner of the bytes, so it doesn't move. + // We wrap the owner of the bytes in, so it doesn't move. // // Since the owner does not move and we don't access it in any way - // before drop, there is nothing that can invalidate the bytes pointer. + // before dropping, there is nothing that can invalidate the bytes pointer. // // Thus, "extending" the lifetime of the reference returned from `F` is fine. // We pretend that we pass it a reference that lives as long as the returned slice. @@ -83,12 +85,39 @@ where // N.B. the HRTB on the `slicer` is important — without it the caller could provide // a short lived slice, unrelated to the owner. - let owner = Box::new(owner); + let owner = Lrc::new(owner); let bytes = slicer(&*owner)?; Ok(OwnedSlice { bytes, owner }) } +impl OwnedSlice { + /// Slice this slice by `slicer`. + /// + /// # Examples + /// + /// ```rust + /// # use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned}; + /// let vec = vec![1, 2, 3, 4]; + /// + /// // Identical to slicing via `&v[1..3]` but produces an owned slice + /// let slice: OwnedSlice = slice_owned(vec, |v| &v[..]); + /// assert_eq!(&*slice, [1, 2, 3, 4]); + /// + /// let slice = slice.slice(|slice| &slice[1..][..2]); + /// assert_eq!(&*slice, [2, 3]); + /// ``` + /// + pub fn slice(self, slicer: impl FnOnce(&[u8]) -> &[u8]) -> OwnedSlice { + // This is basically identical to `try_slice_owned`, + // `slicer` can only return slices of its argument or some static data, + // both of which are valid while `owner` is alive. + + let bytes = slicer(&self); + OwnedSlice { bytes, ..self } + } +} + impl Deref for OwnedSlice { type Target = [u8]; @@ -108,11 +137,11 @@ impl Borrow<[u8]> for OwnedSlice { } } -// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Send` +// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Send` #[cfg(parallel_compiler)] unsafe impl Send for OwnedSlice {} -// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Sync` +// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Sync` #[cfg(parallel_compiler)] unsafe impl Sync for OwnedSlice {} diff --git a/compiler/rustc_data_structures/src/owned_slice/tests.rs b/compiler/rustc_data_structures/src/owned_slice/tests.rs index e151b8c2de0..1eb5378cd1a 100644 --- a/compiler/rustc_data_structures/src/owned_slice/tests.rs +++ b/compiler/rustc_data_structures/src/owned_slice/tests.rs @@ -26,7 +26,7 @@ fn static_storage() { } #[test] -fn slice_the_slice() { +fn slice_owned_the_slice() { let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice); let slice = slice_owned(slice, |s| &s[1..][..4]); let slice = slice_owned(slice, |s| s); @@ -36,6 +36,16 @@ fn slice_the_slice() { } #[test] +fn slice_the_slice() { + let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice) + .slice(|s| &s[1..][..4]) + .slice(|s| s) + .slice(|s| &s[1..]); + + assert_eq!(&*slice, &[1, 2, 3, 4, 5, 6][1..][..4][1..]); +} + +#[test] fn try_and_fail() { let res = try_slice_owned(vec![0], |v| v.get(12..).ok_or(())); diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 8a778866a77..6c3197d8ec2 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -40,7 +40,6 @@ //! [^2] `MTLockRef` is a typedef. pub use crate::marker::*; -use crate::owned_slice::OwnedSlice; use std::collections::HashMap; use std::hash::{BuildHasher, Hash}; use std::ops::{Deref, DerefMut}; @@ -92,6 +91,7 @@ mod mode { } pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode}; + cfg_if! { if #[cfg(not(parallel_compiler))] { pub unsafe auto trait Send {} @@ -244,8 +244,6 @@ cfg_if! { r } - pub type MetadataRef = OwnedSlice; - pub use std::rc::Rc as Lrc; pub use std::rc::Weak as Weak; pub use std::cell::Ref as ReadGuard; @@ -517,8 +515,6 @@ cfg_if! { } } - pub type MetadataRef = OwnedSlice; - /// This makes locks panic if they are already held. /// It is only useful when you are running in a single thread const ERROR_CHECKING: bool = false; diff --git a/compiler/rustc_data_structures/src/sync/worker_local.rs b/compiler/rustc_data_structures/src/sync/worker_local.rs index bfb04ba8a73..d61bb55be68 100644 --- a/compiler/rustc_data_structures/src/sync/worker_local.rs +++ b/compiler/rustc_data_structures/src/sync/worker_local.rs @@ -154,13 +154,6 @@ impl<T> WorkerLocal<T> { } } -impl<T> WorkerLocal<Vec<T>> { - /// Joins the elements of all the worker locals into one Vec - pub fn join(self) -> Vec<T> { - self.into_inner().into_iter().flat_map(|v| v).collect() - } -} - impl<T> Deref for WorkerLocal<T> { type Target = T; diff --git a/compiler/rustc_driver_impl/src/args.rs b/compiler/rustc_driver_impl/src/args.rs index 42c97cc6a9d..a713affa099 100644 --- a/compiler/rustc_driver_impl/src/args.rs +++ b/compiler/rustc_driver_impl/src/args.rs @@ -25,7 +25,7 @@ pub fn arg_expand_all(at_args: &[String]) -> Vec<String> { Ok(arg) => args.extend(arg), Err(err) => rustc_session::early_error( rustc_session::config::ErrorOutputType::default(), - &format!("Failed to load argument file: {err}"), + format!("Failed to load argument file: {err}"), ), } } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 80a9dfd251a..6c204b894a6 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -322,7 +322,7 @@ fn run_compiler( 1 => panic!("make_input should have provided valid inputs"), _ => early_error( config.opts.error_format, - &format!( + format!( "multiple input filenames provided (first two filenames are `{}` and `{}`)", matches.free[0], matches.free[1], ), @@ -527,7 +527,7 @@ fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) { } } Err(InvalidErrorCode) => { - early_error(output, &format!("{code} is not a valid error code")); + early_error(output, format!("{code} is not a valid error code")); } } } @@ -572,7 +572,7 @@ pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Comp let rlink_data = fs::read(file).unwrap_or_else(|err| { sess.emit_fatal(RlinkUnableToRead { err }); }); - let codegen_results = match CodegenResults::deserialize_rlink(rlink_data) { + let codegen_results = match CodegenResults::deserialize_rlink(sess, rlink_data) { Ok(codegen) => codegen, Err(err) => { match err { @@ -586,10 +586,10 @@ pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Comp rlink_version, }) } - CodegenErrors::RustcVersionMismatch { rustc_version, current_version } => { + CodegenErrors::RustcVersionMismatch { rustc_version } => { sess.emit_fatal(RLinkRustcVersionMismatch { rustc_version, - current_version, + current_version: sess.cfg_version, }) } }; @@ -1102,7 +1102,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> { .map(|(flag, _)| format!("{e}. Did you mean `-{flag} {opt}`?")), _ => None, }; - early_error(ErrorOutputType::default(), &msg.unwrap_or_else(|| e.to_string())); + early_error(ErrorOutputType::default(), msg.unwrap_or_else(|| e.to_string())); }); // For all options we just parsed, we check a few aspects: @@ -1250,7 +1250,8 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler)) #[cfg(windows)] if let Some(msg) = info.payload().downcast_ref::<String>() { if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)") { - early_error_no_abort(ErrorOutputType::default(), &msg); + // the error code is already going to be reported when the panic unwinds up the stack + let _ = early_error_no_abort(ErrorOutputType::default(), msg.as_str()); return; } }; @@ -1342,7 +1343,7 @@ pub fn init_rustc_env_logger() { /// other than `RUSTC_LOG`. pub fn init_env_logger(env: &str) { if let Err(error) = rustc_log::init_env_logger(env) { - early_error(ErrorOutputType::default(), &error.to_string()); + early_error(ErrorOutputType::default(), error.to_string()); } } @@ -1409,7 +1410,7 @@ pub fn main() -> ! { arg.into_string().unwrap_or_else(|arg| { early_error( ErrorOutputType::default(), - &format!("argument {i} is not valid Unicode: {arg:?}"), + format!("argument {i} is not valid Unicode: {arg:?}"), ) }) }) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 68e57de5e08..3e38d6afb0b 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -2303,22 +2303,25 @@ impl EmitterWriter { // Colorize addition/replacements with green. for &SubstitutionHighlight { start, end } in highlight_parts { - // Account for tabs when highlighting (#87972). - let tabs: usize = line_to_add - .chars() - .take(start) - .map(|ch| match ch { - '\t' => 3, - _ => 0, - }) - .sum(); - buffer.set_style_range( - *row_num, - max_line_num_len + 3 + start + tabs, - max_line_num_len + 3 + end + tabs, - Style::Addition, - true, - ); + // This is a no-op for empty ranges + if start != end { + // Account for tabs when highlighting (#87972). + let tabs: usize = line_to_add + .chars() + .take(start) + .map(|ch| match ch { + '\t' => 3, + _ => 0, + }) + .sum(); + buffer.set_style_range( + *row_num, + max_line_num_len + 3 + start + tabs, + max_line_num_len + 3 + end + tabs, + Style::Addition, + true, + ); + } } *row_num += 1; } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 22c41f7b93f..074fbb1322c 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -330,12 +330,11 @@ impl CodeSuggestion { }); buf.push_str(&part.snippet); let cur_hi = sm.lookup_char_pos(part.span.hi()); - if cur_hi.line == cur_lo.line && !part.snippet.is_empty() { - // Account for the difference between the width of the current code and the - // snippet being suggested, so that the *later* suggestions are correctly - // aligned on the screen. - acc += len - (cur_hi.col.0 - cur_lo.col.0) as isize; - } + // Account for the difference between the width of the current code and the + // snippet being suggested, so that the *later* suggestions are correctly + // aligned on the screen. Note that cur_hi and cur_lo can be on different + // lines, so cur_hi.col can be smaller than cur_lo.col + acc += len - (cur_hi.col.0 as isize - cur_lo.col.0 as isize); prev_hi = cur_hi; prev_line = sf.get_line(prev_hi.line - 1); for line in part.snippet.split('\n').skip(1) { @@ -478,6 +477,8 @@ pub enum StashKey { /// FRU syntax MaybeFruTypo, CallAssocMethod, + TraitMissingMethod, + OpaqueHiddenTypeMismatch, } fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) { @@ -1739,7 +1740,7 @@ impl DelayedDiagnostic { } fn decorate(mut self) -> Diagnostic { - self.inner.note(format!("delayed at {}", self.note)); + self.inner.note(format!("delayed at {}\n{}", self.inner.emitted_at, self.note)); self.inner } } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index e03576c55f4..fd721749066 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -15,7 +15,8 @@ use rustc_attr::{self as attr, Deprecation, Stability}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{ - Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan, PResult, + Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, IntoDiagnostic, + MultiSpan, PResult, }; use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, RegisteredTools}; @@ -1110,7 +1111,7 @@ impl<'a> ExtCtxt<'a> { pub fn struct_span_err<S: Into<MultiSpan>>( &self, sp: S, - msg: &str, + msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { self.sess.parse_sess.span_diagnostic.struct_span_err(sp, msg) } @@ -1132,14 +1133,14 @@ impl<'a> ExtCtxt<'a> { /// Compilation will be stopped in the near future (at the end of /// the macro expansion phase). #[rustc_lint_diagnostics] - pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { + pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) { self.sess.parse_sess.span_diagnostic.span_err(sp, msg); } #[rustc_lint_diagnostics] - pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { + pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) { self.sess.parse_sess.span_diagnostic.span_warn(sp, msg); } - pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! { + pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! { self.sess.parse_sess.span_diagnostic.span_bug(sp, msg); } pub fn trace_macros_diag(&mut self) { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 7c78970345a..5d369a1879a 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -722,7 +722,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }); } }; - if fragment_kind == AstFragmentKind::Expr && items.is_empty() { + if matches!( + fragment_kind, + AstFragmentKind::Expr | AstFragmentKind::MethodReceiverExpr + ) && items.is_empty() + { self.cx.emit_err(RemoveExprNotSupported { span }); fragment_kind.dummy(span) } else { @@ -1664,7 +1668,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { &UNUSED_ATTRIBUTES, attr.span, self.cx.current_expansion.lint_node_id, - &format!("unused attribute `{}`", attr_name), + format!("unused attribute `{}`", attr_name), BuiltinLintDiagnostics::UnusedBuiltinAttribute { attr_name, macro_name: pprust::path_to_string(&call.path), diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 35572292271..cb8b4899e48 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -48,7 +48,7 @@ pub(super) fn failed_to_match_macro<'cx>( let span = token.span.substitute_dummy(sp); - let mut err = cx.struct_span_err(span, &parse_failure_msg(&token)); + let mut err = cx.struct_span_err(span, parse_failure_msg(&token)); err.span_label(span, label); if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) { err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro"); @@ -170,7 +170,7 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, } Error(err_sp, msg) => { let span = err_sp.substitute_dummy(self.root_span); - self.cx.struct_span_err(span, msg).emit(); + self.cx.struct_span_err(span, msg.as_str()).emit(); self.result = Some(DummyResult::any(span)); } ErrorReported(_) => self.result = Some(DummyResult::any(self.root_span)), diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index 75b6396f0be..34f998274e9 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -110,7 +110,7 @@ use crate::mbe::{KleeneToken, TokenTree}; use rustc_ast::token::{Delimiter, Token, TokenKind}; use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::MultiSpan; +use rustc_errors::{DiagnosticMessage, MultiSpan}; use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER}; use rustc_session::parse::ParseSess; use rustc_span::symbol::kw; @@ -593,7 +593,7 @@ fn check_ops_is_prefix( return; } } - buffer_lint(sess, span.into(), node_id, &format!("unknown macro variable `{}`", name)); + buffer_lint(sess, span.into(), node_id, format!("unknown macro variable `{}`", name)); } /// Returns whether `binder_ops` is a prefix of `occurrence_ops`. @@ -626,7 +626,7 @@ fn ops_is_prefix( if i >= occurrence_ops.len() { let mut span = MultiSpan::from_span(span); span.push_span_label(binder.span, "expected repetition"); - let message = &format!("variable '{}' is still repeating at this depth", name); + let message = format!("variable '{}' is still repeating at this depth", name); buffer_lint(sess, span, node_id, message); return; } @@ -642,7 +642,12 @@ fn ops_is_prefix( } } -fn buffer_lint(sess: &ParseSess, span: MultiSpan, node_id: NodeId, message: &str) { +fn buffer_lint( + sess: &ParseSess, + span: MultiSpan, + node_id: NodeId, + message: impl Into<DiagnosticMessage>, +) { // Macros loaded from other crates have dummy node ids. if node_id != DUMMY_NODE_ID { sess.buffer_lint(&META_VARIABLE_MISUSE, span, node_id, message); diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index a07cb65170d..d523d3eacbe 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -510,7 +510,7 @@ fn out_of_bounds_err<'a>( must be less than {max}" ) }; - cx.struct_span_err(span, &msg) + cx.struct_span_err(span, msg) } fn transcribe_metavar_expr<'a>( diff --git a/compiler/rustc_hir/src/errors.rs b/compiler/rustc_hir/src/errors.rs deleted file mode 100644 index e593ed1044a..00000000000 --- a/compiler/rustc_hir/src/errors.rs +++ /dev/null @@ -1,10 +0,0 @@ -use crate::LangItem; - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)] -pub struct LangItemError(pub LangItem); - -impl ToString for LangItemError { - fn to_string(&self) -> String { - format!("requires `{}` lang_item", self.0.name()) - } -} diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 1f08befb180..4b3bc816b95 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -8,7 +8,6 @@ //! * Functions called by the compiler itself. use crate::def_id::DefId; -use crate::errors::LangItemError; use crate::{MethodKind, Target}; use rustc_ast as ast; @@ -42,13 +41,6 @@ impl LanguageItems { self.items[item as usize] = Some(def_id); } - /// Requires that a given `LangItem` was bound and returns the corresponding `DefId`. - /// If it wasn't bound, e.g. due to a missing `#[lang = "<it.name()>"]`, - /// returns an error encapsulating the `LangItem`. - pub fn require(&self, it: LangItem) -> Result<DefId, LangItemError> { - self.get(it).ok_or_else(|| LangItemError(it)) - } - pub fn iter(&self) -> impl Iterator<Item = (LangItem, DefId)> + '_ { self.items .iter() diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 98d967cc0b8..616de57dc63 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -30,7 +30,6 @@ pub mod def; pub mod def_path_hash_map; pub mod definitions; pub mod diagnostic_items; -pub mod errors; pub use rustc_span::def_id; mod hir; pub mod hir_id; diff --git a/compiler/rustc_hir/src/tests.rs b/compiler/rustc_hir/src/tests.rs index c7ac01b3334..a40a0178710 100644 --- a/compiler/rustc_hir/src/tests.rs +++ b/compiler/rustc_hir/src/tests.rs @@ -10,13 +10,13 @@ fn def_path_hash_depends_on_crate_id() { // the crate-id of the defining crate. This is a desirable property // because the crate-id can be more easily changed than the DefPath // of an item, so, in the case of a crate-local DefPathHash collision, - // the user can simply "role the dice again" for all DefPathHashes in + // the user can simply "roll the dice again" for all DefPathHashes in // the crate by changing the crate disambiguator (e.g. via bumping the // crate's version number). create_session_if_not_set_then(Edition::Edition2024, |_| { - let id0 = StableCrateId::new(Symbol::intern("foo"), false, vec!["1".to_string()]); - let id1 = StableCrateId::new(Symbol::intern("foo"), false, vec!["2".to_string()]); + let id0 = StableCrateId::new(Symbol::intern("foo"), false, vec!["1".to_string()], ""); + let id1 = StableCrateId::new(Symbol::intern("foo"), false, vec!["2".to_string()], ""); let h0 = mk_test_hash(id0); let h1 = mk_test_hash(id1); diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index ed011b9086a..39d1d1f2de5 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -24,7 +24,7 @@ fn generic_arg_mismatch_err( arg: &GenericArg<'_>, param: &GenericParamDef, possible_ordering_error: bool, - help: Option<&str>, + help: Option<String>, ) -> ErrorGuaranteed { let sess = tcx.sess; let mut err = struct_span_err!( @@ -300,7 +300,7 @@ pub fn create_substs_for_generic_args<'tcx, 'a>( arg, param, !args_iter.clone().is_sorted_by_key(|arg| arg.to_ord()), - Some(&format!( + Some(format!( "reorder the arguments: {}: `<{}>`", param_types_present .into_iter() diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 7e591fd25bf..cf082f1ffaa 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -19,7 +19,7 @@ use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{ struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError, - MultiSpan, + MultiSpan, StashKey, }; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; @@ -38,7 +38,6 @@ use rustc_middle::ty::{self, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt} use rustc_middle::ty::{DynKind, ToPredicate}; use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS}; use rustc_span::edit_distance::find_best_match_for_name; -use rustc_span::edition::Edition; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::{sym, Span, DUMMY_SP}; use rustc_target::spec::abi; @@ -3718,7 +3717,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { )); } - if self_ty.span.edition() >= Edition::Edition2021 { + if self_ty.span.edition().rust_2021() { let msg = "trait objects must include the `dyn` keyword"; let label = "add `dyn` keyword before this trait"; let mut diag = @@ -3732,7 +3731,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } // check if the impl trait that we are considering is a impl of a local trait self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag); - diag.emit(); + diag.stash(self_ty.span, StashKey::TraitMissingMethod); } else { let msg = "trait objects without an explicit `dyn` are deprecated"; tcx.struct_span_lint_hir( diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 1cf93c86f4f..d6d1498d708 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -1,6 +1,5 @@ use crate::errors::AutoDerefReachedRecursionLimit; use crate::traits::query::evaluate_obligation::InferCtxtExt; -use crate::traits::NormalizeExt; use crate::traits::{self, TraitEngine, TraitEngineExt}; use rustc_infer::infer::InferCtxt; use rustc_middle::ty::TypeVisitableExt; @@ -9,6 +8,7 @@ use rustc_session::Limit; use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::Span; +use rustc_trait_selection::traits::StructurallyNormalizeExt; #[derive(Copy, Clone, Debug)] pub enum AutoderefKind { @@ -66,14 +66,27 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { } // Otherwise, deref if type is derefable: - let (kind, new_ty) = - if let Some(mt) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) { - (AutoderefKind::Builtin, mt.ty) - } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { - (AutoderefKind::Overloaded, ty) + let (kind, new_ty) = if let Some(ty::TypeAndMut { ty, .. }) = + self.state.cur_ty.builtin_deref(self.include_raw_pointers) + { + debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty)); + // NOTE: we may still need to normalize the built-in deref in case + // we have some type like `&<Ty as Trait>::Assoc`, since users of + // autoderef expect this type to have been structurally normalized. + if self.infcx.tcx.trait_solver_next() + && let ty::Alias(ty::Projection, _) = ty.kind() + { + let (normalized_ty, obligations) = self.structurally_normalize(ty)?; + self.state.obligations.extend(obligations); + (AutoderefKind::Builtin, normalized_ty) } else { - return None; - }; + (AutoderefKind::Builtin, ty) + } + } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { + (AutoderefKind::Overloaded, ty) + } else { + return None; + }; if new_ty.references_error() { return None; @@ -119,14 +132,11 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> { debug!("overloaded_deref_ty({:?})", ty); - let tcx = self.infcx.tcx; // <ty as Deref> let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]); - let cause = traits::ObligationCause::misc(self.span, self.body_id); - let obligation = traits::Obligation::new( tcx, cause.clone(), @@ -138,26 +148,48 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { return None; } - let normalized_ty = self + let (normalized_ty, obligations) = + self.structurally_normalize(tcx.mk_projection(tcx.lang_items().deref_target()?, [ty]))?; + debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); + self.state.obligations.extend(obligations); + + Some(self.infcx.resolve_vars_if_possible(normalized_ty)) + } + + #[instrument(level = "debug", skip(self), ret)] + pub fn structurally_normalize( + &self, + ty: Ty<'tcx>, + ) -> Option<(Ty<'tcx>, Vec<traits::PredicateObligation<'tcx>>)> { + let tcx = self.infcx.tcx; + let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new_in_snapshot(tcx); + + let cause = traits::ObligationCause::misc(self.span, self.body_id); + let normalized_ty = match self .infcx .at(&cause, self.param_env) - .normalize(tcx.mk_projection(tcx.lang_items().deref_target()?, trait_ref.substs)); - let mut fulfillcx = <dyn TraitEngine<'tcx>>::new_in_snapshot(tcx); - let normalized_ty = - normalized_ty.into_value_registering_obligations(self.infcx, &mut *fulfillcx); - let errors = fulfillcx.select_where_possible(&self.infcx); + .structurally_normalize(ty, &mut *fulfill_cx) + { + Ok(normalized_ty) => normalized_ty, + Err(errors) => { + // This shouldn't happen, except for evaluate/fulfill mismatches, + // but that's not a reason for an ICE (`predicate_may_hold` is conservative + // by design). + debug!(?errors, "encountered errors while fulfilling"); + return None; + } + }; + + let errors = fulfill_cx.select_where_possible(&self.infcx); if !errors.is_empty() { // This shouldn't happen, except for evaluate/fulfill mismatches, // but that's not a reason for an ICE (`predicate_may_hold` is conservative // by design). - debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", errors); + debug!(?errors, "encountered errors while fulfilling"); return None; } - let obligations = fulfillcx.pending_obligations(); - debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); - self.state.obligations.extend(obligations); - Some(self.infcx.resolve_vars_if_possible(normalized_ty)) + Some((normalized_ty, fulfill_cx.pending_obligations())) } /// Returns the final type we ended up with, which may be an inference diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index d05d8508408..a98d8e17153 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -298,9 +298,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)); - let unsize_trait = tcx.lang_items().require(LangItem::Unsize).unwrap_or_else(|err| { - tcx.sess.fatal(format!("`CoerceUnsized` implementation {}", err.to_string())); - }); + let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span)); let source = tcx.type_of(impl_did).subst_identity(); let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().subst_identity(); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 9f00dc418ee..22502bd4fdb 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -73,7 +73,6 @@ pub fn provide(providers: &mut Providers) { fn_sig, impl_trait_ref, impl_polarity, - is_foreign_item, generator_kind, collect_mod_item_types, is_type_alias_impl_trait, @@ -1466,10 +1465,6 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( fty } -fn is_foreign_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - matches!(tcx.hir().get_by_def_id(def_id), Node::ForeignItem(..)) -} - fn generator_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<hir::GeneratorKind> { match tcx.hir().get_by_def_id(def_id) { Node::Expr(&rustc_hir::Expr { diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index a33990813b8..e5b5dae551e 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -427,6 +427,8 @@ pub(super) fn explicit_predicates_of<'tcx>( // supertrait). if let ty::Alias(ty::Projection, projection) = ty.kind() { projection.substs == trait_identity_substs + // FIXME(return_type_notation): This check should be more robust + && !tcx.is_impl_trait_in_trait(projection.def_id) && tcx.associated_item(projection.def_id).container_id(tcx) == def_id.to_def_id() } else { diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 6c7c2b9eea2..97c6cb491d1 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -164,7 +164,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else { return tcx.ty_error_with_message( tcx.def_span(def_id), - &format!("unable to find type-dependent def for {:?}", parent_node_id), + format!("unable to find type-dependent def for {:?}", parent_node_id), ); }; let idx = segment @@ -205,14 +205,14 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { } else { return tcx.ty_error_with_message( tcx.def_span(def_id), - &format!("unable to find const parent for {} in pat {:?}", hir_id, pat), + format!("unable to find const parent for {} in pat {:?}", hir_id, pat), ); } } _ => { return tcx.ty_error_with_message( tcx.def_span(def_id), - &format!("unexpected const parent path {:?}", parent_node), + format!("unexpected const parent path {:?}", parent_node), ); } }; @@ -243,7 +243,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { None => { return tcx.ty_error_with_message( tcx.def_span(def_id), - &format!("unexpected anon const res {:?} in path: {:?}", segment.res, path), + format!("unexpected anon const res {:?} in path: {:?}", segment.res, path), ); } }; @@ -253,7 +253,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { _ => return tcx.ty_error_with_message( tcx.def_span(def_id), - &format!("unexpected const parent in type_of(): {parent_node:?}"), + format!("unexpected const parent in type_of(): {parent_node:?}"), ), }; @@ -279,7 +279,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { } else { return tcx.ty_error_with_message( tcx.def_span(def_id), - &format!("const generic parameter not found in {generics:?} at position {arg_idx:?}"), + format!("const generic parameter not found in {generics:?} at position {arg_idx:?}"), ); } } @@ -584,7 +584,8 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T debug!(?concrete_type, "found constraint"); if let Some(prev) = &mut self.found { if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() { - let guar = prev.report_mismatch(&concrete_type, self.tcx); + let guar = + prev.report_mismatch(&concrete_type, self.def_id, self.tcx).emit(); prev.ty = self.tcx.ty_error(guar); } } else { @@ -678,10 +679,10 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T // Only check against typeck if we didn't already error if !hidden.ty.references_error() { for concrete_type in locator.typeck_types { - if tcx.erase_regions(concrete_type.ty) != tcx.erase_regions(hidden.ty) + if concrete_type.ty != tcx.erase_regions(hidden.ty) && !(concrete_type, hidden).references_error() { - hidden.report_mismatch(&concrete_type, tcx); + hidden.report_mismatch(&concrete_type, def_id, tcx).emit(); } } } @@ -722,7 +723,7 @@ fn find_opaque_ty_constraints_for_rpit( if concrete_type.ty != self.found.ty && !(concrete_type, self.found).references_error() { - self.found.report_mismatch(&concrete_type, self.tcx); + self.found.report_mismatch(&concrete_type, self.def_id, self.tcx).emit(); } } } diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index aa664031a87..4a669e3f8b8 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -79,3 +79,14 @@ hir_typeck_arg_mismatch_indeterminate = argument type mismatch was detected, but hir_typeck_suggest_boxing_note = for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html hir_typeck_suggest_boxing_when_appropriate = store this in the heap by calling `Box::new` + +hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method -> + [true] {""} + *[other] {" "}in the current scope +} + +hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}`{$action_or_ty -> + [NONE] {""} + [implement] , perhaps you need to implement it + *[other] , perhaps you need to restrict type parameter `{$action_or_ty}` with it +} diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index bf8259ff70f..bfabd44bb57 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -32,6 +32,7 @@ pub(super) fn check_fn<'a, 'tcx>( fn_def_id: LocalDefId, body: &'tcx hir::Body<'tcx>, can_be_generator: Option<hir::Movability>, + params_can_be_unsized: bool, ) -> Option<GeneratorTypes<'tcx>> { let fn_id = fcx.tcx.hir().local_def_id_to_hir_id(fn_def_id); @@ -94,7 +95,7 @@ pub(super) fn check_fn<'a, 'tcx>( // The check for a non-trivial pattern is a hack to avoid duplicate warnings // for simple cases like `fn foo(x: Trait)`, // where we would error once on the parameter as a whole, and once on the binding `x`. - if param.pat.simple_ident().is_none() && !tcx.features().unsized_fn_params { + if param.pat.simple_ident().is_none() && !params_can_be_unsized { fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span)); } @@ -103,24 +104,8 @@ pub(super) fn check_fn<'a, 'tcx>( fcx.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig); - if let ty::Dynamic(_, _, ty::Dyn) = declared_ret_ty.kind() { - // FIXME: We need to verify that the return type is `Sized` after the return expression has - // been evaluated so that we have types available for all the nodes being returned, but that - // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this - // causes unsized errors caused by the `declared_ret_ty` to point at the return expression, - // while keeping the current ordering we will ignore the tail expression's type because we - // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr` - // because we will trigger "unreachable expression" lints unconditionally. - // Because of all of this, we perform a crude check to know whether the simplest `!Sized` - // case that a newcomer might make, returning a bare trait, and in that case we populate - // the tail expression's type so that the suggestion will be correct, but ignore all other - // possible cases. - fcx.check_expr(&body.value); - fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); - } else { - fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); - fcx.check_return_expr(&body.value, false); - } + fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); + fcx.check_return_expr(&body.value, false); // We insert the deferred_generator_interiors entry after visiting the body. // This ensures that all nested generators appear before the entry of this generator. diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 7046269c2de..9659a0ec13d 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -89,6 +89,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr_def_id, body, closure.movability, + // Closure "rust-call" ABI doesn't support unsized params + false, ); let parent_substs = InternalSubsts::identity_for_item( diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index ce30bbeca0b..102a313067f 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -1,4 +1,6 @@ //! Errors emitted by `rustc_hir_typeck`. +use std::borrow::Cow; + use crate::fluent_generated as fluent; use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, MultiSpan, SubdiagnosticMessage}; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -295,3 +297,25 @@ pub enum SuggestBoxing { end: Span, }, } + +#[derive(Diagnostic)] +#[diag(hir_typeck_no_associated_item, code = "E0599")] +pub struct NoAssociatedItem { + #[primary_span] + pub span: Span, + pub item_kind: &'static str, + pub item_name: Ident, + pub ty_prefix: Cow<'static, str>, + pub ty_str: String, + pub trait_missing_method: bool, +} + +#[derive(Subdiagnostic)] +#[note(hir_typeck_candidate_trait_note)] +pub struct CandidateTraitNote { + #[primary_span] + pub span: Span, + pub trait_name: String, + pub item_name: Ident, + pub action_or_ty: String, +} diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index bba049c3819..adc1b090af6 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -721,7 +721,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // ICE this expression in particular (see #43162). if let ExprKind::Path(QPath::Resolved(_, path)) = e.kind { if path.segments.len() == 1 && path.segments[0].ident.name == sym::rust { - fatally_break_rust(self.tcx.sess); + fatally_break_rust(self.tcx); } } } @@ -1245,6 +1245,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error, Some((rcvr, args)), expected, + false, ) { err.emit(); } @@ -2468,7 +2469,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { self.suggest_method_call( &mut err, - &format!("a method `{field}` also exists, call it with parentheses"), + format!("a method `{field}` also exists, call it with parentheses"), field, expr_t, expr, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 9e78e6acba5..9721e3b427d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -4,7 +4,7 @@ use crate::rvalue_scopes; use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, RawTy}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan, StashKey}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -35,7 +35,9 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use rustc_target::abi::FieldIdx; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::{self, NormalizeExt, ObligationCauseCode, ObligationCtxt}; +use rustc_trait_selection::traits::{ + self, NormalizeExt, ObligationCauseCode, ObligationCtxt, StructurallyNormalizeExt, +}; use std::collections::hash_map::Entry; use std::slice; @@ -853,6 +855,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let item_name = item_segment.ident; let result = self .resolve_fully_qualified_call(span, item_name, ty.normalized, qself.span, hir_id) + .and_then(|r| { + // lint bare trait if the method is found in the trait + if span.edition().rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) { + diag.emit(); + } + Ok(r) + }) .or_else(|error| { let guar = self .tcx @@ -863,17 +872,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => Err(guar), }; + let trait_missing_method = + matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait(); // If we have a path like `MyTrait::missing_method`, then don't register // a WF obligation for `dyn MyTrait` when method lookup fails. Otherwise, // register a WF obligation so that we can detect any additional // errors in the self type. - if !(matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait()) { + if !trait_missing_method { self.register_wf_obligation( ty.raw.into(), qself.span, traits::WellFormed(None), ); } + + // emit or cancel the diagnostic for bare traits + if span.edition().rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) { + if trait_missing_method { + // cancel the diag for bare traits when meeting `MyTrait::missing_method` + diag.cancel(); + } else { + diag.emit(); + } + } + if item_name.name != kw::Empty { if let Some(mut e) = self.report_method_error( span, @@ -883,10 +905,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error, None, Expectation::NoExpectation, + trait_missing_method && span.edition().rust_2021(), // emits missing method for trait only after edition 2021 ) { e.emit(); } } + result }); @@ -1438,10 +1462,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Resolves `typ` by a single level if `typ` is a type variable. + /// + /// When the new solver is enabled, this will also attempt to normalize + /// the type if it's a projection (note that it will not deeply normalize + /// projections within the type, just the outermost layer of the type). + /// /// If no resolution is possible, then an error is reported. /// Numeric inference variables may be left unresolved. pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - let ty = self.resolve_vars_with_obligations(ty); + let mut ty = self.resolve_vars_with_obligations(ty); + + if self.tcx.trait_solver_next() + && let ty::Alias(ty::Projection, _) = ty.kind() + { + match self + .at(&self.misc(sp), self.param_env) + .structurally_normalize(ty, &mut **self.fulfillment_cx.borrow_mut()) + { + Ok(normalized_ty) => { + ty = normalized_ty; + }, + Err(errors) => { + let guar = self.err_ctxt().report_fulfillment_errors(&errors); + return self.tcx.ty_error(guar); + } + } + } + if !ty.is_ty_var() { ty } else { diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 54b222ade03..b97b55d8f7e 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -72,7 +72,6 @@ use rustc_middle::query::Providers; use rustc_middle::traits; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::config; -use rustc_session::Session; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::{sym, Span}; @@ -213,7 +212,7 @@ fn typeck_with_fallback<'tcx>( let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); let fn_sig = fcx.normalize(body.value.span, fn_sig); - check_fn(&mut fcx, fn_sig, decl, def_id, body, None); + check_fn(&mut fcx, fn_sig, decl, def_id, body, None, tcx.features().unsized_fn_params); } else { let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer, span, .. }) = body_ty { Some(fcx.next_ty_var(TypeVariableOrigin { @@ -438,8 +437,8 @@ enum TupleArgumentsFlag { TupleArguments, } -fn fatally_break_rust(sess: &Session) { - let handler = sess.diagnostic(); +fn fatally_break_rust(tcx: TyCtxt<'_>) { + let handler = tcx.sess.diagnostic(); handler.span_bug_no_panic( MultiSpan::new(), "It looks like you're trying to break rust; would you like some ICE?", @@ -451,7 +450,7 @@ fn fatally_break_rust(sess: &Session) { ); handler.note_without_error(format!( "rustc {} running on {}", - option_env!("CFG_VERSION").unwrap_or("unknown_version"), + tcx.sess.cfg_version, config::host_triple(), )); } diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 9155a3d8daa..98529b66602 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -158,7 +158,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let Some((ty, n)) = autoderef.nth(pick.autoderefs) else { return self.tcx.ty_error_with_message( rustc_span::DUMMY_SP, - &format!("failed autoderef {}", pick.autoderefs), + format!("failed autoderef {}", pick.autoderefs), ); }; assert_eq!(n, pick.autoderefs); @@ -471,7 +471,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self_ty, method_self_ty, self.span, pick ); let cause = self.cause( - self.span, + self.self_expr.span, ObligationCauseCode::UnifyReceiver(Box::new(UnifyReceiverContext { assoc_item: pick.item, param_env: self.param_env, @@ -482,13 +482,22 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); } - Err(_) => { - span_bug!( - self.span, - "{} was a subtype of {} but now is not?", - self_ty, - method_self_ty - ); + Err(terr) => { + // FIXME(arbitrary_self_types): We probably should limit the + // situations where this can occur by adding additional restrictions + // to the feature, like the self type can't reference method substs. + if self.tcx.features().arbitrary_self_types { + self.err_ctxt() + .report_mismatched_types(&cause, method_self_ty, self_ty, terr) + .emit(); + } else { + span_bug!( + self.span, + "{} was a subtype of {} but now is not?", + self_ty, + method_self_ty + ); + } } } } diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index cf9290c1a48..6f4d674ba10 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -13,7 +13,7 @@ pub use self::MethodError::*; use crate::errors::OpMethodGenericParams; use crate::FnCtxt; use rustc_data_structures::sync::Lrc; -use rustc_errors::{Applicability, Diagnostic}; +use rustc_errors::{Applicability, Diagnostic, SubdiagnosticMessage}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace}; use rustc_hir::def_id::DefId; @@ -130,7 +130,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn suggest_method_call( &self, err: &mut Diagnostic, - msg: &str, + msg: impl Into<SubdiagnosticMessage> + std::fmt::Debug, method_name: Ident, self_ty: Ty<'tcx>, call_expr: &hir::Expr<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 550a87e6102..17364509844 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2,6 +2,8 @@ //! found or is otherwise invalid. use crate::errors; +use crate::errors::CandidateTraitNote; +use crate::errors::NoAssociatedItem; use crate::Expectation; use crate::FnCtxt; use rustc_ast::ast::Mutability; @@ -38,6 +40,7 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _ use rustc_trait_selection::traits::{ FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, }; +use std::borrow::Cow; use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope}; use super::{CandidateSource, MethodError, NoMatchData}; @@ -112,6 +115,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error: MethodError<'tcx>, args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>, expected: Expectation<'tcx>, + trait_missing_method: bool, ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> { // Avoid suggestions when we don't know what's going on. if rcvr_ty.references_error() { @@ -136,6 +140,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sugg_span, &mut no_match_data, expected, + trait_missing_method, ); } @@ -278,12 +283,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sugg_span: Span, no_match_data: &mut NoMatchData<'tcx>, expected: Expectation<'tcx>, + trait_missing_method: bool, ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> { let mode = no_match_data.mode; let tcx = self.tcx; let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty); - let (ty_str, ty_file) = tcx.short_ty_string(rcvr_ty); - let short_ty_str = with_forced_trimmed_paths!(rcvr_ty.to_string()); + let ((mut ty_str, ty_file), short_ty_str) = if trait_missing_method + && let ty::Dynamic(predicates, _, _) = rcvr_ty.kind() { + ((predicates.to_string(), None), with_forced_trimmed_paths!(predicates.to_string())) + } else { + (tcx.short_ty_string(rcvr_ty), with_forced_trimmed_paths!(rcvr_ty.to_string())) + }; let is_method = mode == Mode::MethodCall; let unsatisfied_predicates = &no_match_data.unsatisfied_predicates; let similar_candidate = no_match_data.similar_candidate; @@ -355,25 +365,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { self.suggest_missing_writer(rcvr_ty, args) } else { - struct_span_err!( - tcx.sess, + tcx.sess.create_err(NoAssociatedItem { span, - E0599, - "no {} named `{}` found for {} `{}` in the current scope", item_kind, item_name, - rcvr_ty.prefix_string(self.tcx), - ty_str_reported, - ) + ty_prefix: if trait_missing_method { + // FIXME(mu001999) E0599 maybe not suitable here because it is for types + Cow::from("trait") + } else { + rcvr_ty.prefix_string(self.tcx) + }, + ty_str: ty_str_reported, + trait_missing_method, + }) }; if tcx.sess.source_map().is_multiline(sugg_span) { err.span_label(sugg_span.with_hi(span.lo()), ""); } - let ty_str = if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 { - short_ty_str - } else { - ty_str - }; + + if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 { + ty_str = short_ty_str; + } + if let Some(file) = ty_file { err.note(format!("the full type name has been written to '{}'", file.display(),)); } @@ -1067,6 +1080,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &static_candidates, unsatisfied_bounds, expected.only_has_type(self), + trait_missing_method, ); } @@ -2375,6 +2389,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { static_candidates: &[CandidateSource], unsatisfied_bounds: bool, return_type: Option<Ty<'tcx>>, + trait_missing_method: bool, ) { let mut alt_rcvr_sugg = false; if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) { @@ -2598,11 +2613,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, _ => None, }; - err.help(if param_type.is_some() { - "items from traits can only be used if the type parameter is bounded by the trait" - } else { - "items from traits can only be used if the trait is implemented and in scope" - }); + if !trait_missing_method { + err.help(if param_type.is_some() { + "items from traits can only be used if the type parameter is bounded by the trait" + } else { + "items from traits can only be used if the trait is implemented and in scope" + }); + } + let candidates_len = candidates.len(); let message = |action| { format!( @@ -2751,27 +2769,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (candidates, Vec::new()) }; - let action = if let Some(param) = param_type { - format!("restrict type parameter `{}` with", param) - } else { - // FIXME: it might only need to be imported into scope, not implemented. - "implement".to_string() - }; match &potential_candidates[..] { [] => {} [trait_info] if trait_info.def_id.is_local() => { - err.span_note( - self.tcx.def_span(trait_info.def_id), - format!( - "`{}` defines an item `{}`, perhaps you need to {} it", - self.tcx.def_path_str(trait_info.def_id), - item_name, - action - ), - ); + err.subdiagnostic(CandidateTraitNote { + span: self.tcx.def_span(trait_info.def_id), + trait_name: self.tcx.def_path_str(trait_info.def_id), + item_name, + action_or_ty: if trait_missing_method { + "NONE".to_string() + } else { + param_type.map_or_else( + || "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented. + ToString::to_string, + ) + }, + }); } trait_infos => { - let mut msg = message(action); + let mut msg = message(param_type.map_or_else( + || "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented. + |param| format!("restrict type parameter `{}` with", param), + )); for (i, trait_info) in trait_infos.iter().enumerate() { msg.push_str(&format!( "\ncandidate #{}: `{}`", diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 59bee69cfff..0f21fc1e662 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -5,11 +5,10 @@ use crate::FnCtxt; use hir::def_id::LocalDefId; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::ErrorGuaranteed; +use rustc_errors::{ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; -use rustc_infer::infer::InferCtxt; use rustc_middle::hir::place::Place as HirPlace; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast}; @@ -83,10 +82,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { wbcx.typeck_results.treat_byte_string_as_slice = mem::take(&mut self.typeck_results.borrow_mut().treat_byte_string_as_slice); - if let Some(e) = self.tainted_by_errors() { - wbcx.typeck_results.tainted_by_errors = Some(e); - } - debug!("writeback: typeck results for {:?} are {:#?}", item_def_id, wbcx.typeck_results); self.tcx.arena.alloc(wbcx.typeck_results) @@ -119,12 +114,21 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { ) -> WritebackCx<'cx, 'tcx> { let owner = body.id().hir_id.owner; - WritebackCx { + let mut wbcx = WritebackCx { fcx, typeck_results: ty::TypeckResults::new(owner), body, rustc_dump_user_substs, + }; + + // HACK: We specifically don't want the (opaque) error from tainting our + // inference context. That'll prevent us from doing opaque type inference + // later on in borrowck, which affects diagnostic spans pretty negatively. + if let Some(e) = fcx.tainted_by_errors() { + wbcx.typeck_results.tainted_by_errors = Some(e); } + + wbcx } fn tcx(&self) -> TyCtxt<'tcx> { @@ -237,7 +241,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // error has been emitted. (#64638) self.fcx.tcx.ty_error_with_message( e.span, - &format!("bad index {:?} for base: `{:?}`", index, base), + format!("bad index {:?} for base: `{:?}`", index, base), ) }); let index_ty = self.fcx.resolve_vars_if_possible(index_ty); @@ -579,13 +583,26 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { continue; } - let hidden_type = hidden_type.remap_generic_params_to_declaration_params( - opaque_type_key, - self.fcx.infcx.tcx, - true, - ); - - self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type); + let hidden_type = + self.tcx().erase_regions(hidden_type.remap_generic_params_to_declaration_params( + opaque_type_key, + self.tcx(), + true, + )); + + if let Some(last_opaque_ty) = self + .typeck_results + .concrete_opaque_types + .insert(opaque_type_key.def_id, hidden_type) + && last_opaque_ty.ty != hidden_type.ty + { + hidden_type + .report_mismatch(&last_opaque_ty, opaque_type_key.def_id, self.tcx()) + .stash( + self.tcx().def_span(opaque_type_key.def_id), + StashKey::OpaqueHiddenTypeMismatch, + ); + } } } @@ -692,15 +709,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fcx_typeck_results.offset_of_data().items_in_stable_order() { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; - - if cfg!(debug_assertions) && container.has_infer() { - span_bug!( - hir_id.to_span(self.fcx.tcx), - "writeback: `{:?}` has inference variables", - container - ); - }; - + let container = self.resolve(container, &hir_id); self.typeck_results.offset_of_data_mut().insert(hir_id, (container, indices.clone())); } } @@ -745,8 +754,7 @@ impl Locatable for hir::HirId { /// The Resolver. This is the type folding engine that detects /// unresolved types and so forth. struct Resolver<'cx, 'tcx> { - tcx: TyCtxt<'tcx>, - infcx: &'cx InferCtxt<'tcx>, + fcx: &'cx FnCtxt<'cx, 'tcx>, span: &'cx dyn Locatable, body: &'tcx hir::Body<'tcx>, @@ -760,18 +768,18 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { span: &'cx dyn Locatable, body: &'tcx hir::Body<'tcx>, ) -> Resolver<'cx, 'tcx> { - Resolver { tcx: fcx.tcx, infcx: fcx, span, body, replaced_with_error: None } + Resolver { fcx, span, body, replaced_with_error: None } } fn report_error(&self, p: impl Into<ty::GenericArg<'tcx>>) -> ErrorGuaranteed { - match self.tcx.sess.has_errors() { + match self.fcx.tcx.sess.has_errors() { Some(e) => e, None => self - .infcx + .fcx .err_ctxt() .emit_inference_failure_err( - self.tcx.hir().body_owner_def_id(self.body.id()), - self.span.to_span(self.tcx), + self.fcx.tcx.hir().body_owner_def_id(self.body.id()), + self.span.to_span(self.fcx.tcx), p.into(), E0282, false, @@ -803,40 +811,46 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EraseEarlyRegions<'tcx> { impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> { fn interner(&self) -> TyCtxt<'tcx> { - self.tcx + self.fcx.tcx } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match self.infcx.fully_resolve(t) { + match self.fcx.fully_resolve(t) { + Ok(t) if self.fcx.tcx.trait_solver_next() => { + // We must normalize erasing regions here, since later lints + // expect that types that show up in the typeck are fully + // normalized. + self.fcx.tcx.try_normalize_erasing_regions(self.fcx.param_env, t).unwrap_or(t) + } Ok(t) => { // Do not anonymize late-bound regions // (e.g. keep `for<'a>` named `for<'a>`). // This allows NLL to generate error messages that // refer to the higher-ranked lifetime names written by the user. - EraseEarlyRegions { tcx: self.tcx }.fold_ty(t) + EraseEarlyRegions { tcx: self.fcx.tcx }.fold_ty(t) } Err(_) => { debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t); let e = self.report_error(t); self.replaced_with_error = Some(e); - self.interner().ty_error(e) + self.fcx.tcx.ty_error(e) } } } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { debug_assert!(!r.is_late_bound(), "Should not be resolving bound region."); - self.tcx.lifetimes.re_erased + self.fcx.tcx.lifetimes.re_erased } fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - match self.infcx.fully_resolve(ct) { - Ok(ct) => self.tcx.erase_regions(ct), + match self.fcx.fully_resolve(ct) { + Ok(ct) => self.fcx.tcx.erase_regions(ct), Err(_) => { debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct); let e = self.report_error(ct); self.replaced_with_error = Some(e); - self.interner().const_error(ct.ty(), e) + self.fcx.tcx.const_error(ct.ty(), e) } } } diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs index dc981c6179e..25bf83f64a0 100644 --- a/compiler/rustc_incremental/src/persist/file_format.rs +++ b/compiler/rustc_incremental/src/persist/file_format.rs @@ -14,6 +14,7 @@ use rustc_data_structures::memmap::Mmap; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_serialize::Encoder; use rustc_session::Session; +use std::borrow::Cow; use std::env; use std::fs; use std::io::{self, Read}; @@ -25,17 +26,12 @@ const FILE_MAGIC: &[u8] = b"RSIC"; /// Change this if the header format changes. const HEADER_FORMAT_VERSION: u16 = 0; -/// A version string that hopefully is always different for compiler versions -/// with different encodings of incremental compilation artifacts. Contains -/// the Git commit hash. -const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION"); - -pub(crate) fn write_file_header(stream: &mut FileEncoder, nightly_build: bool) { +pub(crate) fn write_file_header(stream: &mut FileEncoder, sess: &Session) { stream.emit_raw_bytes(FILE_MAGIC); stream .emit_raw_bytes(&[(HEADER_FORMAT_VERSION >> 0) as u8, (HEADER_FORMAT_VERSION >> 8) as u8]); - let rustc_version = rustc_version(nightly_build); + let rustc_version = rustc_version(sess.is_nightly_build(), sess.cfg_version); assert_eq!(rustc_version.len(), (rustc_version.len() as u8) as usize); stream.emit_raw_bytes(&[rustc_version.len() as u8]); stream.emit_raw_bytes(rustc_version.as_bytes()); @@ -73,7 +69,7 @@ where } }; - write_file_header(&mut encoder, sess.is_nightly_build()); + write_file_header(&mut encoder, sess); match encode(encoder) { Ok(position) => { @@ -100,9 +96,10 @@ where /// - Returns `Err(..)` if some kind of IO error occurred while reading the /// file. pub fn read_file( - report_incremental_info: bool, path: &Path, - nightly_build: bool, + report_incremental_info: bool, + is_nightly_build: bool, + cfg_version: &'static str, ) -> io::Result<Option<(Mmap, usize)>> { let file = match fs::File::open(path) { Ok(file) => file, @@ -152,7 +149,7 @@ pub fn read_file( let mut buffer = vec![0; rustc_version_str_len]; file.read_exact(&mut buffer)?; - if buffer != rustc_version(nightly_build).as_bytes() { + if buffer != rustc_version(is_nightly_build, cfg_version).as_bytes() { report_format_mismatch(report_incremental_info, path, "Different compiler version"); return Ok(None); } @@ -174,17 +171,15 @@ fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: & } } -fn rustc_version(nightly_build: bool) -> String { +/// A version string that hopefully is always different for compiler versions +/// with different encodings of incremental compilation artifacts. Contains +/// the Git commit hash. +fn rustc_version(nightly_build: bool, cfg_version: &'static str) -> Cow<'static, str> { if nightly_build { - if let Some(val) = env::var_os("RUSTC_FORCE_RUSTC_VERSION") { - return val.to_string_lossy().into_owned(); + if let Ok(val) = env::var("RUSTC_FORCE_RUSTC_VERSION") { + return val.into(); } } - RUSTC_VERSION - .expect( - "Cannot use rustc without explicit version for \ - incremental compilation", - ) - .to_string() + cfg_version.into() } diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index ec7fcbdf884..a4407a93ff3 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -73,12 +73,22 @@ impl<T: Default> LoadResult<T> { } } -fn load_data( - report_incremental_info: bool, +fn load_data(path: &Path, sess: &Session) -> LoadResult<(Mmap, usize)> { + load_data_no_sess( + path, + sess.opts.unstable_opts.incremental_info, + sess.is_nightly_build(), + sess.cfg_version, + ) +} + +fn load_data_no_sess( path: &Path, - nightly_build: bool, + report_incremental_info: bool, + is_nightly_build: bool, + cfg_version: &'static str, ) -> LoadResult<(Mmap, usize)> { - match file_format::read_file(report_incremental_info, path, nightly_build) { + match file_format::read_file(path, report_incremental_info, is_nightly_build, cfg_version) { Ok(Some(data_and_pos)) => LoadResult::Ok { data: data_and_pos }, Ok(None) => { // The file either didn't exist or was produced by an incompatible @@ -138,14 +148,13 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { let expected_hash = sess.opts.dep_tracking_hash(false); let mut prev_work_products = FxHashMap::default(); - let nightly_build = sess.is_nightly_build(); // If we are only building with -Zquery-dep-graph but without an actual // incr. comp. session directory, we skip this. Otherwise we'd fail // when trying to load work products. if sess.incr_comp_session_dir_opt().is_some() { let work_products_path = work_products_path(sess); - let load_result = load_data(report_incremental_info, &work_products_path, nightly_build); + let load_result = load_data(&work_products_path, sess); if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result { // Decode the list of work_products @@ -173,10 +182,13 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { } } + let is_nightly_build = sess.is_nightly_build(); + let cfg_version = sess.cfg_version; + MaybeAsync::Async(std::thread::spawn(move || { let _prof_timer = prof.generic_activity("incr_comp_load_dep_graph"); - match load_data(report_incremental_info, &path, nightly_build) { + match load_data_no_sess(&path, report_incremental_info, is_nightly_build, cfg_version) { LoadResult::DataOutOfDate => LoadResult::DataOutOfDate, LoadResult::LoadDepGraph(path, err) => LoadResult::LoadDepGraph(path, err), LoadResult::DecodeIncrCache(err) => LoadResult::DecodeIncrCache(err), @@ -218,11 +230,7 @@ pub fn load_query_result_cache(sess: &Session) -> Option<OnDiskCache<'_>> { let _prof_timer = sess.prof.generic_activity("incr_comp_load_query_result_cache"); - match load_data( - sess.opts.unstable_opts.incremental_info, - &query_cache_path(sess), - sess.is_nightly_build(), - ) { + match load_data(&query_cache_path(sess), sess) { LoadResult::Ok { data: (bytes, start_pos) } => { Some(OnDiskCache::new(sess, bytes, start_pos)) } diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 1441e64e41f..7376be6be8b 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -164,7 +164,7 @@ pub fn build_dep_graph( } }; - file_format::write_file_header(&mut encoder, sess.is_nightly_build()); + file_format::write_file_header(&mut encoder, sess); // First encode the commandline arguments hash sess.opts.dep_tracking_hash(false).encode(&mut encoder); diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 3605e10fecd..de9afbbcaab 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -153,20 +153,22 @@ impl<'tcx> InferCtxt<'tcx> { /// Used by the new solver as that one takes the opaque types at the end of a probe /// to deal with multiple candidates without having to recompute them. - pub fn clone_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> { + pub fn clone_opaque_types_for_query_response( + &self, + ) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { self.inner .borrow() .opaque_type_storage .opaque_types .iter() - .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)) + .map(|(k, v)| (*k, v.hidden_type.ty)) .collect() } - fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> { + fn take_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types) .into_iter() - .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)) + .map(|(k, v)| (k, v.hidden_type.ty)) .collect() } @@ -507,8 +509,22 @@ impl<'tcx> InferCtxt<'tcx> { let a = substitute_value(self.tcx, &result_subst, a); let b = substitute_value(self.tcx, &result_subst, b); debug!(?a, ?b, "constrain opaque type"); - obligations - .extend(self.at(cause, param_env).eq(DefineOpaqueTypes::Yes, a, b)?.obligations); + // We use equate here instead of, for example, just registering the + // opaque type's hidden value directly, because we may be instantiating + // a query response that was canonicalized in an InferCtxt that had + // a different defining anchor. In that case, we may have inferred + // `NonLocalOpaque := LocalOpaque` but can only instantiate it in + // the other direction as `LocalOpaque := NonLocalOpaque`. Using eq + // here allows us to try both directions (in `InferCtxt::handle_opaque_type`). + obligations.extend( + self.at(cause, param_env) + .eq( + DefineOpaqueTypes::Yes, + self.tcx.mk_opaque(a.def_id.to_def_id(), a.substs), + b, + )? + .obligations, + ); } Ok(InferOk { value: result_subst, obligations }) diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 545310ad351..b88ba04b273 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -530,19 +530,18 @@ impl<'tcx> InferCtxt<'tcx> { // these are the same span, but not in cases like `-> (impl // Foo, impl Bar)`. let span = cause.span; - - let mut obligations = vec![]; let prev = self.inner.borrow_mut().opaque_types().register( OpaqueTypeKey { def_id, substs }, OpaqueHiddenType { ty: hidden_ty, span }, origin, ); - if let Some(prev) = prev { - obligations = self - .at(&cause, param_env) + let mut obligations = if let Some(prev) = prev { + self.at(&cause, param_env) .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)? - .obligations; - } + .obligations + } else { + Vec::new() + }; let item_bounds = tcx.explicit_item_bounds(def_id); diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index c9e857141c9..681819703c2 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -80,7 +80,7 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String ($reason: expr) => { early_error( ErrorOutputType::default(), - &format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s), + format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s), ); }; } @@ -139,10 +139,7 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg { ($reason: expr) => { early_error( ErrorOutputType::default(), - &format!( - concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"), - s - ), + format!(concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"), s), ) }; } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index bbf9d9d515d..42d8d228091 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -89,6 +89,7 @@ pub fn register_plugins<'a>( crate_name, sess.crate_types().contains(&CrateType::Executable), sess.opts.cg.metadata.clone(), + sess.cfg_version, ); sess.stable_crate_id.set(stable_crate_id).expect("not yet initialized"); rustc_incremental::prepare_session_directory(sess, crate_name, stable_crate_id)?; @@ -486,6 +487,11 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P files.push(normalize_path(profile_sample.as_path().to_path_buf())); } + // Debugger visualizer files + for debugger_visualizer in tcx.debugger_visualizers(LOCAL_CRATE) { + files.push(normalize_path(debugger_visualizer.path.clone().unwrap())); + } + if sess.binary_dep_depinfo() { if let Some(ref backend) = sess.opts.unstable_opts.codegen_backend { if backend.contains('.') { diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 6483d51a0b9..c441a8ffd6f 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -369,7 +369,7 @@ impl Linker { if sess.opts.unstable_opts.no_link { let rlink_file = self.prepare_outputs.with_extension(config::RLINK_EXT); - CodegenResults::serialize_rlink(&rlink_file, &codegen_results) + CodegenResults::serialize_rlink(sess, &rlink_file, &codegen_results) .map_err(|error| sess.emit_fatal(FailedWritingFile { path: &rlink_file, error }))?; return Ok(()); } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 1bae771e373..28e719a40e5 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -52,7 +52,8 @@ fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) { output_file: None, temps_dir, }; - let sess = build_session(sessopts, io, None, registry, vec![], Default::default(), None, None); + let sess = + build_session(sessopts, io, None, registry, vec![], Default::default(), None, None, ""); (sess, cfg) } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 8d37b1053d8..cb19750203e 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -88,7 +88,7 @@ pub fn create_session( ) { Ok(bundle) => bundle, Err(e) => { - early_error(sopts.error_format, &format!("failed to load fluent bundle: {e}")); + early_error(sopts.error_format, format!("failed to load fluent bundle: {e}")); } }; @@ -104,6 +104,7 @@ pub fn create_session( lint_caps, file_loader, target_override, + rustc_version_str().unwrap_or("unknown"), ); codegen_backend.init(&sess); @@ -220,13 +221,13 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( fn load_backend_from_dylib(path: &Path) -> MakeBackendFn { let lib = unsafe { Library::new(path) }.unwrap_or_else(|err| { let err = format!("couldn't load codegen backend {path:?}: {err}"); - early_error(ErrorOutputType::default(), &err); + early_error(ErrorOutputType::default(), err); }); let backend_sym = unsafe { lib.get::<MakeBackendFn>(b"__rustc_codegen_backend") } .unwrap_or_else(|e| { let err = format!("couldn't load codegen backend: {e}"); - early_error(ErrorOutputType::default(), &err); + early_error(ErrorOutputType::default(), err); }); // Intentionally leak the dynamic library. We can't ever unload it @@ -320,7 +321,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M "failed to find a `codegen-backends` folder \ in the sysroot candidates:\n* {candidates}" ); - early_error(ErrorOutputType::default(), &err); + early_error(ErrorOutputType::default(), err); }); info!("probing {} for a codegen backend", sysroot.display()); @@ -331,7 +332,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M sysroot.display(), e ); - early_error(ErrorOutputType::default(), &err); + early_error(ErrorOutputType::default(), err); }); let mut file: Option<PathBuf> = None; @@ -359,7 +360,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M prev.display(), path.display() ); - early_error(ErrorOutputType::default(), &err); + early_error(ErrorOutputType::default(), err); } file = Some(path.clone()); } @@ -368,7 +369,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M Some(ref s) => load_backend_from_dylib(s), None => { let err = format!("unsupported builtin codegen backend `{backend_name}`"); - early_error(ErrorOutputType::default(), &err); + early_error(ErrorOutputType::default(), err); } } } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index a5639404faf..e1658d3ff82 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -521,18 +521,18 @@ lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its ass lint_opaque_hidden_inferred_bound_sugg = add this bound -lint_drop_ref = calls to `std::mem::drop` with a reference instead of an owned value does nothing +lint_dropping_references = calls to `std::mem::drop` with a reference instead of an owned value does nothing .label = argument has type `{$arg_ty}` .note = use `let _ = ...` to ignore the expression or result -lint_drop_copy = calls to `std::mem::drop` with a value that implements `Copy` does nothing +lint_dropping_copy_types = calls to `std::mem::drop` with a value that implements `Copy` does nothing .label = argument has type `{$arg_ty}` .note = use `let _ = ...` to ignore the expression or result -lint_forget_ref = calls to `std::mem::forget` with a reference instead of an owned value does nothing +lint_forgetting_references = calls to `std::mem::forget` with a reference instead of an owned value does nothing .label = argument has type `{$arg_ty}` .note = use `let _ = ...` to ignore the expression or result -lint_forget_copy = calls to `std::mem::forget` with a value that implements `Copy` does nothing +lint_forgetting_copy_types = calls to `std::mem::forget` with a value that implements `Copy` does nothing .label = argument has type `{$arg_ty}` .note = use `let _ = ...` to ignore the expression or result diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs index 259abc2af11..ed2b384805e 100644 --- a/compiler/rustc_lint/src/drop_forget_useless.rs +++ b/compiler/rustc_lint/src/drop_forget_useless.rs @@ -7,7 +7,7 @@ use crate::{ }; declare_lint! { - /// The `drop_ref` lint checks for calls to `std::mem::drop` with a reference + /// The `dropping_references` lint checks for calls to `std::mem::drop` with a reference /// instead of an owned value. /// /// ### Example @@ -29,13 +29,13 @@ declare_lint! { /// reference itself, which is a no-op. It will not call the `drop` method (from /// the `Drop` trait implementation) on the underlying referenced value, which /// is likely what was intended. - pub DROP_REF, + pub DROPPING_REFERENCES, Warn, "calls to `std::mem::drop` with a reference instead of an owned value" } declare_lint! { - /// The `forget_ref` lint checks for calls to `std::mem::forget` with a reference + /// The `forgetting_references` lint checks for calls to `std::mem::forget` with a reference /// instead of an owned value. /// /// ### Example @@ -52,13 +52,13 @@ declare_lint! { /// Calling `forget` on a reference will only forget the /// reference itself, which is a no-op. It will not forget the underlying /// referenced value, which is likely what was intended. - pub FORGET_REF, + pub FORGETTING_REFERENCES, Warn, "calls to `std::mem::forget` with a reference instead of an owned value" } declare_lint! { - /// The `drop_copy` lint checks for calls to `std::mem::drop` with a value + /// The `dropping_copy_types` lint checks for calls to `std::mem::drop` with a value /// that derives the Copy trait. /// /// ### Example @@ -76,13 +76,13 @@ declare_lint! { /// Calling `std::mem::drop` [does nothing for types that /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html), since the /// value will be copied and moved into the function on invocation. - pub DROP_COPY, + pub DROPPING_COPY_TYPES, Warn, "calls to `std::mem::drop` with a value that implements Copy" } declare_lint! { - /// The `forget_copy` lint checks for calls to `std::mem::forget` with a value + /// The `forgetting_copy_types` lint checks for calls to `std::mem::forget` with a value /// that derives the Copy trait. /// /// ### Example @@ -104,12 +104,12 @@ declare_lint! { /// An alternative, but also valid, explanation is that Copy types do not /// implement the Drop trait, which means they have no destructors. Without a /// destructor, there is nothing for `std::mem::forget` to ignore. - pub FORGET_COPY, + pub FORGETTING_COPY_TYPES, Warn, "calls to `std::mem::forget` with a value that implements Copy" } -declare_lint_pass!(DropForgetUseless => [DROP_REF, FORGET_REF, DROP_COPY, FORGET_COPY]); +declare_lint_pass!(DropForgetUseless => [DROPPING_REFERENCES, FORGETTING_REFERENCES, DROPPING_COPY_TYPES, FORGETTING_COPY_TYPES]); impl<'tcx> LateLintPass<'tcx> for DropForgetUseless { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { @@ -123,16 +123,16 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless { let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr); match fn_name { sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => { - cx.emit_spanned_lint(DROP_REF, expr.span, DropRefDiag { arg_ty, label: arg.span }); + cx.emit_spanned_lint(DROPPING_REFERENCES, expr.span, DropRefDiag { arg_ty, label: arg.span }); }, sym::mem_forget if arg_ty.is_ref() => { - cx.emit_spanned_lint(FORGET_REF, expr.span, ForgetRefDiag { arg_ty, label: arg.span }); + cx.emit_spanned_lint(FORGETTING_REFERENCES, expr.span, ForgetRefDiag { arg_ty, label: arg.span }); }, sym::mem_drop if is_copy && !drop_is_single_call_in_arm => { - cx.emit_spanned_lint(DROP_COPY, expr.span, DropCopyDiag { arg_ty, label: arg.span }); + cx.emit_spanned_lint(DROPPING_COPY_TYPES, expr.span, DropCopyDiag { arg_ty, label: arg.span }); } sym::mem_forget if is_copy => { - cx.emit_spanned_lint(FORGET_COPY, expr.span, ForgetCopyDiag { arg_ty, label: arg.span }); + cx.emit_spanned_lint(FORGETTING_COPY_TYPES, expr.span, ForgetCopyDiag { arg_ty, label: arg.span }); } _ => return, }; diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 8e48806b504..de1c2be2875 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -662,9 +662,9 @@ pub struct ForLoopsOverFalliblesSuggestion<'a> { pub end_span: Span, } -// drop_ref.rs +// drop_forget_useless.rs #[derive(LintDiagnostic)] -#[diag(lint_drop_ref)] +#[diag(lint_dropping_references)] #[note] pub struct DropRefDiag<'a> { pub arg_ty: Ty<'a>, @@ -673,7 +673,7 @@ pub struct DropRefDiag<'a> { } #[derive(LintDiagnostic)] -#[diag(lint_drop_copy)] +#[diag(lint_dropping_copy_types)] #[note] pub struct DropCopyDiag<'a> { pub arg_ty: Ty<'a>, @@ -682,7 +682,7 @@ pub struct DropCopyDiag<'a> { } #[derive(LintDiagnostic)] -#[diag(lint_forget_ref)] +#[diag(lint_forgetting_references)] #[note] pub struct ForgetRefDiag<'a> { pub arg_ty: Ty<'a>, @@ -691,7 +691,7 @@ pub struct ForgetRefDiag<'a> { } #[derive(LintDiagnostic)] -#[diag(lint_forget_copy)] +#[diag(lint_forgetting_copy_types)] #[note] pub struct ForgetCopyDiag<'a> { pub arg_ty: Ty<'a>, diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index eb175e96997..0fe140e08d2 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -103,8 +103,10 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { && let ty = cx.typeck_results().expr_ty(&await_expr) && let ty::Alias(ty::Opaque, ty::AliasTy { def_id: future_def_id, .. }) = ty.kind() && cx.tcx.ty_is_opaque_future(ty) - // FIXME: This also includes non-async fns that return `impl Future`. && let async_fn_def_id = cx.tcx.parent(*future_def_id) + && matches!(cx.tcx.def_kind(async_fn_def_id), DefKind::Fn | DefKind::AssocFn) + // Check that this `impl Future` actually comes from an `async fn` + && cx.tcx.asyncness(async_fn_def_id).is_async() && check_must_use_def( cx, async_fn_def_id, diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 7b774d6865c..c43a0272477 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1463,63 +1463,6 @@ LLVMRustGetBitcodeSliceFromObjectData(const char *data, return BitcodeOrError->getBufferStart(); } -// Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See -// the comment in `back/lto.rs` for why this exists. -extern "C" void -LLVMRustThinLTOGetDICompileUnit(LLVMModuleRef Mod, - DICompileUnit **A, - DICompileUnit **B) { - Module *M = unwrap(Mod); - DICompileUnit **Cur = A; - DICompileUnit **Next = B; - for (DICompileUnit *CU : M->debug_compile_units()) { - *Cur = CU; - Cur = Next; - Next = nullptr; - if (Cur == nullptr) - break; - } -} - -// Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See -// the comment in `back/lto.rs` for why this exists. -extern "C" void -LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) { - Module *M = unwrap(Mod); - - // If the original source module didn't have a `DICompileUnit` then try to - // merge all the existing compile units. If there aren't actually any though - // then there's not much for us to do so return. - if (Unit == nullptr) { - for (DICompileUnit *CU : M->debug_compile_units()) { - Unit = CU; - break; - } - if (Unit == nullptr) - return; - } - - // Use LLVM's built-in `DebugInfoFinder` to find a bunch of debuginfo and - // process it recursively. Note that we used to specifically iterate over - // instructions to ensure we feed everything into it, but `processModule` - // started doing this the same way in LLVM 7 (commit d769eb36ab2b8). - DebugInfoFinder Finder; - Finder.processModule(*M); - - // After we've found all our debuginfo, rewrite all subprograms to point to - // the same `DICompileUnit`. - for (auto &F : Finder.subprograms()) { - F->replaceUnit(Unit); - } - - // Erase any other references to other `DICompileUnit` instances, the verifier - // will later ensure that we don't actually have any other stale references to - // worry about. - auto *MD = M->getNamedMetadata("llvm.dbg.cu"); - MD->clearOperands(); - MD->addOperand(Unit); -} - // Computes the LTO cache key for the provided 'ModId' in the given 'Data', // storing the result in 'KeyOut'. // Currently, this cache key is a SHA-1 hash of anything that could affect diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 001d53b1099..d0d41c614d6 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -253,7 +253,7 @@ fn add_query_desc_cached_impl( quote! { #[allow(unused_variables, unused_braces, rustc::pass_by_value)] #[inline] - pub fn #name<'tcx>(#tcx: TyCtxt<'tcx>, #key: &crate::query::query_keys::#name<'tcx>) -> bool { + pub fn #name<'tcx>(#tcx: TyCtxt<'tcx>, #key: &crate::query::queries::#name::Key<'tcx>) -> bool { #expr } } @@ -262,7 +262,7 @@ fn add_query_desc_cached_impl( // we're taking `key` by reference, but some rustc types usually prefer being passed by value #[allow(rustc::pass_by_value)] #[inline] - pub fn #name<'tcx>(_: TyCtxt<'tcx>, _: &crate::query::query_keys::#name<'tcx>) -> bool { + pub fn #name<'tcx>(_: TyCtxt<'tcx>, _: &crate::query::queries::#name::Key<'tcx>) -> bool { false } } @@ -273,7 +273,7 @@ fn add_query_desc_cached_impl( let desc = quote! { #[allow(unused_variables)] - pub fn #name<'tcx>(tcx: TyCtxt<'tcx>, key: crate::query::query_keys::#name<'tcx>) -> String { + pub fn #name<'tcx>(tcx: TyCtxt<'tcx>, key: crate::query::queries::#name::Key<'tcx>) -> String { let (#tcx, #key) = (tcx, key); ::rustc_middle::ty::print::with_no_trimmed_paths!( format!(#desc) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index e6e7d25773e..209bf395624 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -148,11 +148,15 @@ impl CStore { assert_eq!(self.metas.len(), self.stable_crate_ids.len()); let num = CrateNum::new(self.stable_crate_ids.len()); if let Some(&existing) = self.stable_crate_ids.get(&root.stable_crate_id()) { - let crate_name0 = root.name(); - if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name()) { + // Check for (potential) conflicts with the local crate + if existing == LOCAL_CRATE { + Err(CrateError::SymbolConflictsCurrent(root.name())) + } else if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name()) + { + let crate_name0 = root.name(); Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1)) } else { - Err(CrateError::SymbolConflictsCurrent(crate_name0)) + Err(CrateError::NotFound(root.name())) } } else { self.metas.push(None); @@ -943,7 +947,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { lint::builtin::UNUSED_CRATE_DEPENDENCIES, span, ast::CRATE_NODE_ID, - &format!( + format!( "external crate `{}` unused in `{}`: remove the dependency or add `use {} as _;`", name, self.tcx.crate_name(LOCAL_CRATE), diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index c6af8d63289..1aab4adf0b3 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -220,7 +220,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::owned_slice::slice_owned; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::MetadataRef; use rustc_errors::{DiagnosticArgValue, FatalError, IntoDiagnosticArg}; use rustc_fs_util::try_canonicalize; use rustc_session::config::{self, CrateType}; @@ -246,6 +245,7 @@ pub(crate) struct CrateLocator<'a> { only_needs_metadata: bool, sysroot: &'a Path, metadata_loader: &'a dyn MetadataLoader, + cfg_version: &'static str, // Immutable per-search configuration. crate_name: Symbol, @@ -323,6 +323,7 @@ impl<'a> CrateLocator<'a> { only_needs_metadata, sysroot: &sess.sysroot, metadata_loader, + cfg_version: sess.cfg_version, crate_name, exact_paths: if hash.is_none() { sess.opts @@ -655,7 +656,7 @@ impl<'a> CrateLocator<'a> { } fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<Svh> { - let rustc_version = rustc_version(); + let rustc_version = rustc_version(self.cfg_version); let found_version = metadata.get_rustc_version(); if found_version != rustc_version { info!("Rejecting via version: expected {} got {}", rustc_version, found_version); @@ -782,7 +783,7 @@ fn get_metadata_section<'p>( if !filename.exists() { return Err(MetadataError::NotPresent(filename)); } - let raw_bytes: MetadataRef = match flavor { + let raw_bytes = match flavor { CrateFlavor::Rlib => { loader.get_rlib_metadata(target, filename).map_err(MetadataError::LoadFailure)? } @@ -843,7 +844,7 @@ fn get_metadata_section<'p>( slice_owned(mmap, Deref::deref) } }; - let blob = MetadataBlob::new(raw_bytes); + let blob = MetadataBlob(raw_bytes); if blob.is_compatible() { Ok(blob) } else { @@ -960,6 +961,7 @@ pub(crate) enum CrateError { DlSym(String), LocatorCombined(Box<CombinedLocatorError>), NonDylibPlugin(Symbol), + NotFound(Symbol), } enum MetadataError<'a> { @@ -1097,7 +1099,7 @@ impl CrateError { crate_name, add_info, found_crates, - rustc_version: rustc_version(), + rustc_version: rustc_version(sess.cfg_version), }); } else if !locator.crate_rejections.via_invalid.is_empty() { let mut crate_rejections = Vec::new(); @@ -1130,6 +1132,18 @@ impl CrateError { CrateError::NonDylibPlugin(crate_name) => { sess.emit_err(errors::NoDylibPlugin { span, crate_name }); } + CrateError::NotFound(crate_name) => { + sess.emit_err(errors::CannotFindCrate { + span, + crate_name, + add_info: String::new(), + missing_core, + current_crate: sess.opts.crate_name.clone().unwrap_or("<unknown>".to_string()), + is_nightly_build: sess.is_nightly_build(), + profiler_runtime: Symbol::intern(&sess.opts.unstable_opts.profiler_runtime), + locator_triple: sess.opts.target_triple.clone(), + }); + } } } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 1c36d5e82da..834e2453ee0 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -7,6 +7,7 @@ use crate::rmeta::*; use rustc_ast as ast; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::owned_slice::OwnedSlice; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc, OnceCell}; use rustc_data_structures::unhash::UnhashMap; @@ -18,6 +19,7 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; use rustc_hir::diagnostic_items::DiagnosticItems; use rustc_index::{Idx, IndexVec}; use rustc_middle::metadata::ModChild; +use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::ty::codec::TyDecoder; @@ -50,7 +52,7 @@ mod cstore_impl; /// A `MetadataBlob` internally is just a reference counted pointer to /// the actual data, so cloning it is cheap. #[derive(Clone)] -pub(crate) struct MetadataBlob(Lrc<MetadataRef>); +pub(crate) struct MetadataBlob(pub(crate) OwnedSlice); impl std::ops::Deref for MetadataBlob { type Target = [u8]; @@ -660,10 +662,6 @@ impl<'a, 'tcx, I: Idx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyTable<I, T> implement_ty_decoder!(DecodeContext<'a, 'tcx>); impl MetadataBlob { - pub(crate) fn new(metadata_ref: MetadataRef) -> MetadataBlob { - MetadataBlob(Lrc::new(metadata_ref)) - } - pub(crate) fn is_compatible(&self) -> bool { self.blob().starts_with(METADATA_HEADER) } @@ -961,7 +959,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, sess)) } - fn get_debugger_visualizers(self) -> Vec<rustc_span::DebuggerVisualizerFile> { + fn get_debugger_visualizers(self) -> Vec<DebuggerVisualizerFile> { self.root.debugger_visualizers.decode(self).collect::<Vec<_>>() } @@ -1254,14 +1252,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn is_foreign_item(self, id: DefIndex) -> bool { - if let Some(parent) = self.def_key(id).parent { - matches!(self.def_kind(parent), DefKind::ForeignMod) - } else { - false - } - } - #[inline] fn def_key(self, index: DefIndex) -> DefKey { *self diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index fe880b939ef..7425963d30f 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -114,8 +114,8 @@ macro_rules! provide_one { ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => $compute:block) => { fn $name<'tcx>( $tcx: TyCtxt<'tcx>, - def_id_arg: rustc_middle::query::query_keys::$name<'tcx>, - ) -> rustc_middle::query::query_provided::$name<'tcx> { + def_id_arg: rustc_middle::query::queries::$name::Key<'tcx>, + ) -> rustc_middle::query::queries::$name::ProvidedValue<'tcx> { let _prof_timer = $tcx.prof.generic_activity(concat!("metadata_decode_entry_", stringify!($name))); @@ -280,7 +280,6 @@ provide! { tcx, def_id, other, cdata, } associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) } inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) } - is_foreign_item => { cdata.is_foreign_item(def_id.index) } item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) } is_mir_available => { cdata.is_item_mir_available(def_id.index) } is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) } @@ -324,7 +323,7 @@ provide! { tcx, def_id, other, cdata, extra_filename => { cdata.root.extra_filename.clone() } - traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) } + traits => { tcx.arena.alloc_from_iter(cdata.get_traits()) } trait_impls_in_crate => { tcx.arena.alloc_from_iter(cdata.get_trait_impls()) } implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) } crate_incoherent_impls => { cdata.get_incoherent_impls(tcx, other) } diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs index 05402a58701..4f280bb9d80 100644 --- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs +++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs @@ -1,6 +1,5 @@ use crate::rmeta::DecodeContext; use crate::rmeta::EncodeContext; -use rustc_data_structures::owned_slice::slice_owned; use rustc_data_structures::owned_slice::OwnedSlice; use rustc_hir::def_path_hash_map::{Config as HashMapConfig, DefPathHashMap}; use rustc_middle::parameterized_over_tcx; @@ -47,7 +46,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefPathHashMapRef<'static> fn decode(d: &mut DecodeContext<'a, 'tcx>) -> DefPathHashMapRef<'static> { let len = d.read_usize(); let pos = d.position(); - let o = slice_owned(d.blob().clone(), |blob| &blob[pos..pos + len]); + let o = d.blob().clone().0.slice(|blob| &blob[pos..pos + len]); // Although we already have the data we need via the `OwnedSlice`, we still need // to advance the `DecodeContext`'s position so it's in a valid state after diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 79eb48a1a31..f067bca4b0b 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -19,6 +19,7 @@ use rustc_hir::definitions::DefPathData; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::lang_items::LangItem; use rustc_middle::hir::nested_filter; +use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::{ metadata_symbol_name, ExportedSymbol, SymbolExportInfo, @@ -36,9 +37,7 @@ use rustc_session::config::{CrateType, OptLevel}; use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib}; use rustc_span::hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind}; use rustc_span::symbol::{sym, Symbol}; -use rustc_span::{ - self, DebuggerVisualizerFile, ExternalSource, FileName, SourceFile, Span, SyntaxContext, -}; +use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext}; use std::borrow::Borrow; use std::collections::hash_map::Entry; use std::hash::Hash; @@ -1855,7 +1854,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_debugger_visualizers(&mut self) -> LazyArray<DebuggerVisualizerFile> { empty_proc_macro!(self); - self.lazy_array(self.tcx.debugger_visualizers(LOCAL_CRATE).iter()) + self.lazy_array( + self.tcx + .debugger_visualizers(LOCAL_CRATE) + .iter() + // Erase the path since it may contain privacy sensitive data + // that we don't want to end up in crate metadata. + // The path is only needed for the local crate because of + // `--emit dep-info`. + .map(DebuggerVisualizerFile::path_erased), + ) } fn encode_crate_deps(&mut self) -> LazyArray<CrateDep> { @@ -1930,7 +1938,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_traits(&mut self) -> LazyArray<DefIndex> { empty_proc_macro!(self); - self.lazy_array(self.tcx.traits_in_crate(LOCAL_CRATE).iter().map(|def_id| def_id.index)) + self.lazy_array(self.tcx.traits(LOCAL_CRATE).iter().map(|def_id| def_id.index)) } /// Encodes an index, mapping each trait to its (local) implementations. @@ -2276,7 +2284,7 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) { }; // Encode the rustc version string in a predictable location. - rustc_version().encode(&mut ecx); + rustc_version(tcx.sess.cfg_version).encode(&mut ecx); // Encode all the entries and extra information in the crate, // culminating in the `CrateRoot` which points to all of it. @@ -2321,7 +2329,7 @@ pub fn provide(providers: &mut Providers) { .get(&def_id) .expect("no traits in scope for a doc link") }, - traits_in_crate: |tcx, LocalCrate| { + traits: |tcx, LocalCrate| { let mut traits = Vec::new(); for id in tcx.hir().items() { if matches!(tcx.def_kind(id.owner_id), DefKind::Trait | DefKind::TraitAlias) { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 9eaf330b536..97e67fcf8fd 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -2,12 +2,12 @@ use crate::creader::CrateMetadataRef; use decoder::Metadata; use def_path_hash_map::DefPathHashMapRef; use rustc_data_structures::fx::FxHashMap; +use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use table::TableBuilder; use rustc_ast as ast; use rustc_attr as attr; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::MetadataRef; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, DefPathHash, StableCrateId}; @@ -49,8 +49,8 @@ mod def_path_hash_map; mod encoder; mod table; -pub(crate) fn rustc_version() -> String { - format!("rustc {}", option_env!("CFG_VERSION").unwrap_or("unknown version")) +pub(crate) fn rustc_version(cfg_version: &'static str) -> String { + format!("rustc {}", cfg_version) } /// Metadata encoding version. @@ -246,7 +246,7 @@ pub(crate) struct CrateRoot { proc_macro_data: Option<ProcMacroData>, tables: LazyTables, - debugger_visualizers: LazyArray<rustc_span::DebuggerVisualizerFile>, + debugger_visualizers: LazyArray<DebuggerVisualizerFile>, exported_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>, diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index c6bbf2ef0cd..64d511c261a 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -39,5 +39,7 @@ middle_strict_coherence_needs_negative_coherence = to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled .label = due to this attribute +middle_requires_lang_item = requires `{$name}` lang_item + middle_const_not_used_in_type_alias = const parameter `{$ct}` is part of concrete type but not used in parameter list for the `impl Trait` type alias diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index dc4aa18640f..046186d274c 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -1,5 +1,5 @@ use rustc_macros::Diagnostic; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use crate::ty::Ty; @@ -74,6 +74,14 @@ pub(crate) struct StrictCoherenceNeedsNegativeCoherence { } #[derive(Diagnostic)] +#[diag(middle_requires_lang_item)] +pub(crate) struct RequiresLangItem { + #[primary_span] + pub span: Option<Span>, + pub name: Symbol, +} + +#[derive(Diagnostic)] #[diag(middle_const_not_used_in_type_alias)] pub(super) struct ConstNotUsedTraitAlias { pub ct: String, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 5bf0938d518..3b59df778dc 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1,4 +1,5 @@ use crate::hir::{ModuleItems, Owner}; +use crate::middle::debugger_visualizer::DebuggerVisualizerFile; use crate::query::LocalCrate; use crate::ty::TyCtxt; use rustc_ast as ast; @@ -1165,11 +1166,26 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh { source_file_names.sort_unstable(); + // We have to take care of debugger visualizers explicitly. The HIR (and + // thus `hir_body_hash`) contains the #[debugger_visualizer] attributes but + // these attributes only store the file path to the visualizer file, not + // their content. Yet that content is exported into crate metadata, so any + // changes to it need to be reflected in the crate hash. + let debugger_visualizers: Vec<_> = tcx + .debugger_visualizers(LOCAL_CRATE) + .iter() + // We ignore the path to the visualizer file since it's not going to be + // encoded in crate metadata and we already hash the full contents of + // the file. + .map(DebuggerVisualizerFile::path_erased) + .collect(); + let crate_hash: Fingerprint = tcx.with_stable_hashing_context(|mut hcx| { let mut stable_hasher = StableHasher::new(); hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher); upstream_crates.hash_stable(&mut hcx, &mut stable_hasher); source_file_names.hash_stable(&mut hcx, &mut stable_hasher); + debugger_visualizers.hash_stable(&mut hcx, &mut stable_hasher); if tcx.sess.opts.incremental_relative_spans() { let definitions = tcx.definitions_untracked(); let mut owner_spans: Vec<_> = krate diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 61c9e72db2c..ac0b2844177 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -10,6 +10,7 @@ use crate::query::Providers; use crate::ty::{EarlyBinder, ImplSubject, TyCtxt}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{par_for_each_in, DynSend, DynSync}; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::*; use rustc_query_system::ich::StableHashingContext; @@ -110,6 +111,12 @@ impl<'tcx> TyCtxt<'tcx> { None => self.type_of(def_id).map_bound(ImplSubject::Inherent), } } + + /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`). + pub fn is_foreign_item(self, def_id: impl Into<DefId>) -> bool { + self.opt_parent(def_id.into()) + .map_or(false, |parent| matches!(self.def_kind(parent), DefKind::ForeignMod)) + } } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index c4e41e00520..56171314944 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -280,7 +280,7 @@ pub struct QueryResponse<'tcx, R> { /// should get its hidden type inferred. So we bubble the opaque type /// and the type it was compared against upwards and let the query caller /// handle it. - pub opaque_types: Vec<(Ty<'tcx>, Ty<'tcx>)>, + pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, pub value: R, } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index dc911c88574..22ee2a8c5e5 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -95,7 +95,6 @@ pub mod middle; pub mod mir; pub mod thir; pub mod traits; -#[macro_use] pub mod ty; pub mod util; mod values; diff --git a/compiler/rustc_middle/src/middle/debugger_visualizer.rs b/compiler/rustc_middle/src/middle/debugger_visualizer.rs new file mode 100644 index 00000000000..a0497d805da --- /dev/null +++ b/compiler/rustc_middle/src/middle/debugger_visualizer.rs @@ -0,0 +1,38 @@ +use rustc_data_structures::sync::Lrc; +use std::path::PathBuf; + +#[derive(HashStable)] +#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)] +pub enum DebuggerVisualizerType { + Natvis, + GdbPrettyPrinter, +} + +/// A single debugger visualizer file. +#[derive(HashStable)] +#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)] +pub struct DebuggerVisualizerFile { + /// The complete debugger visualizer source. + pub src: Lrc<[u8]>, + /// Indicates which visualizer type this targets. + pub visualizer_type: DebuggerVisualizerType, + /// The file path to the visualizer file. This is used for reporting + /// visualizer files in dep-info. Before it is written to crate metadata, + /// the path is erased to `None`, so as not to emit potentially privacy + /// sensitive data. + pub path: Option<PathBuf>, +} + +impl DebuggerVisualizerFile { + pub fn new(src: Lrc<[u8]>, visualizer_type: DebuggerVisualizerType, path: PathBuf) -> Self { + DebuggerVisualizerFile { src, visualizer_type, path: Some(path) } + } + + pub fn path_erased(&self) -> Self { + DebuggerVisualizerFile { + src: self.src.clone(), + visualizer_type: self.visualizer_type, + path: None, + } + } +} diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index 343ea1f00f5..9a633e04ce7 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -18,12 +18,8 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns the `DefId` for a given `LangItem`. /// If not found, fatally aborts compilation. pub fn require_lang_item(self, lang_item: LangItem, span: Option<Span>) -> DefId { - self.lang_items().require(lang_item).unwrap_or_else(|err| { - if let Some(span) = span { - self.sess.span_fatal(span, err.to_string()) - } else { - self.sess.fatal(err.to_string()) - } + self.lang_items().get(lang_item).unwrap_or_else(|| { + self.sess.emit_fatal(crate::error::RequiresLangItem { span, name: lang_item.name() }); }) } diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs index 9bb4570ef14..85c5af9ca13 100644 --- a/compiler/rustc_middle/src/middle/mod.rs +++ b/compiler/rustc_middle/src/middle/mod.rs @@ -1,4 +1,5 @@ pub mod codegen_fn_attrs; +pub mod debugger_visualizer; pub mod dependency_format; pub mod exported_symbols; pub mod lang_items; diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index d65ceef2472..055d8e9a352 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,7 +1,8 @@ use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar}; use crate::mir::interpret::ConstValue; -use crate::ty::{layout, query::TyCtxtAt, tls, Ty, ValTree}; +use crate::query::TyCtxtAt; +use crate::ty::{layout, tls, Ty, ValTree}; use rustc_data_structures::sync::Lock; use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorGuaranteed}; diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index ce11dabc195..f53dc8cb0ec 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -1,9 +1,10 @@ use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId}; use crate::mir; +use crate::query::{TyCtxtAt, TyCtxtEnsure}; use crate::ty::subst::InternalSubsts; use crate::ty::visit::TypeVisitableExt; -use crate::ty::{self, query::TyCtxtAt, query::TyCtxtEnsure, TyCtxt}; +use crate::ty::{self, TyCtxt}; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_session::lint; diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 1da94dd7917..5c71910a955 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -101,7 +101,7 @@ impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> { /// pass will be named after the type, and it will consist of a main /// loop that goes over each available MIR and applies `run_pass`. pub trait MirPass<'tcx> { - fn name(&self) -> &str { + fn name(&self) -> &'static str { let name = std::any::type_name::<Self>(); if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 33b7fe0c2dc..21faf1958e9 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -749,6 +749,29 @@ pub enum TerminatorKind<'tcx> { }, } +impl TerminatorKind<'_> { + /// Returns a simple string representation of a `TerminatorKind` variant, independent of any + /// values it might hold (e.g. `TerminatorKind::Call` always returns `"Call"`). + pub const fn name(&self) -> &'static str { + match self { + TerminatorKind::Goto { .. } => "Goto", + TerminatorKind::SwitchInt { .. } => "SwitchInt", + TerminatorKind::Resume => "Resume", + TerminatorKind::Terminate => "Terminate", + TerminatorKind::Return => "Return", + TerminatorKind::Unreachable => "Unreachable", + TerminatorKind::Drop { .. } => "Drop", + TerminatorKind::Call { .. } => "Call", + TerminatorKind::Assert { .. } => "Assert", + TerminatorKind::Yield { .. } => "Yield", + TerminatorKind::GeneratorDrop => "GeneratorDrop", + TerminatorKind::FalseEdge { .. } => "FalseEdge", + TerminatorKind::FalseUnwind { .. } => "FalseUnwind", + TerminatorKind::InlineAsm { .. } => "InlineAsm", + } + } +} + /// Action to be taken when a stack unwind happens. #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] #[derive(TypeFoldable, TypeVisitable)] diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index b45f7caaabe..fd02a16130f 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -28,7 +28,7 @@ pub fn erase<T: EraseType>(src: T) -> Erase<T> { }; Erased::<<T as EraseType>::Result> { - // SAFETY: Is it safe to transmute to MaybeUninit for types with the same sizes. + // SAFETY: It is safe to transmute to MaybeUninit for types with the same sizes. data: unsafe { transmute_copy(&src) }, } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index f564f5e99e8..1528be42f6a 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -12,6 +12,7 @@ use crate::infer::canonical::{self, Canonical}; use crate::lint::LintExpectation; use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; +use crate::middle::debugger_visualizer::DebuggerVisualizerFile; use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use crate::middle::lib_features::LibFeatures; use crate::middle::privacy::EffectiveVisibilities; @@ -25,6 +26,7 @@ use crate::mir::interpret::{ use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; use crate::query::erase::{erase, restore, Erase}; +use crate::query::plumbing::{query_ensure, query_get_at, DynamicQuery}; use crate::thir; use crate::traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, @@ -36,13 +38,12 @@ use crate::traits::query::{ OutlivesBound, }; use crate::traits::specialization_graph; -use crate::traits::{self, ImplSource}; +use crate::traits::{ + CanonicalChalkEnvironmentAndGoal, CodegenObligationError, EvaluationResult, ImplSource, + ObjectSafetyViolation, ObligationCause, OverflowError, WellFormedLoc, +}; use crate::ty::fast_reject::SimplifiedType; use crate::ty::layout::ValidityRequirement; -use crate::ty::query::{ - query_ensure, query_get_at, DynamicQuery, IntoQueryParam, TyCtxtAt, TyCtxtEnsure, - TyCtxtEnsureWithValue, -}; use crate::ty::subst::{GenericArg, SubstsRef}; use crate::ty::util::AlwaysRequiresDrop; use crate::ty::GeneratorDiagnosticData; @@ -90,8 +91,11 @@ use std::sync::Arc; pub mod erase; mod keys; -pub mod on_disk_cache; pub use keys::{AsLocalKey, Key, LocalCrate}; +pub mod on_disk_cache; +#[macro_use] +pub mod plumbing; +pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsure, TyCtxtEnsureWithValue}; // Each of these queries corresponds to a function pointer field in the // `Providers` struct for requesting a value of that type, and a method @@ -726,12 +730,6 @@ rustc_queries! { desc { |tcx| "checking if item is promotable: `{}`", tcx.def_path_str(key) } } - /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`). - query is_foreign_item(key: DefId) -> bool { - desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) } - separate_provide_extern - } - /// Returns `Some(generator_kind)` if the node pointed to by `def_id` is a generator. query generator_kind(def_id: DefId) -> Option<hir::GeneratorKind> { desc { |tcx| "looking up generator kind of `{}`", tcx.def_path_str(def_id) } @@ -1278,7 +1276,7 @@ rustc_queries! { query codegen_select_candidate( key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) - ) -> Result<&'tcx ImplSource<'tcx, ()>, traits::CodegenObligationError> { + ) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> { cache_on_disk_if { true } desc { |tcx| "computing candidate for `{}`", key.1 } } @@ -1299,7 +1297,7 @@ rustc_queries! { desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) } cache_on_disk_if { true } } - query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] { + query object_safety_violations(trait_id: DefId) -> &'tcx [ObjectSafetyViolation] { desc { |tcx| "determining object safety of trait `{}`", tcx.def_path_str(trait_id) } } query check_is_object_safe(trait_id: DefId) -> bool { @@ -1790,12 +1788,18 @@ rustc_queries! { desc { "looking at the source for a crate" } separate_provide_extern } + /// Returns the debugger visualizers defined for this crate. - query debugger_visualizers(_: CrateNum) -> &'tcx Vec<rustc_span::DebuggerVisualizerFile> { + /// NOTE: This query has to be marked `eval_always` because it reads data + /// directly from disk that is not tracked anywhere else. I.e. it + /// represents a genuine input to the query system. + query debugger_visualizers(_: CrateNum) -> &'tcx Vec<DebuggerVisualizerFile> { arena_cache desc { "looking up the debugger visualizers for this crate" } separate_provide_extern + eval_always } + query postorder_cnums(_: ()) -> &'tcx [CrateNum] { eval_always desc { "generating a postorder list of CrateNums" } @@ -1837,8 +1841,7 @@ rustc_queries! { } /// A list of all traits in a crate, used by rustdoc and error reporting. - /// NOTE: Not named just `traits` due to a naming conflict. - query traits_in_crate(_: CrateNum) -> &'tcx [DefId] { + query traits(_: CrateNum) -> &'tcx [DefId] { desc { "fetching all traits in a crate" } separate_provide_extern } @@ -1952,12 +1955,12 @@ rustc_queries! { /// `infcx.predicate_must_hold()` instead. query evaluate_obligation( goal: CanonicalPredicateGoal<'tcx> - ) -> Result<traits::EvaluationResult, traits::OverflowError> { + ) -> Result<EvaluationResult, OverflowError> { desc { "evaluating trait selection obligation `{}`", goal.value.value } } query evaluate_goal( - goal: traits::CanonicalChalkEnvironmentAndGoal<'tcx> + goal: CanonicalChalkEnvironmentAndGoal<'tcx> ) -> Result< &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, NoSolution @@ -2127,8 +2130,8 @@ rustc_queries! { /// all of the cases that the normal `ty::Ty`-based wfcheck does. This is fine, /// because the `ty::Ty`-based wfcheck is always run. query diagnostic_hir_wf_check( - key: (ty::Predicate<'tcx>, traits::WellFormedLoc) - ) -> &'tcx Option<traits::ObligationCause<'tcx>> { + key: (ty::Predicate<'tcx>, WellFormedLoc) + ) -> &'tcx Option<ObligationCause<'tcx>> { arena_cache eval_always no_hash diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/query/plumbing.rs index 647f4826876..97edfc2fca2 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -32,20 +32,12 @@ impl QueryKeyStringCache { } } -#[derive(Clone, Copy)] -pub struct QueryStruct<'tcx> { - pub try_collect_active_jobs: fn(TyCtxt<'tcx>, &mut QueryMap<DepKind>) -> Option<()>, - pub alloc_self_profile_query_strings: fn(TyCtxt<'tcx>, &mut QueryKeyStringCache), - pub encode_query_results: - Option<fn(TyCtxt<'tcx>, &mut CacheEncoder<'_, 'tcx>, &mut EncodedDepNodeIndex)>, -} - pub struct DynamicQuery<'tcx, C: QueryCache> { pub name: &'static str, pub eval_always: bool, - pub dep_kind: rustc_middle::dep_graph::DepKind, + pub dep_kind: DepKind, pub handle_cycle_error: HandleCycleError, - pub query_state: FieldOffset<QueryStates<'tcx>, QueryState<C::Key, crate::dep_graph::DepKind>>, + pub query_state: FieldOffset<QueryStates<'tcx>, QueryState<C::Key, DepKind>>, pub query_cache: FieldOffset<QueryCaches<'tcx>, C>, pub cache_on_disk: fn(tcx: TyCtxt<'tcx>, key: &C::Key) -> bool, pub execute_query: fn(tcx: TyCtxt<'tcx>, k: C::Key) -> C::Value, @@ -60,8 +52,7 @@ pub struct DynamicQuery<'tcx, C: QueryCache> { pub loadable_from_disk: fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool, pub hash_result: HashResult<C::Value>, - pub value_from_cycle_error: - fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<crate::dep_graph::DepKind>]) -> C::Value, + pub value_from_cycle_error: fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> C::Value, pub format_value: fn(&C::Value) -> String, } @@ -69,7 +60,6 @@ pub struct QuerySystemFns<'tcx> { pub engine: QueryEngine, pub local_providers: Providers, pub extern_providers: ExternProviders, - pub query_structs: Vec<QueryStruct<'tcx>>, pub encode_query_results: fn( tcx: TyCtxt<'tcx>, encoder: &mut CacheEncoder<'_, 'tcx>, @@ -221,8 +211,8 @@ macro_rules! separate_provide_extern_decl { ([(separate_provide_extern) $($rest:tt)*][$name:ident]) => { for<'tcx> fn( TyCtxt<'tcx>, - query_keys::$name<'tcx>, - ) -> query_provided::$name<'tcx> + queries::$name::Key<'tcx>, + ) -> queries::$name::ProvidedValue<'tcx> }; ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { separate_provide_extern_decl!([$($modifiers)*][$($args)*]) @@ -252,60 +242,37 @@ macro_rules! define_callbacks { $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => { - // HACK(eddyb) this is like the `impl QueryConfig for queries::$name` - // below, but using type aliases instead of associated types, to bypass - // the limitations around normalizing under HRTB - for example, this: - // `for<'tcx> fn(...) -> <queries::$name<'tcx> as QueryConfig<TyCtxt<'tcx>>>::Value` - // doesn't currently normalize to `for<'tcx> fn(...) -> query_values::$name<'tcx>`. - // This is primarily used by the `provide!` macro in `rustc_metadata`. - #[allow(nonstandard_style, unused_lifetimes)] - pub mod query_keys { - use super::*; - - $(pub type $name<'tcx> = $($K)*;)* - } - #[allow(nonstandard_style, unused_lifetimes)] - pub mod query_keys_local { - use super::*; - - $(pub type $name<'tcx> = local_key_if_separate_extern!([$($modifiers)*] $($K)*);)* - } - #[allow(nonstandard_style, unused_lifetimes)] - pub mod query_values { - use super::*; - - $(pub type $name<'tcx> = $V;)* - } + #[allow(unused_lifetimes)] + pub mod queries { + $(pub mod $name { + use super::super::*; - /// This module specifies the type returned from query providers and the type used for - /// decoding. For regular queries this is the declared returned type `V`, but - /// `arena_cache` will use `<V as Deref>::Target` instead. - #[allow(nonstandard_style, unused_lifetimes)] - pub mod query_provided { - use super::*; + pub type Key<'tcx> = $($K)*; + pub type Value<'tcx> = $V; - $( - pub type $name<'tcx> = query_if_arena!([$($modifiers)*] (<$V as Deref>::Target) ($V)); - )* - } + pub type LocalKey<'tcx> = local_key_if_separate_extern!([$($modifiers)*] $($K)*); - /// This module has a function per query which takes a `query_provided` value and coverts - /// it to a regular `V` value by allocating it on an arena if the query has the - /// `arena_cache` modifier. This will happen when computing the query using a provider or - /// decoding a stored result. - #[allow(nonstandard_style, unused_lifetimes)] - pub mod query_provided_to_value { - use super::*; + /// This type alias specifies the type returned from query providers and the type + /// used for decoding. For regular queries this is the declared returned type `V`, + /// but `arena_cache` will use `<V as Deref>::Target` instead. + pub type ProvidedValue<'tcx> = query_if_arena!( + [$($modifiers)*] + (<$V as Deref>::Target) + ($V) + ); - $( + /// This function takes `ProvidedValue` and coverts it to an erased `Value` by + /// allocating it on an arena if the query has the `arena_cache` modifier. The + /// value is then erased and returned. This will happen when computing the query + /// using a provider or decoding a stored result. #[inline(always)] - pub fn $name<'tcx>( + pub fn provided_to_erased<'tcx>( _tcx: TyCtxt<'tcx>, - value: query_provided::$name<'tcx>, - ) -> Erase<query_values::$name<'tcx>> { + value: ProvidedValue<'tcx>, + ) -> Erase<Value<'tcx>> { erase(query_if_arena!([$($modifiers)*] { - if mem::needs_drop::<query_provided::$name<'tcx>>() { + if mem::needs_drop::<ProvidedValue<'tcx>>() { &*_tcx.query_system.arenas.$name.alloc(value) } else { &*_tcx.arena.dropless.alloc(value) @@ -314,47 +281,41 @@ macro_rules! define_callbacks { (value) )) } - )* - } - #[allow(nonstandard_style, unused_lifetimes)] - pub mod query_storage { - use super::*; - $( - pub type $name<'tcx> = <<$($K)* as Key>::CacheSelector as CacheSelector<'tcx, Erase<$V>>>::Cache; - )* + pub type Storage<'tcx> = < + <$($K)* as keys::Key>::CacheSelector as CacheSelector<'tcx, Erase<$V>> + >::Cache; + + // Ensure that keys grow no larger than 64 bytes + #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] + const _: () = { + if mem::size_of::<Key<'static>>() > 64 { + panic!("{}", concat!( + "the query `", + stringify!($name), + "` has a key type `", + stringify!($($K)*), + "` that is too large" + )); + } + }; + + // Ensure that values grow no larger than 64 bytes + #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] + const _: () = { + if mem::size_of::<Value<'static>>() > 64 { + panic!("{}", concat!( + "the query `", + stringify!($name), + "` has a value type `", + stringify!($V), + "` that is too large" + )); + } + }; + })* } - $( - // Ensure that keys grow no larger than 64 bytes - #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] - const _: () = { - if mem::size_of::<query_keys::$name<'static>>() > 64 { - panic!("{}", concat!( - "the query `", - stringify!($name), - "` has a key type `", - stringify!($($K)*), - "` that is too large" - )); - } - }; - - // Ensure that values grow no larger than 64 bytes - #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] - const _: () = { - if mem::size_of::<query_values::$name<'static>>() > 64 { - panic!("{}", concat!( - "the query `", - stringify!($name), - "` has a value type `", - stringify!($V), - "` that is too large" - )); - } - }; - )* - pub struct QueryArenas<'tcx> { $($(#[$attr])* pub $name: query_if_arena!([$($modifiers)*] (WorkerLocal<TypedArena<<$V as Deref>::Target>>) @@ -375,7 +336,7 @@ macro_rules! define_callbacks { #[derive(Default)] pub struct QueryCaches<'tcx> { - $($(#[$attr])* pub $name: query_storage::$name<'tcx>,)* + $($(#[$attr])* pub $name: queries::$name::Storage<'tcx>,)* } impl<'tcx> TyCtxtEnsure<'tcx> { @@ -433,7 +394,7 @@ macro_rules! define_callbacks { pub struct DynamicQueries<'tcx> { $( - pub $name: DynamicQuery<'tcx, query_storage::$name<'tcx>>, + pub $name: DynamicQuery<'tcx, queries::$name::Storage<'tcx>>, )* } @@ -447,8 +408,8 @@ macro_rules! define_callbacks { pub struct Providers { $(pub $name: for<'tcx> fn( TyCtxt<'tcx>, - query_keys_local::$name<'tcx>, - ) -> query_provided::$name<'tcx>,)* + queries::$name::LocalKey<'tcx>, + ) -> queries::$name::ProvidedValue<'tcx>,)* } pub struct ExternProviders { @@ -493,7 +454,7 @@ macro_rules! define_callbacks { $(pub $name: for<'tcx> fn( TyCtxt<'tcx>, Span, - query_keys::$name<'tcx>, + queries::$name::Key<'tcx>, QueryMode, ) -> Option<Erase<$V>>,)* } @@ -517,11 +478,11 @@ macro_rules! define_feedable { $(impl<'tcx, K: IntoQueryParam<$($K)*> + Copy> TyCtxtFeed<'tcx, K> { $(#[$attr])* #[inline(always)] - pub fn $name(self, value: query_provided::$name<'tcx>) { + pub fn $name(self, value: queries::$name::ProvidedValue<'tcx>) { let key = self.key().into_query_param(); let tcx = self.tcx; - let erased = query_provided_to_value::$name(tcx, value); + let erased = queries::$name::provided_to_erased(tcx, value); let value = restore::<$V>(erased); let cache = &tcx.query_system.caches.$name; @@ -533,12 +494,20 @@ macro_rules! define_feedable { let (value_hash, old_hash): (Fingerprint, Fingerprint) = tcx.with_stable_hashing_context(|mut hcx| (hasher(&mut hcx, &value), hasher(&mut hcx, &old)) ); - assert_eq!( - old_hash, value_hash, - "Trying to feed an already recorded value for query {} key={key:?}:\nold value: {old:?}\nnew value: {value:?}", - stringify!($name), - ) + if old_hash != value_hash { + // We have an inconsistency. This can happen if one of the two + // results is tainted by errors. In this case, delay a bug to + // ensure compilation is doomed, and keep the `old` value. + tcx.sess.delay_span_bug(DUMMY_SP, format!( + "Trying to feed an already recorded value for query {} key={key:?}:\n\ + old value: {old:?}\nnew value: {value:?}", + stringify!($name), + )); + } } else { + // The query is `no_hash`, so we have no way to perform a sanity check. + // If feeding the same value multiple times needs to be supported, + // the query should not be marked `no_hash`. bug!( "Trying to feed an already recorded value for query {} key={key:?}:\nold value: {old:?}\nnew value: {value:?}", stringify!($name), diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 2f0b07d4c71..5b0b40cbfd9 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -701,9 +701,9 @@ impl<'tcx, N> ImplSource<'tcx, N> { } pub fn borrow_nested_obligations(&self) -> &[N] { - match &self { - ImplSource::UserDefined(i) => &i.nested[..], - ImplSource::Param(n, _) => &n, + match self { + ImplSource::UserDefined(i) => &i.nested, + ImplSource::Param(n, _) => n, ImplSource::Builtin(i) => &i.nested, ImplSource::AutoImpl(d) => &d.nested, ImplSource::Closure(c) => &c.nested, @@ -717,6 +717,23 @@ impl<'tcx, N> ImplSource<'tcx, N> { } } + pub fn borrow_nested_obligations_mut(&mut self) -> &mut [N] { + match self { + ImplSource::UserDefined(i) => &mut i.nested, + ImplSource::Param(n, _) => n, + ImplSource::Builtin(i) => &mut i.nested, + ImplSource::AutoImpl(d) => &mut d.nested, + ImplSource::Closure(c) => &mut c.nested, + ImplSource::Generator(c) => &mut c.nested, + ImplSource::Future(c) => &mut c.nested, + ImplSource::Object(d) => &mut d.nested, + ImplSource::FnPointer(d) => &mut d.nested, + ImplSource::TraitAlias(d) => &mut d.nested, + ImplSource::TraitUpcasting(d) => &mut d.nested, + ImplSource::ConstDestruct(i) => &mut i.nested, + } + } + pub fn map<M, F>(self, f: F) -> ImplSource<'tcx, M> where F: FnMut(N) -> M, diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 6b7b910a59b..1511c906d1e 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -124,7 +124,7 @@ impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> { pub struct ExternalConstraintsData<'tcx> { // FIXME: implement this. pub region_constraints: QueryRegionConstraints<'tcx>, - pub opaque_types: Vec<(Ty<'tcx>, Ty<'tcx>)>, + pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, } // FIXME: Having to clone `region_constraints` for folding feels bad and diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index ad9891a5dca..7c5c030c276 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -111,12 +111,30 @@ impl Ord for AdtDefData { } } -/// There should be only one AdtDef for each `did`, therefore -/// it is fine to implement `PartialEq` only based on `did`. impl PartialEq for AdtDefData { #[inline] fn eq(&self, other: &Self) -> bool { - self.did == other.did + // There should be only one `AdtDefData` for each `def_id`, therefore + // it is fine to implement `PartialEq` only based on `def_id`. + // + // Below, we exhaustively destructure `self` and `other` so that if the + // definition of `AdtDefData` changes, a compile-error will be produced, + // reminding us to revisit this assumption. + + let Self { did: self_def_id, variants: _, flags: _, repr: _ } = self; + let Self { did: other_def_id, variants: _, flags: _, repr: _ } = other; + + let res = self_def_id == other_def_id; + + // Double check that implicit assumption detailed above. + if cfg!(debug_assertions) && res { + let deep = self.flags == other.flags + && self.repr == other.repr + && self.variants == other.variants; + assert!(deep, "AdtDefData for the same def-id has differing data"); + } + + res } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 097bfb71a6f..5393dba8c2e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -14,14 +14,14 @@ use crate::middle::resolve_bound_vars; use crate::middle::stability; use crate::mir::interpret::{self, Allocation, ConstAllocation}; use crate::mir::{Body, Local, Place, PlaceElem, ProjectionKind, Promoted}; +use crate::query::plumbing::QuerySystem; use crate::query::LocalCrate; use crate::query::Providers; +use crate::query::{IntoQueryParam, TyCtxtAt}; use crate::thir::Thir; use crate::traits; use crate::traits::solve; use crate::traits::solve::{ExternalConstraints, ExternalConstraintsData}; -use crate::ty::query::QuerySystem; -use crate::ty::query::{self, TyCtxtAt}; use crate::ty::{ self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, FloatTy, FloatVar, FloatVid, GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, @@ -80,8 +80,6 @@ use std::iter; use std::mem; use std::ops::{Bound, Deref}; -use super::query::IntoQueryParam; - const TINY_CONST_EVAL_LIMIT: Limit = Limit(20); #[allow(rustc::usage_of_ty_tykind)] @@ -512,7 +510,7 @@ pub struct GlobalCtxt<'tcx> { untracked: Untracked, - pub query_system: query::QuerySystem<'tcx>, + pub query_system: QuerySystem<'tcx>, pub(crate) query_kinds: &'tcx [DepKindStruct<'tcx>], // Internal caches for metadata decoding. No need to track deps on this. @@ -702,7 +700,11 @@ impl<'tcx> TyCtxt<'tcx> { /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to /// ensure it gets used. #[track_caller] - pub fn ty_error_with_message<S: Into<MultiSpan>>(self, span: S, msg: &str) -> Ty<'tcx> { + pub fn ty_error_with_message<S: Into<MultiSpan>>( + self, + span: S, + msg: impl Into<DiagnosticMessage>, + ) -> Ty<'tcx> { let reported = self.sess.delay_span_bug(span, msg); self.mk_ty_from_kind(Error(reported)) } @@ -1197,7 +1199,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx { iter::once(LOCAL_CRATE) .chain(self.crates(()).iter().copied()) - .flat_map(move |cnum| self.traits_in_crate(cnum).iter().copied()) + .flat_map(move |cnum| self.traits(cnum).iter().copied()) } #[inline] @@ -2435,7 +2437,7 @@ impl<'tcx> TyCtxtAt<'tcx> { /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to /// ensure it gets used. #[track_caller] - pub fn ty_error_with_message(self, msg: &str) -> Ty<'tcx> { + pub fn ty_error_with_message(self, msg: impl Into<DiagnosticMessage>) -> Ty<'tcx> { self.tcx.ty_error_with_message(self.span, msg) } } diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs index bf9806f6406..5c1c419811e 100644 --- a/compiler/rustc_middle/src/ty/context/tls.rs +++ b/compiler/rustc_middle/src/ty/context/tls.rs @@ -1,7 +1,7 @@ use super::{GlobalCtxt, TyCtxt}; use crate::dep_graph::TaskDepsRef; -use crate::ty::query; +use crate::query::plumbing::QueryJobId; use rustc_data_structures::sync::{self, Lock}; use rustc_errors::Diagnostic; #[cfg(not(parallel_compiler))] @@ -22,7 +22,7 @@ pub struct ImplicitCtxt<'a, 'tcx> { /// The current query job, if any. This is updated by `JobOwner::start` in /// `ty::query::plumbing` when executing a query. - pub query: Option<query::QueryJobId>, + pub query: Option<QueryJobId>, /// Where to store diagnostics for the current query job, if any. /// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query. diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 47cf48f46cf..b5a743cfe34 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1,5 +1,6 @@ use crate::fluent_generated as fluent; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use crate::query::TyCtxtAt; use crate::ty::normalize_erasing_regions::NormalizationError; use crate::ty::{self, ReprOptions, Ty, TyCtxt, TypeVisitableExt}; use rustc_errors::{DiagnosticBuilder, Handler, IntoDiagnostic}; @@ -268,7 +269,7 @@ pub struct LayoutCx<'tcx, C> { impl<'tcx> LayoutCalculator for LayoutCx<'tcx, TyCtxt<'tcx>> { type TargetDataLayoutRef = &'tcx TargetDataLayout; - fn delay_bug(&self, txt: &str) { + fn delay_bug(&self, txt: String) { self.tcx.sess.delay_span_bug(DUMMY_SP, txt); } @@ -543,20 +544,20 @@ impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> { } } -impl<'tcx> HasDataLayout for ty::query::TyCtxtAt<'tcx> { +impl<'tcx> HasDataLayout for TyCtxtAt<'tcx> { #[inline] fn data_layout(&self) -> &TargetDataLayout { &self.data_layout } } -impl<'tcx> HasTargetSpec for ty::query::TyCtxtAt<'tcx> { +impl<'tcx> HasTargetSpec for TyCtxtAt<'tcx> { fn target_spec(&self) -> &Target { &self.sess.target } } -impl<'tcx> HasTyCtxt<'tcx> for ty::query::TyCtxtAt<'tcx> { +impl<'tcx> HasTyCtxt<'tcx> for TyCtxtAt<'tcx> { #[inline] fn tcx(&self) -> TyCtxt<'tcx> { **self @@ -683,7 +684,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> { } } -impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> { +impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxtAt<'tcx>> { type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>; #[inline] diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index df324bcc52c..c9cd644fab0 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -37,7 +37,7 @@ use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; -use rustc_errors::ErrorGuaranteed; +use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap}; @@ -122,8 +122,6 @@ pub mod inhabitedness; pub mod layout; pub mod normalize_erasing_regions; pub mod print; -#[macro_use] -pub mod query; pub mod relate; pub mod subst; pub mod trait_def; @@ -1441,14 +1439,26 @@ pub struct OpaqueHiddenType<'tcx> { } impl<'tcx> OpaqueHiddenType<'tcx> { - pub fn report_mismatch(&self, other: &Self, tcx: TyCtxt<'tcx>) -> ErrorGuaranteed { + pub fn report_mismatch( + &self, + other: &Self, + opaque_def_id: LocalDefId, + tcx: TyCtxt<'tcx>, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + if let Some(diag) = tcx + .sess + .diagnostic() + .steal_diagnostic(tcx.def_span(opaque_def_id), StashKey::OpaqueHiddenTypeMismatch) + { + diag.cancel(); + } // Found different concrete types for the opaque type. let sub_diag = if self.span == other.span { TypeMismatchReason::ConflictType { span: self.span } } else { TypeMismatchReason::PreviousUse { span: self.span } }; - tcx.sess.emit_err(OpaqueHiddenTypeMismatch { + tcx.sess.create_err(OpaqueHiddenTypeMismatch { self_ty: self.ty, other_ty: other.ty, other_span: other.span, @@ -1884,7 +1894,20 @@ impl PartialEq for VariantDef { let Self { def_id: lhs_def_id, ctor: _, name: _, discr: _, fields: _, flags: _ } = &self; let Self { def_id: rhs_def_id, ctor: _, name: _, discr: _, fields: _, flags: _ } = other; - lhs_def_id == rhs_def_id + + let res = lhs_def_id == rhs_def_id; + + // Double check that implicit assumption detailed above. + if cfg!(debug_assertions) && res { + let deep = self.ctor == other.ctor + && self.name == other.name + && self.discr == other.discr + && self.fields == other.fields + && self.flags == other.flags; + assert!(deep, "VariantDef for the same def-id has differing data"); + } + + res } } @@ -1939,7 +1962,15 @@ impl PartialEq for FieldDef { let Self { did: rhs_did, name: _, vis: _ } = other; - lhs_did == rhs_did + let res = lhs_did == rhs_did; + + // Double check that implicit assumption detailed above. + if cfg!(debug_assertions) && res { + let deep = self.name == other.name && self.vis == other.vis; + assert!(deep, "FieldDef for the same def-id has differing data"); + } + + res } } diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 810c388ebbe..a2e77d9cdfe 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -56,6 +56,7 @@ trivially_parameterized_over_tcx! { std::string::String, crate::metadata::ModChild, crate::middle::codegen_fn_attrs::CodegenFnAttrs, + crate::middle::debugger_visualizer::DebuggerVisualizerFile, crate::middle::exported_symbols::SymbolExportInfo, crate::middle::resolve_bound_vars::ObjectLifetimeDefault, crate::mir::ConstQualifs, @@ -91,7 +92,6 @@ trivially_parameterized_over_tcx! { rustc_session::cstore::ForeignModule, rustc_session::cstore::LinkagePreference, rustc_session::cstore::NativeLib, - rustc_span::DebuggerVisualizerFile, rustc_span::ExpnData, rustc_span::ExpnHash, rustc_span::ExpnId, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index a8193c3e559..a064174e261 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1,6 +1,6 @@ use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar}; +use crate::query::IntoQueryParam; use crate::query::Providers; -use crate::ty::query::IntoQueryParam; use crate::ty::{ self, ConstInt, ParamConst, ScalarInt, Term, TermKind, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -1164,6 +1164,22 @@ pub trait PrettyPrinter<'tcx>: traits.entry(trait_ref).or_default().extend(proj_ty); } + fn pretty_print_inherent_projection( + self, + alias_ty: &ty::AliasTy<'tcx>, + ) -> Result<Self::Path, Self::Error> { + let def_key = self.tcx().def_key(alias_ty.def_id); + self.path_generic_args( + |cx| { + cx.path_append( + |cx| cx.path_qualified(alias_ty.self_ty(), None), + &def_key.disambiguated_data, + ) + }, + &alias_ty.substs[1..], + ) + } + fn ty_infer_name(&self, _: ty::TyVid) -> Option<Symbol> { None } @@ -2821,7 +2837,11 @@ define_print_and_forward_display! { } ty::AliasTy<'tcx> { - p!(print_def_path(self.def_id, self.substs)); + if let DefKind::Impl { of_trait: false } = cx.tcx().def_kind(cx.tcx().parent(self.def_id)) { + p!(pretty_print_inherent_projection(self)) + } else { + p!(print_def_path(self.def_id, self.substs)); + } } ty::ClosureKind { diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 5a0571f4bb7..e04dbbff9a7 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -151,10 +151,14 @@ pub struct TypeckResults<'tcx> { /// this field will be set to `Some(ErrorGuaranteed)`. pub tainted_by_errors: Option<ErrorGuaranteed>, - /// All the opaque types that have hidden types set - /// by this function. We also store the - /// type here, so that mir-borrowck can use it as a hint for figuring out hidden types, - /// even if they are only set in dead code (which doesn't show up in MIR). + /// All the opaque types that have hidden types set by this function. + /// We also store the type here, so that the compiler can use it as a hint + /// for figuring out hidden types, even if they are only set in dead code + /// (which doesn't show up in MIR). + /// + /// These types are mapped back to the opaque's identity substitutions + /// (with erased regions), which is why we don't associated substs with any + /// of these usages. pub concrete_opaque_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>, /// Tracks the minimum captures required for a closure; diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index c385b00692f..bcab4c0d24b 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -15,6 +15,7 @@ use rustc_middle::mir::Place; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::cast::{mir_cast_kind, CastTy}; +use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{self, Ty, UpvarSubsts}; use rustc_span::Span; @@ -225,49 +226,63 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); let (op,ty) = (Operand::Move(discr), discr_ty); - if let Abi::Scalar(scalar) = layout.unwrap().abi{ - if let Primitive::Int(_, signed) = scalar.primitive() { - let range = scalar.valid_range(&this.tcx); - // FIXME: Handle wraparound cases too. - if range.end >= range.start { - let mut assumer = |range: u128, bin_op: BinOp| { - // We will be overwriting this val if our scalar is signed value - // because sign extension on unsigned types might cause unintended things - let mut range_val = - ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(discr_ty)); - let bool_ty = this.tcx.types.bool; - if signed { - let scalar_size_extend = scalar.size(&this.tcx).sign_extend(range); - let discr_layout = this.tcx.layout_of(this.param_env.and(discr_ty)); - let truncated_val = discr_layout.unwrap().size.truncate(scalar_size_extend); - range_val = ConstantKind::from_bits( - this.tcx, - truncated_val, - ty::ParamEnv::empty().and(discr_ty), - ); - } - let lit_op = this.literal_operand(expr.span, range_val); - let is_bin_op = this.temp(bool_ty, expr_span); - this.cfg.push_assign( - block, - source_info, - is_bin_op, - Rvalue::BinaryOp(bin_op, Box::new(((lit_op), (Operand::Copy(discr))))), - ); - this.cfg.push( - block, - Statement { - source_info, - kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume( - Operand::Copy(is_bin_op), - ))), - }, - ) - }; - assumer(range.end, BinOp::Ge); - assumer(range.start, BinOp::Le); - } - } + if let Abi::Scalar(scalar) = layout.unwrap().abi + && !scalar.is_always_valid(&this.tcx) + && let Primitive::Int(int_width, _signed) = scalar.primitive() + { + let unsigned_ty = int_width.to_ty(this.tcx, false); + let unsigned_place = this.temp(unsigned_ty, expr_span); + this.cfg.push_assign( + block, + source_info, + unsigned_place, + Rvalue::Cast(CastKind::IntToInt, Operand::Copy(discr), unsigned_ty)); + + let bool_ty = this.tcx.types.bool; + let range = scalar.valid_range(&this.tcx); + let merge_op = + if range.start <= range.end { + BinOp::BitAnd + } else { + BinOp::BitOr + }; + + let mut comparer = |range: u128, bin_op: BinOp| -> Place<'tcx> { + let range_val = + ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(unsigned_ty)); + let lit_op = this.literal_operand(expr.span, range_val); + let is_bin_op = this.temp(bool_ty, expr_span); + this.cfg.push_assign( + block, + source_info, + is_bin_op, + Rvalue::BinaryOp(bin_op, Box::new((Operand::Copy(unsigned_place), lit_op))), + ); + is_bin_op + }; + let assert_place = if range.start == 0 { + comparer(range.end, BinOp::Le) + } else { + let start_place = comparer(range.start, BinOp::Ge); + let end_place = comparer(range.end, BinOp::Le); + let merge_place = this.temp(bool_ty, expr_span); + this.cfg.push_assign( + block, + source_info, + merge_place, + Rvalue::BinaryOp(merge_op, Box::new((Operand::Move(start_place), Operand::Move(end_place)))), + ); + merge_place + }; + this.cfg.push( + block, + Statement { + source_info, + kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume( + Operand::Move(assert_place), + ))), + }, + ); } (op,ty) diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 56c87c402fe..b01b6fbf222 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -644,24 +644,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } }; - if let Some(destination) = destination { - if let Some(value) = value { + match (destination, value) { + (Some(destination), Some(value)) => { debug!("stmt_expr Break val block_context.push(SubExpr)"); self.block_context.push(BlockFrame::SubExpr); unpack!(block = self.expr_into_dest(destination, block, value)); self.block_context.pop(); - } else { + } + (Some(destination), None) => { self.cfg.push_assign_unit(block, source_info, destination, self.tcx) } - } else { - assert!(value.is_none(), "`return` and `break` should have a destination"); - if self.tcx.sess.instrument_coverage() { + (None, Some(_)) => { + panic!("`return`, `become` and `break` with value and must have a destination") + } + (None, None) if self.tcx.sess.instrument_coverage() => { // Unlike `break` and `return`, which push an `Assign` statement to MIR, from which // a Coverage code region can be generated, `continue` needs no `Assign`; but // without one, the `InstrumentCoverage` MIR pass cannot generate a code region for // `continue`. Coverage will be missing unless we add a dummy `Assign` to MIR. self.add_dummy_assignment(span, block, source_info); } + (None, None) => {} } let region_scope = self.scopes.breakable_scopes[break_index].region_scope; @@ -671,12 +674,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else { self.scopes.breakable_scopes[break_index].continue_drops.as_mut().unwrap() }; - let mut drop_idx = ROOT_NODE; - for scope in &self.scopes.scopes[scope_index + 1..] { - for drop in &scope.drops { - drop_idx = drops.add_drop(*drop, drop_idx); - } - } + + let drop_idx = self.scopes.scopes[scope_index + 1..] + .iter() + .flat_map(|scope| &scope.drops) + .fold(ROOT_NODE, |drop_idx, &drop| drops.add_drop(drop, drop_idx)); + drops.add_entry(block, drop_idx); // `build_drop_trees` doesn't have access to our source_info, so we diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index f46eb5a0ce1..c8648224ac1 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -130,6 +130,7 @@ impl<'tcx> Cx<'tcx> { ExprKind::Pointer { cast: PointerCast::Unsize, source: self.thir.exprs.push(expr) } } Adjust::Pointer(cast) => ExprKind::Pointer { cast, source: self.thir.exprs.push(expr) }, + Adjust::NeverToAny if adjustment.target.is_never() => return expr, Adjust::NeverToAny => ExprKind::NeverToAny { source: self.thir.exprs.push(expr) }, Adjust::Deref(None) => { adjust_span(&mut expr); diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index 2e68c794356..18895072c3b 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -276,6 +276,7 @@ where assert_eq!(self.elaborator.param_env().reveal(), Reveal::All); let field_ty = tcx.normalize_erasing_regions(self.elaborator.param_env(), f.ty(tcx, substs)); + (tcx.mk_place_field(base_place, field, field_ty), subpath) }) .collect() diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs index e554c470646..35e4c24dc46 100644 --- a/compiler/rustc_mir_transform/src/coverage/debug.rs +++ b/compiler/rustc_mir_transform/src/coverage/debug.rs @@ -118,7 +118,7 @@ use rustc_middle::mir::spanview::{self, SpanViewable}; use rustc_data_structures::fx::FxHashMap; use rustc_middle::mir::coverage::*; -use rustc_middle::mir::{self, BasicBlock, TerminatorKind}; +use rustc_middle::mir::{self, BasicBlock}; use rustc_middle::ty::TyCtxt; use rustc_span::Span; @@ -796,7 +796,7 @@ fn bcb_to_string_sections<'tcx>( } let non_term_blocks = bcb_data.basic_blocks[0..len - 1] .iter() - .map(|&bb| format!("{:?}: {}", bb, term_type(&mir_body[bb].terminator().kind))) + .map(|&bb| format!("{:?}: {}", bb, mir_body[bb].terminator().kind.name())) .collect::<Vec<_>>(); if non_term_blocks.len() > 0 { sections.push(non_term_blocks.join("\n")); @@ -804,28 +804,7 @@ fn bcb_to_string_sections<'tcx>( sections.push(format!( "{:?}: {}", bcb_data.basic_blocks.last().unwrap(), - term_type(&bcb_data.terminator(mir_body).kind) + bcb_data.terminator(mir_body).kind.name(), )); sections } - -/// Returns a simple string representation of a `TerminatorKind` variant, independent of any -/// values it might hold. -pub(super) fn term_type(kind: &TerminatorKind<'_>) -> &'static str { - match kind { - TerminatorKind::Goto { .. } => "Goto", - TerminatorKind::SwitchInt { .. } => "SwitchInt", - TerminatorKind::Resume => "Resume", - TerminatorKind::Terminate => "Terminate", - TerminatorKind::Return => "Return", - TerminatorKind::Unreachable => "Unreachable", - TerminatorKind::Drop { .. } => "Drop", - TerminatorKind::Call { .. } => "Call", - TerminatorKind::Assert { .. } => "Assert", - TerminatorKind::Yield { .. } => "Yield", - TerminatorKind::GeneratorDrop => "GeneratorDrop", - TerminatorKind::FalseEdge { .. } => "FalseEdge", - TerminatorKind::FalseUnwind { .. } => "FalseUnwind", - TerminatorKind::InlineAsm { .. } => "InlineAsm", - } -} diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 97dd1dd09a2..d27200419e2 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,4 +1,3 @@ -use super::debug::term_type; use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB}; use itertools::Itertools; @@ -40,7 +39,7 @@ impl CoverageStatement { "{}: @{}.{}: {:?}", source_range_no_file(tcx, span), bb.index(), - term_type(&term.kind), + term.kind.name(), term.kind ) } diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index 83a335197b3..90b58933df7 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -25,7 +25,6 @@ //! to: `rustc_span::create_default_session_globals_then(|| { test_here(); })`. use super::counters; -use super::debug; use super::graph; use super::spans; @@ -188,12 +187,12 @@ fn debug_basic_blocks(mir_body: &Body<'_>) -> String { | TerminatorKind::Goto { target } | TerminatorKind::InlineAsm { destination: Some(target), .. } | TerminatorKind::Yield { resume: target, .. } => { - format!("{}{:?}:{} -> {:?}", sp, bb, debug::term_type(kind), target) + format!("{}{:?}:{} -> {:?}", sp, bb, kind.name(), target) } TerminatorKind::SwitchInt { targets, .. } => { - format!("{}{:?}:{} -> {:?}", sp, bb, debug::term_type(kind), targets) + format!("{}{:?}:{} -> {:?}", sp, bb, kind.name(), targets) } - _ => format!("{}{:?}:{}", sp, bb, debug::term_type(kind)), + _ => format!("{}{:?}:{}", sp, bb, kind.name()), } }) .collect::<Vec<_>>() @@ -215,7 +214,7 @@ fn print_mir_graphviz(name: &str, mir_body: &Body<'_>) { " {:?} [label=\"{:?}: {}\"];\n{}", bb, bb, - debug::term_type(&data.terminator().kind), + data.terminator().kind.name(), mir_body .basic_blocks .successors(bb) @@ -244,7 +243,7 @@ fn print_coverage_graphviz( " {:?} [label=\"{:?}: {}\"];\n{}", bcb, bcb, - debug::term_type(&bcb_data.terminator(mir_body).kind), + bcb_data.terminator(mir_body).kind.name(), basic_coverage_blocks .successors(bcb) .map(|successor| { format!(" {:?} -> {:?};", bcb, successor) }) diff --git a/compiler/rustc_mir_transform/src/dump_mir.rs b/compiler/rustc_mir_transform/src/dump_mir.rs index 594cbd8977e..746e3d9652d 100644 --- a/compiler/rustc_mir_transform/src/dump_mir.rs +++ b/compiler/rustc_mir_transform/src/dump_mir.rs @@ -12,7 +12,7 @@ use rustc_session::config::OutputType; pub struct Marker(pub &'static str); impl<'tcx> MirPass<'tcx> for Marker { - fn name(&self) -> &str { + fn name(&self) -> &'static str { self.0 } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index ece20d8d3e6..6c2e22a70b9 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -7,6 +7,7 @@ use rustc_index::Idx; 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, InstanceDef, ParamEnv, Ty, TyCtxt}; use rustc_session::config::OptLevel; use rustc_span::{hygiene::ExpnKind, ExpnData, LocalExpnId, Span}; @@ -167,8 +168,20 @@ impl<'tcx> Inliner<'tcx> { ) -> Result<std::ops::Range<BasicBlock>, &'static str> { let callee_attrs = self.tcx.codegen_fn_attrs(callsite.callee.def_id()); self.check_codegen_attributes(callsite, callee_attrs)?; + + let terminator = caller_body[callsite.block].terminator.as_ref().unwrap(); + let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() }; + let destination_ty = destination.ty(&caller_body.local_decls, self.tcx).ty; + for arg in args { + if !arg.ty(&caller_body.local_decls, self.tcx).is_sized(self.tcx, self.param_env) { + // We do not allow inlining functions with unsized params. Inlining these functions + // could create unsized locals, which are unsound and being phased out. + return Err("Call has unsized argument"); + } + } + self.check_mir_is_available(caller_body, &callsite.callee)?; - let callee_body = self.tcx.instance_mir(callsite.callee.def); + let callee_body = try_instance_mir(self.tcx, callsite.callee.def)?; self.check_mir_body(callsite, callee_body, callee_attrs)?; if !self.tcx.consider_optimizing(|| { @@ -188,9 +201,6 @@ impl<'tcx> Inliner<'tcx> { // Check call signature compatibility. // Normally, this shouldn't be required, but trait normalization failure can create a // validation ICE. - let terminator = caller_body[callsite.block].terminator.as_ref().unwrap(); - let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() }; - let destination_ty = destination.ty(&caller_body.local_decls, self.tcx).ty; let output_type = callee_body.return_ty(); if !util::is_subtype(self.tcx, self.param_env, output_type, destination_ty) { trace!(?output_type, ?destination_ty); @@ -1128,3 +1138,27 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { } } } + +#[instrument(skip(tcx), level = "debug")] +fn try_instance_mir<'tcx>( + tcx: TyCtxt<'tcx>, + instance: InstanceDef<'tcx>, +) -> Result<&'tcx Body<'tcx>, &'static str> { + match instance { + ty::InstanceDef::DropGlue(_, Some(ty)) => match ty.kind() { + ty::Adt(def, substs) => { + let fields = def.all_fields(); + for field in fields { + let field_ty = field.ty(tcx, substs); + if field_ty.has_param() && field_ty.has_projections() { + return Err("cannot build drop shim for polymorphic type"); + } + } + + Ok(tcx.instance_mir(instance)) + } + _ => Ok(tcx.instance_mir(instance)), + }, + _ => Ok(tcx.instance_mir(instance)), + } +} diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 6bff535586a..e4dc617620e 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -5,7 +5,6 @@ use crate::MirPass; use rustc_hir::Mutability; use rustc_middle::mir::*; use rustc_middle::ty::layout::ValidityRequirement; -use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, ParamEnv, SubstsRef, Ty, TyCtxt}; use rustc_span::symbol::Symbol; use rustc_target::abi::FieldIdx; @@ -163,18 +162,6 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { return; } - // Transmuting a fieldless enum to its repr is a discriminant read - if let ty::Adt(adt_def, ..) = operand_ty.kind() - && adt_def.is_enum() - && adt_def.is_payloadfree() - && let Some(place) = operand.place() - && let Some(repr_int) = adt_def.repr().int - && repr_int.to_ty(self.tcx) == *cast_ty - { - *rvalue = Rvalue::Discriminant(place); - return; - } - // Transmuting a transparent struct/union to a field's type is a projection if let ty::Adt(adt_def, substs) = operand_ty.kind() && adt_def.repr().transparent() diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index e1b65823a5a..710eed3ed38 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -6,7 +6,7 @@ use crate::{validate, MirPass}; /// Just like `MirPass`, except it cannot mutate `Body`. pub trait MirLint<'tcx> { - fn name(&self) -> &str { + fn name(&self) -> &'static str { let name = std::any::type_name::<Self>(); if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name } } @@ -26,7 +26,7 @@ impl<'tcx, T> MirPass<'tcx> for Lint<T> where T: MirLint<'tcx>, { - fn name(&self) -> &str { + fn name(&self) -> &'static str { self.0.name() } @@ -49,7 +49,7 @@ impl<'tcx, T> MirPass<'tcx> for WithMinOptLevel<T> where T: MirPass<'tcx>, { - fn name(&self) -> &str { + fn name(&self) -> &'static str { self.1.name() } @@ -121,7 +121,7 @@ fn run_passes_inner<'tcx>( validate_body(tcx, body, format!("before pass {}", name)); } - pass.run_pass(tcx, body); + tcx.sess.time(name, || pass.run_pass(tcx, body)); if dump_enabled { dump_mir_for_pass(tcx, body, &name, true); diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 1b96df3aed5..e59219321b7 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -74,7 +74,7 @@ pub fn simplify_cfg<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { } impl<'tcx> MirPass<'tcx> for SimplifyCfg { - fn name(&self) -> &str { + fn name(&self) -> &'static str { &self.name() } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 55c937b305a..35b154b7b34 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -185,9 +185,9 @@ use rustc_middle::mir::interpret::{ErrorHandled, GlobalAlloc, Scalar}; use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; use rustc_middle::mir::visit::Visitor as MirVisitor; use rustc_middle::mir::{self, Local, Location}; +use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast}; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::query::TyCtxtAt; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::{ self, GenericParamDefKind, Instance, InstanceDef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 1c18e6b0b02..ecc50c3f664 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -12,10 +12,9 @@ extern crate rustc_middle; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_hir::lang_items::LangItem; -use rustc_middle::query::Providers; +use rustc_middle::query::{Providers, TyCtxtAt}; use rustc_middle::traits; use rustc_middle::ty::adjustment::CustomCoerceUnsized; -use rustc_middle::ty::query::TyCtxtAt; use rustc_middle::ty::{self, Ty}; mod collector; diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index c10180ee3f4..eafe57a0c02 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -250,13 +250,13 @@ where cgu.create_size_estimate(tcx); } - debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter()); + debug_dump(tcx, "INITIAL PARTITIONING", &initial_partitioning.codegen_units); // Merge until we have at most `max_cgu_count` codegen units. { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus"); partitioner.merge_codegen_units(cx, &mut initial_partitioning); - debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter()); + debug_dump(tcx, "POST MERGING", &initial_partitioning.codegen_units); } // In the next step, we use the inlining map to determine which additional @@ -272,7 +272,7 @@ where cgu.create_size_estimate(tcx); } - debug_dump(tcx, "POST INLINING:", post_inlining.codegen_units.iter()); + debug_dump(tcx, "POST INLINING", &post_inlining.codegen_units); // Next we try to make as many symbols "internal" as possible, so LLVM has // more freedom to optimize. @@ -322,6 +322,8 @@ where result.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); + debug_dump(tcx, "FINAL", &result); + result } @@ -346,33 +348,37 @@ struct PostInliningPartitioning<'tcx> { internalization_candidates: FxHashSet<MonoItem<'tcx>>, } -fn debug_dump<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, label: &str, cgus: I) -where - I: Iterator<Item = &'a CodegenUnit<'tcx>>, - 'tcx: 'a, -{ +fn debug_dump<'a, 'tcx: 'a>(tcx: TyCtxt<'tcx>, label: &str, cgus: &[CodegenUnit<'tcx>]) { let dump = move || { use std::fmt::Write; + let num_cgus = cgus.len(); + let max = cgus.iter().map(|cgu| cgu.size_estimate()).max().unwrap(); + let min = cgus.iter().map(|cgu| cgu.size_estimate()).min().unwrap(); + let ratio = max as f64 / min as f64; + let s = &mut String::new(); - let _ = writeln!(s, "{label}"); + let _ = writeln!( + s, + "{label} ({num_cgus} CodegenUnits, max={max}, min={min}, max/min={ratio:.1}):" + ); for cgu in cgus { let _ = - writeln!(s, "CodegenUnit {} estimated size {} :", cgu.name(), cgu.size_estimate()); + writeln!(s, "CodegenUnit {} estimated size {}:", cgu.name(), cgu.size_estimate()); for (mono_item, linkage) in cgu.items() { let symbol_name = mono_item.symbol_name(tcx).name; let symbol_hash_start = symbol_name.rfind('h'); let symbol_hash = symbol_hash_start.map_or("<no hash>", |i| &symbol_name[i..]); - let _ = writeln!( + let _ = with_no_trimmed_paths!(writeln!( s, " - {} [{:?}] [{}] estimated size {}", mono_item, linkage, symbol_hash, mono_item.size_estimate(tcx) - ); + )); } let _ = writeln!(s); diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 51e90489002..c6e6b46e455 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -662,7 +662,7 @@ impl<'a> StringReader<'a> { &RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, prefix_span, ast::CRATE_NODE_ID, - &format!("prefix `{prefix}` is unknown"), + format!("prefix `{prefix}` is unknown"), BuiltinLintDiagnostics::ReservedPrefix(prefix_span), ); } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 3002f23da75..bcef0f7185f 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -238,6 +238,7 @@ impl<'a> DerefMut for SnapshotParser<'a> { impl<'a> Parser<'a> { #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_span_err<S: Into<MultiSpan>>( &self, sp: S, diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 03279124177..54f9fc5d2b9 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -40,7 +40,8 @@ impl<'a> Parser<'a> { /// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of whether /// or not we have attributes - pub(crate) fn parse_stmt_without_recovery( + // Public for `cfg_eval` macro expansion. + pub fn parse_stmt_without_recovery( &mut self, capture_semi: bool, force_collect: ForceCollect, diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 982c4615aff..928fdce313d 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -186,7 +186,7 @@ fn emit_malformed_attribute( suggestions.push(code); } if should_warn(name) { - sess.buffer_lint(&ILL_FORMED_ATTRIBUTE_INPUT, span, ast::CRATE_NODE_ID, &msg); + sess.buffer_lint(&ILL_FORMED_ATTRIBUTE_INPUT, span, ast::CRATE_NODE_ID, msg); } else { sess.span_diagnostic .struct_span_err(span, error_msg) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 455d7b89f9c..41f92227e7c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -8,7 +8,6 @@ use crate::{errors, fluent_generated as fluent}; use rustc_ast::{ast, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, IntoDiagnosticArg, MultiSpan}; -use rustc_expand::base::resolve_path; use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; @@ -1916,6 +1915,10 @@ impl CheckAttrVisitor<'_> { /// Checks if the items on the `#[debugger_visualizer]` attribute are valid. fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) -> bool { + // Here we only check that the #[debugger_visualizer] attribute is attached + // to nothing other than a module. All other checks are done in the + // `debugger_visualizer` query where they need to be done for decoding + // anyway. match target { Target::Mod => {} _ => { @@ -1924,53 +1927,7 @@ impl CheckAttrVisitor<'_> { } } - let Some(hints) = attr.meta_item_list() else { - self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span }); - return false; - }; - - let hint = match hints.len() { - 1 => &hints[0], - _ => { - self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span }); - return false; - } - }; - - let Some(meta_item) = hint.meta_item() else { - self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span }); - return false; - }; - - let visualizer_path = match (meta_item.name_or_empty(), meta_item.value_str()) { - (sym::natvis_file, Some(value)) => value, - (sym::gdb_script_file, Some(value)) => value, - (_, _) => { - self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: meta_item.span }); - return false; - } - }; - - let file = - match resolve_path(&self.tcx.sess.parse_sess, visualizer_path.as_str(), attr.span) { - Ok(file) => file, - Err(mut err) => { - err.emit(); - return false; - } - }; - - match std::fs::File::open(&file) { - Ok(_) => true, - Err(error) => { - self.tcx.sess.emit_err(errors::DebugVisualizerUnreadable { - span: meta_item.span, - file: &file, - error, - }); - false - } - } + true } /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros. diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs index 8ea95b3f383..3483f7da528 100644 --- a/compiler/rustc_passes/src/debugger_visualizer.rs +++ b/compiler/rustc_passes/src/debugger_visualizer.rs @@ -1,60 +1,69 @@ //! Detecting usage of the `#[debugger_visualizer]` attribute. -use hir::CRATE_HIR_ID; -use rustc_data_structures::fx::FxHashSet; +use rustc_ast::Attribute; use rustc_data_structures::sync::Lrc; use rustc_expand::base::resolve_path; -use rustc_hir as hir; -use rustc_hir::HirId; -use rustc_middle::query::{LocalCrate, Providers}; -use rustc_middle::ty::TyCtxt; -use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType}; +use rustc_middle::{ + middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}, + query::{LocalCrate, Providers}, + ty::TyCtxt, +}; +use rustc_session::Session; +use rustc_span::sym; -use crate::errors::DebugVisualizerUnreadable; +use crate::errors::{DebugVisualizerInvalid, DebugVisualizerUnreadable}; -fn check_for_debugger_visualizer( - tcx: TyCtxt<'_>, - hir_id: HirId, - debugger_visualizers: &mut FxHashSet<DebuggerVisualizerFile>, -) { - let attrs = tcx.hir().attrs(hir_id); - for attr in attrs { +impl DebuggerVisualizerCollector<'_> { + fn check_for_debugger_visualizer(&mut self, attr: &Attribute) { if attr.has_name(sym::debugger_visualizer) { - let Some(list) = attr.meta_item_list() else { - continue + let Some(hints) = attr.meta_item_list() else { + self.sess.emit_err(DebugVisualizerInvalid { span: attr.span }); + return; }; - let meta_item = match list.len() { - 1 => match list[0].meta_item() { - Some(meta_item) => meta_item, - _ => continue, - }, - _ => continue, + let hint = if hints.len() == 1 { + &hints[0] + } else { + self.sess.emit_err(DebugVisualizerInvalid { span: attr.span }); + return; }; - let visualizer_type = match meta_item.name_or_empty() { - sym::natvis_file => DebuggerVisualizerType::Natvis, - sym::gdb_script_file => DebuggerVisualizerType::GdbPrettyPrinter, - _ => continue, + let Some(meta_item) = hint.meta_item() else { + self.sess.emit_err(DebugVisualizerInvalid { span: attr.span }); + return; }; - let file = match meta_item.value_str() { - Some(value) => { - match resolve_path(&tcx.sess.parse_sess, value.as_str(), attr.span) { - Ok(file) => file, - _ => continue, + let (visualizer_type, visualizer_path) = + match (meta_item.name_or_empty(), meta_item.value_str()) { + (sym::natvis_file, Some(value)) => (DebuggerVisualizerType::Natvis, value), + (sym::gdb_script_file, Some(value)) => { + (DebuggerVisualizerType::GdbPrettyPrinter, value) } - } - None => continue, - }; + (_, _) => { + self.sess.emit_err(DebugVisualizerInvalid { span: meta_item.span }); + return; + } + }; + + let file = + match resolve_path(&self.sess.parse_sess, visualizer_path.as_str(), attr.span) { + Ok(file) => file, + Err(mut err) => { + err.emit(); + return; + } + }; match std::fs::read(&file) { Ok(contents) => { - debugger_visualizers - .insert(DebuggerVisualizerFile::new(Lrc::from(contents), visualizer_type)); + self.visualizers.push(DebuggerVisualizerFile::new( + Lrc::from(contents), + visualizer_type, + file, + )); } Err(error) => { - tcx.sess.emit_err(DebugVisualizerUnreadable { + self.sess.emit_err(DebugVisualizerUnreadable { span: meta_item.span, file: &file, error, @@ -65,29 +74,30 @@ fn check_for_debugger_visualizer( } } -/// Traverses and collects the debugger visualizers for a specific crate. -fn debugger_visualizers(tcx: TyCtxt<'_>, _: LocalCrate) -> Vec<DebuggerVisualizerFile> { - // Initialize the collector. - let mut debugger_visualizers = FxHashSet::default(); +struct DebuggerVisualizerCollector<'a> { + sess: &'a Session, + visualizers: Vec<DebuggerVisualizerFile>, +} - // Collect debugger visualizers in this crate. - tcx.hir().for_each_module(|id| { - check_for_debugger_visualizer( - tcx, - tcx.hir().local_def_id_to_hir_id(id), - &mut debugger_visualizers, - ) - }); +impl<'ast> rustc_ast::visit::Visitor<'ast> for DebuggerVisualizerCollector<'_> { + fn visit_attribute(&mut self, attr: &'ast Attribute) { + self.check_for_debugger_visualizer(attr); + rustc_ast::visit::walk_attribute(self, attr); + } +} - // Collect debugger visualizers on the crate attributes. - check_for_debugger_visualizer(tcx, CRATE_HIR_ID, &mut debugger_visualizers); +/// Traverses and collects the debugger visualizers for a specific crate. +fn debugger_visualizers(tcx: TyCtxt<'_>, _: LocalCrate) -> Vec<DebuggerVisualizerFile> { + let resolver_and_krate = tcx.resolver_for_lowering(()).borrow(); + let krate = &*resolver_and_krate.1; - // Extract out the found debugger_visualizer items. - let mut visualizers = debugger_visualizers.into_iter().collect::<Vec<_>>(); + let mut visitor = DebuggerVisualizerCollector { sess: tcx.sess, visualizers: Vec::new() }; + rustc_ast::visit::Visitor::visit_crate(&mut visitor, krate); - // Sort the visualizers so we always get a deterministic query result. - visualizers.sort(); - visualizers + // We are collecting visualizers in AST-order, which is deterministic, + // so we don't need to do any explicit sorting in order to get a + // deterministic query result + visitor.visualizers } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 3c542821b67..4cf0f1305a7 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -15,7 +15,7 @@ #[macro_use] extern crate rustc_middle; -use crate::plumbing::{encode_all_query_results, try_mark_green}; +use crate::plumbing::{__rust_begin_short_backtrace, encode_all_query_results, try_mark_green}; use field_offset::offset_of; use rustc_data_structures::stable_hasher::HashStable; use rustc_data_structures::sync::AtomicU64; @@ -23,13 +23,14 @@ use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepNodeIndex; use rustc_middle::dep_graph::{self, DepKind, DepKindStruct}; use rustc_middle::query::erase::{erase, restore, Erase}; -use rustc_middle::query::on_disk_cache::OnDiskCache; +use rustc_middle::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache}; +use rustc_middle::query::plumbing::{ + DynamicQuery, QueryKeyStringCache, QuerySystem, QuerySystemFns, +}; use rustc_middle::query::AsLocalKey; use rustc_middle::query::{ - query_keys, query_provided, query_provided_to_value, query_storage, query_values, - DynamicQueries, ExternProviders, Providers, QueryCaches, QueryEngine, QueryStates, + queries, DynamicQueries, ExternProviders, Providers, QueryCaches, QueryEngine, QueryStates, }; -use rustc_middle::ty::query::{DynamicQuery, QuerySystem, QuerySystemFns}; use rustc_middle::ty::TyCtxt; use rustc_query_system::dep_graph::SerializedDepNodeIndex; use rustc_query_system::ich::StableHashingContext; @@ -216,7 +217,6 @@ pub fn query_system<'tcx>( engine: engine(incremental), local_providers, extern_providers, - query_structs: make_dep_kind_array!(query_structs).to_vec(), encode_query_results: encode_all_query_results, try_mark_green: try_mark_green, }, diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 5acfeb47a12..244f0e84b43 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -81,8 +81,8 @@ impl QueryContext for QueryCtxt<'_> { fn try_collect_active_jobs(self) -> Option<QueryMap<DepKind>> { let mut jobs = QueryMap::default(); - for query in &self.query_system.fns.query_structs { - (query.try_collect_active_jobs)(self.tcx, &mut jobs); + for collect in super::TRY_COLLECT_ACTIVE_JOBS.iter() { + collect(self.tcx, &mut jobs); } Some(jobs) @@ -183,10 +183,8 @@ pub(super) fn encode_all_query_results<'tcx>( encoder: &mut CacheEncoder<'_, 'tcx>, query_result_index: &mut EncodedDepNodeIndex, ) { - for query in &tcx.query_system.fns.query_structs { - if let Some(encode) = query.encode_query_results { - encode(tcx, encoder, query_result_index); - } + for encode in super::ENCODE_QUERY_RESULTS.iter().copied().filter_map(|e| e) { + encode(tcx, encoder, query_result_index); } } @@ -476,6 +474,16 @@ where } } +macro_rules! item_if_cached { + ([] $tokens:tt) => {}; + ([(cache) $($rest:tt)*] { $($tokens:tt)* }) => { + $($tokens)* + }; + ([$other:tt $($modifiers:tt)*] $tokens:tt) => { + item_if_cached! { [$($modifiers)*] $tokens } + }; +} + macro_rules! expand_if_cached { ([], $tokens:expr) => {{ None @@ -488,167 +496,227 @@ macro_rules! expand_if_cached { }; } +/// Don't show the backtrace for query system by default +/// use `RUST_BACKTRACE=full` to show all the backtraces +#[inline(never)] +pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T +where + F: FnOnce() -> T, +{ + let result = f(); + std::hint::black_box(()); + result +} + // NOTE: `$V` isn't used here, but we still need to match on it so it can be passed to other macros // invoked by `rustc_query_append`. macro_rules! define_queries { ( $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => { - mod get_query_incr { - use super::*; - $( - #[inline(always)] - #[tracing::instrument(level = "trace", skip(tcx))] - pub(super) fn $name<'tcx>( + pub(crate) mod query_impl { $(pub mod $name { + use super::super::*; + use std::marker::PhantomData; + + pub mod get_query_incr { + use super::*; + + // Adding `__rust_end_short_backtrace` marker to backtraces so that we emit the frames + // when `RUST_BACKTRACE=1`, add a new mod with `$name` here is to allow duplicate naming + #[inline(never)] + pub fn __rust_end_short_backtrace<'tcx>( tcx: TyCtxt<'tcx>, span: Span, - key: query_keys::$name<'tcx>, + key: queries::$name::Key<'tcx>, mode: QueryMode, - ) -> Option<Erase<query_values::$name<'tcx>>> { + ) -> Option<Erase<queries::$name::Value<'tcx>>> { get_query_incr( - queries::$name::config(tcx), + QueryType::config(tcx), QueryCtxt::new(tcx), span, key, mode ) } - )* - } + } - mod get_query_non_incr { - use super::*; + pub mod get_query_non_incr { + use super::*; - $( - #[inline(always)] - #[tracing::instrument(level = "trace", skip(tcx))] - pub(super) fn $name<'tcx>( + #[inline(never)] + pub fn __rust_end_short_backtrace<'tcx>( tcx: TyCtxt<'tcx>, span: Span, - key: query_keys::$name<'tcx>, + key: queries::$name::Key<'tcx>, __mode: QueryMode, - ) -> Option<Erase<query_values::$name<'tcx>>> { + ) -> Option<Erase<queries::$name::Value<'tcx>>> { Some(get_query_non_incr( - queries::$name::config(tcx), + QueryType::config(tcx), QueryCtxt::new(tcx), span, key, )) } - )* - } + } - pub(crate) fn engine(incremental: bool) -> QueryEngine { - if incremental { - QueryEngine { - $($name: get_query_incr::$name,)* - } - } else { - QueryEngine { - $($name: get_query_non_incr::$name,)* + pub fn dynamic_query<'tcx>() -> DynamicQuery<'tcx, queries::$name::Storage<'tcx>> { + DynamicQuery { + name: stringify!($name), + eval_always: is_eval_always!([$($modifiers)*]), + dep_kind: dep_graph::DepKind::$name, + handle_cycle_error: handle_cycle_error!([$($modifiers)*]), + query_state: offset_of!(QueryStates<'tcx> => $name), + query_cache: offset_of!(QueryCaches<'tcx> => $name), + cache_on_disk: |tcx, key| ::rustc_middle::query::cached::$name(tcx, key), + execute_query: |tcx, key| erase(tcx.$name(key)), + compute: |tcx, key| { + __rust_begin_short_backtrace(|| + queries::$name::provided_to_erased( + tcx, + call_provider!([$($modifiers)*][tcx, $name, key]) + ) + ) + }, + can_load_from_disk: should_ever_cache_on_disk!([$($modifiers)*] true false), + try_load_from_disk: should_ever_cache_on_disk!([$($modifiers)*] { + |tcx, key, prev_index, index| { + if ::rustc_middle::query::cached::$name(tcx, key) { + let value = $crate::plumbing::try_load_from_disk::< + queries::$name::ProvidedValue<'tcx> + >( + tcx, + prev_index, + index, + ); + value.map(|value| queries::$name::provided_to_erased(tcx, value)) + } else { + None + } + } + } { + |_tcx, _key, _prev_index, _index| None + }), + value_from_cycle_error: |tcx, cycle| { + let result: queries::$name::Value<'tcx> = Value::from_cycle_error(tcx, cycle); + erase(result) + }, + loadable_from_disk: |_tcx, _key, _index| { + should_ever_cache_on_disk!([$($modifiers)*] { + ::rustc_middle::query::cached::$name(_tcx, _key) && + $crate::plumbing::loadable_from_disk(_tcx, _index) + } { + false + }) + }, + hash_result: hash_result!([$($modifiers)*][queries::$name::Value<'tcx>]), + format_value: |value| format!("{:?}", restore::<queries::$name::Value<'tcx>>(*value)), } } - } - - #[allow(nonstandard_style)] - mod queries { - use std::marker::PhantomData; - $( - #[derive(Copy, Clone, Default)] - pub struct $name<'tcx> { - data: PhantomData<&'tcx ()> - } - )* - } + #[derive(Copy, Clone, Default)] + pub struct QueryType<'tcx> { + data: PhantomData<&'tcx ()> + } - #[allow(nonstandard_style)] - mod dynamic_query { - use super::*; + impl<'tcx> QueryConfigRestored<'tcx> for QueryType<'tcx> { + type RestoredValue = queries::$name::Value<'tcx>; + type Config = DynamicConfig< + 'tcx, + queries::$name::Storage<'tcx>, + { is_anon!([$($modifiers)*]) }, + { depth_limit!([$($modifiers)*]) }, + { feedable!([$($modifiers)*]) }, + >; - $( - pub(super) fn $name<'tcx>() -> DynamicQuery<'tcx, query_storage::$name<'tcx>> { - DynamicQuery { - name: stringify!($name), - eval_always: is_eval_always!([$($modifiers)*]), - dep_kind: dep_graph::DepKind::$name, - handle_cycle_error: handle_cycle_error!([$($modifiers)*]), - query_state: offset_of!(QueryStates<'tcx> => $name), - query_cache: offset_of!(QueryCaches<'tcx> => $name), - cache_on_disk: |tcx, key| ::rustc_middle::query::cached::$name(tcx, key), - execute_query: |tcx, key| erase(tcx.$name(key)), - compute: |tcx, key| query_provided_to_value::$name( - tcx, - call_provider!([$($modifiers)*][tcx, $name, key]) - ), - can_load_from_disk: should_ever_cache_on_disk!([$($modifiers)*] true false), - try_load_from_disk: should_ever_cache_on_disk!([$($modifiers)*] { - |tcx, key, prev_index, index| { - if ::rustc_middle::query::cached::$name(tcx, key) { - let value = $crate::plumbing::try_load_from_disk::<query_provided::$name<'tcx>>( - tcx, - prev_index, - index, - ); - value.map(|value| query_provided_to_value::$name(tcx, value)) - } else { - None - } - } - } { - |_tcx, _key, _prev_index, _index| None - }), - value_from_cycle_error: |tcx, cycle| { - let result: query_values::$name<'tcx> = Value::from_cycle_error(tcx, cycle); - erase(result) - }, - loadable_from_disk: |_tcx, _key, _index| { - should_ever_cache_on_disk!([$($modifiers)*] { - ::rustc_middle::query::cached::$name(_tcx, _key) && - $crate::plumbing::loadable_from_disk(_tcx, _index) - } { - false - }) - }, - hash_result: hash_result!([$($modifiers)*][query_values::$name<'tcx>]), - format_value: |value| format!("{:?}", restore::<query_values::$name<'tcx>>(*value)), + #[inline(always)] + fn config(tcx: TyCtxt<'tcx>) -> Self::Config { + DynamicConfig { + dynamic: &tcx.query_system.dynamic_queries.$name, } } - )* - } - $(impl<'tcx> QueryConfigRestored<'tcx> for queries::$name<'tcx> { - type RestoredValue = query_values::$name<'tcx>; - type Config = DynamicConfig< - 'tcx, - query_storage::$name<'tcx>, - { is_anon!([$($modifiers)*]) }, - { depth_limit!([$($modifiers)*]) }, - { feedable!([$($modifiers)*]) }, - >; - - #[inline(always)] - fn config(tcx: TyCtxt<'tcx>) -> Self::Config { - DynamicConfig { - dynamic: &tcx.query_system.dynamic_queries.$name, + #[inline(always)] + fn restore(value: <Self::Config as QueryConfig<QueryCtxt<'tcx>>>::Value) -> Self::RestoredValue { + restore::<queries::$name::Value<'tcx>>(value) } } - #[inline(always)] - fn restore(value: <Self::Config as QueryConfig<QueryCtxt<'tcx>>>::Value) -> Self::RestoredValue { - restore::<query_values::$name<'tcx>>(value) + pub fn try_collect_active_jobs<'tcx>(tcx: TyCtxt<'tcx>, qmap: &mut QueryMap<DepKind>) { + let make_query = |tcx, key| { + let kind = rustc_middle::dep_graph::DepKind::$name; + let name = stringify!($name); + $crate::plumbing::create_query_frame(tcx, rustc_middle::query::descs::$name, key, kind, name) + }; + tcx.query_system.states.$name.try_collect_active_jobs( + tcx, + make_query, + qmap, + ).unwrap(); + } + + pub fn alloc_self_profile_query_strings<'tcx>(tcx: TyCtxt<'tcx>, string_cache: &mut QueryKeyStringCache) { + $crate::profiling_support::alloc_self_profile_query_strings_for_query_cache( + tcx, + stringify!($name), + &tcx.query_system.caches.$name, + string_cache, + ) + } + + item_if_cached! { [$($modifiers)*] { + pub fn encode_query_results<'tcx>( + tcx: TyCtxt<'tcx>, + encoder: &mut CacheEncoder<'_, 'tcx>, + query_result_index: &mut EncodedDepNodeIndex + ) { + $crate::plumbing::encode_query_results::<query_impl::$name::QueryType<'tcx>>( + query_impl::$name::QueryType::config(tcx), + QueryCtxt::new(tcx), + encoder, + query_result_index, + ) + } + }} + })*} + + pub(crate) fn engine(incremental: bool) -> QueryEngine { + if incremental { + QueryEngine { + $($name: query_impl::$name::get_query_incr::__rust_end_short_backtrace,)* + } + } else { + QueryEngine { + $($name: query_impl::$name::get_query_non_incr::__rust_end_short_backtrace,)* + } } - })* + } pub fn dynamic_queries<'tcx>() -> DynamicQueries<'tcx> { DynamicQueries { $( - $name: dynamic_query::$name(), + $name: query_impl::$name::dynamic_query(), )* } } + // These arrays are used for iteration and can't be indexed by `DepKind`. + + const TRY_COLLECT_ACTIVE_JOBS: &[for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap<DepKind>)] = + &[$(query_impl::$name::try_collect_active_jobs),*]; + + const ALLOC_SELF_PROFILE_QUERY_STRINGS: &[ + for<'tcx> fn(TyCtxt<'tcx>, &mut QueryKeyStringCache) + ] = &[$(query_impl::$name::alloc_self_profile_query_strings),*]; + + const ENCODE_QUERY_RESULTS: &[ + Option<for<'tcx> fn( + TyCtxt<'tcx>, + &mut CacheEncoder<'_, 'tcx>, + &mut EncodedDepNodeIndex) + > + ] = &[$(expand_if_cached!([$($modifiers)*], query_impl::$name::encode_query_results)),*]; + #[allow(nonstandard_style)] mod query_callbacks { use super::*; @@ -707,72 +775,13 @@ macro_rules! define_queries { } $(pub(crate) fn $name<'tcx>()-> DepKindStruct<'tcx> { - $crate::plumbing::query_callback::<queries::$name<'tcx>>( + $crate::plumbing::query_callback::<query_impl::$name::QueryType<'tcx>>( is_anon!([$($modifiers)*]), is_eval_always!([$($modifiers)*]), ) })* } - mod query_structs { - use super::*; - use rustc_middle::ty::query::QueryStruct; - use rustc_middle::ty::query::QueryKeyStringCache; - use rustc_middle::dep_graph::DepKind; - use crate::QueryConfigRestored; - - pub(super) const fn dummy_query_struct<'tcx>() -> QueryStruct<'tcx> { - fn noop_try_collect_active_jobs(_: TyCtxt<'_>, _: &mut QueryMap<DepKind>) -> Option<()> { - None - } - fn noop_alloc_self_profile_query_strings(_: TyCtxt<'_>, _: &mut QueryKeyStringCache) {} - - QueryStruct { - try_collect_active_jobs: noop_try_collect_active_jobs, - alloc_self_profile_query_strings: noop_alloc_self_profile_query_strings, - encode_query_results: None, - } - } - - pub(super) use dummy_query_struct as Null; - pub(super) use dummy_query_struct as Red; - pub(super) use dummy_query_struct as TraitSelect; - pub(super) use dummy_query_struct as CompileCodegenUnit; - pub(super) use dummy_query_struct as CompileMonoItem; - - $( - pub(super) const fn $name<'tcx>() -> QueryStruct<'tcx> { QueryStruct { - try_collect_active_jobs: |tcx, qmap| { - let make_query = |tcx, key| { - let kind = rustc_middle::dep_graph::DepKind::$name; - let name = stringify!($name); - $crate::plumbing::create_query_frame(tcx, rustc_middle::query::descs::$name, key, kind, name) - }; - tcx.query_system.states.$name.try_collect_active_jobs( - tcx, - make_query, - qmap, - ) - }, - alloc_self_profile_query_strings: |tcx, string_cache| { - $crate::profiling_support::alloc_self_profile_query_strings_for_query_cache( - tcx, - stringify!($name), - &tcx.query_system.caches.$name, - string_cache, - ) - }, - encode_query_results: expand_if_cached!([$($modifiers)*], |tcx, encoder, query_result_index| - $crate::plumbing::encode_query_results::<super::queries::$name<'tcx>>( - super::queries::$name::config(tcx), - QueryCtxt::new(tcx), - encoder, - query_result_index, - ) - ), - }})* - } - pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct<'tcx>] { arena.alloc_from_iter(make_dep_kind_array!(query_callbacks)) } diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs index 7d9306f8087..fbc6db93e01 100644 --- a/compiler/rustc_query_impl/src/profiling_support.rs +++ b/compiler/rustc_query_impl/src/profiling_support.rs @@ -2,7 +2,7 @@ use measureme::{StringComponent, StringId}; use rustc_data_structures::profiling::SelfProfiler; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE}; use rustc_hir::definitions::DefPathData; -use rustc_middle::ty::query::QueryKeyStringCache; +use rustc_middle::query::plumbing::QueryKeyStringCache; use rustc_middle::ty::TyCtxt; use rustc_query_system::query::QueryCache; use std::fmt::Debug; @@ -243,7 +243,7 @@ pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) { let mut string_cache = QueryKeyStringCache::new(); - for query in &tcx.query_system.fns.query_structs { - (query.alloc_self_profile_query_strings)(tcx, &mut string_cache); + for alloc in super::ALLOC_SELF_PROFILE_QUERY_STRINGS.iter() { + alloc(tcx, &mut string_cache) } } diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index dbfe62ae6e9..730e4c8d30d 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -433,16 +433,22 @@ where (hasher(&mut hcx, &cached_result), hasher(&mut hcx, &result)) }); let formatter = query.format_value(); - debug_assert_eq!( - old_hash, - new_hash, - "Computed query value for {:?}({:?}) is inconsistent with fed value,\n\ - computed={:#?}\nfed={:#?}", - query.dep_kind(), - key, - formatter(&result), - formatter(&cached_result), - ); + if old_hash != new_hash { + // We have an inconsistency. This can happen if one of the two + // results is tainted by errors. In this case, delay a bug to + // ensure compilation is doomed. + qcx.dep_context().sess().delay_span_bug( + DUMMY_SP, + format!( + "Computed query value for {:?}({:?}) is inconsistent with fed value,\n\ + computed={:#?}\nfed={:#?}", + query.dep_kind(), + key, + formatter(&result), + formatter(&cached_result), + ), + ); + } } } job_owner.complete(cache, result, dep_node_index); diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 2438b3a38ed..b3d0e4ba258 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -9,12 +9,9 @@ use crate::def_collector::collect_definitions; use crate::imports::{Import, ImportKind}; use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::Namespace::{self, MacroNS, TypeNS, ValueNS}; -use crate::{ - errors, Determinacy, ExternPreludeEntry, Finalize, Module, ModuleKind, ModuleOrUniformRoot, -}; -use crate::{ - MacroData, NameBinding, NameBindingKind, ParentScope, PathResult, PerNS, ResolutionError, -}; +use crate::{errors, BindingKey, MacroData}; +use crate::{Determinacy, ExternPreludeEntry, Finalize, Module, ModuleKind, ModuleOrUniformRoot}; +use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PerNS, ResolutionError}; use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, VisResolutionError}; use rustc_ast::visit::{self, AssocCtxt, Visitor}; @@ -72,7 +69,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { T: ToNameBinding<'a>, { let binding = def.to_name_binding(self.arenas); - let key = self.new_key(ident, ns); + let key = self.new_disambiguated_key(ident, ns); if let Err(old_binding) = self.try_define(parent, key, binding) { self.report_conflict(parent, ident, ns, old_binding, &binding); } @@ -379,7 +376,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { ImportKind::Single { target, type_ns_only, .. } => { self.r.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { - let key = this.new_key(target, ns); + let key = BindingKey::new(target, ns); let mut resolution = this.resolution(current_module, key).borrow_mut(); resolution.add_single_import(import); } @@ -876,6 +873,11 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { let msg = "macro-expanded `extern crate` items cannot \ shadow names passed with `--extern`"; self.r.tcx.sess.span_err(item.span, msg); + // `return` is intended to discard this binding because it's an + // unregistered ambiguity error which would result in a panic + // caused by inconsistency `path_res` + // more details: https://github.com/rust-lang/rust/pull/111761 + return; } } let entry = self.r.extern_prelude.entry(ident.normalize_to_macros_2_0()).or_insert( diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 6675b8ed59b..ed0a792d387 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -28,10 +28,10 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Span, SyntaxContext}; use thin_vec::ThinVec; -use crate::errors as errs; use crate::imports::{Import, ImportKind}; use crate::late::{PatternSource, Rib}; use crate::path_names_to_string; +use crate::{errors as errs, BindingKey}; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, Finalize}; use crate::{HasGenericParams, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot}; use crate::{LexicalScopeBinding, NameBinding, NameBindingKind, PrivacyError, VisResolutionError}; @@ -550,7 +550,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let sm = self.tcx.sess.source_map(); let def_id = match outer_res { - Res::SelfTyParam { .. } | Res::SelfCtor(_) => { + Res::SelfTyParam { .. } => { err.span_label(span, "can't use `Self` here"); return err; } @@ -1832,7 +1832,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } (msg, None) } else if ident.name == kw::SelfUpper { - ("`Self` is only available in impls, traits, and type definitions".to_string(), None) + // As mentioned above, `opt_ns` being `None` indicates a module path in import. + // We can use this to improve a confusing error for, e.g. `use Self::Variant` in an + // impl + if opt_ns.is_none() { + ("`Self` cannot be used in imports".to_string(), None) + } else { + ( + "`Self` is only available in impls, traits, and type definitions".to_string(), + None, + ) + } } else if ident.name.as_str().chars().next().map_or(false, |c| c.is_ascii_uppercase()) { // Check whether the name refers to an item in the value namespace. let binding = if let Some(ribs) = ribs { @@ -2081,7 +2091,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } let resolutions = self.resolutions(crate_module).borrow(); - let resolution = resolutions.get(&self.new_key(ident, MacroNS))?; + let binding_key = BindingKey::new(ident, MacroNS); + let resolution = resolutions.get(&binding_key)?; let binding = resolution.borrow().binding()?; if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() { let module_name = crate_module.kind.name().unwrap(); diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 755acdd81fe..945c7ce3a9b 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -18,6 +18,7 @@ use crate::late::{ ConstantHasGenerics, HasGenericParams, NoConstantGenericsReason, PathSource, Rib, RibKind, }; use crate::macros::{sub_namespace_match, MacroRulesScope}; +use crate::BindingKey; use crate::{errors, AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize}; use crate::{Import, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot}; use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res}; @@ -865,7 +866,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } }; - let key = self.new_key(ident, ns); + let key = BindingKey::new(ident, ns); let resolution = self.resolution(module, key).try_borrow_mut().map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports. @@ -1174,10 +1175,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { return Res::Err; } } - Res::Def(DefKind::TyParam, _) - | Res::SelfTyParam { .. } - | Res::SelfTyAlias { .. } - | Res::SelfCtor(_) => { + Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => { for rib in ribs { let has_generic_params: HasGenericParams = match rib.kind { RibKind::Normal diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 9e4429507b1..7c4c05d4b94 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -405,17 +405,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { t } - // Define a dummy resolution containing a `Res::Err` as a placeholder for a failed resolution, - // also mark such failed imports as used to avoid duplicate diagnostics. - fn import_dummy_binding(&mut self, import: &'a Import<'a>) { + // Define a dummy resolution containing a `Res::Err` as a placeholder for a failed + // or indeterminate resolution, also mark such failed imports as used to avoid duplicate diagnostics. + fn import_dummy_binding(&mut self, import: &'a Import<'a>, is_indeterminate: bool) { if let ImportKind::Single { target, ref target_bindings, .. } = import.kind { - if target_bindings.iter().any(|binding| binding.get().is_some()) { + if !(is_indeterminate || target_bindings.iter().all(|binding| binding.get().is_none())) + { return; // Has resolution, do not create the dummy binding } let dummy_binding = self.dummy_binding; let dummy_binding = self.import(dummy_binding, import); self.per_ns(|this, ns| { - let key = this.new_key(target, ns); + let key = BindingKey::new(target, ns); let _ = this.try_define(import.parent_scope.module, key, dummy_binding); }); self.record_use(target, dummy_binding, false); @@ -474,7 +475,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // If this import is unresolved then create a dummy import // resolution for it so that later resolve stages won't complain. - self.import_dummy_binding(import); + self.import_dummy_binding(import, is_indeterminate); if let Some(err) = unresolved_import_error { if let ImportKind::Single { source, ref source_bindings, .. } = import.kind { @@ -712,7 +713,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .span_label(import.span, "cannot be imported directly") .emit(); } - let key = this.new_key(target, ns); + let key = BindingKey::new(target, ns); this.update_resolution(parent, key, |_, resolution| { resolution.single_imports.remove(&Interned::new_unchecked(import)); }); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index c053ea222a0..e0611907613 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -6,6 +6,7 @@ //! If you wonder why there's no `early.rs`, that's because it's split into three files - //! `build_reduced_graph.rs`, `macros.rs` and `imports.rs`. +use crate::BindingKey; use crate::{path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding}; use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult}; use crate::{ResolutionError, Resolver, Segment, UseError}; @@ -16,7 +17,7 @@ use rustc_ast::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_errors::{Applicability, DiagnosticArgValue, DiagnosticId, IntoDiagnosticArg}; use rustc_hir::def::Namespace::{self, *}; -use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS}; +use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{BindingAnnotation, PrimTy, TraitCandidate}; use rustc_middle::middle::resolve_bound_vars::Set1; @@ -2967,7 +2968,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // If there is a TraitRef in scope for an impl, then the method must be in the trait. let Some((module, _)) = &self.current_trait_ref else { return; }; ident.span.normalize_to_macros_2_0_and_adjust(module.expansion); - let key = self.r.new_key(ident, ns); + let key = BindingKey::new(ident, ns); let mut binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding); debug!(?binding); if binding.is_none() { @@ -2978,7 +2979,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { TypeNS => ValueNS, _ => ns, }; - let key = self.r.new_key(ident, ns); + let key = BindingKey::new(ident, ns); binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding); debug!(?binding); } @@ -4286,12 +4287,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } } - fn resolve_and_cache_rustdoc_path(&mut self, path_str: &str, ns: Namespace) -> bool { + fn resolve_and_cache_rustdoc_path(&mut self, path_str: &str, ns: Namespace) -> Option<Res> { // FIXME: This caching may be incorrect in case of multiple `macro_rules` // items with the same name in the same module. // Also hygiene is not considered. let mut doc_link_resolutions = std::mem::take(&mut self.r.doc_link_resolutions); - let res = doc_link_resolutions + let res = *doc_link_resolutions .entry(self.parent_scope.module.nearest_parent_mod().expect_local()) .or_default() .entry((Symbol::intern(path_str), ns)) @@ -4306,8 +4307,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { return None; } res - }) - .is_some(); + }); self.r.doc_link_resolutions = doc_link_resolutions; res } @@ -4342,8 +4342,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let mut any_resolved = false; let mut need_assoc = false; for ns in [TypeNS, ValueNS, MacroNS] { - if self.resolve_and_cache_rustdoc_path(&path_str, ns) { - any_resolved = true; + if let Some(res) = self.resolve_and_cache_rustdoc_path(&path_str, ns) { + // Rustdoc ignores tool attribute resolutions and attempts + // to resolve their prefixes for diagnostics. + any_resolved = !matches!(res, Res::NonMacroAttr(NonMacroAttrKind::Tool)); } else if ns != MacroNS { need_assoc = true; } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 323b78fcd98..1e31a0ff278 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -85,6 +85,7 @@ pub mod rustdoc; fluent_messages! { "../messages.ftl" } +#[derive(Debug)] enum Weak { Yes, No, @@ -105,7 +106,7 @@ impl Determinacy { /// A specific scope in which a name can be looked up. /// This enum is currently used only for early resolution (imports and macros), /// but not for late resolution yet. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] enum Scope<'a> { DeriveHelpers(LocalExpnId), DeriveHelpersCompat, @@ -469,6 +470,13 @@ struct BindingKey { disambiguator: u32, } +impl BindingKey { + fn new(ident: Ident, ns: Namespace) -> Self { + let ident = ident.normalize_to_macros_2_0(); + BindingKey { ident, ns, disambiguator: 0 } + } +} + type Resolutions<'a> = RefCell<FxIndexMap<BindingKey, &'a RefCell<NameResolution<'a>>>>; /// One node in the tree of modules. @@ -943,6 +951,7 @@ pub struct Resolver<'a, 'tcx> { empty_module: Module<'a>, module_map: FxHashMap<DefId, Module<'a>>, binding_parent_modules: FxHashMap<Interned<'a, NameBinding<'a>>, Module<'a>>, + underscore_disambiguator: u32, /// Maps glob imports to the names of items actually imported. @@ -1595,7 +1604,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { import_ids } - fn new_key(&mut self, ident: Ident, ns: Namespace) -> BindingKey { + fn new_disambiguated_key(&mut self, ident: Ident, ns: Namespace) -> BindingKey { let ident = ident.normalize_to_macros_2_0(); let disambiguator = if ident.name == kw::Underscore { self.underscore_disambiguator += 1; diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index e2b8d3eea2d..a328447aca9 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -421,7 +421,7 @@ pub enum TrimmedDefPaths { GoodPath, } -#[derive(Clone, Hash)] +#[derive(Clone, Hash, Debug)] pub enum ResolveDocLinks { /// Do not resolve doc links. None, @@ -1319,7 +1319,7 @@ pub(super) fn build_target_config( let (target, target_warnings) = target_result.unwrap_or_else(|e| { early_error( opts.error_format, - &format!( + format!( "Error loading target specification: {}. \ Run `rustc --print target-list` for a list of built-in targets", e @@ -1327,15 +1327,14 @@ pub(super) fn build_target_config( ) }); for warning in target_warnings.warning_messages() { - early_warn(opts.error_format, &warning) + early_warn(opts.error_format, warning) } if !matches!(target.pointer_width, 16 | 32 | 64) { early_error( opts.error_format, - &format!( - "target specification was invalid: \ - unrecognized target-pointer-width {}", + format!( + "target specification was invalid: unrecognized target-pointer-width {}", target.pointer_width ), ) @@ -1599,7 +1598,7 @@ pub fn get_cmd_lint_options( let lint_cap = matches.opt_str("cap-lints").map(|cap| { lint::Level::from_str(&cap) - .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{cap}`"))) + .unwrap_or_else(|| early_error(error_format, format!("unknown lint level: `{cap}`"))) }); (lint_opts, describe_lints, lint_cap) @@ -1616,7 +1615,7 @@ pub fn parse_color(matches: &getopts::Matches) -> ColorConfig { Some(arg) => early_error( ErrorOutputType::default(), - &format!( + format!( "argument for `--color` must be auto, \ always or never (instead was `{arg}`)" ), @@ -1691,7 +1690,7 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig { "future-incompat" => json_future_incompat = true, s => early_error( ErrorOutputType::default(), - &format!("unknown `--json` option `{s}`"), + format!("unknown `--json` option `{s}`"), ), } } @@ -1729,7 +1728,7 @@ pub fn parse_error_format( Some(arg) => early_error( ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)), - &format!( + format!( "argument for `--error-format` must be `human`, `json` or \ `short` (instead was `{arg}`)" ), @@ -1763,7 +1762,7 @@ pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition { Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| { early_error( ErrorOutputType::default(), - &format!( + format!( "argument for `--edition` must be one of: \ {EDITION_NAME_LIST}. (instead was `{arg}`)" ), @@ -1782,7 +1781,7 @@ pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition { } else { format!("edition {edition} is unstable and only available with -Z unstable-options") }; - early_error(ErrorOutputType::default(), &msg) + early_error(ErrorOutputType::default(), msg) } edition @@ -1827,7 +1826,7 @@ fn parse_output_types( let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| { early_error( error_format, - &format!( + format!( "unknown emission type: `{shorthand}` - expected one of: {display}", display = OutputType::shorthands_display(), ), @@ -1866,7 +1865,7 @@ fn should_override_cgus_and_disable_thinlto( for ot in &incompatible { early_warn( error_format, - &format!( + format!( "`--emit={ot}` with `-o` incompatible with \ `-C codegen-units=N` for N > 1", ), @@ -1970,7 +1969,7 @@ fn collect_print_requests( let prints = prints.join(", "); early_error( error_format, - &format!("unknown print request `{req}`. Valid print requests are: {prints}"), + format!("unknown print request `{req}`. Valid print requests are: {prints}"), ); } } @@ -1987,7 +1986,7 @@ pub fn parse_target_triple( Some(target) if target.ends_with(".json") => { let path = Path::new(&target); TargetTriple::from_path(path).unwrap_or_else(|_| { - early_error(error_format, &format!("target file {path:?} does not exist")) + early_error(error_format, format!("target file {path:?} does not exist")) }) } Some(target) => TargetTriple::TargetTriple(target), @@ -2028,7 +2027,7 @@ fn parse_opt_level( arg => { early_error( error_format, - &format!( + format!( "optimization level needs to be \ between 0-3, s or z (instead was `{arg}`)" ), @@ -2059,7 +2058,7 @@ pub(crate) fn parse_assert_incr_state( Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded), Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded), Some(s) => { - early_error(error_format, &format!("unexpected incremental state assertion value: {s}")) + early_error(error_format, format!("unexpected incremental state assertion value: {s}")) } None => None, } @@ -2086,13 +2085,13 @@ fn parse_native_lib_kind( } else { ", the `-Z unstable-options` flag must also be passed to use it" }; - early_error(error_format, &format!("library kind `link-arg` is unstable{why}")) + early_error(error_format, format!("library kind `link-arg` is unstable{why}")) } NativeLibKind::LinkArg } _ => early_error( error_format, - &format!( + format!( "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg" ), ), @@ -2127,16 +2126,13 @@ fn parse_native_lib_modifiers( } else { ", the `-Z unstable-options` flag must also be passed to use it" }; - early_error( - error_format, - &format!("linking modifier `{modifier}` is unstable{why}"), - ) + early_error(error_format, format!("linking modifier `{modifier}` is unstable{why}")) } }; let assign_modifier = |dst: &mut Option<bool>| { if dst.is_some() { let msg = format!("multiple `{modifier}` modifiers in a single `-l` option"); - early_error(error_format, &msg) + early_error(error_format, msg) } else { *dst = Some(value); } @@ -2173,7 +2169,7 @@ fn parse_native_lib_modifiers( // string, like `modifiers = ""`. _ => early_error( error_format, - &format!( + format!( "unknown linking modifier `{modifier}`, expected one \ of: bundle, verbatim, whole-archive, as-needed" ), @@ -2303,7 +2299,7 @@ pub fn parse_externs( } "nounused" => nounused_dep = true, "force" => force = true, - _ => early_error(error_format, &format!("unknown --extern option `{opt}`")), + _ => early_error(error_format, format!("unknown --extern option `{opt}`")), } } } @@ -2369,7 +2365,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let unparsed_crate_types = matches.opt_strs("crate-type"); let crate_types = parse_crate_types_from_list(unparsed_crate_types) - .unwrap_or_else(|e| early_error(error_format, &e)); + .unwrap_or_else(|e| early_error(error_format, e)); let mut unstable_opts = UnstableOptions::build(matches, error_format); let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); @@ -2597,7 +2593,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { }; let working_dir = std::env::current_dir().unwrap_or_else(|e| { - early_error(error_format, &format!("Current directory is invalid: {e}")); + early_error(error_format, format!("Current directory is invalid: {e}")); }); let remap = FilePathMapping::new(remap_path_prefix.clone()); @@ -2669,7 +2665,7 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio "mir-cfg" => MirCFG, name => early_error( efmt, - &format!( + format!( "argument to `unpretty` must be one of `normal`, `identified`, \ `expanded`, `expanded,identified`, `expanded,hygiene`, \ `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \ @@ -2747,7 +2743,7 @@ pub mod nightly_options { if opt.name != "Z" && !has_z_unstable_option { early_error( ErrorOutputType::default(), - &format!( + format!( "the `-Z unstable-options` flag must also be passed to enable \ the flag `{}`", opt.name @@ -2760,11 +2756,10 @@ pub mod nightly_options { match opt.stability { OptionStability::Unstable => { let msg = format!( - "the option `{}` is only accepted on the \ - nightly compiler", + "the option `{}` is only accepted on the nightly compiler", opt.name ); - early_error(ErrorOutputType::default(), &msg); + early_error(ErrorOutputType::default(), msg); } OptionStability::Stable => {} } diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index 8089d81cc22..dc475e8c6d5 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -6,7 +6,8 @@ use crate::search_paths::PathKind; use crate::utils::NativeLibKind; use crate::Session; use rustc_ast as ast; -use rustc_data_structures::sync::{self, AppendOnlyIndexVec, MetadataRef, RwLock}; +use rustc_data_structures::owned_slice::OwnedSlice; +use rustc_data_structures::sync::{self, AppendOnlyIndexVec, RwLock}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions}; use rustc_span::hygiene::{ExpnHash, ExpnId}; @@ -203,8 +204,8 @@ pub enum ExternCrateSource { /// metadata in library -- this trait just serves to decouple rustc_metadata from /// the archive reader, which depends on LLVM. pub trait MetadataLoader: std::fmt::Debug { - fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String>; - fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String>; + fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>; + fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>; } pub type MetadataLoaderDyn = dyn MetadataLoader + Send + Sync + sync::DynSend + sync::DynSync; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 5976b9aa3e7..2c4c4a7a6ce 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -329,21 +329,21 @@ fn build_options<O: Default>( match value { None => early_error( error_format, - &format!( + format!( "{0} option `{1}` requires {2} ({3} {1}=<value>)", outputname, key, type_desc, prefix ), ), Some(value) => early_error( error_format, - &format!( + format!( "incorrect value `{value}` for {outputname} option `{key}` - {type_desc} was expected" ), ), } } } - None => early_error(error_format, &format!("unknown {outputname} option: `{key}`")), + None => early_error(error_format, format!("unknown {outputname} option: `{key}`")), } } return op; diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 5cc9c62617d..7b396dde91b 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -289,7 +289,7 @@ impl ParseSess { lint: &'static Lint, span: impl Into<MultiSpan>, node_id: NodeId, - msg: &str, + msg: impl Into<DiagnosticMessage>, ) { self.buffered_lints.with_lock(|buffered_lints| { buffered_lints.push(BufferedEarlyLint { @@ -307,7 +307,7 @@ impl ParseSess { lint: &'static Lint, span: impl Into<MultiSpan>, node_id: NodeId, - msg: &str, + msg: impl Into<DiagnosticMessage>, diagnostic: BuiltinLintDiagnostics, ) { self.buffered_lints.with_lock(|buffered_lints| { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index a988d7f28e6..4f593083b6f 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -211,6 +211,9 @@ pub struct Session { /// Set of enabled features for the current target, including unstable ones. pub unstable_target_features: FxIndexSet<Symbol>, + + /// The version of the rustc process, possibly including a commit hash and description. + pub cfg_version: &'static str, } pub struct PerfStats { @@ -490,20 +493,6 @@ impl Session { } #[rustc_lint_diagnostics] #[track_caller] - pub fn span_err_or_warn<S: Into<MultiSpan>>( - &self, - is_warning: bool, - sp: S, - msg: impl Into<DiagnosticMessage>, - ) { - if is_warning { - self.span_warn(sp, msg); - } else { - self.span_err(sp, msg); - } - } - #[rustc_lint_diagnostics] - #[track_caller] pub fn span_err<S: Into<MultiSpan>>( &self, sp: S, @@ -1380,6 +1369,7 @@ pub fn build_session( driver_lint_caps: FxHashMap<lint::LintId, lint::Level>, file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>, target_override: Option<Target>, + cfg_version: &'static str, ) -> Session { // FIXME: This is not general enough to make the warning lint completely override // normal diagnostic warnings, since the warning lint can also be denied and changed @@ -1400,10 +1390,10 @@ pub fn build_session( let target_cfg = config::build_target_config(&sopts, target_override, &sysroot); let host_triple = TargetTriple::from_triple(config::host_triple()); let (host, target_warnings) = Target::search(&host_triple, &sysroot).unwrap_or_else(|e| { - early_error(sopts.error_format, &format!("Error loading host specification: {e}")) + early_error(sopts.error_format, format!("Error loading host specification: {e}")) }); for warning in target_warnings.warning_messages() { - early_warn(sopts.error_format, &warning) + early_warn(sopts.error_format, warning) } let loader = file_loader.unwrap_or_else(|| Box::new(RealFileLoader)); @@ -1445,7 +1435,7 @@ pub fn build_session( match profiler { Ok(profiler) => Some(Arc::new(profiler)), Err(e) => { - early_warn(sopts.error_format, &format!("failed to create profiler: {e}")); + early_warn(sopts.error_format, format!("failed to create profiler: {e}")); None } } @@ -1524,6 +1514,7 @@ pub fn build_session( asm_arch, target_features: Default::default(), unstable_target_features: Default::default(), + cfg_version, }; validate_commandline_args_with_session_available(&sess); @@ -1741,18 +1732,22 @@ fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] -pub fn early_error_no_abort(output: config::ErrorOutputType, msg: &str) -> ErrorGuaranteed { +#[must_use = "ErrorGuaranteed must be returned from `run_compiler` in order to exit with a non-zero status code"] +pub fn early_error_no_abort( + output: config::ErrorOutputType, + msg: impl Into<DiagnosticMessage>, +) -> ErrorGuaranteed { early_error_handler(output).struct_err(msg).emit() } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] -pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { +pub fn early_error(output: config::ErrorOutputType, msg: impl Into<DiagnosticMessage>) -> ! { early_error_handler(output).struct_fatal(msg).emit() } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] -pub fn early_warn(output: config::ErrorOutputType, msg: &str) { +pub fn early_warn(output: config::ErrorOutputType, msg: impl Into<DiagnosticMessage>) { early_error_handler(output).struct_warn(msg).emit() } diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 8c58b52a5dc..f65a6aa4fb2 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -146,7 +146,12 @@ pub struct StableCrateId(pub(crate) Hash64); impl StableCrateId { /// Computes the stable ID for a crate with the given name and /// `-Cmetadata` arguments. - pub fn new(crate_name: Symbol, is_exe: bool, mut metadata: Vec<String>) -> StableCrateId { + pub fn new( + crate_name: Symbol, + is_exe: bool, + mut metadata: Vec<String>, + cfg_version: &'static str, + ) -> StableCrateId { let mut hasher = StableHasher::new(); // We must hash the string text of the crate name, not the id, as the id is not stable // across builds. @@ -180,7 +185,7 @@ impl StableCrateId { if let Some(val) = std::env::var_os("RUSTC_FORCE_RUSTC_VERSION") { hasher.write(val.to_string_lossy().into_owned().as_bytes()) } else { - hasher.write(option_env!("CFG_VERSION").unwrap_or("unknown version").as_bytes()); + hasher.write(cfg_version.as_bytes()) } StableCrateId(hasher.finish()) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 97cb734619e..8d70aa47f78 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1257,29 +1257,6 @@ impl SourceFileHash { } } -#[derive(HashStable_Generic)] -#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)] -pub enum DebuggerVisualizerType { - Natvis, - GdbPrettyPrinter, -} - -/// A single debugger visualizer file. -#[derive(HashStable_Generic)] -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)] -pub struct DebuggerVisualizerFile { - /// The complete debugger visualizer source. - pub src: Lrc<[u8]>, - /// Indicates which visualizer type this targets. - pub visualizer_type: DebuggerVisualizerType, -} - -impl DebuggerVisualizerFile { - pub fn new(src: Lrc<[u8]>, visualizer_type: DebuggerVisualizerType) -> Self { - DebuggerVisualizerFile { src, visualizer_type } - } -} - #[derive(Clone)] pub enum SourceFileLines { /// The source file lines, in decoded (random-access) form. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9951d8f4fc1..874d578fe1d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -164,6 +164,7 @@ symbols! { Capture, Center, Clone, + ConstParamTy, Context, Continue, Copy, @@ -1583,6 +1584,7 @@ symbols! { unrestricted_attribute_tokens, unsafe_block_in_unsafe_fn, unsafe_cell, + unsafe_cell_from_mut, unsafe_no_drop_flag, unsafe_pin_internals, unsize, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index a3f262905c7..254ede4e6a0 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -220,7 +220,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> { match *ty.kind() { // Print all nominal types as paths (unlike `pretty_print_type`). ty::FnDef(def_id, substs) - | ty::Alias(_, ty::AliasTy { def_id, substs, .. }) + | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. }) | ty::Closure(def_id, substs) | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs), @@ -241,6 +241,8 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> { Ok(self) } + ty::Alias(ty::Inherent, _) => panic!("unexpected inherent projection"), + _ => self.pretty_print_type(ty), } } diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index c281aa7e83a..da8a16dee8a 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -272,12 +272,11 @@ fn encode_region<'tcx>( s.push('E'); compress(dict, DictKey::Region(region), &mut s); } - RegionKind::ReErased => { + RegionKind::ReEarlyBound(..) | RegionKind::ReErased => { s.push_str("u6region"); compress(dict, DictKey::Region(region), &mut s); } - RegionKind::ReEarlyBound(..) - | RegionKind::ReFree(..) + RegionKind::ReFree(..) | RegionKind::ReStatic | RegionKind::ReError(_) | RegionKind::ReVar(..) @@ -673,6 +672,14 @@ fn encode_ty<'tcx>( typeid.push_str(&s); } + // Type parameters + ty::Param(..) => { + // u5param as vendor extended type + let mut s = String::from("u5param"); + compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); + typeid.push_str(&s); + } + // Unexpected types ty::Bound(..) | ty::Error(..) @@ -680,7 +687,6 @@ fn encode_ty<'tcx>( | ty::GeneratorWitnessMIR(..) | ty::Infer(..) | ty::Alias(..) - | ty::Param(..) | ty::Placeholder(..) => { bug!("encode_ty: unexpected `{:?}`", ty.kind()); } @@ -689,6 +695,42 @@ fn encode_ty<'tcx>( typeid } +/// Transforms predicates for being encoded and used in the substitution dictionary. +fn transform_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + predicates: &List<ty::PolyExistentialPredicate<'tcx>>, + _options: EncodeTyOptions, +) -> &'tcx List<ty::PolyExistentialPredicate<'tcx>> { + let predicates: Vec<ty::PolyExistentialPredicate<'tcx>> = predicates + .iter() + .filter_map(|predicate| match predicate.skip_binder() { + ty::ExistentialPredicate::Trait(trait_ref) => { + let trait_ref = ty::TraitRef::identity(tcx, trait_ref.def_id); + Some(ty::Binder::dummy(ty::ExistentialPredicate::Trait( + ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref), + ))) + } + ty::ExistentialPredicate::Projection(..) => None, + ty::ExistentialPredicate::AutoTrait(..) => Some(predicate), + }) + .collect(); + tcx.mk_poly_existential_predicates(&predicates) +} + +/// Transforms substs for being encoded and used in the substitution dictionary. +fn transform_substs<'tcx>( + tcx: TyCtxt<'tcx>, + substs: SubstsRef<'tcx>, + options: TransformTyOptions, +) -> SubstsRef<'tcx> { + let substs = substs.iter().map(|subst| match subst.unpack() { + GenericArgKind::Type(ty) if ty.is_c_void(tcx) => tcx.mk_unit().into(), + GenericArgKind::Type(ty) => transform_ty(tcx, ty, options).into(), + _ => subst, + }); + tcx.mk_substs_from_iter(substs) +} + // Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms all // c_void types into unit types unconditionally, generalizes pointers if // TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if @@ -697,7 +739,7 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio let mut ty = ty; match ty.kind() { - ty::Float(..) | ty::Char | ty::Str | ty::Never | ty::Foreign(..) | ty::Dynamic(..) => {} + ty::Float(..) | ty::Char | ty::Str | ty::Never | ty::Foreign(..) => {} ty::Bool => { if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { @@ -870,6 +912,14 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio } } + ty::Dynamic(predicates, _region, kind) => { + ty = tcx.mk_dynamic( + transform_predicates(tcx, predicates, options), + tcx.lifetimes.re_erased, + *kind, + ); + } + ty::Bound(..) | ty::Error(..) | ty::GeneratorWitness(..) @@ -885,20 +935,6 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio ty } -/// Transforms substs for being encoded and used in the substitution dictionary. -fn transform_substs<'tcx>( - tcx: TyCtxt<'tcx>, - substs: SubstsRef<'tcx>, - options: TransformTyOptions, -) -> SubstsRef<'tcx> { - let substs = substs.iter().map(|subst| match subst.unpack() { - GenericArgKind::Type(ty) if ty.is_c_void(tcx) => tcx.mk_unit().into(), - GenericArgKind::Type(ty) => transform_ty(tcx, ty, options).into(), - _ => subst, - }); - tcx.mk_substs_from_iter(substs) -} - /// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor /// extended type qualifiers and types for Rust types that are not used at the FFI boundary. #[instrument(level = "trace", skip(tcx))] diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 2235524129e..4cccc639892 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -433,7 +433,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { // Mangle all nominal types as paths. ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs) | ty::FnDef(def_id, substs) - | ty::Alias(_, ty::AliasTy { def_id, substs, .. }) + | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. }) | ty::Closure(def_id, substs) | ty::Generator(def_id, substs, _) => { self = self.print_def_path(def_id, substs)?; @@ -482,6 +482,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { self = r.print(self)?; } + ty::Alias(ty::Inherent, _) => bug!("symbol_names: unexpected inherent projection"), ty::GeneratorWitness(_) => bug!("symbol_names: unexpected `GeneratorWitness`"), ty::GeneratorWitnessMIR(..) => bug!("symbol_names: unexpected `GeneratorWitnessMIR`"), } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 25cc82f01d5..d14e6244f7d 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -506,10 +506,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Param(_) | ty::Placeholder(..) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Alias(ty::Inherent, _) | ty::Error(_) => return, ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"), - ty::Alias(_, alias_ty) => alias_ty, + // Excluding IATs here as they don't have meaningful item bounds. + ty::Alias(ty::Projection | ty::Opaque, alias_ty) => alias_ty, }; for assumption in self.tcx().item_bounds(alias_ty.def_id).subst(self.tcx(), alias_ty.substs) diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index dcfa33ae842..644bfd33970 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -177,14 +177,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return Err(NoSolution); } - if goal.predicate.self_ty().has_non_region_infer() { + // The regions of a type don't affect the size of the type + let tcx = ecx.tcx(); + // We should erase regions from both the param-env and type, since both + // may have infer regions. Specifically, after canonicalizing and instantiating, + // early bound regions turn into region vars in both the new and old solver. + let key = tcx.erase_regions(goal.param_env.and(goal.predicate.self_ty())); + // But if there are inference variables, we have to wait until it's resolved. + if key.has_non_region_infer() { return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); } - let tcx = ecx.tcx(); - let self_ty = tcx.erase_regions(goal.predicate.self_ty()); - - if let Ok(layout) = tcx.layout_of(goal.param_env.and(self_ty)) + if let Ok(layout) = tcx.layout_of(key) && layout.layout.is_pointer_like(&tcx.data_layout) { // FIXME: We could make this faster by making a no-constraints response diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index f5f2fe54217..dc43a3d154a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -885,7 +885,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { return; } - if self.suggest_impl_trait(&mut err, span, &obligation, trait_predicate) { + if self.suggest_impl_trait(&mut err, &obligation, trait_predicate) { err.emit(); return; } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 88525e1b720..10bd027b684 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -306,6 +306,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } } + + // `&[{integral}]` - `FromIterator` needs that. + if let ty::Ref(_, ref_ty, rustc_ast::Mutability::Not) = self_ty.kind() + && let ty::Slice(sty) = ref_ty.kind() + && sty.is_integral() + { + flags.push((sym::_Self, Some("&[{integral}]".to_owned()))); + } }); if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) { 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 ea17f23434b..83511e898f7 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -30,9 +30,9 @@ use rustc_middle::hir::map; use rustc_middle::ty::error::TypeError::{self, Sorts}; use rustc_middle::ty::{ self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, - GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, InternalSubsts, - IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder, - TypeSuperFoldable, TypeVisitableExt, TypeckResults, + GeneratorDiagnosticData, GeneratorInteriorTypeCause, InferTy, InternalSubsts, IsSuggestable, + ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitableExt, TypeckResults, }; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -261,7 +261,6 @@ pub trait TypeErrCtxtExt<'tcx> { fn suggest_impl_trait( &self, err: &mut Diagnostic, - span: Span, obligation: &PredicateObligation<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool; @@ -1792,215 +1791,66 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn suggest_impl_trait( &self, err: &mut Diagnostic, - span: Span, obligation: &PredicateObligation<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { - match obligation.cause.code().peel_derives() { - // Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`. - ObligationCauseCode::SizedReturnType => {} - _ => return false, - } - - let hir = self.tcx.hir(); - let fn_hir_id = hir.local_def_id_to_hir_id(obligation.cause.body_id); - let node = hir.find_by_def_id(obligation.cause.body_id); - let Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(sig, _, body_id), - .. - })) = node - else { + let ObligationCauseCode::SizedReturnType = obligation.cause.code() else { return false; }; - let body = hir.body(*body_id); - let trait_pred = self.resolve_vars_if_possible(trait_pred); - let ty = trait_pred.skip_binder().self_ty(); - let is_object_safe = match ty.kind() { - ty::Dynamic(predicates, _, ty::Dyn) => { - // If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`. - predicates - .principal_def_id() - .map_or(true, |def_id| self.tcx.check_is_object_safe(def_id)) - } - // We only want to suggest `impl Trait` to `dyn Trait`s. - // For example, `fn foo() -> str` needs to be filtered out. - _ => return false, - }; - - let hir::FnRetTy::Return(ret_ty) = sig.decl.output else { + let ty::Dynamic(_, _, ty::Dyn) = trait_pred.self_ty().skip_binder().kind() else { return false; }; - // Use `TypeVisitor` instead of the output type directly to find the span of `ty` for - // cases like `fn foo() -> (dyn Trait, i32) {}`. - // Recursively look for `TraitObject` types and if there's only one, use that span to - // suggest `impl Trait`. - - // Visit to make sure there's a single `return` type to suggest `impl Trait`, - // otherwise suggest using `Box<dyn Trait>` or an enum. - let mut visitor = ReturnsVisitor::default(); - visitor.visit_body(&body); - - let typeck_results = self.typeck_results.as_ref().unwrap(); - let Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id).copied() else { return false; }; - - let ret_types = visitor - .returns - .iter() - .filter_map(|expr| Some((expr.span, typeck_results.node_type_opt(expr.hir_id)?))) - .map(|(expr_span, ty)| (expr_span, self.resolve_vars_if_possible(ty))); - let (last_ty, all_returns_have_same_type, only_never_return) = ret_types.clone().fold( - (None, true, true), - |(last_ty, mut same, only_never_return): (std::option::Option<Ty<'_>>, bool, bool), - (_, ty)| { - let ty = self.resolve_vars_if_possible(ty); - same &= - !matches!(ty.kind(), ty::Error(_)) - && last_ty.map_or(true, |last_ty| { - // FIXME: ideally we would use `can_coerce` here instead, but `typeck` comes - // *after* in the dependency graph. - match (ty.kind(), last_ty.kind()) { - (Infer(InferTy::IntVar(_)), Infer(InferTy::IntVar(_))) - | (Infer(InferTy::FloatVar(_)), Infer(InferTy::FloatVar(_))) - | (Infer(InferTy::FreshIntTy(_)), Infer(InferTy::FreshIntTy(_))) - | ( - Infer(InferTy::FreshFloatTy(_)), - Infer(InferTy::FreshFloatTy(_)), - ) => true, - _ => ty == last_ty, - } - }); - (Some(ty), same, only_never_return && matches!(ty.kind(), ty::Never)) - }, - ); - let mut spans_and_needs_box = vec![]; - - match liberated_sig.output().kind() { - ty::Dynamic(predicates, _, ty::Dyn) => { - let cause = ObligationCause::misc(ret_ty.span, obligation.cause.body_id); - let param_env = ty::ParamEnv::empty(); - - if !only_never_return { - for (expr_span, return_ty) in ret_types { - let self_ty_satisfies_dyn_predicates = |self_ty| { - predicates.iter().all(|predicate| { - let pred = predicate.with_self_ty(self.tcx, self_ty); - let obl = Obligation::new(self.tcx, cause.clone(), param_env, pred); - self.predicate_may_hold(&obl) - }) - }; - - if let ty::Adt(def, substs) = return_ty.kind() - && def.is_box() - && self_ty_satisfies_dyn_predicates(substs.type_at(0)) - { - spans_and_needs_box.push((expr_span, false)); - } else if self_ty_satisfies_dyn_predicates(return_ty) { - spans_and_needs_box.push((expr_span, true)); - } else { - return false; - } - } - } - } - _ => return false, - }; - - let sm = self.tcx.sess.source_map(); - if !ret_ty.span.overlaps(span) { - return false; - } - let snippet = if let hir::TyKind::TraitObject(..) = ret_ty.kind { - if let Ok(snippet) = sm.span_to_snippet(ret_ty.span) { - snippet - } else { - return false; - } - } else { - // Substitute the type, so we can print a fixup given `type Alias = dyn Trait` - let name = liberated_sig.output().to_string(); - let name = - name.strip_prefix('(').and_then(|name| name.strip_suffix(')')).unwrap_or(&name); - if !name.starts_with("dyn ") { - return false; - } - name.to_owned() - }; - err.code(error_code!(E0746)); err.set_primary_message("return type cannot have an unboxed trait object"); err.children.clear(); - let impl_trait_msg = "for information on `impl Trait`, see \ - <https://doc.rust-lang.org/book/ch10-02-traits.html\ - #returning-types-that-implement-traits>"; - let trait_obj_msg = "for information on trait objects, see \ - <https://doc.rust-lang.org/book/ch17-02-trait-objects.html\ - #using-trait-objects-that-allow-for-values-of-different-types>"; - - let has_dyn = snippet.split_whitespace().next().map_or(false, |s| s == "dyn"); - let trait_obj = if has_dyn { &snippet[4..] } else { &snippet }; - if only_never_return { - // No return paths, probably using `panic!()` or similar. - // Suggest `-> impl Trait`, and if `Trait` is object safe, `-> Box<dyn Trait>`. - suggest_trait_object_return_type_alternatives( - err, - ret_ty.span, - trait_obj, - is_object_safe, - ); - } else if let (Some(last_ty), true) = (last_ty, all_returns_have_same_type) { - // Suggest `-> impl Trait`. + + let span = obligation.cause.span; + if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) + && snip.starts_with("dyn ") + { err.span_suggestion( - ret_ty.span, - format!( - "use `impl {1}` as the return type, as all return paths are of type `{}`, \ - which implements `{1}`", - last_ty, trait_obj, - ), - format!("impl {}", trait_obj), - Applicability::MachineApplicable, + span.with_hi(span.lo() + BytePos(4)), + "return an `impl Trait` instead of a `dyn Trait`, \ + if all returned values are the same type", + "impl ", + Applicability::MaybeIncorrect, ); - err.note(impl_trait_msg); - } else { - if is_object_safe { - // Suggest `-> Box<dyn Trait>` and `Box::new(returned_value)`. - err.multipart_suggestion( - "return a boxed trait object instead", - vec![ - (ret_ty.span.shrink_to_lo(), "Box<".to_string()), - (span.shrink_to_hi(), ">".to_string()), - ], - Applicability::MaybeIncorrect, - ); - for (span, needs_box) in spans_and_needs_box { - if needs_box { - err.multipart_suggestion( - "... and box this value", - vec![ - (span.shrink_to_lo(), "Box::new(".to_string()), - (span.shrink_to_hi(), ")".to_string()), - ], - Applicability::MaybeIncorrect, - ); - } - } + } + + let body = self.tcx.hir().body(self.tcx.hir().body_owned_by(obligation.cause.body_id)); + + let mut visitor = ReturnsVisitor::default(); + visitor.visit_body(&body); + + let mut sugg = + vec![(span.shrink_to_lo(), "Box<".to_string()), (span.shrink_to_hi(), ">".to_string())]; + sugg.extend(visitor.returns.into_iter().flat_map(|expr| { + let span = expr.span.find_ancestor_in_same_ctxt(obligation.cause.span).unwrap_or(expr.span); + if !span.can_be_used_for_suggestions() { + vec![] + } else if let hir::ExprKind::Call(path, ..) = expr.kind + && let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, method)) = path.kind + && method.ident.name == sym::new + && let hir::TyKind::Path(hir::QPath::Resolved(.., box_path)) = ty.kind + && box_path.res.opt_def_id().is_some_and(|def_id| Some(def_id) == self.tcx.lang_items().owned_box()) + { + // Don't box `Box::new` + vec![] } else { - // This is currently not possible to trigger because E0038 takes precedence, but - // leave it in for completeness in case anything changes in an earlier stage. - err.note(format!( - "if trait `{}` were object-safe, you could return a trait object", - trait_obj, - )); + vec![ + (span.shrink_to_lo(), "Box::new(".to_string()), + (span.shrink_to_hi(), ")".to_string()), + ] } - err.note(trait_obj_msg); - err.note(format!( - "if all the returned values were of the same type you could use `impl {}` as the \ - return type", - trait_obj, - )); - err.note(impl_trait_msg); - err.note("you can create a new `enum` with a variant for each returned type"); - } + })); + + err.multipart_suggestion( + "box the return type, and wrap all of the returned values in `Box::new`", + sugg, + Applicability::MaybeIncorrect, + ); + true } @@ -4139,37 +3989,6 @@ impl NextTypeParamName for &[hir::GenericParam<'_>] { } } -fn suggest_trait_object_return_type_alternatives( - err: &mut Diagnostic, - ret_ty: Span, - trait_obj: &str, - is_object_safe: bool, -) { - err.span_suggestion( - ret_ty, - format!( - "use `impl {}` as the return type if all return paths have the same type but you \ - want to expose only the trait in the signature", - trait_obj, - ), - format!("impl {}", trait_obj), - Applicability::MaybeIncorrect, - ); - if is_object_safe { - err.multipart_suggestion( - format!( - "use a boxed trait object if all return paths implement trait `{}`", - trait_obj, - ), - vec![ - (ret_ty.shrink_to_lo(), "Box<".to_string()), - (ret_ty.shrink_to_hi(), ">".to_string()), - ], - Applicability::MaybeIncorrect, - ); - } -} - /// Collect the spans that we see the generic param `param_did` struct ReplaceImplTraitVisitor<'a> { ty_spans: &'a mut Vec<Span>, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 223cdc48f0b..f265230ff77 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -17,6 +17,7 @@ pub mod query; mod select; mod specialize; mod structural_match; +mod structural_normalize; mod util; mod vtable; pub mod wf; @@ -62,6 +63,7 @@ pub use self::specialize::{ pub use self::structural_match::{ search_for_adt_const_param_violation, search_for_structural_match_violation, }; +pub use self::structural_normalize::StructurallyNormalizeExt; pub use self::util::elaborate; pub use self::util::{expand_trait_aliases, TraitAliasExpander}; pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices}; @@ -143,35 +145,36 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>( fn pred_known_to_hold_modulo_regions<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - pred: impl ToPredicate<'tcx> + TypeVisitable<TyCtxt<'tcx>>, + pred: impl ToPredicate<'tcx>, ) -> bool { - let has_non_region_infer = pred.has_non_region_infer(); let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred); let result = infcx.evaluate_obligation_no_overflow(&obligation); debug!(?result); - if result.must_apply_modulo_regions() && !has_non_region_infer { + if result.must_apply_modulo_regions() { true } else if result.may_apply() { - // Because of inference "guessing", selection can sometimes claim - // to succeed while the success requires a guess. To ensure - // this function's result remains infallible, we must confirm - // that guess. While imperfect, I believe this is sound. - - // The handling of regions in this area of the code is terrible, - // see issue #29149. We should be able to improve on this with - // NLL. - let ocx = ObligationCtxt::new(infcx); - ocx.register_obligation(obligation); - let errors = ocx.select_all_or_error(); - match errors.as_slice() { - [] => true, - errors => { - debug!(?errors); - false + // Sometimes obligations are ambiguous because the recursive evaluator + // is not smart enough, so we fall back to fulfillment when we're not certain + // that an obligation holds or not. Even still, we must make sure that + // the we do no inference in the process of checking this obligation. + let goal = infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env)); + infcx.probe(|_| { + let ocx = ObligationCtxt::new_in_snapshot(infcx); + ocx.register_obligation(obligation); + + let errors = ocx.select_all_or_error(); + match errors.as_slice() { + // Only known to hold if we did no inference. + [] => infcx.shallow_resolve(goal) == goal, + + errors => { + debug!(?errors); + false + } } - } + }) } else { false } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 8e684b7ac23..51069897120 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1543,7 +1543,10 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( // Check whether the self-type is itself a projection. // If so, extract what we know from the trait and try to come up with a good answer. let bounds = match *obligation.predicate.self_ty().kind() { - ty::Alias(_, ref data) => tcx.item_bounds(data.def_id).subst(tcx, data.substs), + // Excluding IATs here as they don't have meaningful item bounds. + ty::Alias(ty::Projection | ty::Opaque, ref data) => { + tcx.item_bounds(data.def_id).subst(tcx, data.substs) + } ty::Infer(ty::TyVar(_)) => { // If the self-type is an inference variable, then it MAY wind up // being a projected type, so induce an ambiguity. @@ -2260,7 +2263,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( obligation, poly_cache_entry, e, ); debug!("confirm_param_env_candidate: {}", msg); - let err = infcx.tcx.ty_error_with_message(obligation.cause.span, &msg); + let err = infcx.tcx.ty_error_with_message(obligation.cause.span, msg); Progress { term: err.into(), obligations: vec![] } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index a8fb55df2d3..8bc82b9f549 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -143,7 +143,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Before we go into the whole placeholder thing, just // quickly check if the self-type is a projection at all. match obligation.predicate.skip_binder().trait_ref.self_ty().kind() { - ty::Alias(..) => {} + // Excluding IATs here as they don't have meaningful item bounds. + ty::Alias(ty::Projection | ty::Opaque, _) => {} ty::Infer(ty::TyVar(_)) => { span_bug!( obligation.cause.span, @@ -966,16 +967,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) { // The regions of a type don't affect the size of the type let tcx = self.tcx(); - let self_ty = - tcx.erase_regions(tcx.erase_late_bound_regions(obligation.predicate.self_ty())); - + let self_ty = tcx.erase_late_bound_regions(obligation.predicate.self_ty()); + // We should erase regions from both the param-env and type, since both + // may have infer regions. Specifically, after canonicalizing and instantiating, + // early bound regions turn into region vars in both the new and old solver. + let key = tcx.erase_regions(obligation.param_env.and(self_ty)); // But if there are inference variables, we have to wait until it's resolved. - if self_ty.has_non_region_infer() { + if key.has_non_region_infer() { candidates.ambiguous = true; return; } - if let Ok(layout) = tcx.layout_of(obligation.param_env.and(self_ty)) + if let Ok(layout) = tcx.layout_of(key) && layout.layout.is_pointer_like(&tcx.data_layout) { candidates.vec.push(BuiltinCandidate { has_nested: false }); diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 6a648294efd..0d9f55d4c2e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -132,6 +132,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } }; + // The obligations returned by confirmation are recursively evaluated + // so we need to make sure they have the correct depth. + for subobligation in impl_src.borrow_nested_obligations_mut() { + subobligation.set_depth_from_parent(obligation.recursion_depth); + } + if !obligation.predicate.is_const_if_const() { // normalize nested predicates according to parent predicate's constness. impl_src = impl_src.map(|mut o| { @@ -156,7 +162,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let placeholder_self_ty = placeholder_trait_predicate.self_ty(); let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate); let (def_id, substs) = match *placeholder_self_ty.kind() { - ty::Alias(_, ty::AliasTy { def_id, substs, .. }) => (def_id, substs), + // Excluding IATs here as they don't have meaningful item bounds. + ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { + (def_id, substs) + } _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty), }; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index b72ff5b78e4..b366bbd531b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -537,14 +537,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PredicateObligation<'tcx>, ) -> Result<EvaluationResult, OverflowError> { self.evaluation_probe(|this| { - if this.tcx().trait_solver_next() { - this.evaluate_predicates_recursively_in_new_solver([obligation.clone()]) + let goal = + this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env)); + let mut result = if this.tcx().trait_solver_next() { + this.evaluate_predicates_recursively_in_new_solver([obligation.clone()])? } else { this.evaluate_predicate_recursively( TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), obligation.clone(), - ) + )? + }; + // If the predicate has done any inference, then downgrade the + // result to ambiguous. + if this.infcx.shallow_resolve(goal) != goal { + result = result.max(EvaluatedToAmbig); } + Ok(result) }) } @@ -1645,7 +1653,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tcx = self.infcx.tcx; let (def_id, substs) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() { - ty::Alias(_, ty::AliasTy { def_id, substs, .. }) => (def_id, substs), + ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { + (def_id, substs) + } _ => { span_bug!( obligation.cause.span, diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs new file mode 100644 index 00000000000..af8dd0da579 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -0,0 +1,55 @@ +use rustc_infer::infer::at::At; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::traits::{FulfillmentError, TraitEngine}; +use rustc_middle::ty::{self, Ty}; + +use crate::traits::{query::evaluate_obligation::InferCtxtExt, NormalizeExt, Obligation}; + +pub trait StructurallyNormalizeExt<'tcx> { + fn structurally_normalize( + &self, + ty: Ty<'tcx>, + fulfill_cx: &mut dyn TraitEngine<'tcx>, + ) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>>; +} + +impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> { + fn structurally_normalize( + &self, + mut ty: Ty<'tcx>, + fulfill_cx: &mut dyn TraitEngine<'tcx>, + ) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>> { + assert!(!ty.is_ty_var(), "should have resolved vars before calling"); + + if self.infcx.tcx.trait_solver_next() { + while let ty::Alias(ty::Projection, projection_ty) = *ty.kind() { + let new_infer_ty = self.infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::NormalizeProjectionType, + span: self.cause.span, + }); + let obligation = Obligation::new( + self.infcx.tcx, + self.cause.clone(), + self.param_env, + ty::Binder::dummy(ty::ProjectionPredicate { + projection_ty, + term: new_infer_ty.into(), + }), + ); + if self.infcx.predicate_may_hold(&obligation) { + fulfill_cx.register_predicate_obligation(self.infcx, obligation); + let errors = fulfill_cx.select_where_possible(self.infcx); + if !errors.is_empty() { + return Err(errors); + } + ty = self.infcx.resolve_vars_if_possible(new_infer_ty); + } else { + break; + } + } + Ok(ty) + } else { + Ok(self.normalize(ty).into_value_registering_obligations(self.infcx, fulfill_cx)) + } + } +} diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 442d041a8a7..15c19104616 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -238,6 +238,7 @@ fn adjust_for_rust_scalar<'tcx>( layout: TyAndLayout<'tcx>, offset: Size, is_return: bool, + drop_target_pointee: Option<Ty<'tcx>>, ) { // Booleans are always a noundef i1 that needs to be zero-extended. if scalar.is_bool() { @@ -251,14 +252,24 @@ fn adjust_for_rust_scalar<'tcx>( } // Only pointer types handled below. - let Scalar::Initialized { value: Pointer(_), valid_range} = scalar else { return }; + let Scalar::Initialized { value: Pointer(_), valid_range } = scalar else { return }; - if !valid_range.contains(0) { + // Set `nonnull` if the validity range excludes zero, or for the argument to `drop_in_place`, + // which must be nonnull per its documented safety requirements. + if !valid_range.contains(0) || drop_target_pointee.is_some() { attrs.set(ArgAttribute::NonNull); } if let Some(pointee) = layout.pointee_info_at(&cx, offset) { - if let Some(kind) = pointee.safe { + let kind = if let Some(kind) = pointee.safe { + Some(kind) + } else if let Some(pointee) = drop_target_pointee { + // The argument to `drop_in_place` is semantically equivalent to a mutable reference. + Some(PointerKind::MutableRef { unpin: pointee.is_unpin(cx.tcx, cx.param_env()) }) + } else { + None + }; + if let Some(kind) = kind { attrs.pointee_align = Some(pointee.align); // `Box` are not necessarily dereferenceable for the entire duration of the function as @@ -362,10 +373,18 @@ fn fn_abi_new_uncached<'tcx>( use SpecAbi::*; let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall); + let is_drop_in_place = + fn_def_id.is_some() && fn_def_id == cx.tcx.lang_items().drop_in_place_fn(); + let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| -> Result<_, FnAbiError<'tcx>> { let span = tracing::debug_span!("arg_of"); let _entered = span.enter(); let is_return = arg_idx.is_none(); + let is_drop_target = is_drop_in_place && arg_idx == Some(0); + let drop_target_pointee = is_drop_target.then(|| match ty.kind() { + ty::RawPtr(ty::TypeAndMut { ty, .. }) => *ty, + _ => bug!("argument to drop_in_place is not a raw ptr: {:?}", ty), + }); let layout = cx.layout_of(ty)?; let layout = if force_thin_self_ptr && arg_idx == Some(0) { @@ -379,7 +398,15 @@ fn fn_abi_new_uncached<'tcx>( let mut arg = ArgAbi::new(cx, layout, |layout, scalar, offset| { let mut attrs = ArgAttributes::new(); - adjust_for_rust_scalar(*cx, &mut attrs, scalar, *layout, offset, is_return); + adjust_for_rust_scalar( + *cx, + &mut attrs, + scalar, + *layout, + offset, + is_return, + drop_target_pointee, + ); attrs }); diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 088139a6907..498fbd93288 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2623,6 +2623,15 @@ impl ToString for String { } } +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "fmt_arguments_to_string_specialization", since = "CURRENT_RUSTC_VERSION")] +impl ToString for fmt::Arguments<'_> { + #[inline] + fn to_string(&self) -> String { + crate::fmt::format(*self) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<str> for String { #[inline] diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 7347980abbc..bfdb7a92bef 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -502,6 +502,7 @@ impl<T> Arc<T> { /// assert_eq!(*five, 5) /// ``` #[cfg(not(no_global_oom_handling))] + #[inline] #[unstable(feature = "new_uninit", issue = "63291")] #[must_use] pub fn new_uninit() -> Arc<mem::MaybeUninit<T>> { @@ -535,6 +536,7 @@ impl<T> Arc<T> { /// /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] + #[inline] #[unstable(feature = "new_uninit", issue = "63291")] #[must_use] pub fn new_zeroed() -> Arc<mem::MaybeUninit<T>> { @@ -844,6 +846,7 @@ impl<T> Arc<[T]> { /// assert_eq!(*values, [1, 2, 3]) /// ``` #[cfg(not(no_global_oom_handling))] + #[inline] #[unstable(feature = "new_uninit", issue = "63291")] #[must_use] pub fn new_uninit_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> { @@ -871,6 +874,7 @@ impl<T> Arc<[T]> { /// /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] + #[inline] #[unstable(feature = "new_uninit", issue = "63291")] #[must_use] pub fn new_zeroed_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> { @@ -1300,10 +1304,10 @@ impl<T: ?Sized> Arc<T> { mem_to_arcinner: impl FnOnce(*mut u8) -> *mut ArcInner<T>, ) -> *mut ArcInner<T> { let layout = arcinner_layout_for_value_layout(value_layout); - unsafe { - Arc::try_allocate_for_layout(value_layout, allocate, mem_to_arcinner) - .unwrap_or_else(|_| handle_alloc_error(layout)) - } + + let ptr = allocate(layout).unwrap_or_else(|_| handle_alloc_error(layout)); + + unsafe { Self::initialize_arcinner(ptr, layout, mem_to_arcinner) } } /// Allocates an `ArcInner<T>` with sufficient space for @@ -1321,7 +1325,16 @@ impl<T: ?Sized> Arc<T> { let ptr = allocate(layout)?; - // Initialize the ArcInner + let inner = unsafe { Self::initialize_arcinner(ptr, layout, mem_to_arcinner) }; + + Ok(inner) + } + + unsafe fn initialize_arcinner( + ptr: NonNull<[u8]>, + layout: Layout, + mem_to_arcinner: impl FnOnce(*mut u8) -> *mut ArcInner<T>, + ) -> *mut ArcInner<T> { let inner = mem_to_arcinner(ptr.as_non_null_ptr().as_ptr()); debug_assert_eq!(unsafe { Layout::for_value(&*inner) }, layout); @@ -1330,7 +1343,7 @@ impl<T: ?Sized> Arc<T> { ptr::write(&mut (*inner).weak, atomic::AtomicUsize::new(1)); } - Ok(inner) + inner } /// Allocates an `ArcInner<T>` with sufficient space for an unsized inner value. diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs index 2f1ee8b0353..5ecd0479971 100644 --- a/library/alloc/src/vec/in_place_collect.rs +++ b/library/alloc/src/vec/in_place_collect.rs @@ -178,7 +178,8 @@ where ) }; - let len = SpecInPlaceCollect::collect_in_place(&mut iterator, dst_buf, dst_end); + // SAFETY: `dst_buf` and `dst_end` are the start and end of the buffer. + let len = unsafe { SpecInPlaceCollect::collect_in_place(&mut iterator, dst_buf, dst_end) }; let src = unsafe { iterator.as_inner().as_into_iter() }; // check if SourceIter contract was upheld @@ -239,7 +240,7 @@ trait SpecInPlaceCollect<T, I>: Iterator<Item = T> { /// `Iterator::__iterator_get_unchecked` calls with a `TrustedRandomAccessNoCoerce` bound /// on `I` which means the caller of this method must take the safety conditions /// of that trait into consideration. - fn collect_in_place(&mut self, dst: *mut T, end: *const T) -> usize; + unsafe fn collect_in_place(&mut self, dst: *mut T, end: *const T) -> usize; } impl<T, I> SpecInPlaceCollect<T, I> for I @@ -247,7 +248,7 @@ where I: Iterator<Item = T>, { #[inline] - default fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize { + default unsafe fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize { // use try-fold since // - it vectorizes better for some iterator adapters // - unlike most internal iteration methods, it only takes a &mut self @@ -265,7 +266,7 @@ where I: Iterator<Item = T> + TrustedRandomAccessNoCoerce, { #[inline] - fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize { + unsafe fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize { let len = self.size(); let mut drop_guard = InPlaceDrop { inner: dst_buf, dst: dst_buf }; for i in 0..len { diff --git a/library/core/benches/iter.rs b/library/core/benches/iter.rs index 9193c79bee8..60ef83223d1 100644 --- a/library/core/benches/iter.rs +++ b/library/core/benches/iter.rs @@ -404,7 +404,7 @@ fn bench_trusted_random_access_adapters(b: &mut Bencher) { /// Exercises the iter::Copied specialization for slice::Iter #[bench] -fn bench_copied_chunks(b: &mut Bencher) { +fn bench_next_chunk_copied(b: &mut Bencher) { let v = vec![1u8; 1024]; b.iter(|| { @@ -421,7 +421,7 @@ fn bench_copied_chunks(b: &mut Bencher) { /// Exercises the TrustedRandomAccess specialization in ArrayChunks #[bench] -fn bench_trusted_random_access_chunks(b: &mut Bencher) { +fn bench_next_chunk_trusted_random_access(b: &mut Bencher) { let v = vec![1u8; 1024]; b.iter(|| { @@ -437,3 +437,45 @@ fn bench_trusted_random_access_chunks(b: &mut Bencher) { .sum::<Wrapping<u64>>() }) } + +#[bench] +fn bench_next_chunk_filter_even(b: &mut Bencher) { + let a = (0..1024).next_chunk::<1024>().unwrap(); + + b.iter(|| black_box(&a).iter().filter(|&&i| i % 2 == 0).next_chunk::<32>()) +} + +#[bench] +fn bench_next_chunk_filter_predictably_true(b: &mut Bencher) { + let a = (0..1024).next_chunk::<1024>().unwrap(); + + b.iter(|| black_box(&a).iter().filter(|&&i| i < 100).next_chunk::<32>()) +} + +#[bench] +fn bench_next_chunk_filter_mostly_false(b: &mut Bencher) { + let a = (0..1024).next_chunk::<1024>().unwrap(); + + b.iter(|| black_box(&a).iter().filter(|&&i| i > 900).next_chunk::<32>()) +} + +#[bench] +fn bench_next_chunk_filter_map_even(b: &mut Bencher) { + let a = (0..1024).next_chunk::<1024>().unwrap(); + + b.iter(|| black_box(&a).iter().filter_map(|&i| (i % 2 == 0).then(|| i)).next_chunk::<32>()) +} + +#[bench] +fn bench_next_chunk_filter_map_predictably_true(b: &mut Bencher) { + let a = (0..1024).next_chunk::<1024>().unwrap(); + + b.iter(|| black_box(&a).iter().filter_map(|&i| (i < 100).then(|| i)).next_chunk::<32>()) +} + +#[bench] +fn bench_next_chunk_filter_map_mostly_false(b: &mut Bencher) { + let a = (0..1024).next_chunk::<1024>().unwrap(); + + b.iter(|| black_box(&a).iter().filter_map(|&i| (i > 900).then(|| i)).next_chunk::<32>()) +} diff --git a/library/core/src/ascii.rs b/library/core/src/ascii.rs index 7fd14a7e1ea..ef8e4d098ed 100644 --- a/library/core/src/ascii.rs +++ b/library/core/src/ascii.rs @@ -91,7 +91,7 @@ pub struct EscapeDefault(escape::EscapeIterInner<4>); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn escape_default(c: u8) -> EscapeDefault { - let mut data = [0; 4]; + let mut data = [Char::Null; 4]; let range = escape::escape_ascii_into(&mut data, c); EscapeDefault(escape::EscapeIterInner::new(data, range)) } diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 2c3c14853a4..744767aae44 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -2030,6 +2030,27 @@ impl<T> UnsafeCell<T> { } impl<T: ?Sized> UnsafeCell<T> { + /// Converts from `&mut T` to `&mut UnsafeCell<T>`. + /// + /// # Examples + /// + /// ``` + /// # #![feature(unsafe_cell_from_mut)] + /// use std::cell::UnsafeCell; + /// + /// let mut val = 42; + /// let uc = UnsafeCell::from_mut(&mut val); + /// + /// *uc.get_mut() -= 1; + /// assert_eq!(*uc.get_mut(), 41); + /// ``` + #[inline(always)] + #[unstable(feature = "unsafe_cell_from_mut", issue = "111645")] + pub const fn from_mut(value: &mut T) -> &mut UnsafeCell<T> { + // SAFETY: `UnsafeCell<T>` has the same memory layout as `T` due to #[repr(transparent)]. + unsafe { &mut *(value as *mut T as *mut UnsafeCell<T>) } + } + /// Gets a mutable pointer to the wrapped value. /// /// This can be cast to a pointer of any kind. diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 1dfa9c34db1..515b8d20ead 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -392,13 +392,13 @@ impl char { #[inline] pub(crate) fn escape_debug_ext(self, args: EscapeDebugExtArgs) -> EscapeDebug { match self { - '\0' => EscapeDebug::backslash(b'0'), - '\t' => EscapeDebug::backslash(b't'), - '\r' => EscapeDebug::backslash(b'r'), - '\n' => EscapeDebug::backslash(b'n'), - '\\' => EscapeDebug::backslash(b'\\'), - '"' if args.escape_double_quote => EscapeDebug::backslash(b'"'), - '\'' if args.escape_single_quote => EscapeDebug::backslash(b'\''), + '\0' => EscapeDebug::backslash(ascii::Char::Digit0), + '\t' => EscapeDebug::backslash(ascii::Char::SmallT), + '\r' => EscapeDebug::backslash(ascii::Char::SmallR), + '\n' => EscapeDebug::backslash(ascii::Char::SmallN), + '\\' => EscapeDebug::backslash(ascii::Char::ReverseSolidus), + '\"' if args.escape_double_quote => EscapeDebug::backslash(ascii::Char::QuotationMark), + '\'' if args.escape_single_quote => EscapeDebug::backslash(ascii::Char::Apostrophe), _ if args.escape_grapheme_extended && self.is_grapheme_extended() => { EscapeDebug::from_unicode(self.escape_unicode()) } @@ -503,11 +503,11 @@ impl char { #[inline] pub fn escape_default(self) -> EscapeDefault { match self { - '\t' => EscapeDefault::backslash(b't'), - '\r' => EscapeDefault::backslash(b'r'), - '\n' => EscapeDefault::backslash(b'n'), - '\\' | '\'' | '"' => EscapeDefault::backslash(self as u8), - '\x20'..='\x7e' => EscapeDefault::printable(self as u8), + '\t' => EscapeDefault::backslash(ascii::Char::SmallT), + '\r' => EscapeDefault::backslash(ascii::Char::SmallR), + '\n' => EscapeDefault::backslash(ascii::Char::SmallN), + '\\' | '\'' | '"' => EscapeDefault::backslash(self.as_ascii().unwrap()), + '\x20'..='\x7e' => EscapeDefault::printable(self.as_ascii().unwrap()), _ => EscapeDefault::from_unicode(self.escape_unicode()), } } diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs index e186db7052c..5c42912874c 100644 --- a/library/core/src/char/mod.rs +++ b/library/core/src/char/mod.rs @@ -38,6 +38,7 @@ pub use self::methods::encode_utf16_raw; #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] pub use self::methods::encode_utf8_raw; +use crate::ascii; use crate::error::Error; use crate::escape; use crate::fmt::{self, Write}; @@ -152,7 +153,7 @@ pub struct EscapeUnicode(escape::EscapeIterInner<10>); impl EscapeUnicode { fn new(chr: char) -> Self { - let mut data = [0; 10]; + let mut data = [ascii::Char::Null; 10]; let range = escape::escape_unicode_into(&mut data, chr); Self(escape::EscapeIterInner::new(data, range)) } @@ -218,14 +219,14 @@ impl fmt::Display for EscapeUnicode { pub struct EscapeDefault(escape::EscapeIterInner<10>); impl EscapeDefault { - fn printable(chr: u8) -> Self { - let data = [chr, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - Self(escape::EscapeIterInner::new(data, 0..1)) + fn printable(chr: ascii::Char) -> Self { + let data = [chr]; + Self(escape::EscapeIterInner::from_array(data)) } - fn backslash(chr: u8) -> Self { - let data = [b'\\', chr, 0, 0, 0, 0, 0, 0, 0, 0]; - Self(escape::EscapeIterInner::new(data, 0..2)) + fn backslash(chr: ascii::Char) -> Self { + let data = [ascii::Char::ReverseSolidus, chr]; + Self(escape::EscapeIterInner::from_array(data)) } fn from_unicode(esc: EscapeUnicode) -> Self { @@ -307,9 +308,9 @@ impl EscapeDebug { Self(EscapeDebugInner::Char(chr)) } - fn backslash(chr: u8) -> Self { - let data = [b'\\', chr, 0, 0, 0, 0, 0, 0, 0, 0]; - let iter = escape::EscapeIterInner::new(data, 0..2); + fn backslash(chr: ascii::Char) -> Self { + let data = [ascii::Char::ReverseSolidus, chr]; + let iter = escape::EscapeIterInner::from_array(data); Self(EscapeDebugInner::Bytes(iter)) } @@ -318,7 +319,7 @@ impl EscapeDebug { } fn clear(&mut self) { - let bytes = escape::EscapeIterInner::new([0; 10], 0..0); + let bytes = escape::EscapeIterInner::from_array([]); self.0 = EscapeDebugInner::Bytes(bytes); } } diff --git a/library/core/src/escape.rs b/library/core/src/escape.rs index 20ac3cf027f..3d471419bb8 100644 --- a/library/core/src/escape.rs +++ b/library/core/src/escape.rs @@ -1,34 +1,41 @@ //! Helper code for character escaping. +use crate::ascii; use crate::num::NonZeroUsize; use crate::ops::Range; -const HEX_DIGITS: [u8; 16] = *b"0123456789abcdef"; +const HEX_DIGITS: [ascii::Char; 16] = *b"0123456789abcdef".as_ascii().unwrap(); /// Escapes a byte into provided buffer; returns length of escaped /// representation. -pub(crate) fn escape_ascii_into(output: &mut [u8; 4], byte: u8) -> Range<u8> { +pub(crate) fn escape_ascii_into(output: &mut [ascii::Char; 4], byte: u8) -> Range<u8> { + #[inline] + fn backslash(a: ascii::Char) -> ([ascii::Char; 4], u8) { + ([ascii::Char::ReverseSolidus, a, ascii::Char::Null, ascii::Char::Null], 2) + } + let (data, len) = match byte { - b'\t' => ([b'\\', b't', 0, 0], 2), - b'\r' => ([b'\\', b'r', 0, 0], 2), - b'\n' => ([b'\\', b'n', 0, 0], 2), - b'\\' => ([b'\\', b'\\', 0, 0], 2), - b'\'' => ([b'\\', b'\'', 0, 0], 2), - b'"' => ([b'\\', b'"', 0, 0], 2), - b'\x20'..=b'\x7e' => ([byte, 0, 0, 0], 1), - _ => { + b'\t' => backslash(ascii::Char::SmallT), + b'\r' => backslash(ascii::Char::SmallR), + b'\n' => backslash(ascii::Char::SmallN), + b'\\' => backslash(ascii::Char::ReverseSolidus), + b'\'' => backslash(ascii::Char::Apostrophe), + b'\"' => backslash(ascii::Char::QuotationMark), + _ => if let Some(a) = byte.as_ascii() && !byte.is_ascii_control() { + ([a, ascii::Char::Null, ascii::Char::Null, ascii::Char::Null], 1) + } else { let hi = HEX_DIGITS[usize::from(byte >> 4)]; let lo = HEX_DIGITS[usize::from(byte & 0xf)]; - ([b'\\', b'x', hi, lo], 4) + ([ascii::Char::ReverseSolidus, ascii::Char::SmallX, hi, lo], 4) } }; *output = data; - 0..(len as u8) + 0..len } /// Escapes a character into provided buffer using `\u{NNNN}` representation. -pub(crate) fn escape_unicode_into(output: &mut [u8; 10], ch: char) -> Range<u8> { - output[9] = b'}'; +pub(crate) fn escape_unicode_into(output: &mut [ascii::Char; 10], ch: char) -> Range<u8> { + output[9] = ascii::Char::RightCurlyBracket; let ch = ch as u32; output[3] = HEX_DIGITS[((ch >> 20) & 15) as usize]; @@ -41,7 +48,8 @@ pub(crate) fn escape_unicode_into(output: &mut [u8; 10], ch: char) -> Range<u8> // or-ing 1 ensures that for ch==0 the code computes that one digit should // be printed. let start = (ch | 1).leading_zeros() as usize / 4 - 2; - output[start..start + 3].copy_from_slice(b"\\u{"); + const UNICODE_ESCAPE_PREFIX: &[ascii::Char; 3] = b"\\u{".as_ascii().unwrap(); + output[start..][..3].copy_from_slice(UNICODE_ESCAPE_PREFIX); (start as u8)..10 } @@ -52,29 +60,34 @@ pub(crate) fn escape_unicode_into(output: &mut [u8; 10], ch: char) -> Range<u8> /// limited to u8 to reduce size of the structure. #[derive(Clone, Debug)] pub(crate) struct EscapeIterInner<const N: usize> { - // Invariant: data[alive] is all ASCII. - pub(crate) data: [u8; N], + // The element type ensures this is always ASCII, and thus also valid UTF-8. + pub(crate) data: [ascii::Char; N], // Invariant: alive.start <= alive.end <= N. pub(crate) alive: Range<u8>, } impl<const N: usize> EscapeIterInner<N> { - pub fn new(data: [u8; N], alive: Range<u8>) -> Self { + pub fn new(data: [ascii::Char; N], alive: Range<u8>) -> Self { const { assert!(N < 256) }; debug_assert!(alive.start <= alive.end && usize::from(alive.end) <= N, "{alive:?}"); - let this = Self { data, alive }; - debug_assert!(this.as_bytes().is_ascii(), "Expected ASCII, got {:?}", this.as_bytes()); - this + Self { data, alive } + } + + pub fn from_array<const M: usize>(array: [ascii::Char; M]) -> Self { + const { assert!(M <= N) }; + + let mut data = [ascii::Char::Null; N]; + data[..M].copy_from_slice(&array); + Self::new(data, 0..M as u8) } - fn as_bytes(&self) -> &[u8] { + pub fn as_ascii(&self) -> &[ascii::Char] { &self.data[usize::from(self.alive.start)..usize::from(self.alive.end)] } pub fn as_str(&self) -> &str { - // SAFETY: self.data[self.alive] is all ASCII characters. - unsafe { crate::str::from_utf8_unchecked(self.as_bytes()) } + self.as_ascii().as_str() } pub fn len(&self) -> usize { @@ -82,11 +95,11 @@ impl<const N: usize> EscapeIterInner<N> { } pub fn next(&mut self) -> Option<u8> { - self.alive.next().map(|i| self.data[usize::from(i)]) + self.alive.next().map(|i| self.data[usize::from(i)].as_u8()) } pub fn next_back(&mut self) -> Option<u8> { - self.alive.next_back().map(|i| self.data[usize::from(i)]) + self.alive.next_back().map(|i| self.data[usize::from(i)].as_u8()) } pub fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 07b11814f96..201bacb28c7 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -517,8 +517,6 @@ impl CStr { /// # Examples /// /// ``` - /// #![feature(cstr_is_empty)] - /// /// use std::ffi::CStr; /// # use std::ffi::FromBytesWithNulError; /// @@ -533,7 +531,8 @@ impl CStr { /// # } /// ``` #[inline] - #[unstable(feature = "cstr_is_empty", issue = "102444")] + #[stable(feature = "cstr_is_empty", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "cstr_is_empty", since = "CURRENT_RUSTC_VERSION")] pub const fn is_empty(&self) -> bool { // SAFETY: We know there is at least one byte; for empty strings it // is the NUL terminator. diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs index 89d5fac30d3..3bbf5d8770b 100644 --- a/library/core/src/fmt/float.rs +++ b/library/core/src/fmt/float.rs @@ -45,7 +45,8 @@ where &mut buf, &mut parts, ); - fmt.pad_formatted_parts(&formatted) + // SAFETY: `to_exact_fixed_str` and `format_exact` produce only ASCII characters. + unsafe { fmt.pad_formatted_parts(&formatted) } } // Don't inline this so callers that call both this and the above won't wind @@ -71,7 +72,8 @@ where &mut buf, &mut parts, ); - fmt.pad_formatted_parts(&formatted) + // SAFETY: `to_shortest_str` and `format_shortest` produce only ASCII characters. + unsafe { fmt.pad_formatted_parts(&formatted) } } fn float_to_decimal_display<T>(fmt: &mut Formatter<'_>, num: &T) -> Result @@ -116,7 +118,8 @@ where &mut buf, &mut parts, ); - fmt.pad_formatted_parts(&formatted) + // SAFETY: `to_exact_exp_str` and `format_exact` produce only ASCII characters. + unsafe { fmt.pad_formatted_parts(&formatted) } } // Don't inline this so callers that call both this and the above won't wind @@ -143,7 +146,8 @@ where &mut buf, &mut parts, ); - fmt.pad_formatted_parts(&formatted) + // SAFETY: `to_shortest_exp_str` and `format_shortest` produce only ASCII characters. + unsafe { fmt.pad_formatted_parts(&formatted) } } // Common code of floating point LowerExp and UpperExp. diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index bac2f31878b..1786b309c5b 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -1415,7 +1415,11 @@ impl<'a> Formatter<'a> { /// Takes the formatted parts and applies the padding. /// Assumes that the caller already has rendered the parts with required precision, /// so that `self.precision` can be ignored. - fn pad_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result { + /// + /// # Safety + /// + /// Any `numfmt::Part::Copy` parts in `formatted` must contain valid UTF-8. + unsafe fn pad_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result { if let Some(mut width) = self.width { // for the sign-aware zero padding, we render the sign first and // behave as if we had no sign from the beginning. @@ -1438,10 +1442,14 @@ impl<'a> Formatter<'a> { let len = formatted.len(); let ret = if width <= len { // no padding - self.write_formatted_parts(&formatted) + // SAFETY: Per the precondition. + unsafe { self.write_formatted_parts(&formatted) } } else { let post_padding = self.padding(width - len, Alignment::Right)?; - self.write_formatted_parts(&formatted)?; + // SAFETY: Per the precondition. + unsafe { + self.write_formatted_parts(&formatted)?; + } post_padding.write(self) }; self.fill = old_fill; @@ -1449,20 +1457,20 @@ impl<'a> Formatter<'a> { ret } else { // this is the common case and we take a shortcut - self.write_formatted_parts(formatted) + // SAFETY: Per the precondition. + unsafe { self.write_formatted_parts(formatted) } } } - fn write_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result { - fn write_bytes(buf: &mut dyn Write, s: &[u8]) -> Result { + /// # Safety + /// + /// Any `numfmt::Part::Copy` parts in `formatted` must contain valid UTF-8. + unsafe fn write_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result { + unsafe fn write_bytes(buf: &mut dyn Write, s: &[u8]) -> Result { // SAFETY: This is used for `numfmt::Part::Num` and `numfmt::Part::Copy`. // It's safe to use for `numfmt::Part::Num` since every char `c` is between - // `b'0'` and `b'9'`, which means `s` is valid UTF-8. - // It's also probably safe in practice to use for `numfmt::Part::Copy(buf)` - // since `buf` should be plain ASCII, but it's possible for someone to pass - // in a bad value for `buf` into `numfmt::to_shortest_str` since it is a - // public function. - // FIXME: Determine whether this could result in UB. + // `b'0'` and `b'9'`, which means `s` is valid UTF-8. It's safe to use for + // `numfmt::Part::Copy` due to this function's precondition. buf.write_str(unsafe { str::from_utf8_unchecked(s) }) } @@ -1489,11 +1497,15 @@ impl<'a> Formatter<'a> { *c = b'0' + (v % 10) as u8; v /= 10; } - write_bytes(self.buf, &s[..len])?; + // SAFETY: Per the precondition. + unsafe { + write_bytes(self.buf, &s[..len])?; + } } - numfmt::Part::Copy(buf) => { + // SAFETY: Per the precondition. + numfmt::Part::Copy(buf) => unsafe { write_bytes(self.buf, buf)?; - } + }, } } Ok(()) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index d8365ae9bf9..4f42f73ebba 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -52,8 +52,12 @@ impl_int! { i8 i16 i32 i64 i128 isize } impl_uint! { u8 u16 u32 u64 u128 usize } /// A type that represents a specific radix +/// +/// # Safety +/// +/// `digit` must return an ASCII character. #[doc(hidden)] -trait GenericRadix: Sized { +unsafe trait GenericRadix: Sized { /// The number of digits. const BASE: u8; @@ -129,7 +133,7 @@ struct UpperHex; macro_rules! radix { ($T:ident, $base:expr, $prefix:expr, $($x:pat => $conv:expr),+) => { - impl GenericRadix for $T { + unsafe impl GenericRadix for $T { const BASE: u8 = $base; const PREFIX: &'static str = $prefix; fn digit(x: u8) -> u8 { @@ -407,7 +411,7 @@ macro_rules! impl_Exp { let parts = &[ numfmt::Part::Copy(buf_slice), numfmt::Part::Zero(added_precision), - numfmt::Part::Copy(exp_slice) + numfmt::Part::Copy(exp_slice), ]; let sign = if !is_nonnegative { "-" @@ -416,8 +420,9 @@ macro_rules! impl_Exp { } else { "" }; - let formatted = numfmt::Formatted{sign, parts}; - f.pad_formatted_parts(&formatted) + let formatted = numfmt::Formatted { sign, parts }; + // SAFETY: `buf_slice` and `exp_slice` contain only ASCII characters. + unsafe { f.pad_formatted_parts(&formatted) } } $( diff --git a/library/core/src/future/join.rs b/library/core/src/future/join.rs index 35f0dea062e..3f35179ddc2 100644 --- a/library/core/src/future/join.rs +++ b/library/core/src/future/join.rs @@ -4,7 +4,7 @@ use crate::cell::UnsafeCell; use crate::future::{poll_fn, Future}; use crate::mem; use crate::pin::Pin; -use crate::task::{Context, Poll}; +use crate::task::{ready, Context, Poll}; /// Polls multiple futures simultaneously, returning a tuple /// of all results once complete. @@ -118,7 +118,7 @@ macro join_internal { fut }) }; - // Despite how tempting it may be to `let () = fut.poll(cx).ready()?;` + // Despite how tempting it may be to `let () = ready!(fut.poll(cx));` // doing so would defeat the point of `join!`: to start polling eagerly all // of the futures, to allow parallelizing the waits. done &= fut.poll(cx).is_ready(); @@ -180,7 +180,7 @@ impl<F: Future> Future for MaybeDone<F> { // Do not mix match ergonomics with unsafe. match *self.as_mut().get_unchecked_mut() { MaybeDone::Future(ref mut f) => { - let val = Pin::new_unchecked(f).poll(cx).ready()?; + let val = ready!(Pin::new_unchecked(f).poll(cx)); self.set(Self::Done(val)); } MaybeDone::Done(_) => {} diff --git a/library/core/src/iter/adapters/filter.rs b/library/core/src/iter/adapters/filter.rs index a0afaa326ad..723657b9e43 100644 --- a/library/core/src/iter/adapters/filter.rs +++ b/library/core/src/iter/adapters/filter.rs @@ -1,6 +1,9 @@ use crate::fmt; use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; use crate::ops::Try; +use core::array; +use core::mem::{ManuallyDrop, MaybeUninit}; +use core::ops::ControlFlow; /// An iterator that filters the elements of `iter` with `predicate`. /// @@ -57,6 +60,58 @@ where } #[inline] + fn next_chunk<const N: usize>( + &mut self, + ) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>> { + let mut array: [MaybeUninit<Self::Item>; N] = MaybeUninit::uninit_array(); + + struct Guard<'a, T> { + array: &'a mut [MaybeUninit<T>], + initialized: usize, + } + + impl<T> Drop for Guard<'_, T> { + #[inline] + fn drop(&mut self) { + if const { crate::mem::needs_drop::<T>() } { + // SAFETY: self.initialized is always <= N, which also is the length of the array. + unsafe { + core::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut( + self.array.get_unchecked_mut(..self.initialized), + )); + } + } + } + } + + let mut guard = Guard { array: &mut array, initialized: 0 }; + + let result = self.iter.try_for_each(|element| { + let idx = guard.initialized; + guard.initialized = idx + (self.predicate)(&element) as usize; + + // SAFETY: Loop conditions ensure the index is in bounds. + unsafe { guard.array.get_unchecked_mut(idx) }.write(element); + + if guard.initialized < N { ControlFlow::Continue(()) } else { ControlFlow::Break(()) } + }); + + let guard = ManuallyDrop::new(guard); + + match result { + ControlFlow::Break(()) => { + // SAFETY: The loop above is only explicitly broken when the array has been fully initialized + Ok(unsafe { MaybeUninit::array_assume_init(array) }) + } + ControlFlow::Continue(()) => { + let initialized = guard.initialized; + // SAFETY: The range is in bounds since the loop breaks when reaching N elements. + Err(unsafe { array::IntoIter::new_unchecked(array, 0..initialized) }) + } + } + } + + #[inline] fn size_hint(&self) -> (usize, Option<usize>) { let (_, upper) = self.iter.size_hint(); (0, upper) // can't know a lower bound, due to the predicate diff --git a/library/core/src/iter/adapters/filter_map.rs b/library/core/src/iter/adapters/filter_map.rs index 6bdf53f7fc9..693479977db 100644 --- a/library/core/src/iter/adapters/filter_map.rs +++ b/library/core/src/iter/adapters/filter_map.rs @@ -1,6 +1,7 @@ -use crate::fmt; use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::mem::{ManuallyDrop, MaybeUninit}; use crate::ops::{ControlFlow, Try}; +use crate::{array, fmt}; /// An iterator that uses `f` to both filter and map elements from `iter`. /// @@ -62,6 +63,65 @@ where } #[inline] + fn next_chunk<const N: usize>( + &mut self, + ) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>> { + let mut array: [MaybeUninit<Self::Item>; N] = MaybeUninit::uninit_array(); + + struct Guard<'a, T> { + array: &'a mut [MaybeUninit<T>], + initialized: usize, + } + + impl<T> Drop for Guard<'_, T> { + #[inline] + fn drop(&mut self) { + if const { crate::mem::needs_drop::<T>() } { + // SAFETY: self.initialized is always <= N, which also is the length of the array. + unsafe { + core::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut( + self.array.get_unchecked_mut(..self.initialized), + )); + } + } + } + } + + let mut guard = Guard { array: &mut array, initialized: 0 }; + + let result = self.iter.try_for_each(|element| { + let idx = guard.initialized; + let val = (self.f)(element); + guard.initialized = idx + val.is_some() as usize; + + // SAFETY: Loop conditions ensure the index is in bounds. + + unsafe { + let opt_payload_at = core::intrinsics::option_payload_ptr(&val); + let dst = guard.array.as_mut_ptr().add(idx); + crate::ptr::copy_nonoverlapping(opt_payload_at.cast(), dst, 1); + crate::mem::forget(val); + }; + + if guard.initialized < N { ControlFlow::Continue(()) } else { ControlFlow::Break(()) } + }); + + let guard = ManuallyDrop::new(guard); + + match result { + ControlFlow::Break(()) => { + // SAFETY: The loop above is only explicitly broken when the array has been fully initialized + Ok(unsafe { MaybeUninit::array_assume_init(array) }) + } + ControlFlow::Continue(()) => { + let initialized = guard.initialized; + // SAFETY: The range is in bounds since the loop breaks when reaching N elements. + Err(unsafe { array::IntoIter::new_unchecked(array, 0..initialized) }) + } + } + } + + #[inline] fn size_hint(&self) -> (usize, Option<usize>) { let (_, upper) = self.iter.size_hint(); (0, upper) // can't know a lower bound, due to the predicate diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 76b3a32880d..0675e56358f 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -95,6 +95,16 @@ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( on( + _Self = "&[{A}]", + message = "a slice of type `{Self}` cannot be built since we need to store the elements somewhere", + label = "try explicitly collecting into a `Vec<{A}>`", + ), + on( + all(A = "{integer}", any(_Self = "&[{integral}]",)), + message = "a slice of type `{Self}` cannot be built since we need to store the elements somewhere", + label = "try explicitly collecting into a `Vec<{A}>`", + ), + on( _Self = "[{A}]", message = "a slice of type `{Self}` cannot be built since `{Self}` has no definite size", label = "try explicitly collecting into a `Vec<{A}>`", diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 0af04fac909..6c419eb16f3 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -216,6 +216,7 @@ #![feature(intra_doc_pointers)] #![feature(intrinsics)] #![feature(lang_items)] +#![feature(let_chains)] #![feature(link_llvm_intrinsics)] #![feature(macro_metavar_expr)] #![feature(min_specialization)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 47a3e78b4d5..8dab8d1a692 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -43,27 +43,17 @@ use crate::hash::Hasher; /// ``` #[unstable(feature = "internal_impls_macro", issue = "none")] macro marker_impls { - ( $(#[$($meta:tt)*])* $Trait:ident for $( $({$($bounds:tt)*})? $T:ty ),+ $(,)?) => { - // This inner macro is needed because... idk macros are weird. - // It allows repeating `meta` on all impls. - #[unstable(feature = "internal_impls_macro", issue = "none")] - macro _impl { - ( $$({$$($$bounds_:tt)*})? $$T_:ty ) => { - $(#[$($meta)*])* impl<$$($$($$bounds_)*)?> $Trait for $$T_ {} - } - } - $( _impl! { $({$($bounds)*})? $T } )+ + ( $(#[$($meta:tt)*])* $Trait:ident for $({$($bounds:tt)*})? $T:ty $(, $($rest:tt)*)? ) => { + $(#[$($meta)*])* impl< $($($bounds)*)? > $Trait for $T {} + marker_impls! { $(#[$($meta)*])* $Trait for $($($rest)*)? } }, - ( $(#[$($meta:tt)*])* unsafe $Trait:ident for $( $({$($bounds:tt)*})? $T:ty ),+ $(,)?) => { - #[unstable(feature = "internal_impls_macro", issue = "none")] - macro _impl { - ( $$({$$($$bounds_:tt)*})? $$T_:ty ) => { - $(#[$($meta)*])* unsafe impl<$$($$($$bounds_)*)?> $Trait for $$T_ {} - } - } - - $( _impl! { $({$($bounds)*})? $T } )+ + ( $(#[$($meta:tt)*])* $Trait:ident for ) => {}, + + ( $(#[$($meta:tt)*])* unsafe $Trait:ident for $({$($bounds:tt)*})? $T:ty $(, $($rest:tt)*)? ) => { + $(#[$($meta)*])* unsafe impl< $($($bounds)*)? > $Trait for $T {} + marker_impls! { $(#[$($meta)*])* unsafe $Trait for $($($rest)*)? } }, + ( $(#[$($meta:tt)*])* unsafe $Trait:ident for ) => {}, } /// Types that can be transferred across thread boundaries. @@ -986,6 +976,14 @@ pub trait PointerLike {} #[rustc_on_unimplemented(message = "`{Self}` can't be used as a const parameter type")] pub trait ConstParamTy: StructuralEq {} +/// Derive macro generating an impl of the trait `ConstParamTy`. +#[rustc_builtin_macro] +#[unstable(feature = "adt_const_params", issue = "95174")] +#[cfg(not(bootstrap))] +pub macro ConstParamTy($item:item) { + /* compiler built-in */ +} + // FIXME(generic_const_parameter_types): handle `ty::FnDef`/`ty::Closure` // FIXME(generic_const_parameter_types): handle `ty::Tuple` marker_impls! { diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 289305253ec..afbfd6d362d 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -968,7 +968,7 @@ pub const fn replace<T>(dest: &mut T, src: T) -> T { /// Integers and other types implementing [`Copy`] are unaffected by `drop`. /// /// ``` -/// # #![cfg_attr(not(bootstrap), allow(drop_copy))] +/// # #![cfg_attr(not(bootstrap), allow(dropping_copy_types))] /// #[derive(Copy, Clone)] /// struct Foo(u8); /// diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index ebcce79b0f8..20be60d3535 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -28,13 +28,13 @@ pub macro panic_2015 { $crate::panicking::panic($msg) ), // Use `panic_str` instead of `panic_display::<&str>` for non_fmt_panic lint. - ($msg:expr $(,)?) => ( - $crate::panicking::panic_str($msg) - ), + ($msg:expr $(,)?) => ({ + $crate::panicking::panic_str($msg); + }), // Special-case the single-argument case for const_panic. - ("{}", $arg:expr $(,)?) => ( - $crate::panicking::panic_display(&$arg) - ), + ("{}", $arg:expr $(,)?) => ({ + $crate::panicking::panic_display(&$arg); + }), ($fmt:expr, $($arg:tt)+) => ({ // Semicolon to prevent temporaries inside the formatting machinery from // being considered alive in the caller after the panic_fmt call. @@ -52,9 +52,9 @@ pub macro panic_2021 { $crate::panicking::panic("explicit panic") ), // Special-case the single-argument case for const_panic. - ("{}", $arg:expr $(,)?) => ( - $crate::panicking::panic_display(&$arg) - ), + ("{}", $arg:expr $(,)?) => ({ + $crate::panicking::panic_display(&$arg); + }), ($($t:tt)+) => ({ // Semicolon to prevent temporaries inside the formatting machinery from // being considered alive in the caller after the panic_fmt call. @@ -73,9 +73,9 @@ pub macro unreachable_2015 { ), // Use of `unreachable_display` for non_fmt_panic lint. // NOTE: the message ("internal error ...") is embedded directly in unreachable_display - ($msg:expr $(,)?) => ( - $crate::panicking::unreachable_display(&$msg) - ), + ($msg:expr $(,)?) => ({ + $crate::panicking::unreachable_display(&$msg); + }), ($fmt:expr, $($arg:tt)*) => ( $crate::panic!($crate::concat!("internal error: entered unreachable code: ", $fmt), $($arg)*) ), diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index c4b89a63019..6b319b4355c 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -393,6 +393,8 @@ use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver}; /// value in place, preventing the value referenced by that pointer from being moved /// unless it implements [`Unpin`]. /// +/// `Pin<P>` is guaranteed to have the same memory layout and ABI as `P`. +/// /// *See the [`pin` module] documentation for an explanation of pinning.* /// /// [`pin` module]: self diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index ecbf4e66fa4..ff9fa48f311 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -441,10 +441,18 @@ mod mut_ptr; /// /// * `to_drop` must be [valid] for both reads and writes. /// -/// * `to_drop` must be properly aligned. +/// * `to_drop` must be properly aligned, even if `T` has size 0. /// -/// * The value `to_drop` points to must be valid for dropping, which may mean it must uphold -/// additional invariants - this is type-dependent. +/// * `to_drop` must be nonnull, even if `T` has size 0. +/// +/// * The value `to_drop` points to must be valid for dropping, which may mean +/// it must uphold additional invariants. These invariants depend on the type +/// of the value being dropped. For instance, when dropping a Box, the box's +/// pointer to the heap must be valid. +/// +/// * While `drop_in_place` is executing, the only way to access parts of +/// `to_drop` is through the `&mut self` references supplied to the +/// `Drop::drop` methods that `drop_in_place` invokes. /// /// Additionally, if `T` is not [`Copy`], using the pointed-to value after /// calling `drop_in_place` can cause undefined behavior. Note that `*to_drop = @@ -452,8 +460,6 @@ mod mut_ptr; /// again. [`write()`] can be used to overwrite data without causing it to be /// dropped. /// -/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned. -/// /// [valid]: self#safety /// /// # Examples diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 6fd2b87d0e3..5ece1b78c03 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -995,7 +995,7 @@ impl<T> [T] { #[unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[must_use] - pub unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]] { + pub const unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]] { let this = self; // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length let new_len = unsafe { @@ -1043,7 +1043,7 @@ impl<T> [T] { #[inline] #[track_caller] #[must_use] - pub fn as_chunks<const N: usize>(&self) -> (&[[T; N]], &[T]) { + pub const fn as_chunks<const N: usize>(&self) -> (&[[T; N]], &[T]) { assert!(N != 0, "chunk size must be non-zero"); let len = self.len() / N; let (multiple_of_n, remainder) = self.split_at(len * N); @@ -1075,7 +1075,7 @@ impl<T> [T] { #[inline] #[track_caller] #[must_use] - pub fn as_rchunks<const N: usize>(&self) -> (&[T], &[[T; N]]) { + pub const fn as_rchunks<const N: usize>(&self) -> (&[T], &[[T; N]]) { assert!(N != 0, "chunk size must be non-zero"); let len = self.len() / N; let (remainder, multiple_of_n) = self.split_at(self.len() - len * N); @@ -1152,7 +1152,7 @@ impl<T> [T] { #[unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[must_use] - pub unsafe fn as_chunks_unchecked_mut<const N: usize>(&mut self) -> &mut [[T; N]] { + pub const unsafe fn as_chunks_unchecked_mut<const N: usize>(&mut self) -> &mut [[T; N]] { let this = &*self; // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length let new_len = unsafe { @@ -1195,7 +1195,7 @@ impl<T> [T] { #[inline] #[track_caller] #[must_use] - pub fn as_chunks_mut<const N: usize>(&mut self) -> (&mut [[T; N]], &mut [T]) { + pub const fn as_chunks_mut<const N: usize>(&mut self) -> (&mut [[T; N]], &mut [T]) { assert!(N != 0, "chunk size must be non-zero"); let len = self.len() / N; let (multiple_of_n, remainder) = self.split_at_mut(len * N); @@ -1233,7 +1233,7 @@ impl<T> [T] { #[inline] #[track_caller] #[must_use] - pub fn as_rchunks_mut<const N: usize>(&mut self) -> (&mut [T], &mut [[T; N]]) { + pub const fn as_rchunks_mut<const N: usize>(&mut self) -> (&mut [T], &mut [[T; N]]) { assert!(N != 0, "chunk size must be non-zero"); let len = self.len() / N; let (remainder, multiple_of_n) = self.split_at_mut(self.len() - len * N); diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index e6e3b55efa9..eb8595ca90d 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -1085,12 +1085,12 @@ where // SAFETY: left and right must be valid and part of v same for out. unsafe { - let to_copy = if is_less(&*right, &**left) { - get_and_increment(&mut right) - } else { - get_and_increment(left) - }; - ptr::copy_nonoverlapping(to_copy, get_and_increment(out), 1); + let is_l = is_less(&*right, &**left); + let to_copy = if is_l { right } else { *left }; + ptr::copy_nonoverlapping(to_copy, *out, 1); + *out = out.add(1); + right = right.add(is_l as usize); + *left = left.add(!is_l as usize); } } } else { @@ -1113,32 +1113,18 @@ where // SAFETY: left and right must be valid and part of v same for out. unsafe { - let to_copy = if is_less(&*right.sub(1), &*left.sub(1)) { - decrement_and_get(left) - } else { - decrement_and_get(right) - }; - ptr::copy_nonoverlapping(to_copy, decrement_and_get(&mut out), 1); + let is_l = is_less(&*right.sub(1), &*left.sub(1)); + *left = left.sub(is_l as usize); + *right = right.sub(!is_l as usize); + let to_copy = if is_l { *left } else { *right }; + out = out.sub(1); + ptr::copy_nonoverlapping(to_copy, out, 1); } } } // Finally, `hole` gets dropped. If the shorter run was not fully consumed, whatever remains of // it will now be copied into the hole in `v`. - unsafe fn get_and_increment<T>(ptr: &mut *mut T) -> *mut T { - let old = *ptr; - - // SAFETY: ptr.add(1) must still be a valid pointer and part of `v`. - *ptr = unsafe { ptr.add(1) }; - old - } - - unsafe fn decrement_and_get<T>(ptr: &mut *mut T) -> *mut T { - // SAFETY: ptr.sub(1) must still be a valid pointer and part of `v`. - *ptr = unsafe { ptr.sub(1) }; - *ptr - } - // When dropped, copies the range `start..end` into `dest..`. struct MergeHole<T> { start: *mut T, diff --git a/library/core/src/task/mod.rs b/library/core/src/task/mod.rs index c5f89b9a2c6..3f0080e3832 100644 --- a/library/core/src/task/mod.rs +++ b/library/core/src/task/mod.rs @@ -13,5 +13,3 @@ pub use self::wake::{Context, RawWaker, RawWakerVTable, Waker}; mod ready; #[stable(feature = "ready_macro", since = "1.64.0")] pub use ready::ready; -#[unstable(feature = "poll_ready", issue = "89780")] -pub use ready::Ready; diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 5283a576d1b..0a0f702f6fb 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -3,7 +3,6 @@ use crate::convert; use crate::ops::{self, ControlFlow}; use crate::result::Result; -use crate::task::Ready; /// Indicates whether a value is available or if the current task has been /// scheduled to receive a wakeup instead. @@ -95,38 +94,6 @@ impl<T> Poll<T> { pub const fn is_pending(&self) -> bool { !self.is_ready() } - - /// Extracts the successful type of a [`Poll<T>`]. - /// - /// When combined with the `?` operator, this function will - /// propagate any [`Poll::Pending`] values to the caller, and - /// extract the `T` from [`Poll::Ready`]. - /// - /// # Examples - /// - /// ```rust - /// #![feature(poll_ready)] - /// - /// use std::task::{Context, Poll}; - /// use std::future::{self, Future}; - /// use std::pin::Pin; - /// - /// pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> { - /// let mut fut = future::ready(42); - /// let fut = Pin::new(&mut fut); - /// - /// let num = fut.poll(cx).ready()?; - /// # let _ = num; // to silence unused warning - /// // ... use num - /// - /// Poll::Ready(()) - /// } - /// ``` - #[inline] - #[unstable(feature = "poll_ready", issue = "89780")] - pub fn ready(self) -> Ready<T> { - Ready(self) - } } impl<T, E> Poll<Result<T, E>> { diff --git a/library/core/src/task/ready.rs b/library/core/src/task/ready.rs index 8d12625e88d..495d72fd14b 100644 --- a/library/core/src/task/ready.rs +++ b/library/core/src/task/ready.rs @@ -1,8 +1,3 @@ -use core::convert; -use core::fmt; -use core::ops::{ControlFlow, FromResidual, Try}; -use core::task::Poll; - /// Extracts the successful type of a [`Poll<T>`]. /// /// This macro bakes in propagation of [`Pending`] signals by returning early. @@ -60,55 +55,3 @@ pub macro ready($e:expr) { } } } - -/// Extracts the successful type of a [`Poll<T>`]. -/// -/// See [`Poll::ready`] for details. -#[unstable(feature = "poll_ready", issue = "89780")] -pub struct Ready<T>(pub(crate) Poll<T>); - -#[unstable(feature = "poll_ready", issue = "89780")] -impl<T> Try for Ready<T> { - type Output = T; - type Residual = Ready<convert::Infallible>; - - #[inline] - fn from_output(output: Self::Output) -> Self { - Ready(Poll::Ready(output)) - } - - #[inline] - fn branch(self) -> ControlFlow<Self::Residual, Self::Output> { - match self.0 { - Poll::Ready(v) => ControlFlow::Continue(v), - Poll::Pending => ControlFlow::Break(Ready(Poll::Pending)), - } - } -} - -#[unstable(feature = "poll_ready", issue = "89780")] -impl<T> FromResidual for Ready<T> { - #[inline] - fn from_residual(residual: Ready<convert::Infallible>) -> Self { - match residual.0 { - Poll::Pending => Ready(Poll::Pending), - } - } -} - -#[unstable(feature = "poll_ready", issue = "89780")] -impl<T> FromResidual<Ready<convert::Infallible>> for Poll<T> { - #[inline] - fn from_residual(residual: Ready<convert::Infallible>) -> Self { - match residual.0 { - Poll::Pending => Poll::Pending, - } - } -} - -#[unstable(feature = "poll_ready", issue = "89780")] -impl<T> fmt::Debug for Ready<T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Ready").finish() - } -} diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 7f033816901..aee9c89b595 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -386,6 +386,26 @@ fn offset_of() { // Layout of tuples is unstable assert!(offset_of!((u8, u16), 0) <= size_of::<(u8, u16)>() - 1); assert!(offset_of!((u8, u16), 1) <= size_of::<(u8, u16)>() - 2); + + #[repr(C)] + struct Generic<T> { + x: u8, + y: u32, + z: T + } + + trait Trait {} + + // Ensure that this type of generics works + fn offs_of_z<T>() -> usize { + offset_of!(Generic<T>, z) + } + + assert_eq!(offset_of!(Generic<u8>, z), 8); + assert_eq!(offs_of_z::<u8>(), 8); + + // Ensure that it works with the implicit lifetime in `Box<dyn Trait + '_>`. + assert_eq!(offset_of!(Generic<Box<dyn Trait>>, z), 8); } #[test] diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 2a6b1a5ec73..89dfdfafdb1 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -15,6 +15,7 @@ use crate::ffi::OsString; use crate::fmt; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; use crate::path::{Path, PathBuf}; +use crate::sealed::Sealed; use crate::sys::fs as fs_imp; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use crate::time::SystemTime; @@ -1391,6 +1392,16 @@ impl FileTimes { } } +impl AsInnerMut<fs_imp::FileTimes> for FileTimes { + fn as_inner_mut(&mut self) -> &mut fs_imp::FileTimes { + &mut self.0 + } +} + +// For implementing OS extension traits in `std::os` +#[unstable(feature = "file_set_times", issue = "98245")] +impl Sealed for FileTimes {} + impl Permissions { /// Returns `true` if these permissions describe a readonly (unwritable) file. /// diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index a8a0b9f122d..e2480bcbbc7 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1,7 +1,7 @@ use crate::io::prelude::*; use crate::env; -use crate::fs::{self, File, OpenOptions}; +use crate::fs::{self, File, FileTimes, OpenOptions}; use crate::io::{BorrowedBuf, ErrorKind, SeekFrom}; use crate::mem::MaybeUninit; use crate::path::Path; @@ -9,7 +9,7 @@ use crate::str; use crate::sync::Arc; use crate::sys_common::io::test::{tmpdir, TempDir}; use crate::thread; -use crate::time::{Duration, Instant}; +use crate::time::{Duration, Instant, SystemTime}; use rand::RngCore; @@ -1633,3 +1633,53 @@ fn rename_directory() { assert!(new_path.join("newdir").is_dir()); assert!(new_path.join("newdir/temp.txt").exists()); } + +#[test] +fn test_file_times() { + #[cfg(target_os = "ios")] + use crate::os::ios::fs::FileTimesExt; + #[cfg(target_os = "macos")] + use crate::os::macos::fs::FileTimesExt; + #[cfg(target_os = "watchos")] + use crate::os::watchos::fs::FileTimesExt; + #[cfg(windows)] + use crate::os::windows::fs::FileTimesExt; + + let tmp = tmpdir(); + let file = File::create(tmp.join("foo")).unwrap(); + let mut times = FileTimes::new(); + let accessed = SystemTime::UNIX_EPOCH + Duration::from_secs(12345); + let modified = SystemTime::UNIX_EPOCH + Duration::from_secs(54321); + times = times.set_accessed(accessed).set_modified(modified); + #[cfg(any(windows, target_os = "macos", target_os = "ios", target_os = "watchos"))] + let created = SystemTime::UNIX_EPOCH + Duration::from_secs(32123); + #[cfg(any(windows, target_os = "macos", target_os = "ios", target_os = "watchos"))] + { + times = times.set_created(created); + } + match file.set_times(times) { + // Allow unsupported errors on platforms which don't support setting times. + #[cfg(not(any( + windows, + all( + unix, + not(any( + target_os = "android", + target_os = "redox", + target_os = "espidf", + target_os = "horizon" + )) + ) + )))] + Err(e) if e.kind() == ErrorKind::Unsupported => return, + Err(e) => panic!("error setting file times: {e:?}"), + Ok(_) => {} + } + let metadata = file.metadata().unwrap(); + assert_eq!(metadata.accessed().unwrap(), accessed); + assert_eq!(metadata.modified().unwrap(), modified); + #[cfg(any(windows, target_os = "macos", target_os = "ios", target_os = "watchos"))] + { + assert_eq!(metadata.created().unwrap(), created); + } +} diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 541e95d229b..141a18a42dd 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -756,6 +756,15 @@ impl TcpListener { /// ]; /// let listener = TcpListener::bind(&addrs[..]).unwrap(); /// ``` + /// + /// Creates a TCP listener bound to a port assigned by the operating system + /// at `127.0.0.1`. + /// + /// ```no_run + /// use std::net::TcpListener; + /// + /// let socket = TcpListener::bind("127.0.0.1:0").unwrap(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> { super::each_addr(addr, net_imp::TcpListener::bind).map(TcpListener) diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index 9628bcc5108..5ca4ed832f3 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -90,6 +90,15 @@ impl UdpSocket { /// ]; /// let socket = UdpSocket::bind(&addrs[..]).expect("couldn't bind to address"); /// ``` + /// + /// Creates a UDP socket bound to a port assigned by the operating system + /// at `127.0.0.1`. + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:0").unwrap(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> { super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket) diff --git a/library/std/src/os/ios/fs.rs b/library/std/src/os/ios/fs.rs index 4a4637ce072..6d4d54b7c78 100644 --- a/library/std/src/os/ios/fs.rs +++ b/library/std/src/os/ios/fs.rs @@ -1,7 +1,9 @@ #![stable(feature = "metadata_ext", since = "1.1.0")] -use crate::fs::Metadata; -use crate::sys_common::AsInner; +use crate::fs::{self, Metadata}; +use crate::sealed::Sealed; +use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; +use crate::time::SystemTime; #[allow(deprecated)] use crate::os::ios::raw; @@ -140,3 +142,19 @@ impl MetadataExt for Metadata { self.as_inner().as_inner().st_lspare as u32 } } + +/// OS-specific extensions to [`fs::FileTimes`]. +#[unstable(feature = "file_set_times", issue = "98245")] +pub trait FileTimesExt: Sealed { + /// Set the creation time of a file. + #[unstable(feature = "file_set_times", issue = "98245")] + fn set_created(self, t: SystemTime) -> Self; +} + +#[unstable(feature = "file_set_times", issue = "98245")] +impl FileTimesExt for fs::FileTimes { + fn set_created(mut self, t: SystemTime) -> Self { + self.as_inner_mut().set_created(t.into_inner()); + self + } +} diff --git a/library/std/src/os/macos/fs.rs b/library/std/src/os/macos/fs.rs index 91915da6a43..fe82d03d869 100644 --- a/library/std/src/os/macos/fs.rs +++ b/library/std/src/os/macos/fs.rs @@ -1,7 +1,9 @@ #![stable(feature = "metadata_ext", since = "1.1.0")] -use crate::fs::Metadata; -use crate::sys_common::AsInner; +use crate::fs::{self, Metadata}; +use crate::sealed::Sealed; +use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; +use crate::time::SystemTime; #[allow(deprecated)] use crate::os::macos::raw; @@ -146,3 +148,19 @@ impl MetadataExt for Metadata { [qspare[0] as u64, qspare[1] as u64] } } + +/// OS-specific extensions to [`fs::FileTimes`]. +#[unstable(feature = "file_set_times", issue = "98245")] +pub trait FileTimesExt: Sealed { + /// Set the creation time of a file. + #[unstable(feature = "file_set_times", issue = "98245")] + fn set_created(self, t: SystemTime) -> Self; +} + +#[unstable(feature = "file_set_times", issue = "98245")] +impl FileTimesExt for fs::FileTimes { + fn set_created(mut self, t: SystemTime) -> Self { + self.as_inner_mut().set_created(t.into_inner()); + self + } +} diff --git a/library/std/src/os/watchos/fs.rs b/library/std/src/os/watchos/fs.rs index a14fe35a77c..2ecc4c68a96 100644 --- a/library/std/src/os/watchos/fs.rs +++ b/library/std/src/os/watchos/fs.rs @@ -1,7 +1,9 @@ #![stable(feature = "metadata_ext", since = "1.1.0")] -use crate::fs::Metadata; -use crate::sys_common::AsInner; +use crate::fs::{self, Metadata}; +use crate::sealed::Sealed; +use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; +use crate::time::SystemTime; #[allow(deprecated)] use crate::os::watchos::raw; @@ -140,3 +142,19 @@ impl MetadataExt for Metadata { self.as_inner().as_inner().st_lspare as u32 } } + +/// OS-specific extensions to [`fs::FileTimes`]. +#[unstable(feature = "file_set_times", issue = "98245")] +pub trait FileTimesExt: Sealed { + /// Set the creation time of a file. + #[unstable(feature = "file_set_times", issue = "98245")] + fn set_created(self, t: SystemTime) -> Self; +} + +#[unstable(feature = "file_set_times", issue = "98245")] +impl FileTimesExt for fs::FileTimes { + fn set_created(mut self, t: SystemTime) -> Self { + self.as_inner_mut().set_created(t.into_inner()); + self + } +} diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs index a091f06dd53..94509e54796 100644 --- a/library/std/src/os/windows/fs.rs +++ b/library/std/src/os/windows/fs.rs @@ -9,7 +9,8 @@ use crate::io; use crate::path::Path; use crate::sealed::Sealed; use crate::sys; -use crate::sys_common::{AsInner, AsInnerMut}; +use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; +use crate::time::SystemTime; /// Windows-specific extensions to [`fs::File`]. #[stable(feature = "file_offset", since = "1.15.0")] @@ -526,6 +527,22 @@ impl FileTypeExt for fs::FileType { } } +/// Windows-specific extensions to [`fs::FileTimes`]. +#[unstable(feature = "file_set_times", issue = "98245")] +pub trait FileTimesExt: Sealed { + /// Set the creation time of a file. + #[unstable(feature = "file_set_times", issue = "98245")] + fn set_created(self, t: SystemTime) -> Self; +} + +#[unstable(feature = "file_set_times", issue = "98245")] +impl FileTimesExt for fs::FileTimes { + fn set_created(mut self, t: SystemTime) -> Self { + self.as_inner_mut().set_created(t.into_inner()); + self + } +} + /// Creates a new symlink to a non-directory file on the filesystem. /// /// The `link` path will be a file symbolic link pointing to the `original` diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index a2ffd8b1e7e..69a6f3e6d5a 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -19,11 +19,11 @@ pub macro panic_2015 { $crate::rt::begin_panic("explicit panic") }), ($msg:expr $(,)?) => ({ - $crate::rt::begin_panic($msg) + $crate::rt::begin_panic($msg); }), // Special-case the single-argument case for const_panic. ("{}", $arg:expr $(,)?) => ({ - $crate::rt::panic_display(&$arg) + $crate::rt::panic_display(&$arg); }), ($fmt:expr, $($arg:tt)+) => ({ // Semicolon to prevent temporaries inside the formatting machinery from diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 43203c5824d..febdeb51463 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -733,8 +733,9 @@ impl<'a> Components<'a> { } } - // parse a given byte sequence into the corresponding path component - fn parse_single_component<'b>(&self, comp: &'b [u8]) -> Option<Component<'b>> { + // parse a given byte sequence following the OsStr encoding into the + // corresponding path component + unsafe fn parse_single_component<'b>(&self, comp: &'b [u8]) -> Option<Component<'b>> { match comp { b"." if self.prefix_verbatim() => Some(Component::CurDir), b"." => None, // . components are normalized away, except at @@ -754,7 +755,8 @@ impl<'a> Components<'a> { None => (0, self.path), Some(i) => (1, &self.path[..i]), }; - (comp.len() + extra, self.parse_single_component(comp)) + // SAFETY: `comp` is a valid substring, since it is split on a separator. + (comp.len() + extra, unsafe { self.parse_single_component(comp) }) } // parse a component from the right, saying how many bytes to consume to @@ -766,7 +768,8 @@ impl<'a> Components<'a> { None => (0, &self.path[start..]), Some(i) => (1, &self.path[start + i + 1..]), }; - (comp.len() + extra, self.parse_single_component(comp)) + // SAFETY: `comp` is a valid substring, since it is split on a separator. + (comp.len() + extra, unsafe { self.parse_single_component(comp) }) } // trim away repeated separators (i.e., empty components) on the left diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 09db5b11dbf..09e9ae2720f 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -349,6 +349,8 @@ pub struct FilePermissions { pub struct FileTimes { accessed: Option<SystemTime>, modified: Option<SystemTime>, + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] + created: Option<SystemTime>, } #[derive(Copy, Clone, Eq, Debug)] @@ -591,6 +593,11 @@ impl FileTimes { pub fn set_modified(&mut self, t: SystemTime) { self.modified = Some(t); } + + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] + pub fn set_created(&mut self, t: SystemTime) { + self.created = Some(t); + } } impl FileType { @@ -1215,26 +1222,41 @@ impl File { io::ErrorKind::Unsupported, "setting file times not supported", )) - } else if #[cfg(any(target_os = "android", target_os = "macos"))] { + } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] { + let mut buf = [mem::MaybeUninit::<libc::timespec>::uninit(); 3]; + let mut num_times = 0; + let mut attrlist: libc::attrlist = unsafe { mem::zeroed() }; + attrlist.bitmapcount = libc::ATTR_BIT_MAP_COUNT; + if times.created.is_some() { + buf[num_times].write(to_timespec(times.created)?); + num_times += 1; + attrlist.commonattr |= libc::ATTR_CMN_CRTIME; + } + if times.modified.is_some() { + buf[num_times].write(to_timespec(times.modified)?); + num_times += 1; + attrlist.commonattr |= libc::ATTR_CMN_MODTIME; + } + if times.accessed.is_some() { + buf[num_times].write(to_timespec(times.accessed)?); + num_times += 1; + attrlist.commonattr |= libc::ATTR_CMN_ACCTIME; + } + cvt(unsafe { libc::fsetattrlist( + self.as_raw_fd(), + (&attrlist as *const libc::attrlist).cast::<libc::c_void>().cast_mut(), + buf.as_ptr().cast::<libc::c_void>().cast_mut(), + num_times * mem::size_of::<libc::timespec>(), + 0 + ) })?; + Ok(()) + } else if #[cfg(target_os = "android")] { let times = [to_timespec(times.accessed)?, to_timespec(times.modified)?]; - // futimens requires macOS 10.13, and Android API level 19 + // futimens requires Android API level 19 cvt(unsafe { weak!(fn futimens(c_int, *const libc::timespec) -> c_int); match futimens.get() { Some(futimens) => futimens(self.as_raw_fd(), times.as_ptr()), - #[cfg(target_os = "macos")] - None => { - fn ts_to_tv(ts: &libc::timespec) -> libc::timeval { - libc::timeval { - tv_sec: ts.tv_sec, - tv_usec: (ts.tv_nsec / 1000) as _ - } - } - let timevals = [ts_to_tv(×[0]), ts_to_tv(×[1])]; - libc::futimes(self.as_raw_fd(), timevals.as_ptr()) - } - // futimes requires even newer Android. - #[cfg(target_os = "android")] None => return Err(io::const_io_error!( io::ErrorKind::Unsupported, "setting file times requires Android API level >= 19", diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index ce427766d17..21a65bc25f3 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -88,8 +88,10 @@ pub struct FilePermissions { pub struct FileTimes { accessed: Option<c::FILETIME>, modified: Option<c::FILETIME>, + created: Option<c::FILETIME>, } -impl core::fmt::Debug for c::FILETIME { + +impl fmt::Debug for c::FILETIME { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let time = ((self.dwHighDateTime as u64) << 32) | self.dwLowDateTime as u64; f.debug_tuple("FILETIME").field(&time).finish() @@ -582,7 +584,10 @@ impl File { pub fn set_times(&self, times: FileTimes) -> io::Result<()> { let is_zero = |t: c::FILETIME| t.dwLowDateTime == 0 && t.dwHighDateTime == 0; - if times.accessed.map_or(false, is_zero) || times.modified.map_or(false, is_zero) { + if times.accessed.map_or(false, is_zero) + || times.modified.map_or(false, is_zero) + || times.created.map_or(false, is_zero) + { return Err(io::const_io_error!( io::ErrorKind::InvalidInput, "Cannot set file timestamp to 0", @@ -590,18 +595,23 @@ impl File { } let is_max = |t: c::FILETIME| t.dwLowDateTime == c::DWORD::MAX && t.dwHighDateTime == c::DWORD::MAX; - if times.accessed.map_or(false, is_max) || times.modified.map_or(false, is_max) { + if times.accessed.map_or(false, is_max) + || times.modified.map_or(false, is_max) + || times.created.map_or(false, is_max) + { return Err(io::const_io_error!( io::ErrorKind::InvalidInput, "Cannot set file timestamp to 0xFFFF_FFFF_FFFF_FFFF", )); } cvt(unsafe { + let created = + times.created.as_ref().map(|a| a as *const c::FILETIME).unwrap_or(ptr::null()); let accessed = times.accessed.as_ref().map(|a| a as *const c::FILETIME).unwrap_or(ptr::null()); let modified = times.modified.as_ref().map(|a| a as *const c::FILETIME).unwrap_or(ptr::null()); - c::SetFileTime(self.as_raw_handle(), ptr::null_mut(), accessed, modified) + c::SetFileTime(self.as_raw_handle(), created, accessed, modified) })?; Ok(()) } @@ -1005,6 +1015,10 @@ impl FileTimes { pub fn set_modified(&mut self, t: SystemTime) { self.modified = Some(t.into_inner()); } + + pub fn set_created(&mut self, t: SystemTime) { + self.created = Some(t.into_inner()); + } } impl FileType { diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs index 8752f46ff81..6f020940df1 100644 --- a/library/std/src/sys_common/backtrace.rs +++ b/library/std/src/sys_common/backtrace.rs @@ -68,13 +68,17 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: } let mut hit = false; - let mut stop = false; backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { hit = true; + + // Any frames between `__rust_begin_short_backtrace` and `__rust_end_short_backtrace` + // are omitted from the backtrace in short mode, `__rust_end_short_backtrace` will be + // called before the panic hook, so we won't ignore any frames if there is no + // invoke of `__rust_begin_short_backtrace`. if print_fmt == PrintFmt::Short { if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { if start && sym.contains("__rust_begin_short_backtrace") { - stop = true; + start = false; return; } if sym.contains("__rust_end_short_backtrace") { @@ -88,9 +92,6 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: res = bt_fmt.frame().symbol(frame, symbol); } }); - if stop { - return false; - } #[cfg(target_os = "nto")] if libc::__my_thread_exit as *mut libc::c_void == frame.ip() { if !hit && start { diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 9420c4fec5f..8f8778efee7 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -139,7 +139,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.8", ] [[package]] @@ -488,9 +488,9 @@ dependencies = [ [[package]] name = "object" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" dependencies = [ "memchr", ] @@ -654,19 +654,19 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.137" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" [[package]] name = "serde_derive" -version = "1.0.137" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", - "syn 1.0.102", + "syn 2.0.8", ] [[package]] @@ -704,9 +704,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.15" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "bcc02725fd69ab9f26eab07fad303e2497fad6fb9eba4f96c4d1687bdf704ad9" dependencies = [ "proc-macro2", "quote", diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 746c8dcfce0..367c6190967 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -37,7 +37,7 @@ filetime = "0.2" cc = "1.0.69" libc = "0.2" hex = "0.4" -object = { version = "0.29.0", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] } +object = { version = "0.31.1", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] } serde = "1.0.137" # Directly use serde_derive rather than through the derive feature of serde to allow building both # in parallel and to allow serde_json and toml to start building as soon as serde has been built. diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index f22cdad7df4..50ace987193 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -109,7 +109,7 @@ def _download(path, url, probably_big, verbose, exception): "-L", # Follow redirect. "-y", "30", "-Y", "10", # timeout if speed is < 10 bytes/sec for > 30 seconds "--connect-timeout", "30", # timeout if cannot connect within 30 seconds - "--retry", "3", "-Sf", url], + "--retry", "3", "-SRf", url], stdout=outfile, #Implements cli redirect operator '>' verbose=verbose, exception=True, # Will raise RuntimeError on failure diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 5c37fab5470..cf7c6596c02 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -942,7 +942,6 @@ impl<'a> Builder<'a> { self.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), paths); } - /// NOTE: keep this in sync with `rustdoc::clean::utils::doc_rust_lang_org_channel`, or tests will fail on beta/stable. pub fn doc_rust_lang_org_channel(&self) -> String { let channel = match &*self.config.channel { "stable" => &self.version, diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index c32fe59bbf0..edca8fe9b13 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -146,6 +146,22 @@ fn alias_and_path_for_library() { ); } +#[test] +fn test_beta_rev_parsing() { + use crate::extract_beta_rev; + + // single digit revision + assert_eq!(extract_beta_rev("1.99.9-beta.7 (xxxxxx)"), Some("7".to_string())); + // multiple digits + assert_eq!(extract_beta_rev("1.99.9-beta.777 (xxxxxx)"), Some("777".to_string())); + // nightly channel (no beta revision) + assert_eq!(extract_beta_rev("1.99.9-nightly (xxxxxx)"), None); + // stable channel (no beta revision) + assert_eq!(extract_beta_rev("1.99.9 (xxxxxxx)"), None); + // invalid string + assert_eq!(extract_beta_rev("invalid"), None); +} + mod defaults { use super::{configure, first, run_build}; use crate::builder::*; diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 710c8b52194..e192cda9a9a 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -350,7 +350,7 @@ impl SplitDebuginfo { } /// LTO mode used for compiling rustc itself. -#[derive(Default, Clone, PartialEq)] +#[derive(Default, Clone, PartialEq, Debug)] pub enum RustcLto { Off, #[default] @@ -508,29 +508,42 @@ struct TomlConfig { profile: Option<String>, } +/// Describes how to handle conflicts in merging two [`TomlConfig`] +#[derive(Copy, Clone, Debug)] +enum ReplaceOpt { + /// Silently ignore a duplicated value + IgnoreDuplicate, + /// Override the current value, even if it's `Some` + Override, + /// Exit with an error on duplicate values + ErrorOnDuplicate, +} + trait Merge { - fn merge(&mut self, other: Self); + fn merge(&mut self, other: Self, replace: ReplaceOpt); } impl Merge for TomlConfig { fn merge( &mut self, - TomlConfig { build, install, llvm, rust, dist, target, profile: _, changelog_seen: _ }: Self, + TomlConfig { build, install, llvm, rust, dist, target, profile: _, changelog_seen }: Self, + replace: ReplaceOpt, ) { - fn do_merge<T: Merge>(x: &mut Option<T>, y: Option<T>) { + fn do_merge<T: Merge>(x: &mut Option<T>, y: Option<T>, replace: ReplaceOpt) { if let Some(new) = y { if let Some(original) = x { - original.merge(new); + original.merge(new, replace); } else { *x = Some(new); } } } - do_merge(&mut self.build, build); - do_merge(&mut self.install, install); - do_merge(&mut self.llvm, llvm); - do_merge(&mut self.rust, rust); - do_merge(&mut self.dist, dist); + self.changelog_seen.merge(changelog_seen, replace); + do_merge(&mut self.build, build, replace); + do_merge(&mut self.install, install, replace); + do_merge(&mut self.llvm, llvm, replace); + do_merge(&mut self.rust, rust, replace); + do_merge(&mut self.dist, dist, replace); assert!(target.is_none(), "merging target-specific config is not currently supported"); } } @@ -547,10 +560,33 @@ macro_rules! define_config { } impl Merge for $name { - fn merge(&mut self, other: Self) { + fn merge(&mut self, other: Self, replace: ReplaceOpt) { $( - if !self.$field.is_some() { - self.$field = other.$field; + match replace { + ReplaceOpt::IgnoreDuplicate => { + if self.$field.is_none() { + self.$field = other.$field; + } + }, + ReplaceOpt::Override => { + if other.$field.is_some() { + self.$field = other.$field; + } + } + ReplaceOpt::ErrorOnDuplicate => { + if other.$field.is_some() { + if self.$field.is_some() { + if cfg!(test) { + panic!("overriding existing option") + } else { + eprintln!("overriding existing option: `{}`", stringify!($field)); + crate::detail_exit(2); + } + } else { + self.$field = other.$field; + } + } + } } )* } @@ -623,6 +659,37 @@ macro_rules! define_config { } } +impl<T> Merge for Option<T> { + fn merge(&mut self, other: Self, replace: ReplaceOpt) { + match replace { + ReplaceOpt::IgnoreDuplicate => { + if self.is_none() { + *self = other; + } + } + ReplaceOpt::Override => { + if other.is_some() { + *self = other; + } + } + ReplaceOpt::ErrorOnDuplicate => { + if other.is_some() { + if self.is_some() { + if cfg!(test) { + panic!("overriding existing option") + } else { + eprintln!("overriding existing option"); + crate::detail_exit(2); + } + } else { + *self = other; + } + } + } + } + } +} + define_config! { /// TOML representation of various global build decisions. #[derive(Default)] @@ -864,28 +931,27 @@ impl Config { pub fn parse(args: &[String]) -> Config { #[cfg(test)] - let get_toml = |_: &_| TomlConfig::default(); + fn get_toml(_: &Path) -> TomlConfig { + TomlConfig::default() + } + #[cfg(not(test))] - let get_toml = |file: &Path| { + fn get_toml(file: &Path) -> TomlConfig { let contents = t!(fs::read_to_string(file), format!("config file {} not found", file.display())); // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of // TomlConfig and sub types to be monomorphized 5x by toml. - match toml::from_str(&contents) + toml::from_str(&contents) .and_then(|table: toml::Value| TomlConfig::deserialize(table)) - { - Ok(table) => table, - Err(err) => { - eprintln!("failed to parse TOML configuration '{}': {}", file.display(), err); + .unwrap_or_else(|err| { + eprintln!("failed to parse TOML configuration '{}': {err}", file.display()); crate::detail_exit(2); - } - } - }; - + }) + } Self::parse_inner(args, get_toml) } - fn parse_inner<'a>(args: &[String], get_toml: impl 'a + Fn(&Path) -> TomlConfig) -> Config { + fn parse_inner(args: &[String], get_toml: impl Fn(&Path) -> TomlConfig) -> Config { let mut flags = Flags::parse(&args); let mut config = Config::default_opts(); @@ -998,8 +1064,40 @@ impl Config { include_path.push("defaults"); include_path.push(format!("config.{}.toml", include)); let included_toml = get_toml(&include_path); - toml.merge(included_toml); + toml.merge(included_toml, ReplaceOpt::IgnoreDuplicate); + } + + let mut override_toml = TomlConfig::default(); + for option in flags.set.iter() { + fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> { + toml::from_str(&option) + .and_then(|table: toml::Value| TomlConfig::deserialize(table)) + } + + let mut err = match get_table(option) { + Ok(v) => { + override_toml.merge(v, ReplaceOpt::ErrorOnDuplicate); + continue; + } + Err(e) => e, + }; + // We want to be able to set string values without quotes, + // like in `configure.py`. Try adding quotes around the right hand side + if let Some((key, value)) = option.split_once("=") { + if !value.contains('"') { + match get_table(&format!(r#"{key}="{value}""#)) { + Ok(v) => { + override_toml.merge(v, ReplaceOpt::ErrorOnDuplicate); + continue; + } + Err(e) => err = e, + } + } + } + eprintln!("failed to parse override `{option}`: `{err}"); + crate::detail_exit(2) } + toml.merge(override_toml, ReplaceOpt::Override); config.changelog_seen = toml.changelog_seen; diff --git a/src/bootstrap/config/tests.rs b/src/bootstrap/config/tests.rs index d913ca295e2..4de84b543ed 100644 --- a/src/bootstrap/config/tests.rs +++ b/src/bootstrap/config/tests.rs @@ -1,13 +1,11 @@ -use super::{Config, Flags, TomlConfig}; +use super::{Config, Flags}; use clap::CommandFactory; use std::{env, path::Path}; -fn toml(config: &str) -> impl '_ + Fn(&Path) -> TomlConfig { - |&_| toml::from_str(config).unwrap() -} - fn parse(config: &str) -> Config { - Config::parse_inner(&["check".to_owned(), "--config=/does/not/exist".to_owned()], toml(config)) + Config::parse_inner(&["check".to_owned(), "--config=/does/not/exist".to_owned()], |&_| { + toml::from_str(config).unwrap() + }) } #[test] @@ -94,3 +92,70 @@ fn detect_src_and_out() { fn clap_verify() { Flags::command().debug_assert(); } + +#[test] +fn override_toml() { + let config = Config::parse_inner( + &[ + "check".to_owned(), + "--config=/does/not/exist".to_owned(), + "--set=changelog-seen=1".to_owned(), + "--set=rust.lto=fat".to_owned(), + "--set=rust.deny-warnings=false".to_owned(), + "--set=build.gdb=\"bar\"".to_owned(), + "--set=build.tools=[\"cargo\"]".to_owned(), + "--set=llvm.build-config={\"foo\" = \"bar\"}".to_owned(), + ], + |&_| { + toml::from_str( + r#" +changelog-seen = 0 +[rust] +lto = "off" +deny-warnings = true + +[build] +gdb = "foo" +tools = [] + +[llvm] +download-ci-llvm = false +build-config = {} + "#, + ) + .unwrap() + }, + ); + assert_eq!(config.changelog_seen, Some(1), "setting top-level value"); + assert_eq!( + config.rust_lto, + crate::config::RustcLto::Fat, + "setting string value without quotes" + ); + assert_eq!(config.gdb, Some("bar".into()), "setting string value with quotes"); + assert_eq!(config.deny_warnings, false, "setting boolean value"); + assert_eq!( + config.tools, + Some(["cargo".to_string()].into_iter().collect()), + "setting list value" + ); + assert_eq!( + config.llvm_build_config, + [("foo".to_string(), "bar".to_string())].into_iter().collect(), + "setting dictionary value" + ); +} + +#[test] +#[should_panic] +fn override_toml_duplicate() { + Config::parse_inner( + &[ + "check".to_owned(), + "--config=/does/not/exist".to_owned(), + "--set=changelog-seen=1".to_owned(), + "--set=changelog-seen=2".to_owned(), + ], + |&_| toml::from_str("changelog-seen = 0").unwrap(), + ); +} diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs index 3e82a381a1b..25df5b2573b 100644 --- a/src/bootstrap/download.rs +++ b/src/bootstrap/download.rs @@ -219,7 +219,7 @@ impl Config { "30", // timeout if cannot connect within 30 seconds "--retry", "3", - "-Sf", + "-SRf", ]); curl.arg(url); let f = File::create(tempfile).unwrap(); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 6e0c0e01af8..80e71577798 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -158,6 +158,9 @@ pub struct Flags { #[arg(global(true))] /// paths for the subcommand pub paths: Vec<PathBuf>, + /// override options in config.toml + #[arg(global(true), value_hint = clap::ValueHint::Other, long, value_name = "section.option=value")] + pub set: Vec<String>, /// arguments passed to subcommands #[arg(global(true), last(true), value_name = "ARGS")] pub free_args: Vec<String>, @@ -365,7 +368,7 @@ pub enum Subcommand { #[arg(long)] all: bool, }, - /// Duild distribution artifacts + /// Build distribution artifacts Dist, /// Install distribution artifacts Install, diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 3756976dee0..6ee50ee6573 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1324,7 +1324,7 @@ impl Build { match &self.config.channel[..] { "stable" => num.to_string(), "beta" => { - if self.rust_info().is_managed_git_subrepository() && !self.config.omit_git_hash { + if !self.config.omit_git_hash { format!("{}-beta.{}", num, self.beta_prerelease_version()) } else { format!("{}-beta", num) @@ -1336,18 +1336,28 @@ impl Build { } fn beta_prerelease_version(&self) -> u32 { + fn extract_beta_rev_from_file<P: AsRef<Path>>(version_file: P) -> Option<String> { + let version = fs::read_to_string(version_file).ok()?; + + extract_beta_rev(&version) + } + if let Some(s) = self.prerelease_version.get() { return s; } - // Figure out how many merge commits happened since we branched off master. - // That's our beta number! - // (Note that we use a `..` range, not the `...` symmetric difference.) - let count = + // First check if there is a version file available. + // If available, we read the beta revision from that file. + // This only happens when building from a source tarball when Git should not be used. + let count = extract_beta_rev_from_file(self.src.join("version")).unwrap_or_else(|| { + // Figure out how many merge commits happened since we branched off master. + // That's our beta number! + // (Note that we use a `..` range, not the `...` symmetric difference.) output(self.config.git().arg("rev-list").arg("--count").arg("--merges").arg(format!( "refs/remotes/origin/{}..HEAD", self.config.stage0_metadata.config.nightly_branch - ))); + ))) + }); let n = count.trim().parse().unwrap(); self.prerelease_version.set(Some(n)); n @@ -1707,6 +1717,17 @@ to download LLVM rather than building it. } } +/// Extract the beta revision from the full version string. +/// +/// The full version string looks like "a.b.c-beta.y". And we need to extract +/// the "y" part from the string. +pub fn extract_beta_rev(version: &str) -> Option<String> { + let parts = version.splitn(2, "-beta.").collect::<Vec<_>>(); + let count = parts.get(1).and_then(|s| s.find(' ').map(|p| (&s[..p]).to_string())); + + count +} + #[cfg(unix)] fn chmod(path: &Path, perms: u32) { use std::os::unix::fs::*; diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs index 67cb8837391..040a12f5d10 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/llvm.rs @@ -185,6 +185,7 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool { ("arm-unknown-linux-gnueabi", false), ("arm-unknown-linux-gnueabihf", false), ("armv7-unknown-linux-gnueabihf", false), + ("loongarch64-unknown-linux-gnu", false), ("mips-unknown-linux-gnu", false), ("mips64-unknown-linux-gnuabi64", false), ("mips64el-unknown-linux-gnuabi64", false), diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/render_tests.rs index bedf34d89e8..fa0a4806618 100644 --- a/src/bootstrap/render_tests.rs +++ b/src/bootstrap/render_tests.rs @@ -168,9 +168,14 @@ impl<'a> Renderer<'a> { if !self.failures.is_empty() { println!("\nfailures:\n"); for failure in &self.failures { - if let Some(stdout) = &failure.stdout { + if failure.stdout.is_some() || failure.message.is_some() { println!("---- {} stdout ----", failure.name); - println!("{stdout}"); + if let Some(stdout) = &failure.stdout { + println!("{stdout}"); + } + if let Some(message) = &failure.message { + println!("note: {message}"); + } } } diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 2d600704e02..2b72d6c48eb 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -620,6 +620,8 @@ impl Step for Miri { cargo.env("MIRIFLAGS", "-O -Zmir-opt-level=4 -Cdebug-assertions=yes"); // Optimizations can change backtraces cargo.env("MIRI_SKIP_UI_CHECKS", "1"); + // `MIRI_SKIP_UI_CHECKS` and `MIRI_BLESS` are incompatible + cargo.env_remove("MIRI_BLESS"); // Optimizations can change error locations and remove UB so don't run `fail` tests. cargo.args(&["tests/pass", "tests/panic"]); diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index 5898a21d613..e799d7c9688 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -257,6 +257,22 @@ For targets: `i586-unknown-linux-gnu` (\*) Compressed debug is enabled by default for gas (assembly) on Linux/x86 targets, but that makes our `compiler_builtins` incompatible with binutils < 2.32. +### `loongarch64-linux-gnu.defconfig` + +For targets: `loongarch64-unknown-linux-gnu` + +- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET} +- Path and misc options > Use a mirror = ENABLE +- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc +- Target options > Target Architecture = loongarch +- Target options > Bitness = 64-bit +- Operating System > Target OS = linux +- Operating System > Linux kernel version = 5.19.16 +- Binary utilities > Version of binutils = 2.40 +- C-library > glibc version = 2.36 +- C compiler > gcc version = 12.2.0 +- C compiler > C++ = ENABLE -- to cross compile LLVM + ### `mips-linux-gnu.defconfig` For targets: `mips-unknown-linux-gnu` diff --git a/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile new file mode 100644 index 00000000000..78689c429c2 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile @@ -0,0 +1,30 @@ +FROM ubuntu:22.04 + +COPY scripts/cross-apt-packages.sh /scripts/ +RUN sh /scripts/cross-apt-packages.sh + +# The latest released version does not support LoongArch. +COPY scripts/crosstool-ng-git.sh /scripts/ +RUN sh /scripts/crosstool-ng-git.sh + +COPY scripts/rustbuild-setup.sh /scripts/ +RUN sh /scripts/rustbuild-setup.sh +WORKDIR /tmp + +COPY scripts/crosstool-ng-build.sh /scripts/ +COPY host-x86_64/dist-loongarch64-linux/loongarch64-unknown-linux-gnu.defconfig /tmp/crosstool.defconfig +RUN /scripts/crosstool-ng-build.sh + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +ENV PATH=$PATH:/x-tools/loongarch64-unknown-linux-gnu/bin + +ENV CC_loongarch64_unknown_linux_gnu=loongarch64-unknown-linux-gnu-gcc \ + AR_loongarch64_unknown_linux_gnu=loongarch64-unknown-linux-gnu-ar \ + CXX_loongarch64_unknown_linux_gnu=loongarch64-unknown-linux-gnu-g++ + +ENV HOSTS=loongarch64-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs +ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-loongarch64-linux/loongarch64-unknown-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-loongarch64-linux/loongarch64-unknown-linux-gnu.defconfig new file mode 100644 index 00000000000..576f3631cd5 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-loongarch64-linux/loongarch64-unknown-linux-gnu.defconfig @@ -0,0 +1,14 @@ +CT_CONFIG_VERSION="4" +CT_EXPERIMENTAL=y +CT_PREFIX_DIR="/x-tools/${CT_TARGET}" +CT_USE_MIRROR=y +CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc" +CT_ARCH_LOONGARCH=y +# CT_DEMULTILIB is not set +CT_ARCH_USE_MMU=y +CT_ARCH_ARCH="loongarch64" +CT_KERNEL_LINUX=y +CT_LINUX_V_5_19=y +CT_GLIBC_V_2_36=y +CT_CC_GCC_ENABLE_DEFAULT_PIE=y +CT_CC_LANG_CXX=y 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 6b4966ddeb4..806935b827f 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.16.3 \ No newline at end of file +0.16.4 \ No newline at end of file diff --git a/src/ci/docker/scripts/cross-apt-packages.sh b/src/ci/docker/scripts/cross-apt-packages.sh index 2f8bf119424..398362ca52f 100644 --- a/src/ci/docker/scripts/cross-apt-packages.sh +++ b/src/ci/docker/scripts/cross-apt-packages.sh @@ -22,6 +22,7 @@ apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install patch \ pkg-config \ python3 \ + rsync \ sudo \ texinfo \ unzip \ diff --git a/src/ci/docker/scripts/crosstool-ng-git.sh b/src/ci/docker/scripts/crosstool-ng-git.sh new file mode 100644 index 00000000000..449cc476f9a --- /dev/null +++ b/src/ci/docker/scripts/crosstool-ng-git.sh @@ -0,0 +1,17 @@ +#!/bin/sh +set -ex + +URL=https://github.com/crosstool-ng/crosstool-ng +REV=943364711a650d9b9e84c1b42c91cc0265b6ab5c + +mkdir crosstool-ng +cd crosstool-ng +git init +git fetch --depth=1 ${URL} ${REV} +git reset --hard FETCH_HEAD +./bootstrap +./configure --prefix=/usr/local +make -j$(nproc) +make install +cd .. +rm -rf crosstool-ng diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index f81e740936b..fd619467fc1 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -359,6 +359,9 @@ jobs: - name: dist-i686-linux <<: *job-linux-8c + - name: dist-loongarch64-linux + <<: *job-linux-8c + - name: dist-mips-linux <<: *job-linux-8c diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py index 7cd5e88f6a2..8d03d3759bf 100644 --- a/src/ci/stage-build.py +++ b/src/ci/stage-build.py @@ -48,7 +48,6 @@ RUSTC_PGO_CRATES = [ LLVM_BOLT_CRATES = LLVM_PGO_CRATES - class Pipeline: # Paths def checkout_path(self) -> Path: @@ -451,6 +450,44 @@ def cmd( ) return subprocess.run(args, env=environment, check=True) +class BenchmarkRunner: + def run_rustc(self, pipeline: Pipeline): + raise NotImplementedError + + def run_llvm(self, pipeline: Pipeline): + raise NotImplementedError + + def run_bolt(self, pipeline: Pipeline): + raise NotImplementedError + +class DefaultBenchmarkRunner(BenchmarkRunner): + def run_rustc(self, pipeline: Pipeline): + # Here we're profiling the `rustc` frontend, so we also include `Check`. + # The benchmark set includes various stress tests that put the frontend under pressure. + run_compiler_benchmarks( + pipeline, + profiles=["Check", "Debug", "Opt"], + scenarios=["All"], + crates=RUSTC_PGO_CRATES, + env=dict( + LLVM_PROFILE_FILE=str(pipeline.rustc_profile_template_path()) + ) + ) + def run_llvm(self, pipeline: Pipeline): + run_compiler_benchmarks( + pipeline, + profiles=["Debug", "Opt"], + scenarios=["Full"], + crates=LLVM_PGO_CRATES + ) + + def run_bolt(self, pipeline: Pipeline): + run_compiler_benchmarks( + pipeline, + profiles=["Check", "Debug", "Opt"], + scenarios=["Full"], + crates=LLVM_BOLT_CRATES + ) def run_compiler_benchmarks( pipeline: Pipeline, @@ -580,14 +617,10 @@ def create_pipeline() -> Pipeline: raise Exception(f"Optimized build is not supported for platform {sys.platform}") -def gather_llvm_profiles(pipeline: Pipeline): +def gather_llvm_profiles(pipeline: Pipeline, runner: BenchmarkRunner): LOGGER.info("Running benchmarks with PGO instrumented LLVM") - run_compiler_benchmarks( - pipeline, - profiles=["Debug", "Opt"], - scenarios=["Full"], - crates=LLVM_PGO_CRATES - ) + + runner.run_llvm(pipeline) profile_path = pipeline.llvm_profile_merged_file() LOGGER.info(f"Merging LLVM PGO profiles to {profile_path}") @@ -609,20 +642,12 @@ def gather_llvm_profiles(pipeline: Pipeline): delete_directory(pipeline.llvm_profile_dir_root()) -def gather_rustc_profiles(pipeline: Pipeline): +def gather_rustc_profiles(pipeline: Pipeline, runner: BenchmarkRunner): LOGGER.info("Running benchmarks with PGO instrumented rustc") - # Here we're profiling the `rustc` frontend, so we also include `Check`. - # The benchmark set includes various stress tests that put the frontend under pressure. - run_compiler_benchmarks( - pipeline, - profiles=["Check", "Debug", "Opt"], - scenarios=["All"], - crates=RUSTC_PGO_CRATES, - env=dict( - LLVM_PROFILE_FILE=str(pipeline.rustc_profile_template_path()) - ) - ) + + runner.run_rustc(pipeline) + profile_path = pipeline.rustc_profile_merged_file() LOGGER.info(f"Merging Rustc PGO profiles to {profile_path}") @@ -644,14 +669,10 @@ def gather_rustc_profiles(pipeline: Pipeline): delete_directory(pipeline.rustc_profile_dir_root()) -def gather_llvm_bolt_profiles(pipeline: Pipeline): +def gather_llvm_bolt_profiles(pipeline: Pipeline, runner: BenchmarkRunner): LOGGER.info("Running benchmarks with BOLT instrumented LLVM") - run_compiler_benchmarks( - pipeline, - profiles=["Check", "Debug", "Opt"], - scenarios=["Full"], - crates=LLVM_BOLT_CRATES - ) + + runner.run_bolt(pipeline) merged_profile_path = pipeline.llvm_bolt_profile_merged_file() profile_files_path = Path("/tmp/prof.fdata") @@ -744,7 +765,7 @@ def record_metrics(pipeline: Pipeline, timer: Timer): log_metrics(metrics) -def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: List[str]): +def execute_build_pipeline(timer: Timer, pipeline: Pipeline, runner: BenchmarkRunner, final_build_args: List[str]): # Clear and prepare tmp directory shutil.rmtree(pipeline.opt_artifacts(), ignore_errors=True) os.makedirs(pipeline.opt_artifacts(), exist_ok=True) @@ -762,7 +783,7 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: L record_metrics(pipeline, rustc_build) with stage1.section("Gather profiles"): - gather_llvm_profiles(pipeline) + gather_llvm_profiles(pipeline, runner) print_free_disk_space(pipeline) clear_llvm_files(pipeline) @@ -781,7 +802,7 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: L record_metrics(pipeline, rustc_build) with stage2.section("Gather profiles"): - gather_rustc_profiles(pipeline) + gather_rustc_profiles(pipeline, runner) print_free_disk_space(pipeline) clear_llvm_files(pipeline) @@ -804,7 +825,7 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: L record_metrics(pipeline, rustc_build) with stage3.section("Gather profiles"): - gather_llvm_bolt_profiles(pipeline) + gather_llvm_bolt_profiles(pipeline, runner) # LLVM is not being cleared here, we want to reuse the previous build print_free_disk_space(pipeline) @@ -819,7 +840,7 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: L record_metrics(pipeline, stage4) -if __name__ == "__main__": +def run(runner: BenchmarkRunner): logging.basicConfig( level=logging.DEBUG, format="%(name)s %(levelname)-4s: %(message)s", @@ -832,8 +853,9 @@ if __name__ == "__main__": timer = Timer() pipeline = create_pipeline() + try: - execute_build_pipeline(timer, pipeline, build_args) + execute_build_pipeline(timer, pipeline, runner, build_args) except BaseException as e: LOGGER.error("The multi-stage build has failed") raise e @@ -842,3 +864,7 @@ if __name__ == "__main__": print_free_disk_space(pipeline) print_binary_sizes(pipeline) + +if __name__ == "__main__": + runner = DefaultBenchmarkRunner() + run(runner) diff --git a/src/doc/embedded-book b/src/doc/embedded-book -Subproject d9eb4c3f75435b008881062ffa77bf0d1527b37 +Subproject f2aed2fe8e9f55508c86ba3aa4b6789b18a08a2 diff --git a/src/doc/nomicon b/src/doc/nomicon -Subproject b5f7500fc40775096c2bbd204eae096612cf904 +Subproject b5f018fb5930cb733b0a8aaf2eed975d4771e74 diff --git a/src/doc/reference b/src/doc/reference -Subproject 28dc0f3576b55f5e57c5d6e65cd68ba3161e9fd +Subproject 553d99b02a53b4133a40d5bd2e19958c67487c0 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject 28dbeaf5c44bc7f5111ad412e99f2d7c5cec6c9 +Subproject f1e637883fafeb83bdd5906ee7f467e4d35b733 diff --git a/src/doc/rustc/src/exploit-mitigations.md b/src/doc/rustc/src/exploit-mitigations.md index 98b49e07171..a82a53248d4 100644 --- a/src/doc/rustc/src/exploit-mitigations.md +++ b/src/doc/rustc/src/exploit-mitigations.md @@ -115,9 +115,9 @@ equivalent. <tr> <td>Stack smashing protection </td> - <td>No + <td>Yes </td> - <td> + <td>Nightly </td> </tr> <tr> @@ -432,18 +432,16 @@ saved return instruction pointer, and checking if this value has changed when returning from a function. This is also known as “Stack Protector” or “Stack Smashing Protector (SSP)”. -The Rust compiler does not support stack smashing protection. However, more -comprehensive alternatives to stack smashing protection exist, such as -shadow and safe stack (see backward-edge control flow protection). +The Rust compiler supports stack smashing protection on nightly builds[42].  Fig. 14. IDA Pro listing cross references to `__stack_chk_fail` in hello-rust. To check if stack smashing protection is enabled for a given binary, search -for cross references to `__stack_chk_fail`. The only cross references to -`__stack_chk_fail` in hello-rust are from the statically-linked libbacktrace -library (see Fig. 14). +for cross references to `__stack_chk_fail`. The presence of these +cross-references in Rust-compiled code (e.g., `hello_rust::main`) indicates +that the stack smashing protection is enabled (see Fig. 14). ### Forward-edge control flow protection @@ -697,3 +695,6 @@ defaults (unrelated to `READ_IMPLIES_EXEC`). 41. “ControlFlowIntegrity.” The Rust Unstable Book. [https://doc.rust-lang.org/unstable-book/compiler-flags/sanitizer.html#controlflowintegrity](../unstable-book/compiler-flags/sanitizer.html#controlflowintegrity). + +42. bbjornse. “add codegen option for using LLVM stack smash protection #84197.” + GitHub. <https://github.com/rust-lang/rust/pull/84197> diff --git a/src/doc/rustc/src/images/image3.png b/src/doc/rustc/src/images/image3.png index a49e14b5ed2..ef02c605ead 100644 --- a/src/doc/rustc/src/images/image3.png +++ b/src/doc/rustc/src/images/image3.png Binary files differdiff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index d22e1cf7f68..3b2463aa5b2 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -88,6 +88,7 @@ target | notes `arm-unknown-linux-gnueabi` | ARMv6 Linux (kernel 3.2, glibc 2.17) `arm-unknown-linux-gnueabihf` | ARMv6 Linux, hardfloat (kernel 3.2, glibc 2.17) `armv7-unknown-linux-gnueabihf` | ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17) +[`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36) `mips-unknown-linux-gnu` | MIPS Linux (kernel 4.4, glibc 2.23) `mips64-unknown-linux-gnuabi64` | MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23) `mips64el-unknown-linux-gnuabi64` | MIPS64 (LE) Linux, n64 ABI (kernel 4.4, glibc 2.23) @@ -266,7 +267,6 @@ target | std | host | notes `i686-uwp-windows-gnu` | ? | | `i686-uwp-windows-msvc` | ? | | `i686-wrs-vxworks` | ? | | -[`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | ? | | LoongArch64 Linux (LP64D ABI) [`m68k-unknown-linux-gnu`](platform-support/m68k-unknown-linux-gnu.md) | ? | | Motorola 680x0 Linux `mips-unknown-linux-uclibc` | ✓ | | MIPS Linux with uClibc [`mips64-openwrt-linux-musl`](platform-support/mips64-openwrt-linux-musl.md) | ? | | MIPS64 for OpenWrt Linux MUSL diff --git a/src/doc/rustc/src/platform-support/loongarch-linux.md b/src/doc/rustc/src/platform-support/loongarch-linux.md index 16ccaf46b2f..999e71f8028 100644 --- a/src/doc/rustc/src/platform-support/loongarch-linux.md +++ b/src/doc/rustc/src/platform-support/loongarch-linux.md @@ -1,6 +1,6 @@ # loongarch\*-unknown-linux-\* -**Tier: 3** +**Tier: 2** [LoongArch] is a new RISC ISA developed by Loongson Technology Corporation Limited. diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index 089c03a0d64..9f65f1eeeb7 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -19,6 +19,7 @@ complete -c x.py -n "__fish_use_subcommand" -l rust-profile-generate -d 'generat complete -c x.py -n "__fish_use_subcommand" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_use_subcommand" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F complete -c x.py -n "__fish_use_subcommand" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_use_subcommand" -l set -d 'override options in config.toml' -r -f complete -c x.py -n "__fish_use_subcommand" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_use_subcommand" -s i -l incremental -d 'use incremental compilation' complete -c x.py -n "__fish_use_subcommand" -l include-default-paths -d 'include default paths in addition to the provided ones' @@ -36,7 +37,7 @@ complete -c x.py -n "__fish_use_subcommand" -f -a "doc" -d 'Build documentation' complete -c x.py -n "__fish_use_subcommand" -f -a "test" -d 'Build and run some test suites' complete -c x.py -n "__fish_use_subcommand" -f -a "bench" -d 'Build and run some benchmarks' complete -c x.py -n "__fish_use_subcommand" -f -a "clean" -d 'Clean out build directories' -complete -c x.py -n "__fish_use_subcommand" -f -a "dist" -d 'Duild distribution artifacts' +complete -c x.py -n "__fish_use_subcommand" -f -a "dist" -d 'Build distribution artifacts' complete -c x.py -n "__fish_use_subcommand" -f -a "install" -d 'Install distribution artifacts' complete -c x.py -n "__fish_use_subcommand" -f -a "run" -d 'Run tools contained in this repository' complete -c x.py -n "__fish_use_subcommand" -f -a "setup" -d 'Set up the environment for development' @@ -62,6 +63,7 @@ complete -c x.py -n "__fish_seen_subcommand_from build" -l rust-profile-generate complete -c x.py -n "__fish_seen_subcommand_from build" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from build" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F complete -c x.py -n "__fish_seen_subcommand_from build" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from build" -l set -d 'override options in config.toml' -r -f complete -c x.py -n "__fish_seen_subcommand_from build" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_seen_subcommand_from build" -s i -l incremental -d 'use incremental compilation' complete -c x.py -n "__fish_seen_subcommand_from build" -l include-default-paths -d 'include default paths in addition to the provided ones' @@ -91,6 +93,7 @@ complete -c x.py -n "__fish_seen_subcommand_from check" -l rust-profile-generate complete -c x.py -n "__fish_seen_subcommand_from check" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from check" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F complete -c x.py -n "__fish_seen_subcommand_from check" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from check" -l set -d 'override options in config.toml' -r -f complete -c x.py -n "__fish_seen_subcommand_from check" -l all-targets -d 'Check all targets' complete -c x.py -n "__fish_seen_subcommand_from check" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_seen_subcommand_from check" -s i -l incremental -d 'use incremental compilation' @@ -125,6 +128,7 @@ complete -c x.py -n "__fish_seen_subcommand_from clippy" -l rust-profile-generat complete -c x.py -n "__fish_seen_subcommand_from clippy" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from clippy" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F complete -c x.py -n "__fish_seen_subcommand_from clippy" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l set -d 'override options in config.toml' -r -f complete -c x.py -n "__fish_seen_subcommand_from clippy" -l fix complete -c x.py -n "__fish_seen_subcommand_from clippy" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_seen_subcommand_from clippy" -s i -l incremental -d 'use incremental compilation' @@ -155,6 +159,7 @@ complete -c x.py -n "__fish_seen_subcommand_from fix" -l rust-profile-generate - complete -c x.py -n "__fish_seen_subcommand_from fix" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from fix" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F complete -c x.py -n "__fish_seen_subcommand_from fix" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from fix" -l set -d 'override options in config.toml' -r -f complete -c x.py -n "__fish_seen_subcommand_from fix" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_seen_subcommand_from fix" -s i -l incremental -d 'use incremental compilation' complete -c x.py -n "__fish_seen_subcommand_from fix" -l include-default-paths -d 'include default paths in addition to the provided ones' @@ -184,6 +189,7 @@ complete -c x.py -n "__fish_seen_subcommand_from fmt" -l rust-profile-generate - complete -c x.py -n "__fish_seen_subcommand_from fmt" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from fmt" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F complete -c x.py -n "__fish_seen_subcommand_from fmt" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l set -d 'override options in config.toml' -r -f complete -c x.py -n "__fish_seen_subcommand_from fmt" -l check -d 'check formatting instead of applying' complete -c x.py -n "__fish_seen_subcommand_from fmt" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_seen_subcommand_from fmt" -s i -l incremental -d 'use incremental compilation' @@ -214,6 +220,7 @@ complete -c x.py -n "__fish_seen_subcommand_from doc" -l rust-profile-generate - complete -c x.py -n "__fish_seen_subcommand_from doc" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from doc" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F complete -c x.py -n "__fish_seen_subcommand_from doc" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from doc" -l set -d 'override options in config.toml' -r -f complete -c x.py -n "__fish_seen_subcommand_from doc" -l open -d 'open the docs in a browser' complete -c x.py -n "__fish_seen_subcommand_from doc" -l json -d 'render the documentation in JSON format in addition to the usual HTML format' complete -c x.py -n "__fish_seen_subcommand_from doc" -s v -l verbose -d 'use verbose output (-vv for very verbose)' @@ -251,6 +258,7 @@ complete -c x.py -n "__fish_seen_subcommand_from test" -l rust-profile-generate complete -c x.py -n "__fish_seen_subcommand_from test" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from test" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F complete -c x.py -n "__fish_seen_subcommand_from test" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from test" -l set -d 'override options in config.toml' -r -f complete -c x.py -n "__fish_seen_subcommand_from test" -l no-fail-fast -d 'run all tests regardless of failure' complete -c x.py -n "__fish_seen_subcommand_from test" -l no-doc -d 'do not run doc tests' complete -c x.py -n "__fish_seen_subcommand_from test" -l doc -d 'only run doc tests' @@ -288,6 +296,7 @@ complete -c x.py -n "__fish_seen_subcommand_from bench" -l rust-profile-generate complete -c x.py -n "__fish_seen_subcommand_from bench" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from bench" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F complete -c x.py -n "__fish_seen_subcommand_from bench" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from bench" -l set -d 'override options in config.toml' -r -f complete -c x.py -n "__fish_seen_subcommand_from bench" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_seen_subcommand_from bench" -s i -l incremental -d 'use incremental compilation' complete -c x.py -n "__fish_seen_subcommand_from bench" -l include-default-paths -d 'include default paths in addition to the provided ones' @@ -317,6 +326,7 @@ complete -c x.py -n "__fish_seen_subcommand_from clean" -l rust-profile-generate complete -c x.py -n "__fish_seen_subcommand_from clean" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from clean" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F complete -c x.py -n "__fish_seen_subcommand_from clean" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from clean" -l set -d 'override options in config.toml' -r -f complete -c x.py -n "__fish_seen_subcommand_from clean" -l all complete -c x.py -n "__fish_seen_subcommand_from clean" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_seen_subcommand_from clean" -s i -l incremental -d 'use incremental compilation' @@ -347,6 +357,7 @@ complete -c x.py -n "__fish_seen_subcommand_from dist" -l rust-profile-generate complete -c x.py -n "__fish_seen_subcommand_from dist" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from dist" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F complete -c x.py -n "__fish_seen_subcommand_from dist" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from dist" -l set -d 'override options in config.toml' -r -f complete -c x.py -n "__fish_seen_subcommand_from dist" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_seen_subcommand_from dist" -s i -l incremental -d 'use incremental compilation' complete -c x.py -n "__fish_seen_subcommand_from dist" -l include-default-paths -d 'include default paths in addition to the provided ones' @@ -376,6 +387,7 @@ complete -c x.py -n "__fish_seen_subcommand_from install" -l rust-profile-genera complete -c x.py -n "__fish_seen_subcommand_from install" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from install" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F complete -c x.py -n "__fish_seen_subcommand_from install" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from install" -l set -d 'override options in config.toml' -r -f complete -c x.py -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_seen_subcommand_from install" -s i -l incremental -d 'use incremental compilation' complete -c x.py -n "__fish_seen_subcommand_from install" -l include-default-paths -d 'include default paths in addition to the provided ones' @@ -406,6 +418,7 @@ complete -c x.py -n "__fish_seen_subcommand_from run" -l rust-profile-generate - complete -c x.py -n "__fish_seen_subcommand_from run" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from run" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F complete -c x.py -n "__fish_seen_subcommand_from run" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from run" -l set -d 'override options in config.toml' -r -f complete -c x.py -n "__fish_seen_subcommand_from run" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_seen_subcommand_from run" -s i -l incremental -d 'use incremental compilation' complete -c x.py -n "__fish_seen_subcommand_from run" -l include-default-paths -d 'include default paths in addition to the provided ones' @@ -435,6 +448,7 @@ complete -c x.py -n "__fish_seen_subcommand_from setup" -l rust-profile-generate complete -c x.py -n "__fish_seen_subcommand_from setup" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from setup" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F complete -c x.py -n "__fish_seen_subcommand_from setup" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from setup" -l set -d 'override options in config.toml' -r -f complete -c x.py -n "__fish_seen_subcommand_from setup" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_seen_subcommand_from setup" -s i -l incremental -d 'use incremental compilation' complete -c x.py -n "__fish_seen_subcommand_from setup" -l include-default-paths -d 'include default paths in addition to the provided ones' @@ -464,6 +478,7 @@ complete -c x.py -n "__fish_seen_subcommand_from suggest" -l rust-profile-genera complete -c x.py -n "__fish_seen_subcommand_from suggest" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from suggest" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F complete -c x.py -n "__fish_seen_subcommand_from suggest" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l set -d 'override options in config.toml' -r -f complete -c x.py -n "__fish_seen_subcommand_from suggest" -l run -d 'run suggested tests' complete -c x.py -n "__fish_seen_subcommand_from suggest" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_seen_subcommand_from suggest" -s i -l incremental -d 'use incremental compilation' diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index fad2391e61f..569c186555c 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -43,6 +43,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml') [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') @@ -63,7 +64,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('test', 'test', [CompletionResultType]::ParameterValue, 'Build and run some test suites') [CompletionResult]::new('bench', 'bench', [CompletionResultType]::ParameterValue, 'Build and run some benchmarks') [CompletionResult]::new('clean', 'clean', [CompletionResultType]::ParameterValue, 'Clean out build directories') - [CompletionResult]::new('dist', 'dist', [CompletionResultType]::ParameterValue, 'Duild distribution artifacts') + [CompletionResult]::new('dist', 'dist', [CompletionResultType]::ParameterValue, 'Build distribution artifacts') [CompletionResult]::new('install', 'install', [CompletionResultType]::ParameterValue, 'Install distribution artifacts') [CompletionResult]::new('run', 'run', [CompletionResultType]::ParameterValue, 'Run tools contained in this repository') [CompletionResult]::new('setup', 'setup', [CompletionResultType]::ParameterValue, 'Set up the environment for development') @@ -93,6 +94,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml') [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') @@ -129,6 +131,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml') [CompletionResult]::new('--all-targets', 'all-targets', [CompletionResultType]::ParameterName, 'Check all targets') [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') @@ -170,6 +173,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml') [CompletionResult]::new('--fix', 'fix', [CompletionResultType]::ParameterName, 'fix') [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') @@ -207,6 +211,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml') [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') @@ -243,6 +248,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml') [CompletionResult]::new('--check', 'check', [CompletionResultType]::ParameterName, 'check formatting instead of applying') [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') @@ -280,6 +286,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml') [CompletionResult]::new('--open', 'open', [CompletionResultType]::ParameterName, 'open the docs in a browser') [CompletionResult]::new('--json', 'json', [CompletionResultType]::ParameterName, 'render the documentation in JSON format in addition to the usual HTML format') [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') @@ -324,6 +331,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml') [CompletionResult]::new('--no-fail-fast', 'no-fail-fast', [CompletionResultType]::ParameterName, 'run all tests regardless of failure') [CompletionResult]::new('--no-doc', 'no-doc', [CompletionResultType]::ParameterName, 'do not run doc tests') [CompletionResult]::new('--doc', 'doc', [CompletionResultType]::ParameterName, 'only run doc tests') @@ -368,6 +376,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml') [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') @@ -404,6 +413,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml') [CompletionResult]::new('--all', 'all', [CompletionResultType]::ParameterName, 'all') [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') @@ -441,6 +451,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml') [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') @@ -477,6 +488,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml') [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') @@ -514,6 +526,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml') [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') @@ -550,6 +563,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml') [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') @@ -586,6 +600,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml') [CompletionResult]::new('--run', 'run', [CompletionResultType]::ParameterName, 'run suggested tests') [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index 931cc4353b2..322afdb2883 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -61,7 +61,7 @@ _x.py() { case "${cmd}" in x.py) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]... build check clippy fix fmt doc test bench clean dist install run setup suggest" + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]... build check clippy fix fmt doc test bench clean dist install run setup suggest" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -155,6 +155,10 @@ _x.py() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --set) + COMPREPLY=("${cur}") + return 0 + ;; *) COMPREPLY=() ;; @@ -163,7 +167,7 @@ _x.py() { return 0 ;; x.py__bench) - opts="-v -i -j -h --test-args --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --test-args --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -261,6 +265,10 @@ _x.py() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --set) + COMPREPLY=("${cur}") + return 0 + ;; *) COMPREPLY=() ;; @@ -269,7 +277,7 @@ _x.py() { return 0 ;; x.py__build) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -363,6 +371,10 @@ _x.py() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --set) + COMPREPLY=("${cur}") + return 0 + ;; *) COMPREPLY=() ;; @@ -371,7 +383,7 @@ _x.py() { return 0 ;; x.py__check) - opts="-v -i -j -h --all-targets --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --all-targets --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -465,6 +477,10 @@ _x.py() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --set) + COMPREPLY=("${cur}") + return 0 + ;; *) COMPREPLY=() ;; @@ -473,7 +489,7 @@ _x.py() { return 0 ;; x.py__clean) - opts="-v -i -j -h --all --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --all --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -567,6 +583,10 @@ _x.py() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --set) + COMPREPLY=("${cur}") + return 0 + ;; *) COMPREPLY=() ;; @@ -575,7 +595,7 @@ _x.py() { return 0 ;; x.py__clippy) - opts="-A -D -W -F -v -i -j -h --fix --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + opts="-A -D -W -F -v -i -j -h --fix --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -685,6 +705,10 @@ _x.py() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --set) + COMPREPLY=("${cur}") + return 0 + ;; *) COMPREPLY=() ;; @@ -693,7 +717,7 @@ _x.py() { return 0 ;; x.py__dist) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -787,6 +811,10 @@ _x.py() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --set) + COMPREPLY=("${cur}") + return 0 + ;; *) COMPREPLY=() ;; @@ -795,7 +823,7 @@ _x.py() { return 0 ;; x.py__doc) - opts="-v -i -j -h --open --json --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --open --json --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -889,6 +917,10 @@ _x.py() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --set) + COMPREPLY=("${cur}") + return 0 + ;; *) COMPREPLY=() ;; @@ -897,7 +929,7 @@ _x.py() { return 0 ;; x.py__fix) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -991,6 +1023,10 @@ _x.py() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --set) + COMPREPLY=("${cur}") + return 0 + ;; *) COMPREPLY=() ;; @@ -999,7 +1035,7 @@ _x.py() { return 0 ;; x.py__fmt) - opts="-v -i -j -h --check --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --check --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1093,6 +1129,10 @@ _x.py() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --set) + COMPREPLY=("${cur}") + return 0 + ;; *) COMPREPLY=() ;; @@ -1101,7 +1141,7 @@ _x.py() { return 0 ;; x.py__install) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1195,6 +1235,10 @@ _x.py() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --set) + COMPREPLY=("${cur}") + return 0 + ;; *) COMPREPLY=() ;; @@ -1203,7 +1247,7 @@ _x.py() { return 0 ;; x.py__run) - opts="-v -i -j -h --args --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --args --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1301,6 +1345,10 @@ _x.py() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --set) + COMPREPLY=("${cur}") + return 0 + ;; *) COMPREPLY=() ;; @@ -1309,7 +1357,7 @@ _x.py() { return 0 ;; x.py__setup) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [<PROFILE>|hook|vscode|link] [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [<PROFILE>|hook|vscode|link] [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1403,6 +1451,10 @@ _x.py() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --set) + COMPREPLY=("${cur}") + return 0 + ;; *) COMPREPLY=() ;; @@ -1411,7 +1463,7 @@ _x.py() { return 0 ;; x.py__suggest) - opts="-v -i -j -h --run --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --run --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1505,6 +1557,10 @@ _x.py() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --set) + COMPREPLY=("${cur}") + return 0 + ;; *) COMPREPLY=() ;; @@ -1513,7 +1569,7 @@ _x.py() { return 0 ;; x.py__test) - opts="-v -i -j -h --no-fail-fast --skip --test-args --rustc-args --no-doc --doc --bless --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --no-fail-fast --skip --test-args --rustc-args --no-doc --doc --bless --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1631,6 +1687,10 @@ _x.py() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --set) + COMPREPLY=("${cur}") + return 0 + ;; *) COMPREPLY=() ;; diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 4b0aee9c3ad..09e7ed293d4 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -551,7 +551,15 @@ impl<'a, I: Iterator<Item = Event<'a>>> SummaryLine<'a, I> { } fn check_if_allowed_tag(t: &Tag<'_>) -> bool { - matches!(t, Tag::Paragraph | Tag::Emphasis | Tag::Strong | Tag::Link(..) | Tag::BlockQuote) + matches!( + t, + Tag::Paragraph + | Tag::Emphasis + | Tag::Strong + | Tag::Strikethrough + | Tag::Link(..) + | Tag::BlockQuote + ) } fn is_forbidden_tag(t: &Tag<'_>) -> bool { @@ -773,7 +781,7 @@ impl<'tcx> ExtraInfo<'tcx> { ExtraInfo { def_id, sp, tcx } } - fn error_invalid_codeblock_attr(&self, msg: &str, help: &str) { + fn error_invalid_codeblock_attr(&self, msg: String, help: &str) { if let Some(def_id) = self.def_id.as_local() { self.tcx.struct_span_lint_hir( crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, @@ -948,7 +956,7 @@ impl LangString { } { if let Some(extra) = extra { extra.error_invalid_codeblock_attr( - &format!("unknown attribute `{}`. Did you mean `{}`?", x, flag), + format!("unknown attribute `{}`. Did you mean `{}`?", x, flag), help, ); } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index d6773169639..0a2f5f6653c 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1751,7 +1751,7 @@ fn render_impl( if trait_.is_none() && i.inner_impl().items.is_empty() { w.write_str( "<div class=\"item-info\">\ - <div class=\"stab empty-impl\">This impl block contains no items.</div> + <div class=\"stab empty-impl\">This impl block contains no items.</div>\ </div>", ); } diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css index 99cf8e443f0..c1324c0760e 100644 --- a/src/librustdoc/html/static/css/settings.css +++ b/src/librustdoc/html/static/css/settings.css @@ -1,6 +1,5 @@ .setting-line { margin: 1.2em 0.6em; - position: relative; } .setting-radio input, .setting-check input { @@ -15,11 +14,6 @@ .setting-radio input { border-radius: 50%; } -.setting-check input:checked { - content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">\ - <path d="M7,25L17,32L33,12" fill="none" stroke="black" stroke-width="5"/>\ - <path d="M7,23L17,30L33,10" fill="none" stroke="white" stroke-width="5"/></svg>'); -} .setting-radio span, .setting-check span { padding-bottom: 1px; @@ -52,6 +46,9 @@ .setting-check input:checked { background-color: var(--settings-input-color); border-width: 1px; + content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">\ + <path d="M7,25L17,32L33,12" fill="none" stroke="black" stroke-width="5"/>\ + <path d="M7,23L17,30L33,10" fill="none" stroke="white" stroke-width="5"/></svg>'); } .setting-radio input:focus, .setting-check input:focus { box-shadow: 0 0 1px 1px var(--settings-input-color); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 5460bce21a5..0a56916edcd 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -192,11 +192,11 @@ fn init_logging() { Ok("auto") | Err(VarError::NotPresent) => io::stdout().is_terminal(), Ok(value) => early_error( ErrorOutputType::default(), - &format!("invalid log color value '{}': expected one of always, never, or auto", value), + format!("invalid log color value '{}': expected one of always, never, or auto", value), ), Err(VarError::NotUnicode(value)) => early_error( ErrorOutputType::default(), - &format!( + format!( "invalid log color value '{}': expected one of always, never, or auto", value.to_string_lossy() ), @@ -228,7 +228,7 @@ fn get_args() -> Option<Vec<String>> { .map_err(|arg| { early_warn( ErrorOutputType::default(), - &format!("Argument {} is not valid Unicode: {:?}", i, arg), + format!("Argument {} is not valid Unicode: {:?}", i, arg), ); }) .ok() @@ -721,7 +721,7 @@ fn main_args(at_args: &[String]) -> MainResult { let matches = match options.parse(&args[1..]) { Ok(m) => m, Err(err) => { - early_error(ErrorOutputType::default(), &err.to_string()); + early_error(ErrorOutputType::default(), err.to_string()); } }; diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index a885ff0ca5e..9e6894a77df 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -8,7 +8,7 @@ use rustc_data_structures::{ fx::{FxHashMap, FxHashSet}, intern::Interned, }; -use rustc_errors::{Applicability, Diagnostic}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticMessage}; use rustc_hir::def::Namespace::*; use rustc_hir::def::{DefKind, Namespace, PerNS}; use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; @@ -24,6 +24,7 @@ use rustc_span::BytePos; use smallvec::{smallvec, SmallVec}; use std::borrow::Cow; +use std::fmt::Display; use std::mem; use std::ops::Range; @@ -148,7 +149,7 @@ impl TryFrom<ResolveRes> for Res { Def(kind, id) => Ok(Res::Def(kind, id)), PrimTy(prim) => Ok(Res::Primitive(PrimitiveType::from_hir(prim))), // e.g. `#[derive]` - NonMacroAttr(..) | Err => Result::Err(()), + ToolMod | NonMacroAttr(..) | Err => Result::Err(()), other => bug!("unrecognized res {:?}", other), } } @@ -841,7 +842,7 @@ impl PreprocessingError { match self { PreprocessingError::MultipleAnchors => report_multiple_anchors(cx, diag_info), PreprocessingError::Disambiguator(range, msg) => { - disambiguator_error(cx, diag_info, range.clone(), msg) + disambiguator_error(cx, diag_info, range.clone(), msg.as_str()) } PreprocessingError::MalformedGenerics(err, path_str) => { report_malformed_generics(cx, diag_info, *err, path_str) @@ -1185,7 +1186,7 @@ impl LinkCollector<'_, '_> { } suggest_disambiguator(resolved, diag, path_str, &ori_link.link, sp); }; - report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, diag_info, callback); + report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, diag_info, callback); } fn report_rawptr_assoc_feature_gate(&self, dox: &str, ori_link: &Range<usize>, item: &Item) { @@ -1581,7 +1582,7 @@ impl Suggestion { fn report_diagnostic( tcx: TyCtxt<'_>, lint: &'static Lint, - msg: &str, + msg: impl Into<DiagnosticMessage> + Display, DiagnosticInfo { item, ori_link: _, dox, link_range }: &DiagnosticInfo<'_>, decorate: impl FnOnce(&mut Diagnostic, Option<rustc_span::Span>), ) { @@ -1649,7 +1650,7 @@ fn resolution_failure( report_diagnostic( tcx, BROKEN_INTRA_DOC_LINKS, - &format!("unresolved link to `{}`", path_str), + format!("unresolved link to `{}`", path_str), &diag_info, |diag, sp| { let item = |res: Res| format!("the {} `{}`", res.descr(), res.name(tcx),); @@ -1865,20 +1866,20 @@ fn resolution_failure( fn report_multiple_anchors(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>) { let msg = format!("`{}` contains multiple anchors", diag_info.ori_link); - anchor_failure(cx, diag_info, &msg, 1) + anchor_failure(cx, diag_info, msg, 1) } fn report_anchor_conflict(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>, def_id: DefId) { let (link, kind) = (diag_info.ori_link, Res::from_def_id(cx.tcx, def_id).descr()); let msg = format!("`{link}` contains an anchor, but links to {kind}s are already anchored"); - anchor_failure(cx, diag_info, &msg, 0) + anchor_failure(cx, diag_info, msg, 0) } /// Report an anchor failure. fn anchor_failure( cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>, - msg: &str, + msg: String, anchor_idx: usize, ) { report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, sp| { @@ -1898,7 +1899,7 @@ fn disambiguator_error( cx: &DocContext<'_>, mut diag_info: DiagnosticInfo<'_>, disambiguator_range: Range<usize>, - msg: &str, + msg: impl Into<DiagnosticMessage> + Display, ) { diag_info.link_range = disambiguator_range; report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, _sp| { @@ -1919,7 +1920,7 @@ fn report_malformed_generics( report_diagnostic( cx.tcx, BROKEN_INTRA_DOC_LINKS, - &format!("unresolved link to `{}`", path_str), + format!("unresolved link to `{}`", path_str), &diag_info, |diag, sp| { let note = match err { @@ -1994,7 +1995,7 @@ fn ambiguity_error( } } - report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, diag_info, |diag, sp| { + report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, diag_info, |diag, sp| { if let Some(sp) = sp { diag.span_label(sp, "ambiguous link"); } else { @@ -2046,7 +2047,7 @@ fn privacy_error(cx: &DocContext<'_>, diag_info: &DiagnosticInfo<'_>, path_str: let msg = format!("public documentation for `{}` links to private item `{}`", item_name, path_str); - report_diagnostic(cx.tcx, PRIVATE_INTRA_DOC_LINKS, &msg, diag_info, |diag, sp| { + report_diagnostic(cx.tcx, PRIVATE_INTRA_DOC_LINKS, msg, diag_info, |diag, sp| { if let Some(sp) = sp { diag.span_label(sp, "this item is private"); } diff --git a/src/llvm-project b/src/llvm-project -Subproject ea6fa9c2d43aaf0f11559719eda9b54d356d541 +Subproject 533d3f338b804d54e5d0ac4fba6276af23002d9 diff --git a/src/rustdoc-json-types/Cargo.toml b/src/rustdoc-json-types/Cargo.toml index d63caa7ad70..d3548036d4c 100644 --- a/src/rustdoc-json-types/Cargo.toml +++ b/src/rustdoc-json-types/Cargo.toml @@ -12,3 +12,4 @@ rustc-hash = "1.1.0" [dev-dependencies] serde_json = "1.0" +bincode = "1" diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 3556834071f..ba8eeaa6682 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; use std::path::PathBuf; /// rustdoc format-version. -pub const FORMAT_VERSION: u32 = 25; +pub const FORMAT_VERSION: u32 = 26; /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information /// about the language items in the local crate, as well as info about external items to allow @@ -83,7 +83,6 @@ pub struct Item { /// Stringified versions of the attributes on this item (e.g. `"#[inline]"`) pub attrs: Vec<String>, pub deprecation: Option<Deprecation>, - #[serde(flatten)] pub inner: ItemEnum, } @@ -222,7 +221,7 @@ pub enum ItemKind { } #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[serde(tag = "kind", content = "inner", rename_all = "snake_case")] +#[serde(rename_all = "snake_case")] pub enum ItemEnum { Module(Module), ExternCrate { @@ -543,7 +542,6 @@ pub enum Term { #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] -#[serde(tag = "kind", content = "inner")] pub enum Type { /// Structs, enums, and unions ResolvedPath(Path), diff --git a/src/rustdoc-json-types/tests.rs b/src/rustdoc-json-types/tests.rs index 399ff54b294..1126d5f786f 100644 --- a/src/rustdoc-json-types/tests.rs +++ b/src/rustdoc-json-types/tests.rs @@ -8,11 +8,15 @@ fn test_struct_info_roundtrip() { impls: vec![], }); + // JSON let struct_json = serde_json::to_string(&s).unwrap(); - let de_s = serde_json::from_str(&struct_json).unwrap(); - assert_eq!(s, de_s); + + // Bincode + let encoded: Vec<u8> = bincode::serialize(&s).unwrap(); + let decoded: ItemEnum = bincode::deserialize(&encoded).unwrap(); + assert_eq!(s, decoded); } #[test] @@ -24,9 +28,13 @@ fn test_union_info_roundtrip() { impls: vec![], }); + // JSON let union_json = serde_json::to_string(&u).unwrap(); - let de_u = serde_json::from_str(&union_json).unwrap(); - assert_eq!(u, de_u); + + // Bincode + let encoded: Vec<u8> = bincode::serialize(&u).unwrap(); + let decoded: ItemEnum = bincode::deserialize(&encoded).unwrap(); + assert_eq!(u, decoded); } diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 21dad9eb74a..8b28c68e04f 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -24,6 +24,7 @@ static HOSTS: &[&str] = &[ "i686-pc-windows-gnu", "i686-pc-windows-msvc", "i686-unknown-linux-gnu", + "loongarch64-unknown-linux-gnu", "mips-unknown-linux-gnu", "mips64-unknown-linux-gnuabi64", "mips64el-unknown-linux-gnuabi64", @@ -97,6 +98,7 @@ static TARGETS: &[&str] = &[ "i686-unknown-linux-gnu", "i686-unknown-linux-musl", "i686-unknown-uefi", + "loongarch64-unknown-linux-gnu", "m68k-unknown-linux-gnu", "mips-unknown-linux-gnu", "mips-unknown-linux-musl", diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 09276c703a473ab33daaeb94917232e80eefd62 +Subproject 64fb38c97ac4d3a327fc9032c862dd28c8833b1 diff --git a/src/tools/clippy/.github/workflows/clippy.yml b/src/tools/clippy/.github/workflows/clippy.yml index b9921301197..a9d42159c4b 100644 --- a/src/tools/clippy/.github/workflows/clippy.yml +++ b/src/tools/clippy/.github/workflows/clippy.yml @@ -39,7 +39,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Install toolchain run: rustup show active-toolchain diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml index 93198aabdb5..30a156c925b 100644 --- a/src/tools/clippy/.github/workflows/clippy_bors.yml +++ b/src/tools/clippy/.github/workflows/clippy_bors.yml @@ -27,7 +27,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 with: ref: ${{ github.ref }} @@ -83,7 +83,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Install toolchain run: rustup show active-toolchain @@ -149,7 +149,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Install toolchain run: rustup show active-toolchain @@ -173,7 +173,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Install toolchain run: rustup show active-toolchain @@ -233,7 +233,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Install toolchain run: rustup show active-toolchain diff --git a/src/tools/clippy/.github/workflows/clippy_dev.yml b/src/tools/clippy/.github/workflows/clippy_dev.yml index 14f20212add..514706d64c8 100644 --- a/src/tools/clippy/.github/workflows/clippy_dev.yml +++ b/src/tools/clippy/.github/workflows/clippy_dev.yml @@ -25,7 +25,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 # Run - name: Build diff --git a/src/tools/clippy/.github/workflows/deploy.yml b/src/tools/clippy/.github/workflows/deploy.yml index 71d71d10359..f42928c2cd1 100644 --- a/src/tools/clippy/.github/workflows/deploy.yml +++ b/src/tools/clippy/.github/workflows/deploy.yml @@ -21,10 +21,10 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 with: ref: ${{ env.TARGET_BRANCH }} path: 'out' diff --git a/src/tools/clippy/.github/workflows/remark.yml b/src/tools/clippy/.github/workflows/remark.yml index 0bc2f49f5e9..7d25b6a2b79 100644 --- a/src/tools/clippy/.github/workflows/remark.yml +++ b/src/tools/clippy/.github/workflows/remark.yml @@ -16,10 +16,10 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Setup Node.js - uses: actions/setup-node@v1.4.4 + uses: actions/setup-node@v3 with: node-version: '14.x' diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index ebf5b58a586..79f2a47110b 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -4620,6 +4620,7 @@ Released 2018-09-13 [`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else [`empty_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_drop [`empty_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum +[`empty_line_after_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_doc_comments [`empty_line_after_outer_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_outer_attr [`empty_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_loop [`empty_structs_with_brackets`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_structs_with_brackets @@ -4785,6 +4786,7 @@ Released 2018-09-13 [`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy +[`manual_next_back`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_next_back [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains @@ -4897,6 +4899,7 @@ Released 2018-09-13 [`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding [`no_mangle_with_rust_abi`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_mangle_with_rust_abi [`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal +[`non_minimal_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_minimal_cfg [`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions [`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty [`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool @@ -4978,6 +4981,7 @@ Released 2018-09-13 [`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref [`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref +[`ref_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_patterns [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md index 6745e15c006..d712d3e6750 100644 --- a/src/tools/clippy/README.md +++ b/src/tools/clippy/README.md @@ -278,7 +278,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT <!-- REUSE-IgnoreStart --> -Copyright 2014-2022 The Rust Project Developers +Copyright 2014-2023 The Rust Project Developers Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license diff --git a/src/tools/clippy/book/src/development/type_checking.md b/src/tools/clippy/book/src/development/type_checking.md index 225de849566..d7c2775b896 100644 --- a/src/tools/clippy/book/src/development/type_checking.md +++ b/src/tools/clippy/book/src/development/type_checking.md @@ -133,7 +133,7 @@ in this chapter: - [Type checking](https://rustc-dev-guide.rust-lang.org/type-checking.html) - [Ty module](https://rustc-dev-guide.rust-lang.org/ty.html) -[Adt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html#variant.Adt +[Adt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/sty/enum.TyKind.html#variant.Adt [AdtDef]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/adt/struct.AdtDef.html [expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.expr_ty [node_type]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.node_type @@ -142,9 +142,9 @@ in this chapter: [kind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.kind [LateContext]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LateContext.html [LateLintPass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html -[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckResults.html#method.pat_ty +[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/typeck_results/struct.TypeckResults.html#method.pat_ty [Ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html -[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html +[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/sty/enum.TyKind.html [TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html [middle_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_middle/ty/struct.Ty.html [hir_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/struct.Ty.html diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index 37e1e6a742f..98e69c7fd26 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -17,7 +17,7 @@ if_chain = "1.0" itertools = "0.10.1" pulldown-cmark = { version = "0.9", default-features = false } quine-mc_cluskey = "0.2" -regex-syntax = "0.6" +regex-syntax = "0.7" serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", optional = true } tempfile = { version = "3.2", optional = true } diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs index a36df55d0bd..a8dc0cb3b58 100644 --- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs +++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs @@ -38,7 +38,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { _ => return, }; let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else { return }; - let Some((Constant::Bool(val), _)) = constant(cx, cx.typeck_results(), condition) else { return }; + let Some(Constant::Bool(val)) = constant(cx, cx.typeck_results(), condition) else { return }; if val { span_lint_and_help( cx, diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs index 751c262673b..897495ba108 100644 --- a/src/tools/clippy/clippy_lints/src/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/attrs.rs @@ -178,6 +178,52 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does + /// Checks for empty lines after documenation comments. + /// + /// ### Why is this bad? + /// The documentation comment was most likely meant to be an inner attribute or regular comment. + /// If it was intended to be a documentation comment, then the empty line should be removed to + /// be more idiomatic. + /// + /// ### Known problems + /// Only detects empty lines immediately following the documentation. If the doc comment is followed + /// by an attribute and then an empty line, this lint will not trigger. Use `empty_line_after_outer_attr` + /// in combination with this lint to detect both cases. + /// + /// Does not detect empty lines after doc attributes (e.g. `#[doc = ""]`). + /// + /// ### Example + /// ```rust + /// /// Some doc comment with a blank line after it. + /// + /// fn not_quite_good_code() { } + /// ``` + /// + /// Use instead: + /// ```rust + /// /// Good (no blank line) + /// fn this_is_fine() { } + /// ``` + /// + /// ```rust + /// // Good (convert to a regular comment) + /// + /// fn this_is_fine_too() { } + /// ``` + /// + /// ```rust + /// //! Good (convert to a comment on an inner attribute) + /// + /// fn this_is_fine_as_well() { } + /// ``` + #[clippy::version = "1.70.0"] + pub EMPTY_LINE_AFTER_DOC_COMMENTS, + nursery, + "empty line after documentation comments" +} + +declare_clippy_lint! { + /// ### What it does /// Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category. /// /// ### Why is this bad? @@ -292,6 +338,30 @@ declare_clippy_lint! { "ensures that all `allow` and `expect` attributes have a reason" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `any` and `all` combinators in `cfg` with only one condition. + /// + /// ### Why is this bad? + /// If there is only one condition, no need to wrap it into `any` or `all` combinators. + /// + /// ### Example + /// ```rust + /// #[cfg(any(unix))] + /// pub struct Bar; + /// ``` + /// + /// Use instead: + /// ```rust + /// #[cfg(unix)] + /// pub struct Bar; + /// ``` + #[clippy::version = "1.71.0"] + pub NON_MINIMAL_CFG, + style, + "ensure that all `cfg(any())` and `cfg(all())` have more than one condition" +} + declare_lint_pass!(Attributes => [ ALLOW_ATTRIBUTES_WITHOUT_REASON, INLINE_ALWAYS, @@ -604,6 +674,8 @@ impl_lint_pass!(EarlyAttributes => [ DEPRECATED_CFG_ATTR, MISMATCHED_TARGET_OS, EMPTY_LINE_AFTER_OUTER_ATTR, + EMPTY_LINE_AFTER_DOC_COMMENTS, + NON_MINIMAL_CFG, ]); impl EarlyLintPass for EarlyAttributes { @@ -614,15 +686,22 @@ impl EarlyLintPass for EarlyAttributes { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { check_deprecated_cfg_attr(cx, attr, &self.msrv); check_mismatched_target_os(cx, attr); + check_minimal_cfg_condition(cx, attr); } extract_msrv_attr!(EarlyContext); } +/// Check for empty lines after outer attributes. +/// +/// Attributes and documenation comments are both considered outer attributes +/// by the AST. However, the average user likely considers them to be different. +/// Checking for empty lines after each of these attributes is split into two different +/// lints but can share the same logic. fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::Item) { let mut iter = item.attrs.iter().peekable(); while let Some(attr) = iter.next() { - if matches!(attr.kind, AttrKind::Normal(..)) + if (matches!(attr.kind, AttrKind::Normal(..)) || matches!(attr.kind, AttrKind::DocComment(..))) && attr.style == AttrStyle::Outer && is_present_in_source(cx, attr.span) { @@ -639,13 +718,20 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It let lines = without_block_comments(lines); if lines.iter().filter(|l| l.trim().is_empty()).count() > 2 { - span_lint( - cx, - EMPTY_LINE_AFTER_OUTER_ATTR, - begin_of_attr_to_item, - "found an empty line after an outer attribute. \ - Perhaps you forgot to add a `!` to make it an inner attribute?", - ); + let (lint_msg, lint_type) = match attr.kind { + AttrKind::DocComment(..) => ( + "found an empty line after a doc comment. \ + Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`?", + EMPTY_LINE_AFTER_DOC_COMMENTS, + ), + AttrKind::Normal(..) => ( + "found an empty line after an outer attribute. \ + Perhaps you forgot to add a `!` to make it an inner attribute?", + EMPTY_LINE_AFTER_OUTER_ATTR, + ), + }; + + span_lint(cx, lint_type, begin_of_attr_to_item, lint_msg); } } } @@ -690,6 +776,48 @@ fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &Msr } } +fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { + for item in items.iter() { + if let NestedMetaItem::MetaItem(meta) = item { + if !meta.has_name(sym::any) && !meta.has_name(sym::all) { + continue; + } + if let MetaItemKind::List(list) = &meta.kind { + check_nested_cfg(cx, list); + if list.len() == 1 { + span_lint_and_then( + cx, + NON_MINIMAL_CFG, + meta.span, + "unneeded sub `cfg` when there is only one condition", + |diag| { + if let Some(snippet) = snippet_opt(cx, list[0].span()) { + diag.span_suggestion(meta.span, "try", snippet, Applicability::MaybeIncorrect); + } + }, + ); + } else if list.is_empty() && meta.has_name(sym::all) { + span_lint_and_then( + cx, + NON_MINIMAL_CFG, + meta.span, + "unneeded sub `cfg` when there is no condition", + |_| {}, + ); + } + } + } + } +} + +fn check_minimal_cfg_condition(cx: &EarlyContext<'_>, attr: &Attribute) { + if attr.has_name(sym::cfg) && + let Some(items) = attr.meta_item_list() + { + check_nested_cfg(cx, &items); + } +} + fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) { fn find_os(name: &str) -> Option<&'static str> { UNIX_SYSTEMS diff --git a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs index c4520d00392..814108ed8a7 100644 --- a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs +++ b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs @@ -1,5 +1,6 @@ use crate::reference::DEREF_ADDROF; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_from_proc_macro; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; use clippy_utils::{get_parent_expr, is_lint_allowed}; @@ -47,8 +48,8 @@ declare_clippy_lint! { declare_lint_pass!(BorrowDerefRef => [BORROW_DEREF_REF]); -impl LateLintPass<'_> for BorrowDerefRef { - fn check_expr(&mut self, cx: &LateContext<'_>, e: &rustc_hir::Expr<'_>) { +impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { + fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) { if_chain! { if !e.span.from_expansion(); if let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind; @@ -58,6 +59,7 @@ impl LateLintPass<'_> for BorrowDerefRef { if !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..) ); let ref_ty = cx.typeck_results().expr_ty(deref_target); if let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind(); + if !is_from_proc_macro(cx, e); then{ if let Some(parent_expr) = get_parent_expr(cx, e){ diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs index dfa949d1af2..e42c3fe2432 100644 --- a/src/tools/clippy/clippy_lints/src/box_default.rs +++ b/src/tools/clippy/clippy_lints/src/box_default.rs @@ -8,7 +8,9 @@ use rustc_hir::{ Block, Expr, ExprKind, Local, Node, QPath, TyKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::{lint::in_external_macro, ty::print::with_forced_trimmed_paths}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::print::with_forced_trimmed_paths; +use rustc_middle::ty::IsSuggestable; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -49,7 +51,6 @@ impl LateLintPass<'_> for BoxDefault { && path_def_id(cx, ty).map_or(false, |id| Some(id) == cx.tcx.lang_items().owned_box()) && is_default_equivalent(cx, arg) { - let arg_ty = cx.typeck_results().expr_ty(arg); span_lint_and_sugg( cx, BOX_DEFAULT, @@ -58,8 +59,10 @@ impl LateLintPass<'_> for BoxDefault { "try", if is_plain_default(arg_path) || given_type(cx, expr) { "Box::default()".into() - } else { + } else if let Some(arg_ty) = cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true) { with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()")) + } else { + return }, Applicability::MachineApplicable ); diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs b/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs index 322dc41b3a1..da756129db3 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs @@ -21,8 +21,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, fn is_known_nan(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { match constant(cx, cx.typeck_results(), e) { - Some((Constant::F64(n), _)) => n.is_nan(), - Some((Constant::F32(n), _)) => n.is_nan(), + Some(Constant::F64(n)) => n.is_nan(), + Some(Constant::F32(n)) => n.is_nan(), _ => false, } } diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs index 95c2ecbf791..84b99ad5c24 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs @@ -15,7 +15,7 @@ use rustc_target::abi::IntegerType; use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION}; fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> { - if let Some((Constant::Int(c), _)) = constant(cx, cx.typeck_results(), expr) { + if let Some(Constant::Int(c)) = constant(cx, cx.typeck_results(), expr) { Some(c) } else { None diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs index a20a97d4e56..a83dfd94dc2 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs @@ -29,7 +29,7 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast // Don't lint for positive constants. let const_val = constant(cx, cx.typeck_results(), cast_op); if_chain! { - if let Some((Constant::Int(n), _)) = const_val; + if let Some(Constant::Int(n)) = const_val; if let ty::Int(ity) = *cast_from.kind(); if sext(cx.tcx, n, ity) >= 0; then { diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs index 799e71e847a..ea17e7a6071 100644 --- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs +++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs @@ -3,10 +3,10 @@ use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_hir::{Expr, ExprKind, Node}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::sym; +use rustc_span::{sym, BytePos, Pos, Span}; declare_clippy_lint! { /// ### What it does @@ -31,6 +31,31 @@ declare_clippy_lint! { "`dbg!` macro is intended as a debugging tool" } +/// Gets the span of the statement up to the next semicolon, if and only if the next +/// non-whitespace character actually is a semicolon. +/// E.g. +/// ```rust,ignore +/// +/// dbg!(); +/// ^^^^^^^ this span is returned +/// +/// foo!(dbg!()); +/// no span is returned +/// ``` +fn span_including_semi(cx: &LateContext<'_>, span: Span) -> Option<Span> { + let sm = cx.sess().source_map(); + let sf = sm.lookup_source_file(span.hi()); + let src = sf.src.as_ref()?.get(span.hi().to_usize()..)?; + let first_non_whitespace = src.find(|c: char| !c.is_whitespace())?; + + if src.as_bytes()[first_non_whitespace] == b';' { + let hi = span.hi() + BytePos::from_usize(first_non_whitespace + 1); + Some(span.with_hi(hi)) + } else { + None + } +} + #[derive(Copy, Clone)] pub struct DbgMacro { allow_dbg_in_tests: bool, @@ -55,13 +80,25 @@ impl LateLintPass<'_> for DbgMacro { return; } let mut applicability = Applicability::MachineApplicable; - let suggestion = match expr.peel_drop_temps().kind { + + let (sugg_span, suggestion) = match expr.peel_drop_temps().kind { // dbg!() - ExprKind::Block(_, _) => String::new(), - // dbg!(1) - ExprKind::Match(val, ..) => { - snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability).to_string() + ExprKind::Block(..) => { + // If the `dbg!` macro is a "free" statement and not contained within other expressions, + // remove the whole statement. + if let Some(Node::Stmt(stmt)) = cx.tcx.hir().find_parent(expr.hir_id) + && let Some(span) = span_including_semi(cx, stmt.span.source_callsite()) + { + (span, String::new()) + } else { + (macro_call.span, String::from("()")) + } }, + // dbg!(1) + ExprKind::Match(val, ..) => ( + macro_call.span, + snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability).to_string(), + ), // dbg!(2, 3) ExprKind::Tup( [ @@ -82,7 +119,7 @@ impl LateLintPass<'_> for DbgMacro { "..", &mut applicability, ); - format!("({snippet})") + (macro_call.span, format!("({snippet})")) }, _ => return, }; @@ -90,7 +127,7 @@ impl LateLintPass<'_> for DbgMacro { span_lint_and_sugg( cx, DBG_MACRO, - macro_call.span, + sugg_span, "the `dbg!` macro is intended as a debugging tool", "remove the invocation before committing it to a version control system", suggestion, diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 04993e49287..423eee47742 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -48,9 +48,11 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::attrs::BLANKET_CLIPPY_RESTRICTION_LINTS_INFO, crate::attrs::DEPRECATED_CFG_ATTR_INFO, crate::attrs::DEPRECATED_SEMVER_INFO, + crate::attrs::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO, crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO, crate::attrs::INLINE_ALWAYS_INFO, crate::attrs::MISMATCHED_TARGET_OS_INFO, + crate::attrs::NON_MINIMAL_CFG_INFO, crate::attrs::USELESS_ATTRIBUTE_INFO, crate::await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE_INFO, crate::await_holding_invalid::AWAIT_HOLDING_LOCK_INFO, @@ -347,6 +349,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::ITER_WITH_DRAIN_INFO, crate::methods::MANUAL_FILTER_MAP_INFO, crate::methods::MANUAL_FIND_MAP_INFO, + crate::methods::MANUAL_NEXT_BACK_INFO, crate::methods::MANUAL_OK_OR_INFO, crate::methods::MANUAL_SATURATING_ARITHMETIC_INFO, crate::methods::MANUAL_SPLIT_ONCE_INFO, @@ -485,7 +488,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::operators::FLOAT_EQUALITY_WITHOUT_ABS_INFO, crate::operators::IDENTITY_OP_INFO, crate::operators::INEFFECTIVE_BIT_MASK_INFO, - crate::operators::INTEGER_ARITHMETIC_INFO, crate::operators::INTEGER_DIVISION_INFO, crate::operators::MISREFACTORED_ASSIGN_OP_INFO, crate::operators::MODULO_ARITHMETIC_INFO, @@ -535,6 +537,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::redundant_slicing::REDUNDANT_SLICING_INFO, crate::redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES_INFO, crate::ref_option_ref::REF_OPTION_REF_INFO, + crate::ref_patterns::REF_PATTERNS_INFO, crate::reference::DEREF_ADDROF_INFO, crate::regex::INVALID_REGEX_INFO, crate::regex::TRIVIAL_REGEX_INFO, diff --git a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs index e529d81a7e9..9bd7a0dc0f3 100644 --- a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs +++ b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs @@ -1,4 +1,4 @@ -use clippy_utils::{diagnostics::span_lint_and_sugg, is_from_proc_macro, match_def_path, paths}; +use clippy_utils::{diagnostics::span_lint_and_sugg, match_def_path, paths}; use hir::{def::Res, ExprKind}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -55,7 +55,8 @@ impl LateLintPass<'_> for DefaultConstructedUnitStructs { if let ty::Adt(def, ..) = cx.typeck_results().expr_ty(expr).kind(); if def.is_struct(); if let var @ ty::VariantDef { ctor: Some((hir::def::CtorKind::Const, _)), .. } = def.non_enum_variant(); - if !var.is_field_list_non_exhaustive() && !is_from_proc_macro(cx, expr); + if !var.is_field_list_non_exhaustive(); + if !expr.span.from_expansion() && !qpath.span().from_expansion(); then { span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs index b2f7d026cc8..9c60edb1794 100644 --- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs +++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs @@ -98,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { let is_copy = is_copy(cx, arg_ty); let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr); let (lint, msg) = match fn_name { - // early return for uplifted lints: drop_ref, drop_copy, forget_ref, forget_copy + // early return for uplifted lints: dropping_references, dropping_copy_types, forgetting_references, forgetting_copy_types sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => return, sym::mem_forget if arg_ty.is_ref() => return, sym::mem_drop if is_copy && !drop_is_single_call_in_arm => return, diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs index a1a2c398a8a..3c55a563af4 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs @@ -114,7 +114,7 @@ declare_lint_pass!(FloatingPointArithmetic => [ // Returns the specialized log method for a given base if base is constant // and is one of 2, 10 and e fn get_specialized_log_method(cx: &LateContext<'_>, base: &Expr<'_>) -> Option<&'static str> { - if let Some((value, _)) = constant(cx, cx.typeck_results(), base) { + if let Some(value) = constant(cx, cx.typeck_results(), base) { if F32(2.0) == value || F64(2.0) == value { return Some("log2"); } else if F32(10.0) == value || F64(10.0) == value { @@ -193,8 +193,8 @@ fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { constant(cx, cx.typeck_results(), lhs), constant(cx, cx.typeck_results(), rhs), ) { - (Some((value, _)), _) if F32(1.0) == value || F64(1.0) == value => rhs, - (_, Some((value, _))) if F32(1.0) == value || F64(1.0) == value => lhs, + (Some(value), _) if F32(1.0) == value || F64(1.0) == value => rhs, + (_, Some(value)) if F32(1.0) == value || F64(1.0) == value => lhs, _ => return, }; @@ -237,7 +237,7 @@ fn get_integer_from_float_constant(value: &Constant) -> Option<i32> { fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { // Check receiver - if let Some((value, _)) = constant(cx, cx.typeck_results(), receiver) { + if let Some(value) = constant(cx, cx.typeck_results(), receiver) { if let Some(method) = if F32(f32_consts::E) == value || F64(f64_consts::E) == value { Some("exp") } else if F32(2.0) == value || F64(2.0) == value { @@ -258,7 +258,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: } // Check argument - if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) { + if let Some(value) = constant(cx, cx.typeck_results(), &args[0]) { let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { ( SUBOPTIMAL_FLOPS, @@ -298,7 +298,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: } fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { - if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) { + if let Some(value) = constant(cx, cx.typeck_results(), &args[0]) { if value == Int(2) { if let Some(parent) = get_parent_expr(cx, expr) { if let Some(grandparent) = get_parent_expr(cx, parent) { @@ -384,8 +384,8 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option<String> { _ ) = &add_rhs.kind; if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi"; - if let Some((lvalue, _)) = constant(cx, cx.typeck_results(), largs_1); - if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), rargs_1); + if let Some(lvalue) = constant(cx, cx.typeck_results(), largs_1); + if let Some(rvalue) = constant(cx, cx.typeck_results(), rargs_1); if Int(2) == lvalue && Int(2) == rvalue; then { return Some(format!("{}.hypot({})", Sugg::hir(cx, largs_0, "..").maybe_par(), Sugg::hir(cx, rargs_0, ".."))); @@ -416,7 +416,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, lhs, rhs) = expr.kind; if cx.typeck_results().expr_ty(lhs).is_floating_point(); - if let Some((value, _)) = constant(cx, cx.typeck_results(), rhs); + if let Some(value) = constant(cx, cx.typeck_results(), rhs); if F32(1.0) == value || F64(1.0) == value; if let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind; if cx.typeck_results().expr_ty(self_arg).is_floating_point(); @@ -669,8 +669,8 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { mul_lhs, mul_rhs, ) = &div_lhs.kind; - if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), div_rhs); - if let Some((lvalue, _)) = constant(cx, cx.typeck_results(), mul_rhs); + if let Some(rvalue) = constant(cx, cx.typeck_results(), div_rhs); + if let Some(lvalue) = constant(cx, cx.typeck_results(), mul_rhs); then { // TODO: also check for constant values near PI/180 or 180/PI if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) && diff --git a/src/tools/clippy/clippy_lints/src/fn_null_check.rs b/src/tools/clippy/clippy_lints/src/fn_null_check.rs index d8f4a5fe221..521045a9fed 100644 --- a/src/tools/clippy/clippy_lints/src/fn_null_check.rs +++ b/src/tools/clippy/clippy_lints/src/fn_null_check.rs @@ -89,11 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for FnNullCheck { // Catching: // (fn_ptr as *<const/mut> <ty>) == <const that evaluates to null_ptr> - _ if matches!( - constant(cx, cx.typeck_results(), to_check), - Some((Constant::RawPtr(0), _)) - ) => - { + _ if matches!(constant(cx, cx.typeck_results(), to_check), Some(Constant::RawPtr(0))) => { lint_expr(cx, expr); }, diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs index 012aa5a1d1d..ee7973b82ab 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs @@ -101,10 +101,10 @@ fn get_int_max(ty: Ty<'_>) -> Option<u128> { fn get_const<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<(u128, BinOpKind, &'tcx Expr<'tcx>)> { if let ExprKind::Binary(op, l, r) = expr.kind { let tr = cx.typeck_results(); - if let Some((Constant::Int(c), _)) = constant(cx, tr, r) { + if let Some(Constant::Int(c)) = constant(cx, tr, r) { return Some((c, op.node, l)); }; - if let Some((Constant::Int(c), _)) = constant(cx, tr, l) { + if let Some(Constant::Int(c)) = constant(cx, tr, l) { return Some((c, invert_op(op.node)?, r)); } } diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs index bdeddf44df7..7a269e98ff1 100644 --- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs +++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs @@ -254,7 +254,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> { let parent_id = map.parent_id(expr.hir_id); if let Some(hir::Node::Expr(parent_expr)) = map.find(parent_id); if let hir::ExprKind::Index(_, index_expr) = parent_expr.kind; - if let Some((Constant::Int(index_value), _)) = constant(cx, cx.typeck_results(), index_expr); + if let Some(Constant::Int(index_value)) = constant(cx, cx.typeck_results(), index_expr); if let Ok(index_value) = index_value.try_into(); if index_value < max_suggested_slice; diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs index 924a361c0f6..22c14d9b04d 100644 --- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs @@ -191,18 +191,14 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { /// Returns a tuple of options with the start and end (exclusive) values of /// the range. If the start or end is not constant, None is returned. fn to_const_range(cx: &LateContext<'_>, range: higher::Range<'_>, array_size: u128) -> (Option<u128>, Option<u128>) { - let s = range - .start - .map(|expr| constant(cx, cx.typeck_results(), expr).map(|(c, _)| c)); + let s = range.start.map(|expr| constant(cx, cx.typeck_results(), expr)); let start = match s { Some(Some(Constant::Int(x))) => Some(x), Some(_) => None, None => Some(0), }; - let e = range - .end - .map(|expr| constant(cx, cx.typeck_results(), expr).map(|(c, _)| c)); + let e = range.end.map(|expr| constant(cx, cx.typeck_results(), expr)); let end = match e { Some(Some(Constant::Int(x))) => { if range.limits == RangeLimits::Closed { diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs index 16772a9d598..e6614180920 100644 --- a/src/tools/clippy/clippy_lints/src/let_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs @@ -1,10 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_from_proc_macro; use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type}; use clippy_utils::{is_must_use_func_call, paths}; -use rustc_hir::{ExprKind, Local, PatKind}; +use rustc_hir::{Local, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::IsSuggestable; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{BytePos, Span}; @@ -138,7 +140,7 @@ const SYNC_GUARD_PATHS: [&[&str]; 3] = [ ]; impl<'tcx> LateLintPass<'tcx> for LetUnderscore { - fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &Local<'tcx>) { if !in_external_macro(cx.tcx.sess, local.span) && let PatKind::Wild = local.pat.kind && let Some(init) = local.init @@ -191,15 +193,17 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { if local.pat.default_binding_modes && local.ty.is_none() { // When `default_binding_modes` is true, the `let` keyword is present. - // Ignore function calls that return impl traits... - if let Some(init) = local.init && - matches!(init.kind, ExprKind::Call(_, _) | ExprKind::MethodCall(_, _, _, _)) { - let expr_ty = cx.typeck_results().expr_ty(init); - if expr_ty.is_impl_trait() { - return; - } - } + // Ignore unnameable types + if let Some(init) = local.init + && !cx.typeck_results().expr_ty(init).is_suggestable(cx.tcx, true) + { + return; + } + // Ignore if it is from a procedural macro... + if is_from_proc_macro(cx, init) { + return; + } span_lint_and_help( cx, diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 3517842a01e..b442a4ac5f6 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -266,6 +266,7 @@ mod redundant_pub_crate; mod redundant_slicing; mod redundant_static_lifetimes; mod ref_option_ref; +mod ref_patterns; mod reference; mod regex; mod return_self_not_must_use; @@ -331,8 +332,11 @@ mod zero_div_zero; mod zero_sized_map_values; // end lints modules, do not remove this comment, it’s used in `update_lints` -use crate::utils::conf::{format_error, TryConf}; pub use crate::utils::conf::{lookup_conf_file, Conf}; +use crate::utils::{ + conf::{format_error, metadata::get_configuration_metadata, TryConf}, + FindAll, +}; /// Register all pre expansion lints /// @@ -471,7 +475,22 @@ pub(crate) struct LintInfo { pub fn explain(name: &str) { let target = format!("clippy::{}", name.to_ascii_uppercase()); match declared_lints::LINTS.iter().find(|info| info.lint.name == target) { - Some(info) => print!("{}", info.explanation), + Some(info) => { + println!("{}", info.explanation); + // Check if the lint has configuration + let mdconf = get_configuration_metadata(); + if let Some(config_vec_positions) = mdconf + .iter() + .find_all(|cconf| cconf.lints.contains(&info.lint.name_lower()[8..].to_owned())) + { + // If it has, print it + println!("### Configuration for {}:\n", info.lint.name_lower()); + for position in config_vec_positions { + let conf = &mdconf[position]; + println!(" - {}: {} (default: {})", conf.name, conf.doc, conf.default); + } + } + }, None => println!("unknown lint: {name}"), } } @@ -971,6 +990,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation)); store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments)); store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule)); + store.register_early_pass(|| Box::new(ref_patterns::RefPatterns)); store.register_late_pass(|_| Box::new(default_constructed_unit_structs::DefaultConstructedUnitStructs)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs index bba9bb445a7..09b2032e20f 100644 --- a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs +++ b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs @@ -25,7 +25,7 @@ declare_clippy_lint! { /// /// ### Known problems /// This lint suggests replacing `filter_map()` or `flat_map()` applied to a `Lines` - /// instance in all cases. There two cases where the suggestion might not be + /// instance in all cases. There are two cases where the suggestion might not be /// appropriate or necessary: /// /// - If the `Lines` instance can never produce any error, or if an error is produced diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs index 1247370b74a..3f8b42ffe80 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -38,7 +38,6 @@ declare_clippy_lint! { /// Could be written: /// /// ```rust - /// # #![feature(let_else)] /// # fn main () { /// # let w = Some(0); /// let Some(v) = w else { return }; @@ -69,29 +68,23 @@ impl_lint_pass!(ManualLetElse => [MANUAL_LET_ELSE]); impl<'tcx> LateLintPass<'tcx> for ManualLetElse { fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) { - let if_let_or_match = if_chain! { - if self.msrv.meets(msrvs::LET_ELSE); - if !in_external_macro(cx.sess(), stmt.span); - if let StmtKind::Local(local) = stmt.kind; - if let Some(init) = local.init; - if local.els.is_none(); - if local.ty.is_none(); - if init.span.ctxt() == stmt.span.ctxt(); - if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init); - then { - if_let_or_match - } else { - return; - } - }; + if !self.msrv.meets(msrvs::LET_ELSE) || in_external_macro(cx.sess(), stmt.span) { + return; + } + if let StmtKind::Local(local) = stmt.kind && + let Some(init) = local.init && + local.els.is_none() && + local.ty.is_none() && + init.span.ctxt() == stmt.span.ctxt() && + let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init) { match if_let_or_match { IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => if_chain! { if expr_is_simple_identity(let_pat, if_then); if let Some(if_else) = if_else; if expr_diverges(cx, if_else); then { - emit_manual_let_else(cx, stmt.span, if_let_expr, let_pat, if_else); + emit_manual_let_else(cx, stmt.span, if_let_expr, local.pat, let_pat, if_else); } }, IfLetOrMatch::Match(match_expr, arms, source) => { @@ -128,15 +121,23 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse { return; } - emit_manual_let_else(cx, stmt.span, match_expr, pat_arm.pat, diverging_arm.body); + emit_manual_let_else(cx, stmt.span, match_expr, local.pat, pat_arm.pat, diverging_arm.body); }, } + }; } extract_msrv_attr!(LateContext); } -fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat: &Pat<'_>, else_body: &Expr<'_>) { +fn emit_manual_let_else( + cx: &LateContext<'_>, + span: Span, + expr: &Expr<'_>, + local: &Pat<'_>, + pat: &Pat<'_>, + else_body: &Expr<'_>, +) { span_lint_and_then( cx, MANUAL_LET_ELSE, @@ -145,12 +146,11 @@ fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat: |diag| { // This is far from perfect, for example there needs to be: // * mut additions for the bindings - // * renamings of the bindings + // * renamings of the bindings for `PatKind::Or` // * unused binding collision detection with existing ones // * putting patterns with at the top level | inside () // for this to be machine applicable. let mut app = Applicability::HasPlaceholders; - let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", &mut app); let (sn_expr, _) = snippet_with_context(cx, expr.span, span.ctxt(), "", &mut app); let (sn_else, _) = snippet_with_context(cx, else_body.span, span.ctxt(), "", &mut app); @@ -159,10 +159,21 @@ fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat: } else { format!("{{ {sn_else} }}") }; - let sn_bl = if matches!(pat.kind, PatKind::Or(..)) { - format!("({sn_pat})") - } else { - sn_pat.into_owned() + let sn_bl = match pat.kind { + PatKind::Or(..) => { + let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", &mut app); + format!("({sn_pat})") + }, + // Replace the variable name iff `TupleStruct` has one argument like `Variant(v)`. + PatKind::TupleStruct(ref w, args, ..) if args.len() == 1 => { + let sn_wrapper = cx.sess().source_map().span_to_snippet(w.span()).unwrap_or_default(); + let (sn_inner, _) = snippet_with_context(cx, local.span, span.ctxt(), "", &mut app); + format!("{sn_wrapper}({sn_inner})") + }, + _ => { + let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", &mut app); + sn_pat.into_owned() + }, }; let sugg = format!("let {sn_bl} = {sn_expr} else {else_bl};"); diag.span_suggestion(span, "consider writing", sugg, app); diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index 7d28c111624..93d977a5c96 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -144,7 +144,7 @@ fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx E // Returns the length of the `expr` if it's a constant string or char. fn constant_length(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> { - let (value, _) = constant(cx, cx.typeck_results(), expr)?; + let value = constant(cx, cx.typeck_results(), expr)?; match value { Constant::Str(value) => Some(value.len() as u128), Constant::Char(value) => Some(value.len_utf8() as u128), diff --git a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs index 33bc20dad6b..0064619ef89 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs @@ -1,10 +1,12 @@ +use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_lint_allowed; use clippy_utils::is_wild; use clippy_utils::source::snippet_with_applicability; use clippy_utils::span_contains_comment; use rustc_ast::{Attribute, LitKind}; use rustc_errors::Applicability; -use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Guard, Pat}; +use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Guard, Pat, PatKind, QPath}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty; use rustc_span::source_map::Spanned; @@ -99,6 +101,14 @@ where } } + for arm in iter_without_last.clone() { + if let Some(pat) = arm.1 { + if !is_lint_allowed(cx, REDUNDANT_PATTERN_MATCHING, pat.hir_id) && is_some(pat.kind) { + return false; + } + } + } + // The suggestion may be incorrect, because some arms can have `cfg` attributes // evaluated into `false` and so such arms will be stripped before. let mut applicability = Applicability::MaybeIncorrect; @@ -170,3 +180,13 @@ fn find_bool_lit(ex: &ExprKind<'_>) -> Option<bool> { _ => None, } } + +fn is_some(path_kind: PatKind<'_>) -> bool { + match path_kind { + PatKind::TupleStruct(QPath::Resolved(_, path), [first, ..], _) if is_wild(first) => { + let name = path.segments[0].ident; + name.name == rustc_span::sym::Some + }, + _ => false, + } +} diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index a48f4c77f85..ae8262ace96 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -282,9 +282,8 @@ impl<'a> NormalizedPat<'a> { // TODO: Handle negative integers. They're currently treated as a wild match. ExprKind::Lit(lit) => match lit.node { LitKind::Str(sym, _) => Self::LitStr(sym), - LitKind::ByteStr(ref bytes, _) => Self::LitBytes(bytes), + LitKind::ByteStr(ref bytes, _) | LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes), LitKind::Byte(val) => Self::LitInt(val.into()), - LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes), LitKind::Char(val) => Self::LitInt(val.into()), LitKind::Int(val, _) => Self::LitInt(val), LitKind::Bool(val) => Self::LitBool(val), diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index 87b63eead25..55ec9d4474f 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -25,9 +25,9 @@ mod wild_in_or_pats; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet_opt, walk_span_to_context}; -use clippy_utils::{higher, in_constant, is_span_match}; +use clippy_utils::{higher, in_constant, is_span_match, tokenize_with_text}; use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; -use rustc_lexer::{tokenize, TokenKind}; +use rustc_lexer::TokenKind; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -1147,12 +1147,7 @@ fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { // Assume true. This would require either an invalid span, or one which crosses file boundaries. return true; }; - let mut pos = 0usize; - let mut iter = tokenize(&snip).map(|t| { - let start = pos; - pos += t.len as usize; - (t.kind, start..pos) - }); + let mut iter = tokenize_with_text(&snip); // Search for the token sequence [`#`, `[`, `cfg`] while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) { @@ -1163,7 +1158,7 @@ fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { ) }); if matches!(iter.next(), Some((TokenKind::OpenBracket, _))) - && matches!(iter.next(), Some((TokenKind::Ident, range)) if &snip[range.clone()] == "cfg") + && matches!(iter.next(), Some((TokenKind::Ident, "cfg"))) { return true; } diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs index ae69ca8a339..abf2525a61c 100644 --- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs @@ -34,7 +34,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) if let Arm { pat, guard: None, .. } = *arm { if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind { let lhs_const = match lhs { - Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0, + Some(lhs) => constant(cx, cx.typeck_results(), lhs)?, None => { let min_val_const = ty.numeric_min_val(cx.tcx)?; let min_constant = mir::ConstantKind::from_value( @@ -45,7 +45,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) }, }; let rhs_const = match rhs { - Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0, + Some(rhs) => constant(cx, cx.typeck_results(), rhs)?, None => { let max_val_const = ty.numeric_max_val(cx.tcx)?; let max_constant = mir::ConstantKind::from_value( diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs index af121f317cd..e81e09da425 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs @@ -189,73 +189,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op if arms.len() == 2 { let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind); - let found_good_method = match node_pair { - ( - PatKind::TupleStruct(ref path_left, patterns_left, _), - PatKind::TupleStruct(ref path_right, patterns_right, _), - ) if patterns_left.len() == 1 && patterns_right.len() == 1 => { - if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) { - find_good_method_for_match( - cx, - arms, - path_left, - path_right, - Item::Lang(ResultOk), - Item::Lang(ResultErr), - "is_ok()", - "is_err()", - ) - .or_else(|| { - find_good_method_for_match( - cx, - arms, - path_left, - path_right, - Item::Diag(sym::IpAddr, sym!(V4)), - Item::Diag(sym::IpAddr, sym!(V6)), - "is_ipv4()", - "is_ipv6()", - ) - }) - } else { - None - } - }, - (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Path(ref path_right)) - | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, patterns, _)) - if patterns.len() == 1 => - { - if let PatKind::Wild = patterns[0].kind { - find_good_method_for_match( - cx, - arms, - path_left, - path_right, - Item::Lang(OptionSome), - Item::Lang(OptionNone), - "is_some()", - "is_none()", - ) - .or_else(|| { - find_good_method_for_match( - cx, - arms, - path_left, - path_right, - Item::Lang(PollReady), - Item::Lang(PollPending), - "is_ready()", - "is_pending()", - ) - }) - } else { - None - } - }, - _ => None, - }; - - if let Some(good_method) = found_good_method { + if let Some(good_method) = found_good_method(cx, arms, node_pair) { let span = expr.span.to(op.span); let result_expr = match &op.kind { ExprKind::AddrOf(_, _, borrowed) => borrowed, @@ -279,6 +213,127 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op } } +fn found_good_method<'a>( + cx: &LateContext<'_>, + arms: &[Arm<'_>], + node: (&PatKind<'_>, &PatKind<'_>), +) -> Option<&'a str> { + match node { + ( + PatKind::TupleStruct(ref path_left, patterns_left, _), + PatKind::TupleStruct(ref path_right, patterns_right, _), + ) if patterns_left.len() == 1 && patterns_right.len() == 1 => { + if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) { + find_good_method_for_match( + cx, + arms, + path_left, + path_right, + Item::Lang(ResultOk), + Item::Lang(ResultErr), + "is_ok()", + "is_err()", + ) + .or_else(|| { + find_good_method_for_match( + cx, + arms, + path_left, + path_right, + Item::Diag(sym::IpAddr, sym!(V4)), + Item::Diag(sym::IpAddr, sym!(V6)), + "is_ipv4()", + "is_ipv6()", + ) + }) + } else { + None + } + }, + (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Path(ref path_right)) + | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, patterns, _)) + if patterns.len() == 1 => + { + if let PatKind::Wild = patterns[0].kind { + find_good_method_for_match( + cx, + arms, + path_left, + path_right, + Item::Lang(OptionSome), + Item::Lang(OptionNone), + "is_some()", + "is_none()", + ) + .or_else(|| { + find_good_method_for_match( + cx, + arms, + path_left, + path_right, + Item::Lang(PollReady), + Item::Lang(PollPending), + "is_ready()", + "is_pending()", + ) + }) + } else { + None + } + }, + (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Wild) if patterns.len() == 1 => { + if let PatKind::Wild = patterns[0].kind { + get_good_method(cx, arms, path_left) + } else { + None + } + }, + (PatKind::Path(ref path_left), PatKind::Wild) => get_good_method(cx, arms, path_left), + _ => None, + } +} + +fn get_ident(path: &QPath<'_>) -> Option<rustc_span::symbol::Ident> { + match path { + QPath::Resolved(_, path) => { + let name = path.segments[0].ident; + Some(name) + }, + _ => None, + } +} + +fn get_good_method<'a>(cx: &LateContext<'_>, arms: &[Arm<'_>], path_left: &QPath<'_>) -> Option<&'a str> { + if let Some(name) = get_ident(path_left) { + return match name.as_str() { + "Ok" => { + find_good_method_for_matches_macro(cx, arms, path_left, Item::Lang(ResultOk), "is_ok()", "is_err()") + }, + "Err" => { + find_good_method_for_matches_macro(cx, arms, path_left, Item::Lang(ResultErr), "is_err()", "is_ok()") + }, + "Some" => find_good_method_for_matches_macro( + cx, + arms, + path_left, + Item::Lang(OptionSome), + "is_some()", + "is_none()", + ), + "None" => find_good_method_for_matches_macro( + cx, + arms, + path_left, + Item::Lang(OptionNone), + "is_none()", + "is_some()", + ), + _ => None, + }; + } + None +} + #[derive(Clone, Copy)] enum Item { Lang(LangItem), @@ -289,10 +344,11 @@ fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expecte let Some(id) = cx.typeck_results().qpath_res(path, pat.hir_id).opt_def_id() else { return false }; match expected_item { - Item::Lang(expected_lang_item) => { - let expected_id = cx.tcx.lang_items().require(expected_lang_item).unwrap(); - cx.tcx.parent(id) == expected_id - }, + Item::Lang(expected_lang_item) => cx + .tcx + .lang_items() + .get(expected_lang_item) + .map_or(false, |expected_id| cx.tcx.parent(id) == expected_id), Item::Diag(expected_ty, expected_variant) => { let ty = cx.typeck_results().pat_ty(pat); @@ -345,3 +401,29 @@ fn find_good_method_for_match<'a>( _ => None, } } + +fn find_good_method_for_matches_macro<'a>( + cx: &LateContext<'_>, + arms: &[Arm<'_>], + path_left: &QPath<'_>, + expected_item_left: Item, + should_be_left: &'a str, + should_be_right: &'a str, +) -> Option<&'a str> { + let first_pat = arms[0].pat; + + let body_node_pair = if is_pat_variant(cx, first_pat, path_left, expected_item_left) { + (&arms[0].body.kind, &arms[1].body.kind) + } else { + return None; + }; + + match body_node_pair { + (ExprKind::Lit(lit_left), ExprKind::Lit(lit_right)) => match (&lit_left.node, &lit_right.node) { + (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left), + (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right), + _ => None, + }, + _ => None, + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs index c830958d5c8..d1609eebfdc 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs @@ -13,7 +13,7 @@ use super::ITER_NTH_ZERO; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) { if_chain! { if is_trait_method(cx, expr, sym::Iterator); - if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), arg); + if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg); then { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs index 64c09214a76..b631cd00cda 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs @@ -9,7 +9,7 @@ use super::ITERATOR_STEP_BY_ZERO; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) { if is_trait_method(cx, expr, sym::Iterator) { - if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), arg) { + if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg) { span_lint( cx, ITERATOR_STEP_BY_ZERO, diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs b/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs new file mode 100644 index 00000000000..5f3fec53827 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs @@ -0,0 +1,38 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; +use clippy_utils::ty::implements_trait; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + rev_call: &'tcx Expr<'_>, + rev_recv: &'tcx Expr<'_>, +) { + let rev_recv_ty = cx.typeck_results().expr_ty(rev_recv); + + // check that the receiver of `rev` implements `DoubleEndedIterator` and + // that `rev` and `next` come from `Iterator` + if cx + .tcx + .get_diagnostic_item(sym::DoubleEndedIterator) + .map_or(false, |double_ended_iterator| { + implements_trait(cx, rev_recv_ty, double_ended_iterator, &[]) + }) + && is_trait_method(cx, rev_call, sym::Iterator) + && is_trait_method(cx, expr, sym::Iterator) + { + span_lint_and_sugg( + cx, + super::MANUAL_NEXT_BACK, + expr.span.with_lo(rev_recv.span.hi()), + "manual backwards iteration", + "use", + String::from(".next_back()"), + Applicability::MachineApplicable, + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 06b88e34d24..9a594d964ab 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -45,6 +45,7 @@ mod iter_overeager_cloned; mod iter_skip_next; mod iter_with_drain; mod iterator_step_by_zero; +mod manual_next_back; mod manual_ok_or; mod manual_saturating_arithmetic; mod manual_str_repeat; @@ -3132,8 +3133,11 @@ declare_clippy_lint! { /// ### Example /// ```rust /// # let iterator = vec![1].into_iter(); - /// let len = iterator.clone().collect::<Vec<_>>().len(); - /// // should be + /// let len = iterator.collect::<Vec<_>>().len(); + /// ``` + /// Use instead: + /// ```rust + /// # let iterator = vec![1].into_iter(); /// let len = iterator.count(); /// ``` #[clippy::version = "1.30.0"] @@ -3193,6 +3197,29 @@ declare_clippy_lint! { "calling `drain` in order to `clear` a container" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `.rev().next()` on a `DoubleEndedIterator` + /// + /// ### Why is this bad? + /// `.next_back()` is cleaner. + /// + /// ### Example + /// ```rust + /// # let foo = [0; 10]; + /// foo.iter().rev().next(); + /// ``` + /// Use instead: + /// ```rust + /// # let foo = [0; 10]; + /// foo.iter().next_back(); + /// ``` + #[clippy::version = "1.71.0"] + pub MANUAL_NEXT_BACK, + style, + "manual reverse iteration of `DoubleEndedIterator`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3321,6 +3348,7 @@ impl_lint_pass!(Methods => [ NEEDLESS_COLLECT, SUSPICIOUS_COMMAND_ARG_SPACE, CLEAR_WITH_DRAIN, + MANUAL_NEXT_BACK, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3677,6 +3705,7 @@ impl Methods { ("iter", []) => iter_next_slice::check(cx, expr, recv2), ("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg), ("skip_while", [_]) => skip_while_next::check(cx, expr), + ("rev", [])=> manual_next_back::check(cx, expr, recv, recv2), _ => {}, } } @@ -3741,13 +3770,13 @@ impl Methods { unnecessary_sort_by::check(cx, expr, recv, arg, true); }, ("splitn" | "rsplitn", [count_arg, pat_arg]) => { - if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) { + if let Some(Constant::Int(count)) = constant(cx, cx.typeck_results(), count_arg) { suspicious_splitn::check(cx, name, expr, recv, count); str_splitn::check(cx, name, expr, recv, pat_arg, count, &self.msrv); } }, ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => { - if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) { + if let Some(Constant::Int(count)) = constant(cx, cx.typeck_results(), count_arg) { suspicious_splitn::check(cx, name, expr, recv, count); } }, diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index 0b0c6adc504..6841aaf626c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -1,6 +1,5 @@ use super::NEEDLESS_COLLECT; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; -use clippy_utils::higher; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, make_normalized_projection, make_projection}; @@ -8,6 +7,7 @@ use clippy_utils::{ can_move_expr_to_closure, get_enclosing_block, get_parent_node, is_trait_method, path_to_local, path_to_local_id, CaptureKind, }; +use clippy_utils::{fn_def_id, higher}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; @@ -16,7 +16,7 @@ use rustc_hir::{ }; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::{self, AssocKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; +use rustc_middle::ty::{self, AssocKind, Clause, EarlyBinder, GenericArg, GenericArgKind, PredicateKind, Ty}; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol}; @@ -32,6 +32,8 @@ pub(super) fn check<'tcx>( if let Some(parent) = get_parent_node(cx.tcx, collect_expr.hir_id) { match parent { Node::Expr(parent) => { + check_collect_into_intoiterator(cx, parent, collect_expr, call_span, iter_expr); + if let ExprKind::MethodCall(name, _, args @ ([] | [_]), _) = parent.kind { let mut app = Applicability::MachineApplicable; let name = name.ident.as_str(); @@ -134,6 +136,68 @@ pub(super) fn check<'tcx>( } } +/// checks for for collecting into a (generic) method or function argument +/// taking an `IntoIterator` +fn check_collect_into_intoiterator<'tcx>( + cx: &LateContext<'tcx>, + parent: &'tcx Expr<'tcx>, + collect_expr: &'tcx Expr<'tcx>, + call_span: Span, + iter_expr: &'tcx Expr<'tcx>, +) { + if let Some(id) = fn_def_id(cx, parent) { + let args = match parent.kind { + ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) => args, + _ => &[], + }; + // find the argument index of the `collect_expr` in the + // function / method call + if let Some(arg_idx) = args.iter().position(|e| e.hir_id == collect_expr.hir_id).map(|i| { + if matches!(parent.kind, ExprKind::MethodCall(_, _, _, _)) { + i + 1 + } else { + i + } + }) { + // extract the input types of the function/method call + // that contains `collect_expr` + let inputs = cx + .tcx + .liberate_late_bound_regions(id, cx.tcx.fn_sig(id).subst_identity()) + .inputs(); + + // map IntoIterator generic bounds to their signature + // types and check whether the argument type is an + // `IntoIterator` + if cx + .tcx + .param_env(id) + .caller_bounds() + .into_iter() + .filter_map(|p| { + if let PredicateKind::Clause(Clause::Trait(t)) = p.kind().skip_binder() + && cx.tcx.is_diagnostic_item(sym::IntoIterator,t.trait_ref.def_id) { + Some(t.self_ty()) + } else { + None + } + }) + .any(|ty| ty == inputs[arg_idx]) + { + span_lint_and_sugg( + cx, + NEEDLESS_COLLECT, + call_span.with_lo(iter_expr.span.hi()), + NEEDLESS_COLLECT_MSG, + "remove this call", + String::new(), + Applicability::MachineApplicable, + ); + } + } + } +} + /// Checks if the given method call matches the expected signature of `([&[mut]] self) -> bool` fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool { cx.typeck_results().type_dependent_def_id(call_id).map_or(false, |id| { diff --git a/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs b/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs index a345ec813ff..bb4cdd2a6fa 100644 --- a/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs +++ b/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{constant_context, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_lang_item; @@ -14,7 +14,7 @@ pub(super) fn check<'tcx>( recv: &'tcx Expr<'_>, repeat_arg: &'tcx Expr<'_>, ) { - if constant_context(cx, cx.typeck_results()).expr(repeat_arg) == Some(Constant::Int(1)) { + if constant(cx, cx.typeck_results(), repeat_arg) == Some(Constant::Int(1)) { let ty = cx.typeck_results().expr_ty(recv).peel_refs(); if ty.is_str() { span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs index 91f7ce1dbe5..5ea12c44184 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs @@ -316,7 +316,7 @@ fn parse_iter_usage<'tcx>( }; }, ("nth" | "skip", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => { - if let Some((Constant::Int(idx), _)) = constant(cx, cx.typeck_results(), idx_expr) { + if let Some(Constant::Int(idx)) = constant(cx, cx.typeck_results(), idx_expr) { let span = if name.ident.as_str() == "nth" { e.span } else { diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index 3752b9a946f..303f0125690 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -16,9 +16,12 @@ use rustc_span::source_map::{ExpnKind, Span}; use clippy_utils::sugg::Sugg; use clippy_utils::{ - get_parent_expr, in_constant, is_integer_literal, is_no_std_crate, iter_input_pats, last_path_segment, SpanlessEq, + get_parent_expr, in_constant, is_integer_literal, is_lint_allowed, is_no_std_crate, iter_input_pats, + last_path_segment, SpanlessEq, }; +use crate::ref_patterns::REF_PATTERNS; + declare_clippy_lint! { /// ### What it does /// Checks for function arguments and let bindings denoted as @@ -162,6 +165,10 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { return; } for arg in iter_input_pats(decl, body) { + // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue. + if !is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id) { + return; + } if let PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..) = arg.pat.kind { span_lint( cx, @@ -180,6 +187,8 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { if let StmtKind::Local(local) = stmt.kind; if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind; if let Some(init) = local.init; + // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue. + if is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id); then { let ctxt = local.span.ctxt(); let mut app = Applicability::MachineApplicable; diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs index 71281a0b40b..62af42a3961 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -146,7 +146,7 @@ fn is_parent_stmt(cx: &LateContext<'_>, id: HirId) -> bool { impl<'tcx> LateLintPass<'tcx> for NeedlessBool { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { use self::Expression::{Bool, RetBool}; - if e.span.from_expansion() { + if e.span.from_expansion() || !span_extract_comment(cx.tcx.sess.source_map(), e.span).is_empty() { return; } if let Some(higher::If { @@ -209,8 +209,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { } if let Some((lhs_a, a)) = fetch_assign(then) && let Some((lhs_b, b)) = fetch_assign(r#else) && - SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b) && - span_extract_comment(cx.tcx.sess.source_map(), e.span).is_empty() + SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b) { let mut applicability = Applicability::MachineApplicable; let cond = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability); diff --git a/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs index d29ca37eaeb..f4863600ccc 100644 --- a/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs @@ -121,7 +121,7 @@ fn detect_absurd_comparison<'tcx>( fn detect_extreme_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<ExtremeExpr<'tcx>> { let ty = cx.typeck_results().expr_ty(expr); - let cv = constant(cx, cx.typeck_results(), expr)?.0; + let cv = constant(cx, cx.typeck_results(), expr)?; let which = match (ty.kind(), cv) { (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => ExtremeType::Minimum, diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs index f72595987ee..5c240276b76 100644 --- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -21,7 +21,7 @@ const HARD_CODED_ALLOWED_BINARY: &[[&str; 2]] = &[ ["f64", "f64"], ["std::num::Saturating", "std::num::Saturating"], ["std::num::Wrapping", "std::num::Wrapping"], - ["std::string::String", "&str"], + ["std::string::String", "str"], ]; const HARD_CODED_ALLOWED_UNARY: &[&str] = &["f32", "f64", "std::num::Saturating", "std::num::Wrapping"]; const INTEGER_METHODS: &[&str] = &["saturating_div", "wrapping_div", "wrapping_rem", "wrapping_rem_euclid"]; @@ -113,7 +113,7 @@ impl ArithmeticSideEffects { if let hir::ExprKind::Lit(lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node { return Some(n) } - if let Some((Constant::Int(n), _)) = constant(cx, cx.typeck_results(), expr) { + if let Some(Constant::Int(n)) = constant(cx, cx.typeck_results(), expr) { return Some(n); } None @@ -144,8 +144,10 @@ impl ArithmeticSideEffects { ) { return; }; - let lhs_ty = cx.typeck_results().expr_ty(lhs); - let rhs_ty = cx.typeck_results().expr_ty(rhs); + let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs); + let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs); + let lhs_ty = cx.typeck_results().expr_ty(actual_lhs).peel_refs(); + let rhs_ty = cx.typeck_results().expr_ty(actual_rhs).peel_refs(); if self.has_allowed_binary(lhs_ty, rhs_ty) { return; } @@ -154,8 +156,6 @@ impl ArithmeticSideEffects { // At least for integers, shifts are already handled by the CTFE return; } - let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs); - let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs); match ( Self::literal_integer(cx, actual_lhs), Self::literal_integer(cx, actual_rhs), diff --git a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs index 1369b3e7462..1fddf0f50e3 100644 --- a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs +++ b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs @@ -166,7 +166,7 @@ fn check_ineffective_gt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op: } fn fetch_int_literal(cx: &LateContext<'_>, lit: &Expr<'_>) -> Option<u128> { - match constant(cx, cx.typeck_results(), lit)?.0 { + match constant(cx, cx.typeck_results(), lit)? { Constant::Int(n) => Some(n), _ => None, } diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_nan.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_nan.rs index 786ae1552ad..e18064b7061 100644 --- a/src/tools/clippy/clippy_lints/src/operators/cmp_nan.rs +++ b/src/tools/clippy/clippy_lints/src/operators/cmp_nan.rs @@ -18,7 +18,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, op: BinOpKind, lhs: &Exp } fn is_nan(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { - if let Some((value, _)) = constant(cx, cx.typeck_results(), e) { + if let Some(value) = constant(cx, cx.typeck_results(), e) { match value { Constant::F32(num) => num.is_nan(), Constant::F64(num) => num.is_nan(), diff --git a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs index 49e662cacb0..f120be13836 100644 --- a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs +++ b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs @@ -19,7 +19,7 @@ pub(crate) fn check<'tcx>( if op == BinOpKind::Div && let ExprKind::MethodCall(method_path, self_arg, [], _) = left.kind && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration) - && let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right) + && let Some(Constant::Int(divisor)) = constant(cx, cx.typeck_results(), right) { let suggested_fn = match (method_path.ident.as_str(), divisor) { ("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis", diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs index 97ddcdb2479..15dff126be7 100644 --- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs +++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{constant, Constant}; +use clippy_utils::consts::{constant_with_source, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::get_item_name; use clippy_utils::sugg::Sugg; @@ -18,9 +18,16 @@ pub(crate) fn check<'tcx>( right: &'tcx Expr<'_>, ) { if (op == BinOpKind::Eq || op == BinOpKind::Ne) && (is_float(cx, left) || is_float(cx, right)) { - if is_allowed(cx, left) || is_allowed(cx, right) { - return; - } + let left_is_local = match constant_with_source(cx, cx.typeck_results(), left) { + Some((c, s)) if !is_allowed(&c) => s.is_local(), + Some(_) => return, + None => true, + }; + let right_is_local = match constant_with_source(cx, cx.typeck_results(), right) { + Some((c, s)) if !is_allowed(&c) => s.is_local(), + Some(_) => return, + None => true, + }; // Allow comparing the results of signum() if is_signum(cx, left) && is_signum(cx, right) { @@ -34,10 +41,7 @@ pub(crate) fn check<'tcx>( } } let is_comparing_arrays = is_array(cx, left) || is_array(cx, right); - let (lint, msg) = get_lint_and_message( - is_named_constant(cx, left) || is_named_constant(cx, right), - is_comparing_arrays, - ); + let (lint, msg) = get_lint_and_message(left_is_local && right_is_local, is_comparing_arrays); span_lint_and_then(cx, lint, expr.span, msg, |diag| { let lhs = Sugg::hir(cx, left, ".."); let rhs = Sugg::hir(cx, right, ".."); @@ -59,44 +63,33 @@ pub(crate) fn check<'tcx>( } } -fn get_lint_and_message( - is_comparing_constants: bool, - is_comparing_arrays: bool, -) -> (&'static rustc_lint::Lint, &'static str) { - if is_comparing_constants { +fn get_lint_and_message(is_local: bool, is_comparing_arrays: bool) -> (&'static rustc_lint::Lint, &'static str) { + if is_local { ( - FLOAT_CMP_CONST, + FLOAT_CMP, if is_comparing_arrays { - "strict comparison of `f32` or `f64` constant arrays" + "strict comparison of `f32` or `f64` arrays" } else { - "strict comparison of `f32` or `f64` constant" + "strict comparison of `f32` or `f64`" }, ) } else { ( - FLOAT_CMP, + FLOAT_CMP_CONST, if is_comparing_arrays { - "strict comparison of `f32` or `f64` arrays" + "strict comparison of `f32` or `f64` constant arrays" } else { - "strict comparison of `f32` or `f64`" + "strict comparison of `f32` or `f64` constant" }, ) } } -fn is_named_constant<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { - if let Some((_, res)) = constant(cx, cx.typeck_results(), expr) { - res - } else { - false - } -} - -fn is_allowed<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { - match constant(cx, cx.typeck_results(), expr) { - Some((Constant::F32(f), _)) => f == 0.0 || f.is_infinite(), - Some((Constant::F64(f), _)) => f == 0.0 || f.is_infinite(), - Some((Constant::Vec(vec), _)) => vec.iter().all(|f| match f { +fn is_allowed(val: &Constant) -> bool { + match val { + &Constant::F32(f) => f == 0.0 || f.is_infinite(), + &Constant::F64(f) => f == 0.0 || f.is_infinite(), + Constant::Vec(vec) => vec.iter().all(|f| match f { Constant::F32(f) => *f == 0.0 || (*f).is_infinite(), Constant::F64(f) => *f == 0.0 || (*f).is_infinite(), _ => false, diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs index 19599731bd6..d63a836e73d 100644 --- a/src/tools/clippy/clippy_lints/src/operators/mod.rs +++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs @@ -98,32 +98,6 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for integer arithmetic operations which could overflow or panic. - /// - /// Specifically, checks for any operators (`+`, `-`, `*`, `<<`, etc) which are capable - /// of overflowing according to the [Rust - /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), - /// or which can panic (`/`, `%`). No bounds analysis or sophisticated reasoning is - /// attempted. - /// - /// ### Why is this bad? - /// Integer overflow will trigger a panic in debug builds or will wrap in - /// release mode. Division by zero will cause a panic in either mode. In some applications one - /// wants explicitly checked, wrapping or saturating arithmetic. - /// - /// ### Example - /// ```rust - /// # let a = 0; - /// a + 1; - /// ``` - #[clippy::version = "pre 1.29.0"] - pub INTEGER_ARITHMETIC, - restriction, - "any integer arithmetic expression which could overflow or panic" -} - -declare_clippy_lint! { - /// ### What it does /// Checks for float arithmetic. /// /// ### Why is this bad? @@ -787,7 +761,6 @@ pub struct Operators { impl_lint_pass!(Operators => [ ABSURD_EXTREME_COMPARISONS, ARITHMETIC_SIDE_EFFECTS, - INTEGER_ARITHMETIC, FLOAT_ARITHMETIC, ASSIGN_OP_PATTERN, MISREFACTORED_ASSIGN_OP, diff --git a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs index af4e74947f4..a2c3a4d8ba7 100644 --- a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs @@ -40,7 +40,7 @@ struct OperandInfo { fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<OperandInfo> { match constant(cx, cx.typeck_results(), operand) { - Some((Constant::Int(v), _)) => match *cx.typeck_results().expr_ty(expr).kind() { + Some(Constant::Int(v)) => match *cx.typeck_results().expr_ty(expr).kind() { ty::Int(ity) => { let value = sext(cx.tcx, v, ity); return Some(OperandInfo { @@ -58,10 +58,10 @@ fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> }, _ => {}, }, - Some((Constant::F32(f), _)) => { + Some(Constant::F32(f)) => { return Some(floating_point_operand_info(&f)); }, - Some((Constant::F64(f), _)) => { + Some(Constant::F64(f)) => { return Some(floating_point_operand_info(&f)); }, _ => {}, diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs index 77fd45b199a..102845ceed0 100644 --- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs @@ -1,8 +1,6 @@ -use super::{FLOAT_ARITHMETIC, INTEGER_ARITHMETIC}; +use super::FLOAT_ARITHMETIC; use clippy_utils::consts::constant_simple; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_from_proc_macro; -use clippy_utils::is_integer_literal; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::source_map::Span; @@ -45,31 +43,8 @@ impl Context { _ => (), } - let (l_ty, r_ty) = (cx.typeck_results().expr_ty(l), cx.typeck_results().expr_ty(r)); - if l_ty.peel_refs().is_integral() && r_ty.peel_refs().is_integral() { - if is_from_proc_macro(cx, expr) { - return; - } - match op { - hir::BinOpKind::Div | hir::BinOpKind::Rem => match &r.kind { - hir::ExprKind::Lit(_lit) => (), - hir::ExprKind::Unary(hir::UnOp::Neg, expr) => { - if is_integer_literal(expr, 1) { - span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); - self.expr_id = Some(expr.hir_id); - } - }, - _ => { - span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); - self.expr_id = Some(expr.hir_id); - }, - }, - _ => { - span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); - self.expr_id = Some(expr.hir_id); - }, - } - } else if r_ty.peel_refs().is_floating_point() && r_ty.peel_refs().is_floating_point() { + let (_, r_ty) = (cx.typeck_results().expr_ty(l), cx.typeck_results().expr_ty(r)); + if r_ty.peel_refs().is_floating_point() && r_ty.peel_refs().is_floating_point() { span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); self.expr_id = Some(expr.hir_id); } @@ -80,17 +55,9 @@ impl Context { return; } let ty = cx.typeck_results().expr_ty(arg); - if constant_simple(cx, cx.typeck_results(), expr).is_none() { - if ty.is_integral() { - if is_from_proc_macro(cx, expr) { - return; - } - span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); - self.expr_id = Some(expr.hir_id); - } else if ty.is_floating_point() { - span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); - self.expr_id = Some(expr.hir_id); - } + if constant_simple(cx, cx.typeck_results(), expr).is_none() && ty.is_floating_point() { + span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); + self.expr_id = Some(expr.hir_id); } } diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs index bbbcda069c5..aa6d4004268 100644 --- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs @@ -122,7 +122,7 @@ fn try_get_option_occurrence<'tcx>( ExprKind::Unary(UnOp::Deref, inner_expr) | ExprKind::AddrOf(_, _, inner_expr) => inner_expr, _ => expr, }; - let inner_pat = try_get_inner_pat(cx, pat)?; + let (inner_pat, is_result) = try_get_inner_pat_and_is_result(cx, pat)?; if_chain! { if let PatKind::Binding(bind_annotation, _, id, None) = inner_pat.kind; if let Some(some_captures) = can_move_expr_to_closure(cx, if_then); @@ -176,7 +176,7 @@ fn try_get_option_occurrence<'tcx>( ), none_expr: format!( "{}{}", - if method_sugg == "map_or" { "" } else { "|| " }, + if method_sugg == "map_or" { "" } else if is_result { "|_| " } else { "|| "}, Sugg::hir_with_context(cx, none_body, ctxt, "..", &mut app), ), }); @@ -186,11 +186,13 @@ fn try_get_option_occurrence<'tcx>( None } -fn try_get_inner_pat<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<&'tcx Pat<'tcx>> { +fn try_get_inner_pat_and_is_result<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<(&'tcx Pat<'tcx>, bool)> { if let PatKind::TupleStruct(ref qpath, [inner_pat], ..) = pat.kind { let res = cx.qpath_res(qpath, pat.hir_id); - if is_res_lang_ctor(cx, res, OptionSome) || is_res_lang_ctor(cx, res, ResultOk) { - return Some(inner_pat); + if is_res_lang_ctor(cx, res, OptionSome) { + return Some((inner_pat, false)); + } else if is_res_lang_ctor(cx, res, ResultOk) { + return Some((inner_pat, true)); } } None diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index fc655fe2d0b..dd7ded491e7 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -319,7 +319,7 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<R _ => return None, }; if let Some(id) = path_to_local(l) { - if let Some((c, _)) = constant(cx, cx.typeck_results(), r) { + if let Some(c) = constant(cx, cx.typeck_results(), r) { return Some(RangeBounds { val: c, expr: r, @@ -331,7 +331,7 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<R }); } } else if let Some(id) = path_to_local(r) { - if let Some((c, _)) = constant(cx, cx.typeck_results(), l) { + if let Some(c) = constant(cx, cx.typeck_results(), l) { return Some(RangeBounds { val: c, expr: l, @@ -451,8 +451,8 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) { if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::Range::hir(expr); let ty = cx.typeck_results().expr_ty(start); if let ty::Int(_) | ty::Uint(_) = ty.kind(); - if let Some((start_idx, _)) = constant(cx, cx.typeck_results(), start); - if let Some((end_idx, _)) = constant(cx, cx.typeck_results(), end); + if let Some(start_idx) = constant(cx, cx.typeck_results(), start); + if let Some(end_idx) = constant(cx, cx.typeck_results(), end); if let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx); if is_empty_range(limits, ordering); then { diff --git a/src/tools/clippy/clippy_lints/src/ref_patterns.rs b/src/tools/clippy/clippy_lints/src/ref_patterns.rs new file mode 100644 index 00000000000..b1530eed1c1 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/ref_patterns.rs @@ -0,0 +1,44 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use rustc_ast::ast::{BindingAnnotation, Pat, PatKind}; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for usages of the `ref` keyword. + /// ### Why is this bad? + /// The `ref` keyword can be confusing for people unfamiliar with it, and often + /// it is more concise to use `&` instead. + /// ### Example + /// ```rust + /// let opt = Some(5); + /// if let Some(ref foo) = opt {} + /// ``` + /// Use instead: + /// ```rust + /// let opt = Some(5); + /// if let Some(foo) = &opt {} + /// ``` + #[clippy::version = "1.71.0"] + pub REF_PATTERNS, + restriction, + "use of a ref pattern, e.g. Some(ref value)" +} +declare_lint_pass!(RefPatterns => [REF_PATTERNS]); + +impl EarlyLintPass for RefPatterns { + fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) { + if let PatKind::Ident(BindingAnnotation::REF, _, _) = pat.kind + && !pat.span.from_expansion() + { + span_lint_and_help( + cx, + REF_PATTERNS, + pat.span, + "usage of ref pattern", + None, + "consider using `&` for clarity instead", + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs index b8b32df6cc6..ef19c6f4617 100644 --- a/src/tools/clippy/clippy_lints/src/regex.rs +++ b/src/tools/clippy/clippy_lints/src/regex.rs @@ -122,37 +122,39 @@ fn lint_syntax_error(cx: &LateContext<'_>, error: ®ex_syntax::Error, unescape } fn const_str<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<String> { - constant(cx, cx.typeck_results(), e).and_then(|(c, _)| match c { + constant(cx, cx.typeck_results(), e).and_then(|c| match c { Constant::Str(s) => Some(s), _ => None, }) } fn is_trivial_regex(s: ®ex_syntax::hir::Hir) -> Option<&'static str> { - use regex_syntax::hir::Anchor::{EndText, StartText}; - use regex_syntax::hir::HirKind::{Alternation, Anchor, Concat, Empty, Literal}; + use regex_syntax::hir::HirKind::{Alternation, Concat, Empty, Literal, Look}; + use regex_syntax::hir::Look as HirLook; let is_literal = |e: &[regex_syntax::hir::Hir]| e.iter().all(|e| matches!(*e.kind(), Literal(_))); match *s.kind() { - Empty | Anchor(_) => Some("the regex is unlikely to be useful as it is"), + Empty | Look(_) => Some("the regex is unlikely to be useful as it is"), Literal(_) => Some("consider using `str::contains`"), Alternation(ref exprs) => { - if exprs.iter().all(|e| e.kind().is_empty()) { + if exprs.iter().all(|e| matches!(e.kind(), Empty)) { Some("the regex is unlikely to be useful as it is") } else { None } }, Concat(ref exprs) => match (exprs[0].kind(), exprs[exprs.len() - 1].kind()) { - (&Anchor(StartText), &Anchor(EndText)) if exprs[1..(exprs.len() - 1)].is_empty() => { + (&Look(HirLook::Start), &Look(HirLook::End)) if exprs[1..(exprs.len() - 1)].is_empty() => { Some("consider using `str::is_empty`") }, - (&Anchor(StartText), &Anchor(EndText)) if is_literal(&exprs[1..(exprs.len() - 1)]) => { + (&Look(HirLook::Start), &Look(HirLook::End)) if is_literal(&exprs[1..(exprs.len() - 1)]) => { Some("consider using `==` on `str`s") }, - (&Anchor(StartText), &Literal(_)) if is_literal(&exprs[1..]) => Some("consider using `str::starts_with`"), - (&Literal(_), &Anchor(EndText)) if is_literal(&exprs[1..(exprs.len() - 1)]) => { + (&Look(HirLook::Start), &Literal(_)) if is_literal(&exprs[1..]) => { + Some("consider using `str::starts_with`") + }, + (&Literal(_), &Look(HirLook::End)) if is_literal(&exprs[1..(exprs.len() - 1)]) => { Some("consider using `str::ends_with`") }, _ if is_literal(exprs) => Some("consider using `str::contains`"), @@ -175,10 +177,7 @@ fn check_set<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) { } fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) { - let mut parser = regex_syntax::ParserBuilder::new() - .unicode(true) - .allow_invalid_utf8(!utf8) - .build(); + let mut parser = regex_syntax::ParserBuilder::new().unicode(true).utf8(!utf8).build(); if let ExprKind::Lit(lit) = expr.kind { if let LitKind::Str(ref r, style) = lit.node { diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs index 52e22c0c630..b0db56bb417 100644 --- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs +++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs @@ -15,6 +15,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"), ("clippy::identity_conversion", "clippy::useless_conversion"), ("clippy::if_let_some_result", "clippy::match_result_ok"), + ("clippy::integer_arithmetic", "clippy::arithmetic_side_effects"), ("clippy::logic_bug", "clippy::overly_complex_bool_expr"), ("clippy::new_without_default_derive", "clippy::new_without_default"), ("clippy::option_and_then_some", "clippy::bind_instead_of_map"), @@ -32,13 +33,13 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::zero_width_space", "clippy::invisible_characters"), ("clippy::clone_double_ref", "suspicious_double_ref_op"), ("clippy::drop_bounds", "drop_bounds"), - ("clippy::drop_copy", "drop_copy"), - ("clippy::drop_ref", "drop_ref"), + ("clippy::drop_copy", "dropping_copy_types"), + ("clippy::drop_ref", "dropping_references"), ("clippy::for_loop_over_option", "for_loops_over_fallibles"), ("clippy::for_loop_over_result", "for_loops_over_fallibles"), ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"), - ("clippy::forget_copy", "forget_copy"), - ("clippy::forget_ref", "forget_ref"), + ("clippy::forget_copy", "forgetting_copy_types"), + ("clippy::forget_ref", "forgetting_references"), ("clippy::into_iter_on_array", "array_into_iter"), ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"), ("clippy::invalid_ref", "invalid_value"), diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 5b588e914fd..483f860a8b5 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -132,7 +132,7 @@ declare_clippy_lint! { /// Probably lots of false positives. If an index comes from a known valid position (e.g. /// obtained via `char_indices` over the same string), it is totally OK. /// - /// # Example + /// ### Example /// ```rust,should_panic /// &"Ölkanne"[1..]; /// ``` diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index b5f11b4acae..4ccda15068b 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -37,12 +37,12 @@ declare_clippy_lint! { #[clippy::version = "1.38.0"] pub TYPE_REPETITION_IN_BOUNDS, nursery, - "types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`" + "types are repeated unnecessarily in trait bounds, use `+` instead of using `T: _, T: _`" } declare_clippy_lint! { /// ### What it does - /// Checks for cases where generics are being used and multiple + /// Checks for cases where generics or trait objects are being used and multiple /// syntax specifications for trait bounds are used simultaneously. /// /// ### Why is this bad? @@ -167,6 +167,61 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { } } } + + fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) { + if_chain! { + if let TyKind::Ref(.., mut_ty) = &ty.kind; + if let TyKind::TraitObject(bounds, ..) = mut_ty.ty.kind; + if bounds.len() > 2; + then { + + // Build up a hash of every trait we've seen + // When we see a trait for the first time, add it to unique_traits + // so we can later use it to build a string of all traits exactly once, without duplicates + + let mut seen_def_ids = FxHashSet::default(); + let mut unique_traits = Vec::new(); + + // Iterate the bounds and add them to our seen hash + // If we haven't yet seen it, add it to the fixed traits + for bound in bounds.iter() { + let Some(def_id) = bound.trait_ref.trait_def_id() else { continue; }; + + let new_trait = seen_def_ids.insert(def_id); + + if new_trait { + unique_traits.push(bound); + } + } + + // If the number of unique traits isn't the same as the number of traits in the bounds, + // there must be 1 or more duplicates + if bounds.len() != unique_traits.len() { + let mut bounds_span = bounds[0].span; + + for bound in bounds.iter().skip(1) { + bounds_span = bounds_span.to(bound.span); + } + + let fixed_trait_snippet = unique_traits + .iter() + .filter_map(|b| snippet_opt(cx, b.span)) + .collect::<Vec<_>>() + .join(" + "); + + span_lint_and_sugg( + cx, + TRAIT_DUPLICATION_IN_BOUNDS, + bounds_span, + "this trait bound is already specified in trait declaration", + "try", + fixed_trait_snippet, + Applicability::MaybeIncorrect, + ); + } + } + } + } } impl TraitBounds { diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs index e75d7f6bf1d..4944381da24 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs @@ -31,9 +31,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t match arg.kind { // Catching: // transmute over constants that resolve to `null`. - ExprKind::Path(ref _qpath) - if matches!(constant(cx, cx.typeck_results(), arg), Some((Constant::RawPtr(0), _))) => - { + ExprKind::Path(ref _qpath) if matches!(constant(cx, cx.typeck_results(), arg), Some(Constant::RawPtr(0))) => { lint_expr(cx, expr); true }, diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs index 1e407fc4138..770914e99e1 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{constant_context, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::{is_integer_literal, is_path_diagnostic_item}; use rustc_hir::{Expr, ExprKind}; @@ -16,9 +16,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t } // Catching transmute over constants that resolve to `null`. - let mut const_eval_context = constant_context(cx, cx.typeck_results()); if let ExprKind::Path(ref _qpath) = arg.kind && - let Some(Constant::RawPtr(0)) = const_eval_context.expr(arg) + let Some(Constant::RawPtr(0)) = constant(cx, cx.typeck_results(), arg) { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true; diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index ddbe6b2c790..28c3fc859e3 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; +use clippy_utils::is_ty_alias; use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts}; @@ -138,6 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if_chain! { if let ExprKind::Path(ref qpath) = path.kind; if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); + if !is_ty_alias(qpath); then { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(arg); diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 935ea90d245..3c2bf5abab2 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -308,7 +308,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { bind!(self, vec); kind!("CStr(ref {vec})"); chain!(self, "let [{:?}] = **{vec}", vec.value); - } + }, LitKind::Str(s, _) => { bind!(self, s); kind!("Str({s}, _)"); diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs index 5f05d971fce..f6de66bb514 100644 --- a/src/tools/clippy/clippy_lints/src/utils/conf.rs +++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs @@ -174,16 +174,15 @@ macro_rules! define_Conf { } } - #[cfg(feature = "internal")] pub mod metadata { - use crate::utils::internal_lints::metadata_collector::ClippyConfiguration; + use crate::utils::ClippyConfiguration; macro_rules! wrap_option { () => (None); ($x:literal) => (Some($x)); } - pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> { + pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> { vec![ $( { diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 3d0d4a52511..7a1cd3effae 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -8,7 +8,11 @@ //! a simple mistake) use crate::renamed_lints::RENAMED_LINTS; -use crate::utils::internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type}; +use crate::utils::{ + collect_configs, + internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type}, + ClippyConfiguration, +}; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{match_type, walk_ptrs_ty_depth}; @@ -520,111 +524,6 @@ impl Serialize for ApplicabilityInfo { } } -// ================================================================== -// Configuration -// ================================================================== -#[derive(Debug, Clone, Default)] -pub struct ClippyConfiguration { - name: String, - config_type: &'static str, - default: String, - lints: Vec<String>, - doc: String, - #[allow(dead_code)] - deprecation_reason: Option<&'static str>, -} - -impl ClippyConfiguration { - pub fn new( - name: &'static str, - config_type: &'static str, - default: String, - doc_comment: &'static str, - deprecation_reason: Option<&'static str>, - ) -> Self { - let (lints, doc) = parse_config_field_doc(doc_comment) - .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string())); - - Self { - name: to_kebab(name), - lints, - doc, - config_type, - default, - deprecation_reason, - } - } - - fn to_markdown_paragraph(&self) -> String { - format!( - "### {}\n{}\n\n**Default Value:** `{}` (`{}`)\n\n{}\n\n", - self.name, - self.doc - .lines() - .map(|line| line.strip_prefix(" ").unwrap_or(line)) - .join("\n"), - self.default, - self.config_type, - self.lints - .iter() - .map(|name| name.to_string().split_whitespace().next().unwrap().to_string()) - .map(|name| format!("* [{name}](https://rust-lang.github.io/rust-clippy/master/index.html#{name})")) - .join("\n"), - ) - } - - fn to_markdown_table_entry(&self) -> String { - format!("| [{}](#{}) | `{}` |", self.name, self.name, self.default) - } -} - -fn collect_configs() -> Vec<ClippyConfiguration> { - crate::utils::conf::metadata::get_configuration_metadata() -} - -/// This parses the field documentation of the config struct. -/// -/// ```rust, ignore -/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin") -/// ``` -/// -/// Would yield: -/// ```rust, ignore -/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin") -/// ``` -fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> { - const DOC_START: &str = " Lint: "; - if_chain! { - if doc_comment.starts_with(DOC_START); - if let Some(split_pos) = doc_comment.find('.'); - then { - let mut doc_comment = doc_comment.to_string(); - let mut documentation = doc_comment.split_off(split_pos); - - // Extract lints - doc_comment.make_ascii_lowercase(); - let lints: Vec<String> = doc_comment - .split_off(DOC_START.len()) - .split(", ") - .map(str::to_string) - .collect(); - - // Format documentation correctly - // split off leading `.` from lint name list and indent for correct formatting - documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n "); - - Some((lints, documentation)) - } else { - None - } - } -} - -/// Transforms a given `snake_case_string` to a tasty `kebab-case-string` -fn to_kebab(config_name: &str) -> String { - config_name.replace('_', "-") -} - impl fmt::Display for ClippyConfiguration { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result { writeln!( diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index dc647af264c..d3ea7cafa80 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -4,3 +4,143 @@ pub mod dump_hir; pub mod format_args_collector; #[cfg(feature = "internal")] pub mod internal_lints; +#[cfg(feature = "internal")] +use itertools::Itertools; + +/// Transforms a given `snake_case_string` to a tasty `kebab-case-string` +fn to_kebab(config_name: &str) -> String { + config_name.replace('_', "-") +} + +// ================================================================== +// Configuration +// ================================================================== +#[derive(Debug, Clone, Default)] //~ ERROR no such field +pub struct ClippyConfiguration { + pub name: String, + #[allow(dead_code)] + config_type: &'static str, + pub default: String, + pub lints: Vec<String>, + pub doc: String, + #[allow(dead_code)] + deprecation_reason: Option<&'static str>, +} + +impl ClippyConfiguration { + pub fn new( + name: &'static str, + config_type: &'static str, + default: String, + doc_comment: &'static str, + deprecation_reason: Option<&'static str>, + ) -> Self { + let (lints, doc) = parse_config_field_doc(doc_comment) + .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string())); + + Self { + name: to_kebab(name), + lints, + doc, + config_type, + default, + deprecation_reason, + } + } + + #[cfg(feature = "internal")] + fn to_markdown_paragraph(&self) -> String { + format!( + "### {}\n{}\n\n**Default Value:** `{}` (`{}`)\n\n{}\n\n", + self.name, + self.doc + .lines() + .map(|line| line.strip_prefix(" ").unwrap_or(line)) + .join("\n"), + self.default, + self.config_type, + self.lints + .iter() + .map(|name| name.to_string().split_whitespace().next().unwrap().to_string()) + .map(|name| format!("* [{name}](https://rust-lang.github.io/rust-clippy/master/index.html#{name})")) + .join("\n"), + ) + } + + #[cfg(feature = "internal")] + fn to_markdown_table_entry(&self) -> String { + format!("| [{}](#{}) | `{}` |", self.name, self.name, self.default) + } +} + +#[cfg(feature = "internal")] +fn collect_configs() -> Vec<ClippyConfiguration> { + crate::utils::conf::metadata::get_configuration_metadata() +} + +/// This parses the field documentation of the config struct. +/// +/// ```rust, ignore +/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin") +/// ``` +/// +/// Would yield: +/// ```rust, ignore +/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin") +/// ``` +fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> { + const DOC_START: &str = " Lint: "; + if_chain! { + if doc_comment.starts_with(DOC_START); + if let Some(split_pos) = doc_comment.find('.'); + then { + let mut doc_comment = doc_comment.to_string(); + let mut documentation = doc_comment.split_off(split_pos); + + // Extract lints + doc_comment.make_ascii_lowercase(); + let lints: Vec<String> = doc_comment + .split_off(DOC_START.len()) + .split(", ") + .map(str::to_string) + .collect(); + + // Format documentation correctly + // split off leading `.` from lint name list and indent for correct formatting + documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n "); + + Some((lints, documentation)) + } else { + None + } + } +} + +// Shamelessly stolen from find_all (https://github.com/nectariner/find_all) +pub trait FindAll: Iterator + Sized { + fn find_all<P>(&mut self, predicate: P) -> Option<Vec<usize>> + where + P: FnMut(&Self::Item) -> bool; +} + +impl<I> FindAll for I +where + I: Iterator, +{ + fn find_all<P>(&mut self, mut predicate: P) -> Option<Vec<usize>> + where + P: FnMut(&Self::Item) -> bool, + { + let mut occurences = Vec::<usize>::default(); + for (index, element) in self.enumerate() { + if predicate(&element) { + occurences.push(index); + } + } + + match occurences.len() { + 0 => None, + _ => Some(occurences), + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs index 297a80e5767..7329e508106 100644 --- a/src/tools/clippy/clippy_lints/src/vec.rs +++ b/src/tools/clippy/clippy_lints/src/vec.rs @@ -84,7 +84,7 @@ impl UselessVec { let mut applicability = Applicability::MachineApplicable; let snippet = match *vec_args { higher::VecArgs::Repeat(elem, len) => { - if let Some((Constant::Int(len_constant), _)) = constant(cx, cx.typeck_results(), len) { + if let Some(Constant::Int(len_constant)) = constant(cx, cx.typeck_results(), len) { #[expect(clippy::cast_possible_truncation)] if len_constant as u64 * size_of(cx, elem) > self.too_large_for_stack { return; diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs index 36f910c983f..a9089fba3c5 100644 --- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs +++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs @@ -7,7 +7,7 @@ use rustc_hir::{ def::{DefKind, Res}, Item, ItemKind, PathSegment, UseKind, }; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::kw; @@ -117,6 +117,10 @@ impl_lint_pass!(WildcardImports => [ENUM_GLOB_USE, WILDCARD_IMPORTS]); impl LateLintPass<'_> for WildcardImports { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { + if cx.sess().is_test_crate() { + return; + } + if is_test_module_or_function(cx.tcx, item) { self.test_modules_deep = self.test_modules_deep.saturating_add(1); } diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 8075881e3bb..fb772644c0d 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1,18 +1,21 @@ #![allow(clippy::float_cmp)] +use crate::source::{get_source_text, walk_span_to_context}; use crate::{clip, is_direct_expn_of, sext, unsext}; use if_chain::if_chain; use rustc_ast::ast::{self, LitFloatType, LitKind}; use rustc_data_structures::sync::Lrc; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}; +use rustc_lexer::tokenize; use rustc_lint::LateContext; use rustc_middle::mir; use rustc_middle::mir::interpret::Scalar; -use rustc_middle::ty::SubstsRef; use rustc_middle::ty::{self, EarlyBinder, FloatTy, ScalarInt, Ty, TyCtxt}; +use rustc_middle::ty::{List, SubstsRef}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::Symbol; +use rustc_span::SyntaxContext; use std::cmp::Ordering::{self, Equal}; use std::hash::{Hash, Hasher}; use std::iter; @@ -210,8 +213,7 @@ pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant { match *lit { LitKind::Str(ref is, _) => Constant::Str(is.to_string()), LitKind::Byte(b) => Constant::Int(u128::from(b)), - LitKind::ByteStr(ref s, _) => Constant::Binary(Lrc::clone(s)), - LitKind::CStr(ref s, _) => Constant::Binary(Lrc::clone(s)), + LitKind::ByteStr(ref s, _) | LitKind::CStr(ref s, _) => Constant::Binary(Lrc::clone(s)), LitKind::Char(c) => Constant::Char(c), LitKind::Int(n, _) => Constant::Int(n), LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty { @@ -228,27 +230,46 @@ pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant { } } +/// The source of a constant value. +pub enum ConstantSource { + /// The value is determined solely from the expression. + Local, + /// The value is dependent on a defined constant. + Constant, +} +impl ConstantSource { + pub fn is_local(&self) -> bool { + matches!(self, Self::Local) + } +} + +/// Attempts to evaluate the expression as a constant. pub fn constant<'tcx>( lcx: &LateContext<'tcx>, typeck_results: &ty::TypeckResults<'tcx>, e: &Expr<'_>, -) -> Option<(Constant, bool)> { - let mut cx = ConstEvalLateContext { - lcx, - typeck_results, - param_env: lcx.param_env, - needed_resolution: false, - substs: ty::List::empty(), - }; - cx.expr(e).map(|cst| (cst, cx.needed_resolution)) +) -> Option<Constant> { + ConstEvalLateContext::new(lcx, typeck_results).expr(e) +} + +/// Attempts to evaluate the expression as a constant. +pub fn constant_with_source<'tcx>( + lcx: &LateContext<'tcx>, + typeck_results: &ty::TypeckResults<'tcx>, + e: &Expr<'_>, +) -> Option<(Constant, ConstantSource)> { + let mut ctxt = ConstEvalLateContext::new(lcx, typeck_results); + let res = ctxt.expr(e); + res.map(|x| (x, ctxt.source)) } +/// Attempts to evaluate an expression only if it's value is not dependent on other items. pub fn constant_simple<'tcx>( lcx: &LateContext<'tcx>, typeck_results: &ty::TypeckResults<'tcx>, e: &Expr<'_>, ) -> Option<Constant> { - constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) }) + constant_with_source(lcx, typeck_results, e).and_then(|(c, s)| s.is_local().then_some(c)) } pub fn constant_full_int<'tcx>( @@ -297,29 +318,25 @@ impl Ord for FullInt { } } -/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`. -pub fn constant_context<'a, 'tcx>( - lcx: &'a LateContext<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, -) -> ConstEvalLateContext<'a, 'tcx> { - ConstEvalLateContext { - lcx, - typeck_results, - param_env: lcx.param_env, - needed_resolution: false, - substs: ty::List::empty(), - } -} - pub struct ConstEvalLateContext<'a, 'tcx> { lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, param_env: ty::ParamEnv<'tcx>, - needed_resolution: bool, + source: ConstantSource, substs: SubstsRef<'tcx>, } impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { + fn new(lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>) -> Self { + Self { + lcx, + typeck_results, + param_env: lcx.param_env, + source: ConstantSource::Local, + substs: List::empty(), + } + } + /// Simple constant folding: Insert an expression, get a constant or none. pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> { match e.kind { @@ -454,11 +471,9 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, substs), None) .ok() .map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty))?; - let result = miri_to_const(self.lcx.tcx, result); - if result.is_some() { - self.needed_resolution = true; - } - result + let result = miri_to_const(self.lcx.tcx, result)?; + self.source = ConstantSource::Constant; + Some(result) }, // FIXME: cover all usable cases. _ => None, @@ -492,8 +507,33 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { /// A block can only yield a constant if it only has one constant expression. fn block(&mut self, block: &Block<'_>) -> Option<Constant> { - if block.stmts.is_empty() { - block.expr.as_ref().and_then(|b| self.expr(b)) + if block.stmts.is_empty() + && let Some(expr) = block.expr + { + // Try to detect any `cfg`ed statements or empty macro expansions. + let span = block.span.data(); + if span.ctxt == SyntaxContext::root() { + 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) = src.as_str() + { + use rustc_lexer::TokenKind::{Whitespace, LineComment, BlockComment, Semi, OpenBrace}; + if !tokenize(src) + .map(|t| t.kind) + .filter(|t| !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi)) + .eq([OpenBrace]) + { + self.source = ConstantSource::Constant; + } + } else { + // Unable to access the source. Assume a non-local dependency. + self.source = ConstantSource::Constant; + } + } + + self.expr(expr) } else { None } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 9b7408d5133..a49246a7832 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1,6 +1,7 @@ use crate::consts::constant_simple; use crate::macros::macro_backtrace; -use crate::source::snippet_opt; +use crate::source::{get_source_text, snippet_opt, walk_span_to_context, SpanRange}; +use crate::tokenize_with_text; use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxHasher; use rustc_hir::def::Res; @@ -13,8 +14,9 @@ use rustc_hir::{ use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::LateContext; use rustc_middle::ty::TypeckResults; -use rustc_span::{sym, Symbol}; +use rustc_span::{sym, BytePos, ExpnKind, MacroKind, Symbol, SyntaxContext}; use std::hash::{Hash, Hasher}; +use std::ops::Range; /// Callback that is called when two expressions are not equal in the sense of `SpanlessEq`, but /// other conditions would make them equal. @@ -65,6 +67,8 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { pub fn inter_expr(&mut self) -> HirEqInterExpr<'_, 'a, 'tcx> { HirEqInterExpr { inner: self, + left_ctxt: SyntaxContext::root(), + right_ctxt: SyntaxContext::root(), locals: HirIdMap::default(), } } @@ -92,6 +96,8 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { pub struct HirEqInterExpr<'a, 'b, 'tcx> { inner: &'a mut SpanlessEq<'b, 'tcx>, + left_ctxt: SyntaxContext, + right_ctxt: SyntaxContext, // When binding are declared, the binding ID in the left expression is mapped to the one on the // right. For example, when comparing `{ let x = 1; x + 2 }` and `{ let y = 1; y + 2 }`, @@ -126,52 +132,88 @@ impl HirEqInterExpr<'_, '_, '_> { } /// Checks whether two blocks are the same. + #[expect(clippy::similar_names)] fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool { - match (left.stmts, left.expr, right.stmts, right.expr) { - ([], None, [], None) => { - // For empty blocks, check to see if the tokens are equal. This will catch the case where a macro - // expanded to nothing, or the cfg attribute was used. - let (Some(left), Some(right)) = ( - snippet_opt(self.inner.cx, left.span), - snippet_opt(self.inner.cx, right.span), - ) else { return true }; - let mut left_pos = 0; - let left = tokenize(&left) - .map(|t| { - let end = left_pos + t.len as usize; - let s = &left[left_pos..end]; - left_pos = end; - (t, s) - }) - .filter(|(t, _)| { - !matches!( - t.kind, - TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace - ) - }) - .map(|(_, s)| s); - let mut right_pos = 0; - let right = tokenize(&right) - .map(|t| { - let end = right_pos + t.len as usize; - let s = &right[right_pos..end]; - right_pos = end; - (t, s) - }) - .filter(|(t, _)| { - !matches!( - t.kind, - TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace - ) - }) - .map(|(_, s)| s); - left.eq(right) - }, - _ => { - over(left.stmts, right.stmts, |l, r| self.eq_stmt(l, r)) - && both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r)) - }, + use TokenKind::{BlockComment, LineComment, Semi, Whitespace}; + if left.stmts.len() != right.stmts.len() { + return false; + } + let lspan = left.span.data(); + let rspan = right.span.data(); + if lspan.ctxt != SyntaxContext::root() && rspan.ctxt != SyntaxContext::root() { + // Don't try to check in between statements inside macros. + return over(left.stmts, right.stmts, |left, right| self.eq_stmt(left, right)) + && both(&left.expr, &right.expr, |left, right| self.eq_expr(left, right)); + } + if lspan.ctxt != rspan.ctxt { + return false; } + + let mut lstart = lspan.lo; + let mut rstart = rspan.lo; + + for (left, right) in left.stmts.iter().zip(right.stmts) { + if !self.eq_stmt(left, right) { + return false; + } + + // Try to detect any `cfg`ed statements or empty macro expansions. + let Some(lstmt_span) = walk_span_to_context(left.span, lspan.ctxt) else { + return false; + }; + let Some(rstmt_span) = walk_span_to_context(right.span, rspan.ctxt) else { + return false; + }; + let lstmt_span = lstmt_span.data(); + let rstmt_span = rstmt_span.data(); + + if lstmt_span.lo < lstart && rstmt_span.lo < rstart { + // Can happen when macros expand to multiple statements, or rearrange statements. + // Nothing in between the statements to check in this case. + continue; + } + if lstmt_span.lo < lstart || rstmt_span.lo < rstart { + // Only one of the blocks had a weird macro. + return false; + } + if !eq_span_tokens(self.inner.cx, lstart..lstmt_span.lo, rstart..rstmt_span.lo, |t| { + !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi) + }) { + return false; + } + + lstart = lstmt_span.hi; + rstart = rstmt_span.hi; + } + + let (lend, rend) = match (left.expr, right.expr) { + (Some(left), Some(right)) => { + if !self.eq_expr(left, right) { + return false; + } + let Some(lexpr_span) = walk_span_to_context(left.span, lspan.ctxt) else { + return false; + }; + let Some(rexpr_span) = walk_span_to_context(right.span, rspan.ctxt) else { + return false; + }; + (lexpr_span.lo(), rexpr_span.lo()) + }, + (None, None) => (lspan.hi, rspan.hi), + (Some(_), None) | (None, Some(_)) => return false, + }; + + if lend < lstart && rend < rstart { + // Can happen when macros rearrange the input. + // Nothing in between the statements to check in this case. + return true; + } else if lend < lstart || rend < rstart { + // Only one of the blocks had a weird macro + return false; + } + eq_span_tokens(self.inner.cx, lstart..lend, rstart..rend, |t| { + !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi) + }) } fn should_ignore(&mut self, expr: &Expr<'_>) -> bool { @@ -207,7 +249,7 @@ impl HirEqInterExpr<'_, '_, '_> { #[expect(clippy::similar_names)] pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool { - if !self.inner.allow_side_effects && left.span.ctxt() != right.span.ctxt() { + if !self.check_ctxt(left.span.ctxt(), right.span.ctxt()) { return false; } @@ -440,6 +482,45 @@ impl HirEqInterExpr<'_, '_, '_> { fn eq_type_binding(&mut self, left: &TypeBinding<'_>, right: &TypeBinding<'_>) -> bool { left.ident.name == right.ident.name && self.eq_ty(left.ty(), right.ty()) } + + fn check_ctxt(&mut self, left: SyntaxContext, right: SyntaxContext) -> bool { + if self.left_ctxt == left && self.right_ctxt == right { + return true; + } else if self.left_ctxt == left || self.right_ctxt == right { + // Only one context has changed. This can only happen if the two nodes are written differently. + return false; + } else if left != SyntaxContext::root() { + let mut left_data = left.outer_expn_data(); + let mut right_data = right.outer_expn_data(); + loop { + use TokenKind::{BlockComment, LineComment, Whitespace}; + if left_data.macro_def_id != right_data.macro_def_id + || (matches!(left_data.kind, ExpnKind::Macro(MacroKind::Bang, name) if name == sym::cfg) + && !eq_span_tokens(self.inner.cx, left_data.call_site, right_data.call_site, |t| { + !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. }) + })) + { + // Either a different chain of macro calls, or different arguments to the `cfg` macro. + return false; + } + let left_ctxt = left_data.call_site.ctxt(); + let right_ctxt = right_data.call_site.ctxt(); + if left_ctxt == SyntaxContext::root() && right_ctxt == SyntaxContext::root() { + break; + } + if left_ctxt == SyntaxContext::root() || right_ctxt == SyntaxContext::root() { + // Different lengths for the expansion stack. This can only happen if nodes are written differently, + // or shouldn't be compared to start with. + return false; + } + left_data = left_ctxt.outer_expn_data(); + right_data = right_ctxt.outer_expn_data(); + } + } + self.left_ctxt = left; + self.right_ctxt = right; + true + } } /// Some simple reductions like `{ return }` => `return` @@ -1038,3 +1119,34 @@ pub fn hash_expr(cx: &LateContext<'_>, e: &Expr<'_>) -> u64 { h.hash_expr(e); h.finish() } + +#[expect(clippy::similar_names)] +fn eq_span_tokens( + cx: &LateContext<'_>, + left: impl SpanRange, + right: impl SpanRange, + 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) + && let Some(lsrc) = lsrc.as_str() + && let Some(rsrc) = get_source_text(cx, right) + && let Some(rsrc) = rsrc.as_str() + { + let pred = |t: &(_, _)| pred(t.0); + let map = |(_, x)| x; + + let ltok = tokenize_with_text(lsrc) + .filter(pred) + .map(map); + let rtok = tokenize_with_text(rsrc) + .filter(pred) + .map(map); + ltok.eq(rtok) + } else { + // Unable to access the source. Conservatively assume the blocks aren't equal. + false + } + } + f(cx, left.into_range(), right.into_range(), pred) +} diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 964104fc31d..575c29a6b6f 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1,5 +1,6 @@ #![feature(array_chunks)] #![feature(box_patterns)] +#![feature(if_let_guard)] #![feature(let_chains)] #![feature(lint_reasons)] #![feature(never_type)] @@ -76,6 +77,7 @@ use std::sync::OnceLock; use std::sync::{Mutex, MutexGuard}; use if_chain::if_chain; +use itertools::Itertools; use rustc_ast::ast::{self, LitKind, RangeLimits}; use rustc_ast::Attribute; use rustc_data_structures::fx::FxHashMap; @@ -282,6 +284,15 @@ pub fn is_wild(pat: &Pat<'_>) -> bool { matches!(pat.kind, PatKind::Wild) } +/// Checks if the given `QPath` belongs to a type alias. +pub fn is_ty_alias(qpath: &QPath<'_>) -> bool { + match *qpath { + QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias, ..)), + QPath::TypeRelative(ty, _) if let TyKind::Path(qpath) = ty.kind => { is_ty_alias(&qpath) }, + _ => false, + } +} + /// Checks if the method call given in `expr` belongs to the given trait. /// This is a deprecated function, consider using [`is_trait_method`]. pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool { @@ -1488,7 +1499,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree())) && let min_const_kind = ConstantKind::from_value(const_val, bnd_ty) && let Some(min_const) = miri_to_const(cx.tcx, min_const_kind) - && let Some((start_const, _)) = constant(cx, cx.typeck_results(), start) + && let Some(start_const) = constant(cx, cx.typeck_results(), start) { start_const == min_const } else { @@ -1504,7 +1515,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree())) && let max_const_kind = ConstantKind::from_value(const_val, bnd_ty) && let Some(max_const) = miri_to_const(cx.tcx, max_const_kind) - && let Some((end_const, _)) = constant(cx, cx.typeck_results(), end) + && let Some(end_const) = constant(cx, cx.typeck_results(), end) { end_const == max_const } else { @@ -1536,7 +1547,7 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool return true; } let enclosing_body = cx.tcx.hir().enclosing_body_owner(e.hir_id); - if let Some((Constant::Int(v), _)) = constant(cx, cx.tcx.typeck(enclosing_body), e) { + if let Some(Constant::Int(v)) = constant(cx, cx.tcx.typeck(enclosing_body), e) { return value == v; } false @@ -2480,6 +2491,17 @@ pub fn walk_to_expr_usage<'tcx, T>( None } +/// Tokenizes the input while keeping the text associated with each token. +pub fn tokenize_with_text(s: &str) -> impl Iterator<Item = (TokenKind, &str)> { + let mut pos = 0; + tokenize(s).map(move |t| { + let end = pos + t.len; + let range = pos as usize..end as usize; + pos = end; + (t.kind, s.get(range).unwrap_or_default()) + }) +} + /// Checks whether a given span has any comment token /// This checks for all types of comment: line "//", block "/**", doc "///" "//!" pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool { @@ -2496,23 +2518,11 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool { /// Comments are returned wrapped with their relevant delimiters pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String { let snippet = sm.span_to_snippet(span).unwrap_or_default(); - let mut comments_buf: Vec<String> = Vec::new(); - let mut index: usize = 0; - - for token in tokenize(&snippet) { - let token_range = index..(index + token.len as usize); - index += token.len as usize; - match token.kind { - TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } => { - if let Some(comment) = snippet.get(token_range) { - comments_buf.push(comment.to_string()); - } - }, - _ => (), - } - } - - comments_buf.join("\n") + let res = tokenize_with_text(&snippet) + .filter(|(t, _)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. })) + .map(|(_, s)| s) + .join("\n"); + res } pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span { diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index 62fa37660fa..0f60290644a 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -2,14 +2,64 @@ #![allow(clippy::module_name_repetitions)] +use rustc_data_structures::sync::Lrc; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; use rustc_session::Session; -use rustc_span::hygiene; use rustc_span::source_map::{original_sp, SourceMap}; +use rustc_span::{hygiene, SourceFile}; use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext, DUMMY_SP}; use std::borrow::Cow; +use std::ops::Range; + +/// A type which can be converted to the range portion of a `Span`. +pub trait SpanRange { + fn into_range(self) -> Range<BytePos>; +} +impl SpanRange for Span { + fn into_range(self) -> Range<BytePos> { + let data = self.data(); + data.lo..data.hi + } +} +impl SpanRange for SpanData { + fn into_range(self) -> Range<BytePos> { + self.lo..self.hi + } +} +impl SpanRange for Range<BytePos> { + fn into_range(self) -> Range<BytePos> { + self + } +} + +pub struct SourceFileRange { + pub sf: Lrc<SourceFile>, + pub range: Range<usize>, +} +impl SourceFileRange { + /// Attempts to get the text from the source file. This can fail if the source text isn't + /// loaded. + pub fn as_str(&self) -> Option<&str> { + self.sf.src.as_ref().and_then(|x| x.get(self.range.clone())) + } +} + +/// 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>( diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 60b8a5ac071..bc7fb711ed8 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-05-05" +channel = "nightly-2023-05-20" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.rs b/src/tools/clippy/tests/ui-internal/custom_ice_message.rs index acb98d7ba98..99ce7028390 100644 --- a/src/tools/clippy/tests/ui-internal/custom_ice_message.rs +++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.rs @@ -3,6 +3,7 @@ //@normalize-stderr-test: "produce_ice.rs:\d*:\d*" -> "produce_ice.rs" //@normalize-stderr-test: "', .*clippy_lints" -> "', clippy_lints" //@normalize-stderr-test: "'rustc'" -> "'<unnamed>'" +//@normalize-stderr-test: "running on .*" -> "running on <target>" //@normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> "" #![deny(clippy::internal)] diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr index b4619e980f3..0fc385cd693 100644 --- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr +++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr @@ -1,12 +1,14 @@ thread '<unnamed>' panicked at 'Would you like some help with that?', clippy_lints/src/utils/internal_lints/produce_ice.rs note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -error: internal compiler error: unexpected panic - -note: the compiler unexpectedly panicked. this is a bug. +error: the compiler unexpectedly panicked. this is a bug. note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new +note: rustc 1.71.0-nightly (521f4dae1 2023-05-19) running on <target> + +note: compiler flags: -C prefer-dynamic -Z ui-testing + note: Clippy version: foo thread panicked while panicking. aborting. diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs index ab408bdf261..f95af1017bc 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs @@ -458,4 +458,12 @@ pub fn issue_10583(a: u16) -> u16 { 10 / a } +pub fn issue_10767() { + let n = &1.0; + n + n; + 3.1_f32 + &1.2_f32; + &3.4_f32 + 1.5_f32; + &3.5_f32 + &1.3_f32; +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.fixed b/src/tools/clippy/tests/ui/borrow_deref_ref.fixed index 165e4bc8272..75526461792 100644 --- a/src/tools/clippy/tests/ui/borrow_deref_ref.fixed +++ b/src/tools/clippy/tests/ui/borrow_deref_ref.fixed @@ -1,7 +1,11 @@ //@run-rustfix +//@aux-build: proc_macros.rs #![allow(dead_code, unused_variables)] +extern crate proc_macros; +use proc_macros::with_span; + fn main() {} mod should_lint { @@ -47,6 +51,17 @@ mod should_not_lint2 { } } +with_span!( + span + + fn just_returning(x: &u32) -> &u32 { + x + } + + fn dont_lint_proc_macro() { + let a = &mut &*just_returning(&12); + } +); // this mod explains why we should not lint `& &* (&T)` mod false_negative { fn foo() { diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.rs b/src/tools/clippy/tests/ui/borrow_deref_ref.rs index 66c8d69bef9..e319d365f7e 100644 --- a/src/tools/clippy/tests/ui/borrow_deref_ref.rs +++ b/src/tools/clippy/tests/ui/borrow_deref_ref.rs @@ -1,7 +1,11 @@ //@run-rustfix +//@aux-build: proc_macros.rs #![allow(dead_code, unused_variables)] +extern crate proc_macros; +use proc_macros::with_span; + fn main() {} mod should_lint { @@ -47,6 +51,17 @@ mod should_not_lint2 { } } +with_span!( + span + + fn just_returning(x: &u32) -> &u32 { + x + } + + fn dont_lint_proc_macro() { + let a = &mut &*just_returning(&12); + } +); // this mod explains why we should not lint `& &* (&T)` mod false_negative { fn foo() { diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.stderr b/src/tools/clippy/tests/ui/borrow_deref_ref.stderr index d72de37c69f..1e47cda6796 100644 --- a/src/tools/clippy/tests/ui/borrow_deref_ref.stderr +++ b/src/tools/clippy/tests/ui/borrow_deref_ref.stderr @@ -1,5 +1,5 @@ error: deref on an immutable reference - --> $DIR/borrow_deref_ref.rs:10:17 + --> $DIR/borrow_deref_ref.rs:14:17 | LL | let b = &*a; | ^^^ help: if you would like to reborrow, try removing `&*`: `a` @@ -7,13 +7,13 @@ LL | let b = &*a; = note: `-D clippy::borrow-deref-ref` implied by `-D warnings` error: deref on an immutable reference - --> $DIR/borrow_deref_ref.rs:12:22 + --> $DIR/borrow_deref_ref.rs:16:22 | LL | let b = &mut &*bar(&12); | ^^^^^^^^^^ help: if you would like to reborrow, try removing `&*`: `bar(&12)` error: deref on an immutable reference - --> $DIR/borrow_deref_ref.rs:55:23 + --> $DIR/borrow_deref_ref.rs:70:23 | LL | let addr_y = &&*x as *const _ as usize; // assert ok | ^^^ help: if you would like to reborrow, try removing `&*`: `x` diff --git a/src/tools/clippy/tests/ui/box_default.fixed b/src/tools/clippy/tests/ui/box_default.fixed index e6331290420..840902b5323 100644 --- a/src/tools/clippy/tests/ui/box_default.fixed +++ b/src/tools/clippy/tests/ui/box_default.fixed @@ -35,6 +35,13 @@ fn main() { let _more = ret_ty_fn(); call_ty_fn(Box::default()); issue_10381(); + + // `Box::<Option<_>>::default()` would be valid here, but not `Box::default()` or + // `Box::<Option<[closure@...]>::default()` + // + // Would have a suggestion after https://github.com/rust-lang/rust/blob/fdd030127cc68afec44a8d3f6341525dd34e50ae/compiler/rustc_middle/src/ty/diagnostics.rs#L554-L563 + let mut unnameable = Box::new(Option::default()); + let _ = unnameable.insert(|| {}); } fn ret_ty_fn() -> Box<bool> { diff --git a/src/tools/clippy/tests/ui/box_default.rs b/src/tools/clippy/tests/ui/box_default.rs index 34a05a29c5a..3618486a473 100644 --- a/src/tools/clippy/tests/ui/box_default.rs +++ b/src/tools/clippy/tests/ui/box_default.rs @@ -35,6 +35,13 @@ fn main() { let _more = ret_ty_fn(); call_ty_fn(Box::new(u8::default())); issue_10381(); + + // `Box::<Option<_>>::default()` would be valid here, but not `Box::default()` or + // `Box::<Option<[closure@...]>::default()` + // + // Would have a suggestion after https://github.com/rust-lang/rust/blob/fdd030127cc68afec44a8d3f6341525dd34e50ae/compiler/rustc_middle/src/ty/diagnostics.rs#L554-L563 + let mut unnameable = Box::new(Option::default()); + let _ = unnameable.insert(|| {}); } fn ret_ty_fn() -> Box<bool> { diff --git a/src/tools/clippy/tests/ui/box_default.stderr b/src/tools/clippy/tests/ui/box_default.stderr index c9834863601..13dfc5ae48a 100644 --- a/src/tools/clippy/tests/ui/box_default.stderr +++ b/src/tools/clippy/tests/ui/box_default.stderr @@ -73,25 +73,25 @@ LL | call_ty_fn(Box::new(u8::default())); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:41:5 + --> $DIR/box_default.rs:48:5 | LL | Box::new(bool::default()) | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<bool>::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:58:28 + --> $DIR/box_default.rs:65:28 | LL | let _: Box<dyn Read> = Box::new(ImplementsDefault::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:67:17 + --> $DIR/box_default.rs:74:17 | LL | let _ = Box::new(WeirdPathed::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<WeirdPathed>::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:79:18 + --> $DIR/box_default.rs:86:18 | LL | Some(Box::new(Foo::default())) | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Foo>::default()` diff --git a/src/tools/clippy/tests/ui/collapsible_if.fixed b/src/tools/clippy/tests/ui/collapsible_if.fixed index d2aba2ac59b..c6514a55934 100644 --- a/src/tools/clippy/tests/ui/collapsible_if.fixed +++ b/src/tools/clippy/tests/ui/collapsible_if.fixed @@ -1,5 +1,10 @@ //@run-rustfix -#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] +#![allow( + clippy::assertions_on_constants, + clippy::equatable_if_let, + clippy::nonminimal_bool, + clippy::eq_op +)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff --git a/src/tools/clippy/tests/ui/collapsible_if.rs b/src/tools/clippy/tests/ui/collapsible_if.rs index e0bef7f9c97..2c85b68df63 100644 --- a/src/tools/clippy/tests/ui/collapsible_if.rs +++ b/src/tools/clippy/tests/ui/collapsible_if.rs @@ -1,5 +1,10 @@ //@run-rustfix -#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] +#![allow( + clippy::assertions_on_constants, + clippy::equatable_if_let, + clippy::nonminimal_bool, + clippy::eq_op +)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff --git a/src/tools/clippy/tests/ui/collapsible_if.stderr b/src/tools/clippy/tests/ui/collapsible_if.stderr index 6327444df21..c687bae1acc 100644 --- a/src/tools/clippy/tests/ui/collapsible_if.stderr +++ b/src/tools/clippy/tests/ui/collapsible_if.stderr @@ -1,5 +1,5 @@ error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:9:5 + --> $DIR/collapsible_if.rs:14:5 | LL | / if x == "hello" { LL | | if y == "world" { @@ -17,7 +17,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:15:5 + --> $DIR/collapsible_if.rs:20:5 | LL | / if x == "hello" || x == "world" { LL | | if y == "world" || y == "hello" { @@ -34,7 +34,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:21:5 + --> $DIR/collapsible_if.rs:26:5 | LL | / if x == "hello" && x == "world" { LL | | if y == "world" || y == "hello" { @@ -51,7 +51,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:27:5 + --> $DIR/collapsible_if.rs:32:5 | LL | / if x == "hello" || x == "world" { LL | | if y == "world" && y == "hello" { @@ -68,7 +68,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:33:5 + --> $DIR/collapsible_if.rs:38:5 | LL | / if x == "hello" && x == "world" { LL | | if y == "world" && y == "hello" { @@ -85,7 +85,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:39:5 + --> $DIR/collapsible_if.rs:44:5 | LL | / if 42 == 1337 { LL | | if 'a' != 'A' { @@ -102,7 +102,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:95:5 + --> $DIR/collapsible_if.rs:100:5 | LL | / if x == "hello" { LL | | if y == "world" { // Collapsible @@ -119,7 +119,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:154:5 + --> $DIR/collapsible_if.rs:159:5 | LL | / if matches!(true, true) { LL | | if matches!(true, true) {} @@ -127,7 +127,7 @@ LL | | } | |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}` error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:159:5 + --> $DIR/collapsible_if.rs:164:5 | LL | / if matches!(true, true) && truth() { LL | | if matches!(true, true) {} diff --git a/src/tools/clippy/tests/ui/dbg_macro.rs b/src/tools/clippy/tests/ui/dbg_macro.rs index 8701e3cd29f..10788d40481 100644 --- a/src/tools/clippy/tests/ui/dbg_macro.rs +++ b/src/tools/clippy/tests/ui/dbg_macro.rs @@ -4,6 +4,7 @@ fn foo(n: u32) -> u32 { if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } } +fn bar(_: ()) {} fn factorial(n: u32) -> u32 { if dbg!(n <= 1) { @@ -21,6 +22,32 @@ fn main() { dbg!(1, 2, 3, 4, 5); } +fn issue9914() { + macro_rules! foo { + ($x:expr) => { + $x; + }; + } + macro_rules! foo2 { + ($x:expr) => { + $x; + }; + } + macro_rules! expand_to_dbg { + () => { + dbg!(); + }; + } + + dbg!(); + #[allow(clippy::let_unit_value)] + let _ = dbg!(); + bar(dbg!()); + foo!(dbg!()); + foo2!(foo!(dbg!())); + expand_to_dbg!(); +} + mod issue7274 { trait Thing<'b> { fn foo(&self); diff --git a/src/tools/clippy/tests/ui/dbg_macro.stderr b/src/tools/clippy/tests/ui/dbg_macro.stderr index ddb5f1342e9..530e7663317 100644 --- a/src/tools/clippy/tests/ui/dbg_macro.stderr +++ b/src/tools/clippy/tests/ui/dbg_macro.stderr @@ -11,7 +11,7 @@ LL | if let Some(n) = n.checked_sub(4) { n } else { n } | ~~~~~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:9:8 + --> $DIR/dbg_macro.rs:10:8 | LL | if dbg!(n <= 1) { | ^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | if n <= 1 { | ~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:10:9 + --> $DIR/dbg_macro.rs:11:9 | LL | dbg!(1) | ^^^^^^^ @@ -33,7 +33,7 @@ LL | 1 | error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:12:9 + --> $DIR/dbg_macro.rs:13:9 | LL | dbg!(n * factorial(n - 1)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | n * factorial(n - 1) | error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:17:5 + --> $DIR/dbg_macro.rs:18:5 | LL | dbg!(42); | ^^^^^^^^ @@ -55,7 +55,7 @@ LL | 42; | ~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:18:5 + --> $DIR/dbg_macro.rs:19:5 | LL | dbg!(dbg!(dbg!(42))); | ^^^^^^^^^^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | dbg!(dbg!(42)); | ~~~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:19:14 + --> $DIR/dbg_macro.rs:20:14 | LL | foo(3) + dbg!(factorial(4)); | ^^^^^^^^^^^^^^^^^^ @@ -77,7 +77,7 @@ LL | foo(3) + factorial(4); | ~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:20:5 + --> $DIR/dbg_macro.rs:21:5 | LL | dbg!(1, 2, dbg!(3, 4)); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | (1, 2, dbg!(3, 4)); | ~~~~~~~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:21:5 + --> $DIR/dbg_macro.rs:22:5 | LL | dbg!(1, 2, 3, 4, 5); | ^^^^^^^^^^^^^^^^^^^ @@ -99,7 +99,63 @@ LL | (1, 2, 3, 4, 5); | ~~~~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:41:9 + --> $DIR/dbg_macro.rs:42:5 + | +LL | dbg!(); + | ^^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL - dbg!(); +LL + + | + +error: the `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:44:13 + | +LL | let _ = dbg!(); + | ^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL | let _ = (); + | ~~ + +error: the `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:45:9 + | +LL | bar(dbg!()); + | ^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL | bar(()); + | ~~ + +error: the `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:46:10 + | +LL | foo!(dbg!()); + | ^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL | foo!(()); + | ~~ + +error: the `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:47:16 + | +LL | foo2!(foo!(dbg!())); + | ^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL | foo2!(foo!(())); + | ~~ + +error: the `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:68:9 | LL | dbg!(2); | ^^^^^^^ @@ -110,7 +166,7 @@ LL | 2; | ~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:47:5 + --> $DIR/dbg_macro.rs:74:5 | LL | dbg!(1); | ^^^^^^^ @@ -121,7 +177,7 @@ LL | 1; | ~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:52:5 + --> $DIR/dbg_macro.rs:79:5 | LL | dbg!(1); | ^^^^^^^ @@ -132,7 +188,7 @@ LL | 1; | ~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:58:9 + --> $DIR/dbg_macro.rs:85:9 | LL | dbg!(1); | ^^^^^^^ @@ -142,5 +198,5 @@ help: remove the invocation before committing it to a version control system LL | 1; | ~ -error: aborting due to 13 previous errors +error: aborting due to 18 previous errors diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed b/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed index 4c2d1ea48e1..e1012f38bba 100644 --- a/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed +++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed @@ -105,6 +105,7 @@ fn main() { // should lint let _ = PhantomData::<usize>; let _: PhantomData<i32> = PhantomData; + let _: PhantomData<i32> = std::marker::PhantomData; let _ = UnitStruct; // should not lint @@ -116,4 +117,21 @@ fn main() { let _ = EmptyStruct::default(); let _ = FakeDefault::default(); let _ = <FakeDefault as Default>::default(); + + macro_rules! in_macro { + ($i:ident) => {{ + let _ = UnitStruct::default(); + let _ = $i::default(); + }}; + } + + in_macro!(UnitStruct); + + macro_rules! struct_from_macro { + () => { + UnitStruct + }; + } + + let _ = <struct_from_macro!()>::default(); } diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs b/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs index 850793dd5de..c7b4313dbf0 100644 --- a/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs +++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs @@ -105,6 +105,7 @@ fn main() { // should lint let _ = PhantomData::<usize>::default(); let _: PhantomData<i32> = PhantomData::default(); + let _: PhantomData<i32> = std::marker::PhantomData::default(); let _ = UnitStruct::default(); // should not lint @@ -116,4 +117,21 @@ fn main() { let _ = EmptyStruct::default(); let _ = FakeDefault::default(); let _ = <FakeDefault as Default>::default(); + + macro_rules! in_macro { + ($i:ident) => {{ + let _ = UnitStruct::default(); + let _ = $i::default(); + }}; + } + + in_macro!(UnitStruct); + + macro_rules! struct_from_macro { + () => { + UnitStruct + }; + } + + let _ = <struct_from_macro!()>::default(); } diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr b/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr index 4058943d087..61a32fb10e5 100644 --- a/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr +++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr @@ -25,10 +25,16 @@ LL | let _: PhantomData<i32> = PhantomData::default(); | ^^^^^^^^^^^ help: remove this call to `default` error: use of `default` to create a unit struct - --> $DIR/default_constructed_unit_structs.rs:108:23 + --> $DIR/default_constructed_unit_structs.rs:108:55 + | +LL | let _: PhantomData<i32> = std::marker::PhantomData::default(); + | ^^^^^^^^^^^ help: remove this call to `default` + +error: use of `default` to create a unit struct + --> $DIR/default_constructed_unit_structs.rs:109:23 | LL | let _ = UnitStruct::default(); | ^^^^^^^^^^^ help: remove this call to `default` -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs new file mode 100644 index 00000000000..e843770f578 --- /dev/null +++ b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs @@ -0,0 +1,132 @@ +//@aux-build:proc_macro_attr.rs +#![warn(clippy::empty_line_after_doc_comments)] +#![allow(clippy::assertions_on_constants)] +#![feature(custom_inner_attributes)] +#![rustfmt::skip] + +#[macro_use] +extern crate proc_macro_attr; + +mod some_mod { + //! This doc comment should *NOT* produce a warning + + mod some_inner_mod { + fn some_noop() {} + } +} + +/// This should produce a warning + +fn with_doc_and_newline() { assert!(true)} + +// This should *NOT* produce a warning +#[crate_type = "lib"] + +/// some comment +fn with_one_newline_and_comment() { assert!(true) } + +// This should *NOT* produce a warning +#[crate_type = "lib"] +/// some comment +fn with_no_newline_and_comment() { assert!(true) } + + +// This should *NOT* produce a warning +#[crate_type = "lib"] + +fn with_one_newline() { assert!(true) } + +// This should *NOT* produce a warning +#[crate_type = "lib"] + + +fn with_two_newlines() { assert!(true) } + + +// This should *NOT* produce a warning +#[crate_type = "lib"] + +enum Baz { + One, + Two +} + +// This should *NOT* produce a warning +#[crate_type = "lib"] + +struct Foo { + one: isize, + two: isize +} + +// This should *NOT* produce a warning +#[crate_type = "lib"] + +mod foo { +} + +/// This doc comment should produce a warning + +/** This is also a doc comment and should produce a warning + */ + +// This should *NOT* produce a warning +#[allow(non_camel_case_types)] +#[allow(missing_docs)] +#[allow(missing_docs)] +fn three_attributes() { assert!(true) } + +// This should *NOT* produce a warning +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +// This should *NOT* produce a warning +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4 +} + +// This should *NOT* produce a warning because the empty line is inside a block comment +#[crate_type = "lib"] +/* + +*/ +pub struct S; + +// This should *NOT* produce a warning +#[crate_type = "lib"] +/* test */ +pub struct T; + +// This should *NOT* produce a warning +// See https://github.com/rust-lang/rust-clippy/issues/5567 +#[fake_async_trait] +pub trait Bazz { + fn foo() -> Vec<u8> { + let _i = ""; + + + + vec![] + } +} + +#[derive(Clone, Copy)] +#[dummy(string = "first line + +second line +")] +pub struct Args; + +fn main() {} diff --git a/src/tools/clippy/tests/ui/empty_line_after_doc_comments.stderr b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.stderr new file mode 100644 index 00000000000..2ca1b51679e --- /dev/null +++ b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.stderr @@ -0,0 +1,36 @@ +error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`? + --> $DIR/empty_line_after_doc_comments.rs:18:1 + | +LL | / /// This should produce a warning +LL | | +LL | | fn with_doc_and_newline() { assert!(true)} + | |_ + | + = note: `-D clippy::empty-line-after-doc-comments` implied by `-D warnings` + +error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`? + --> $DIR/empty_line_after_doc_comments.rs:68:1 + | +LL | / /// This doc comment should produce a warning +LL | | +LL | | /** This is also a doc comment and should produce a warning +LL | | */ +... | +LL | | #[allow(missing_docs)] +LL | | fn three_attributes() { assert!(true) } + | |_ + +error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`? + --> $DIR/empty_line_after_doc_comments.rs:70:1 + | +LL | / /** This is also a doc comment and should produce a warning +LL | | */ +LL | | +LL | | // This should *NOT* produce a warning +... | +LL | | #[allow(missing_docs)] +LL | | fn three_attributes() { assert!(true) } + | |_ + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/float_arithmetic.rs b/src/tools/clippy/tests/ui/float_arithmetic.rs index 60fa7569eb9..a928c35e8bc 100644 --- a/src/tools/clippy/tests/ui/float_arithmetic.rs +++ b/src/tools/clippy/tests/ui/float_arithmetic.rs @@ -1,4 +1,4 @@ -#![warn(clippy::integer_arithmetic, clippy::float_arithmetic)] +#![warn(clippy::arithmetic_side_effects, clippy::float_arithmetic)] #![allow( unused, clippy::shadow_reuse, diff --git a/src/tools/clippy/tests/ui/integer_arithmetic.rs b/src/tools/clippy/tests/ui/integer_arithmetic.rs deleted file mode 100644 index ab9b6094c2c..00000000000 --- a/src/tools/clippy/tests/ui/integer_arithmetic.rs +++ /dev/null @@ -1,109 +0,0 @@ -//@aux-build:proc_macro_derive.rs - -#![warn(clippy::integer_arithmetic, clippy::float_arithmetic)] -#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::op_ref)] - -extern crate proc_macro_derive; - -#[derive(proc_macro_derive::ShadowDerive)] -pub struct Nothing; - -#[rustfmt::skip] -fn main() { - let mut i = 1i32; - let mut var1 = 13i32; - let mut var2 = -1i32; - 1 + i; - i * 2; - 1 % - i / 2; // no error, this is part of the expression in the preceding line - i - 2 + 2 - i; - -i; - i >> 1; - i << 1; - - // no error, overflows are checked by `overflowing_literals` - -1; - -(-1); - - i & 1; // no wrapping - i | 1; - i ^ 1; - - i += 1; - i -= 1; - i *= 2; - i /= 2; - i /= 0; - i /= -1; - i /= var1; - i /= var2; - i %= 2; - i %= 0; - i %= -1; - i %= var1; - i %= var2; - i <<= 3; - i >>= 2; - - // no errors - i |= 1; - i &= 1; - i ^= i; - - // No errors for the following items because they are constant expressions - enum Foo { - Bar = -2, - } - struct Baz([i32; 1 + 1]); - union Qux { - field: [i32; 1 + 1], - } - type Alias = [i32; 1 + 1]; - - const FOO: i32 = -2; - static BAR: i32 = -2; - - let _: [i32; 1 + 1] = [0, 0]; - - let _: [i32; 1 + 1] = { - let a: [i32; 1 + 1] = [0, 0]; - a - }; - - trait Trait { - const ASSOC: i32 = 1 + 1; - } - - impl Trait for Foo { - const ASSOC: i32 = { - let _: [i32; 1 + 1]; - fn foo() {} - 1 + 1 - }; - } -} - -// warn on references as well! (#5328) -pub fn int_arith_ref() { - 3 + &1; - &3 + 1; - &3 + &1; -} - -pub fn foo(x: &i32) -> i32 { - let a = 5; - a + x -} - -pub fn bar(x: &i32, y: &i32) -> i32 { - x + y -} - -pub fn baz(x: i32, y: &i32) -> i32 { - x + y -} - -pub fn qux(x: i32, y: i32) -> i32 { - (&x + &y) -} diff --git a/src/tools/clippy/tests/ui/integer_arithmetic.stderr b/src/tools/clippy/tests/ui/integer_arithmetic.stderr deleted file mode 100644 index add3b6b90fa..00000000000 --- a/src/tools/clippy/tests/ui/integer_arithmetic.stderr +++ /dev/null @@ -1,169 +0,0 @@ -error: this operation will panic at runtime - --> $DIR/integer_arithmetic.rs:37:5 - | -LL | i /= 0; - | ^^^^^^ attempt to divide `_` by zero - | - = note: `#[deny(unconditional_panic)]` on by default - -error: this operation will panic at runtime - --> $DIR/integer_arithmetic.rs:42:5 - | -LL | i %= 0; - | ^^^^^^ attempt to calculate the remainder of `_` with a divisor of zero - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:16:5 - | -LL | 1 + i; - | ^^^^^ - | - = note: `-D clippy::integer-arithmetic` implied by `-D warnings` - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:17:5 - | -LL | i * 2; - | ^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:18:5 - | -LL | / 1 % -LL | | i / 2; // no error, this is part of the expression in the preceding line - | |_____^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:20:5 - | -LL | i - 2 + 2 - i; - | ^^^^^^^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:21:5 - | -LL | -i; - | ^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:22:5 - | -LL | i >> 1; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:23:5 - | -LL | i << 1; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:33:5 - | -LL | i += 1; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:34:5 - | -LL | i -= 1; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:35:5 - | -LL | i *= 2; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:38:11 - | -LL | i /= -1; - | ^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:39:5 - | -LL | i /= var1; - | ^^^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:40:5 - | -LL | i /= var2; - | ^^^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:43:11 - | -LL | i %= -1; - | ^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:44:5 - | -LL | i %= var1; - | ^^^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:45:5 - | -LL | i %= var2; - | ^^^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:46:5 - | -LL | i <<= 3; - | ^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:47:5 - | -LL | i >>= 2; - | ^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:89:5 - | -LL | 3 + &1; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:90:5 - | -LL | &3 + 1; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:91:5 - | -LL | &3 + &1; - | ^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:96:5 - | -LL | a + x - | ^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:100:5 - | -LL | x + y - | ^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:104:5 - | -LL | x + y - | ^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:108:5 - | -LL | (&x + &y) - | ^^^^^^^^^ - -error: aborting due to 27 previous errors - diff --git a/src/tools/clippy/tests/ui/issue-111399.rs b/src/tools/clippy/tests/ui/issue-111399.rs new file mode 100644 index 00000000000..b65e6c7261a --- /dev/null +++ b/src/tools/clippy/tests/ui/issue-111399.rs @@ -0,0 +1,13 @@ +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +// Check that rustc doesn't crash on the trait bound `Self::Ty: std::marker::Freeze`. + +pub struct Struct; + +impl Struct { + pub type Ty = usize; + pub const CT: Self::Ty = 42; +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/let_underscore_untyped.rs b/src/tools/clippy/tests/ui/let_underscore_untyped.rs index 8486137d3a6..2c313ff35d5 100644 --- a/src/tools/clippy/tests/ui/let_underscore_untyped.rs +++ b/src/tools/clippy/tests/ui/let_underscore_untyped.rs @@ -1,6 +1,12 @@ +//@aux-build: proc_macros.rs + #![allow(unused)] #![warn(clippy::let_underscore_untyped)] +extern crate proc_macros; +use proc_macros::with_span; + +use clippy_utils::is_from_proc_macro; use std::future::Future; use std::{boxed::Box, fmt::Display}; @@ -32,6 +38,14 @@ fn g() -> impl Fn() { || {} } +with_span!( + span + + fn dont_lint_proc_macro() { + let _ = a(); + } +); + fn main() { let _ = a(); let _ = b(1); @@ -40,6 +54,7 @@ fn main() { let _ = e(); let _ = f(); let _ = g(); + let closure = || {}; _ = a(); _ = b(1); diff --git a/src/tools/clippy/tests/ui/let_underscore_untyped.stderr b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr index 6844cb998f7..bbf2508af10 100644 --- a/src/tools/clippy/tests/ui/let_underscore_untyped.stderr +++ b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr @@ -1,60 +1,60 @@ error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:36:5 + --> $DIR/let_underscore_untyped.rs:50:5 | LL | let _ = a(); | ^^^^^^^^^^^^ | help: consider adding a type annotation - --> $DIR/let_underscore_untyped.rs:36:10 + --> $DIR/let_underscore_untyped.rs:50:10 | LL | let _ = a(); | ^ = note: `-D clippy::let-underscore-untyped` implied by `-D warnings` error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:37:5 + --> $DIR/let_underscore_untyped.rs:51:5 | LL | let _ = b(1); | ^^^^^^^^^^^^^ | help: consider adding a type annotation - --> $DIR/let_underscore_untyped.rs:37:10 + --> $DIR/let_underscore_untyped.rs:51:10 | LL | let _ = b(1); | ^ error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:39:5 + --> $DIR/let_underscore_untyped.rs:53:5 | LL | let _ = d(&1); | ^^^^^^^^^^^^^^ | help: consider adding a type annotation - --> $DIR/let_underscore_untyped.rs:39:10 + --> $DIR/let_underscore_untyped.rs:53:10 | LL | let _ = d(&1); | ^ error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:40:5 + --> $DIR/let_underscore_untyped.rs:54:5 | LL | let _ = e(); | ^^^^^^^^^^^^ | help: consider adding a type annotation - --> $DIR/let_underscore_untyped.rs:40:10 + --> $DIR/let_underscore_untyped.rs:54:10 | LL | let _ = e(); | ^ error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:41:5 + --> $DIR/let_underscore_untyped.rs:55:5 | LL | let _ = f(); | ^^^^^^^^^^^^ | help: consider adding a type annotation - --> $DIR/let_underscore_untyped.rs:41:10 + --> $DIR/let_underscore_untyped.rs:55:10 | LL | let _ = f(); | ^ diff --git a/src/tools/clippy/tests/ui/manual_let_else.rs b/src/tools/clippy/tests/ui/manual_let_else.rs index d175597a44a..3996d775f55 100644 --- a/src/tools/clippy/tests/ui/manual_let_else.rs +++ b/src/tools/clippy/tests/ui/manual_let_else.rs @@ -8,6 +8,12 @@ )] #![warn(clippy::manual_let_else)] +enum Variant { + A(usize, usize), + B(usize), + C, +} + fn g() -> Option<()> { None } @@ -135,6 +141,15 @@ fn fire() { }; } create_binding_if_some!(w, g()); + + fn e() -> Variant { + Variant::A(0, 0) + } + + // Should not be renamed + let v = if let Variant::A(a, 0) = e() { a } else { return }; + // Should be renamed + let v = if let Variant::B(b) = e() { b } else { return }; } fn not_fire() { diff --git a/src/tools/clippy/tests/ui/manual_let_else.stderr b/src/tools/clippy/tests/ui/manual_let_else.stderr index 52aac6bc673..f6f56f7b00e 100644 --- a/src/tools/clippy/tests/ui/manual_let_else.stderr +++ b/src/tools/clippy/tests/ui/manual_let_else.stderr @@ -1,13 +1,13 @@ error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:18:5 + --> $DIR/manual_let_else.rs:24:5 | LL | let v = if let Some(v_some) = g() { v_some } else { return }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { return };` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };` | = note: `-D clippy::manual-let-else` implied by `-D warnings` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:19:5 + --> $DIR/manual_let_else.rs:25:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -18,13 +18,13 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + return; LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:25:5 + --> $DIR/manual_let_else.rs:31:5 | LL | / let v = if let Some(v) = g() { LL | | // Blocks around the identity should have no impact @@ -45,25 +45,25 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:38:9 + --> $DIR/manual_let_else.rs:44:9 | LL | let v = if let Some(v_some) = g() { v_some } else { continue }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { continue };` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { continue };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:39:9 + --> $DIR/manual_let_else.rs:45:9 | LL | let v = if let Some(v_some) = g() { v_some } else { break }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { break };` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { break };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:43:5 + --> $DIR/manual_let_else.rs:49:5 | LL | let v = if let Some(v_some) = g() { v_some } else { panic!() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { panic!() };` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { panic!() };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:46:5 + --> $DIR/manual_let_else.rs:52:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -74,13 +74,13 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + std::process::abort() LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:53:5 + --> $DIR/manual_let_else.rs:59:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -91,13 +91,13 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + if true { return } else { panic!() } LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:60:5 + --> $DIR/manual_let_else.rs:66:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -109,14 +109,14 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + if true {} LL + panic!(); LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:70:5 + --> $DIR/manual_let_else.rs:76:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -129,7 +129,7 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + match () { LL + _ if panic!() => {}, LL + _ => panic!(), @@ -138,13 +138,13 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:80:5 + --> $DIR/manual_let_else.rs:86:5 | LL | let v = if let Some(v_some) = g() { v_some } else { if panic!() {} }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { if panic!() {} };` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { if panic!() {} };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:83:5 + --> $DIR/manual_let_else.rs:89:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -157,7 +157,7 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + match panic!() { LL + _ => {}, LL + } @@ -165,7 +165,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:92:5 + --> $DIR/manual_let_else.rs:98:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -178,7 +178,7 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { if true { +LL ~ let Some(v) = g() else { if true { LL + return; LL + } else { LL + panic!("diverge"); @@ -186,7 +186,7 @@ LL + } }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:101:5 + --> $DIR/manual_let_else.rs:107:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -199,7 +199,7 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + match (g(), g()) { LL + (Some(_), None) => return, LL + (None, Some(_)) => { @@ -215,7 +215,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:118:5 + --> $DIR/manual_let_else.rs:124:5 | LL | / let (v, w) = if let Some(v_some) = g().map(|v| (v, 42)) { LL | | v_some @@ -226,13 +226,13 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g().map(|v| (v, 42)) else { +LL ~ let Some((v, w)) = g().map(|v| (v, 42)) else { LL + return; LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:125:5 + --> $DIR/manual_let_else.rs:131:5 | LL | / let v = if let (Some(v_some), w_some) = (g(), 0) { LL | | (w_some, v_some) @@ -249,10 +249,10 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:134:13 + --> $DIR/manual_let_else.rs:140:13 | LL | let $n = if let Some(v) = $e { v } else { return }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some($n) = g() else { return };` ... LL | create_binding_if_some!(w, g()); | ------------------------------- in this macro invocation @@ -260,13 +260,25 @@ LL | create_binding_if_some!(w, g()); = note: this error originates in the macro `create_binding_if_some` (in Nightly builds, run with -Z macro-backtrace for more info) error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:247:5 + --> $DIR/manual_let_else.rs:150:5 + | +LL | let v = if let Variant::A(a, 0) = e() { a } else { return }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(a, 0) = e() else { return };` + +error: this could be rewritten as `let...else` + --> $DIR/manual_let_else.rs:152:5 + | +LL | let v = if let Variant::B(b) = e() { b } else { return }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::B(v) = e() else { return };` + +error: this could be rewritten as `let...else` + --> $DIR/manual_let_else.rs:262:5 | LL | / let _ = match ff { LL | | Some(value) => value, LL | | _ => macro_call!(), LL | | }; - | |______^ help: consider writing: `let Some(value) = ff else { macro_call!() };` + | |______^ help: consider writing: `let Some(_) = ff else { macro_call!() };` -error: aborting due to 18 previous errors +error: aborting due to 20 previous errors diff --git a/src/tools/clippy/tests/ui/manual_let_else_match.stderr b/src/tools/clippy/tests/ui/manual_let_else_match.stderr index 7abaa0b85d2..bacc14dc967 100644 --- a/src/tools/clippy/tests/ui/manual_let_else_match.stderr +++ b/src/tools/clippy/tests/ui/manual_let_else_match.stderr @@ -5,7 +5,7 @@ LL | / let v = match g() { LL | | Some(v_some) => v_some, LL | | None => return, LL | | }; - | |______^ help: consider writing: `let Some(v_some) = g() else { return };` + | |______^ help: consider writing: `let Some(v) = g() else { return };` | = note: `-D clippy::manual-let-else` implied by `-D warnings` @@ -16,7 +16,7 @@ LL | / let v = match g() { LL | | Some(v_some) => v_some, LL | | _ => return, LL | | }; - | |______^ help: consider writing: `let Some(v_some) = g() else { return };` + | |______^ help: consider writing: `let Some(v) = g() else { return };` error: this could be rewritten as `let...else` --> $DIR/manual_let_else_match.rs:44:9 diff --git a/src/tools/clippy/tests/ui/manual_next_back.fixed b/src/tools/clippy/tests/ui/manual_next_back.fixed new file mode 100644 index 00000000000..e8a47063ad6 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_next_back.fixed @@ -0,0 +1,36 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::manual_next_back)] + +struct FakeIter(std::ops::Range<i32>); + +impl FakeIter { + fn rev(self) -> Self { + self + } + + fn next(&self) {} +} + +impl DoubleEndedIterator for FakeIter { + fn next_back(&mut self) -> Option<Self::Item> { + self.0.next_back() + } +} + +impl Iterator for FakeIter { + type Item = i32; + fn next(&mut self) -> Option<Self::Item> { + self.0.next() + } +} + +fn main() { + // should not lint + FakeIter(0..10).rev().next(); + + // should lint + let _ = (0..10).next_back().unwrap(); + let _ = "something".bytes().next_back(); +} diff --git a/src/tools/clippy/tests/ui/manual_next_back.rs b/src/tools/clippy/tests/ui/manual_next_back.rs new file mode 100644 index 00000000000..9ec89242241 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_next_back.rs @@ -0,0 +1,36 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::manual_next_back)] + +struct FakeIter(std::ops::Range<i32>); + +impl FakeIter { + fn rev(self) -> Self { + self + } + + fn next(&self) {} +} + +impl DoubleEndedIterator for FakeIter { + fn next_back(&mut self) -> Option<Self::Item> { + self.0.next_back() + } +} + +impl Iterator for FakeIter { + type Item = i32; + fn next(&mut self) -> Option<Self::Item> { + self.0.next() + } +} + +fn main() { + // should not lint + FakeIter(0..10).rev().next(); + + // should lint + let _ = (0..10).rev().next().unwrap(); + let _ = "something".bytes().rev().next(); +} diff --git a/src/tools/clippy/tests/ui/manual_next_back.stderr b/src/tools/clippy/tests/ui/manual_next_back.stderr new file mode 100644 index 00000000000..94ccaa9e4cc --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_next_back.stderr @@ -0,0 +1,16 @@ +error: manual backwards iteration + --> $DIR/manual_next_back.rs:34:20 + | +LL | let _ = (0..10).rev().next().unwrap(); + | ^^^^^^^^^^^^^ help: use: `.next_back()` + | + = note: `-D clippy::manual-next-back` implied by `-D warnings` + +error: manual backwards iteration + --> $DIR/manual_next_back.rs:35:32 + | +LL | let _ = "something".bytes().rev().next(); + | ^^^^^^^^^^^^^ help: use: `.next_back()` + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed index 7215660da67..60f59066173 100644 --- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed +++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed @@ -15,7 +15,7 @@ fn main() { let _y = matches!(x, Some(0)); // Lint - let _w = matches!(x, Some(_)); + let _w = x.is_some(); // Turn into is_none let _z = x.is_none(); diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr index 46f67ef4900..b72fe10b748 100644 --- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr +++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr @@ -10,7 +10,7 @@ LL | | }; | = note: `-D clippy::match-like-matches-macro` implied by `-D warnings` -error: match expression looks like `matches!` macro +error: redundant pattern matching, consider using `is_some()` --> $DIR/match_expr_like_matches_macro.rs:21:14 | LL | let _w = match x { @@ -18,7 +18,9 @@ LL | let _w = match x { LL | | Some(_) => true, LL | | _ => false, LL | | }; - | |_____^ help: try this: `matches!(x, Some(_))` + | |_____^ help: try this: `x.is_some()` + | + = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_none()` --> $DIR/match_expr_like_matches_macro.rs:27:14 @@ -29,8 +31,6 @@ LL | | Some(_) => false, LL | | None => true, LL | | }; | |_____^ help: try this: `x.is_none()` - | - = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:33:15 diff --git a/src/tools/clippy/tests/ui/match_same_arms.rs b/src/tools/clippy/tests/ui/match_same_arms.rs index 0b9342c9c42..3914b45464c 100644 --- a/src/tools/clippy/tests/ui/match_same_arms.rs +++ b/src/tools/clippy/tests/ui/match_same_arms.rs @@ -53,4 +53,84 @@ mod issue4244 { } } -fn main() {} +macro_rules! m { + (foo) => {}; + (bar) => {}; +} +macro_rules! foo { + () => { + 1 + }; +} +macro_rules! bar { + () => { + 1 + }; +} + +fn main() { + let x = 0; + let _ = match 0 { + 0 => { + m!(foo); + x + }, + 1 => { + m!(bar); + x + }, + _ => 1, + }; + + let _ = match 0 { + 0 => { + m!(foo); + 0 + }, + 1 => { + m!(bar); + 0 + }, + _ => 1, + }; + + let _ = match 0 { + 0 => { + let mut x = 0; + #[cfg(not_enabled)] + { + x = 5; + } + #[cfg(not(not_enabled))] + { + x = 6; + } + x + }, + 1 => { + let mut x = 0; + #[cfg(also_not_enabled)] + { + x = 5; + } + #[cfg(not(also_not_enabled))] + { + x = 6; + } + x + }, + _ => 0, + }; + + let _ = match 0 { + 0 => foo!(), + 1 => bar!(), + _ => 1, + }; + + let _ = match 0 { + 0 => cfg!(not_enabled), + 1 => cfg!(also_not_enabled), + _ => false, + }; +} diff --git a/src/tools/clippy/tests/ui/match_same_arms2.rs b/src/tools/clippy/tests/ui/match_same_arms2.rs index 82b2c433d99..60b2975be04 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.rs +++ b/src/tools/clippy/tests/ui/match_same_arms2.rs @@ -239,4 +239,10 @@ fn main() { 3 => core::convert::identity::<u32>(todo!()), _ => 5, }; + + let _ = match 0 { + 0 => cfg!(not_enable), + 1 => cfg!(not_enable), + _ => false, + }; } diff --git a/src/tools/clippy/tests/ui/match_same_arms2.stderr b/src/tools/clippy/tests/ui/match_same_arms2.stderr index 06cd4300054..8fb461bd286 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.stderr +++ b/src/tools/clippy/tests/ui/match_same_arms2.stderr @@ -192,5 +192,20 @@ note: other arm here LL | Some(Bar { x: 0, y: 5, .. }) => 1, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 12 previous errors +error: this match arm has an identical body to another arm + --> $DIR/match_same_arms2.rs:245:9 + | +LL | 1 => cfg!(not_enable), + | -^^^^^^^^^^^^^^^^^^^^ + | | + | help: try merging the arm patterns: `1 | 0` + | + = help: or try changing either arm body +note: other arm here + --> $DIR/match_same_arms2.rs:244:9 + | +LL | 0 => cfg!(not_enable), + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/mem_forget.rs b/src/tools/clippy/tests/ui/mem_forget.rs index 5137448a6d4..edb9d87d032 100644 --- a/src/tools/clippy/tests/ui/mem_forget.rs +++ b/src/tools/clippy/tests/ui/mem_forget.rs @@ -5,7 +5,7 @@ use std::mem as memstuff; use std::mem::forget as forgetSomething; #[warn(clippy::mem_forget)] -#[allow(forget_copy)] +#[allow(forgetting_copy_types)] fn main() { let five: i32 = 5; forgetSomething(five); diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs index f28153e56b0..4ef6f0ca92f 100644 --- a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs +++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs @@ -2,7 +2,7 @@ #![allow(unused)] #![allow(deref_nullptr)] #![allow(clippy::unnecessary_operation)] -#![allow(drop_copy)] +#![allow(dropping_copy_types)] #![warn(clippy::multiple_unsafe_ops_per_block)] extern crate proc_macros; diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.fixed b/src/tools/clippy/tests/ui/needless_bool/fixable.fixed index f860852e7b7..bf1911881c8 100644 --- a/src/tools/clippy/tests/ui/needless_bool/fixable.fixed +++ b/src/tools/clippy/tests/ui/needless_bool/fixable.fixed @@ -63,6 +63,13 @@ fn main() { needless_bool2(x); needless_bool3(x); needless_bool_condition(); + + if a == b { + true + } else { + // Do not lint as this comment might be important + false + }; } fn bool_ret3(x: bool) -> bool { diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.rs b/src/tools/clippy/tests/ui/needless_bool/fixable.rs index 6680dab5b6d..a6c465d4fbd 100644 --- a/src/tools/clippy/tests/ui/needless_bool/fixable.rs +++ b/src/tools/clippy/tests/ui/needless_bool/fixable.rs @@ -99,6 +99,13 @@ fn main() { needless_bool2(x); needless_bool3(x); needless_bool_condition(); + + if a == b { + true + } else { + // Do not lint as this comment might be important + false + }; } fn bool_ret3(x: bool) -> bool { diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr index d2c48376f76..fa906374fb3 100644 --- a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr +++ b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr @@ -91,7 +91,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a < b` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:105:5 + --> $DIR/fixable.rs:112:5 | LL | / if x { LL | | return true; @@ -101,7 +101,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:113:5 + --> $DIR/fixable.rs:120:5 | LL | / if x { LL | | return false; @@ -111,7 +111,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:121:5 + --> $DIR/fixable.rs:128:5 | LL | / if x && y { LL | | return true; @@ -121,7 +121,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x && y` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:129:5 + --> $DIR/fixable.rs:136:5 | LL | / if x && y { LL | | return false; @@ -131,7 +131,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !(x && y)` error: equality checks against true are unnecessary - --> $DIR/fixable.rs:137:8 + --> $DIR/fixable.rs:144:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` @@ -139,25 +139,25 @@ LL | if x == true {}; = note: `-D clippy::bool-comparison` implied by `-D warnings` error: equality checks against false can be replaced by a negation - --> $DIR/fixable.rs:141:8 + --> $DIR/fixable.rs:148:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: equality checks against true are unnecessary - --> $DIR/fixable.rs:151:8 + --> $DIR/fixable.rs:158:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` error: equality checks against false can be replaced by a negation - --> $DIR/fixable.rs:152:8 + --> $DIR/fixable.rs:159:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:161:12 + --> $DIR/fixable.rs:168:12 | LL | } else if returns_bool() { | ____________^ @@ -168,7 +168,7 @@ LL | | }; | |_____^ help: you can reduce it to: `{ !returns_bool() }` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:174:5 + --> $DIR/fixable.rs:181:5 | LL | / if unsafe { no(4) } & 1 != 0 { LL | | true @@ -178,13 +178,13 @@ LL | | }; | |_____^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:179:30 + --> $DIR/fixable.rs:186:30 | LL | let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `unsafe { no(4) } & 1 != 0` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:182:9 + --> $DIR/fixable.rs:189:9 | LL | if unsafe { no(4) } & 1 != 0 { true } else { false } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)` diff --git a/src/tools/clippy/tests/ui/needless_collect.fixed b/src/tools/clippy/tests/ui/needless_collect.fixed index 024c22de225..b7e80af5015 100644 --- a/src/tools/clippy/tests/ui/needless_collect.fixed +++ b/src/tools/clippy/tests/ui/needless_collect.fixed @@ -62,4 +62,16 @@ fn main() { let _ = sample.iter().next().is_none(); let _ = sample.iter().any(|x| x == &0); + + #[allow(clippy::double_parens)] + { + Vec::<u8>::new().extend((0..10)); + foo((0..10)); + bar((0..10).collect::<Vec<_>>(), (0..10)); + baz((0..10), (), ('a'..='z')) + } } + +fn foo(_: impl IntoIterator<Item = usize>) {} +fn bar<I: IntoIterator<Item = usize>>(_: Vec<usize>, _: I) {} +fn baz<I: IntoIterator<Item = usize>>(_: I, _: (), _: impl IntoIterator<Item = char>) {} diff --git a/src/tools/clippy/tests/ui/needless_collect.rs b/src/tools/clippy/tests/ui/needless_collect.rs index 7ed7babec30..680b6fa5b55 100644 --- a/src/tools/clippy/tests/ui/needless_collect.rs +++ b/src/tools/clippy/tests/ui/needless_collect.rs @@ -62,4 +62,16 @@ fn main() { let _ = sample.iter().collect::<VecWrapper<_>>().is_empty(); let _ = sample.iter().collect::<VecWrapper<_>>().contains(&&0); + + #[allow(clippy::double_parens)] + { + Vec::<u8>::new().extend((0..10).collect::<Vec<_>>()); + foo((0..10).collect::<Vec<_>>()); + bar((0..10).collect::<Vec<_>>(), (0..10).collect::<Vec<_>>()); + baz((0..10), (), ('a'..='z').collect::<Vec<_>>()) + } } + +fn foo(_: impl IntoIterator<Item = usize>) {} +fn bar<I: IntoIterator<Item = usize>>(_: Vec<usize>, _: I) {} +fn baz<I: IntoIterator<Item = usize>>(_: I, _: (), _: impl IntoIterator<Item = char>) {} diff --git a/src/tools/clippy/tests/ui/needless_collect.stderr b/src/tools/clippy/tests/ui/needless_collect.stderr index 584d2a1d835..ad22a7b057e 100644 --- a/src/tools/clippy/tests/ui/needless_collect.stderr +++ b/src/tools/clippy/tests/ui/needless_collect.stderr @@ -90,5 +90,29 @@ error: avoid using `collect()` when not needed LL | let _ = sample.iter().collect::<VecWrapper<_>>().contains(&&0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == &0)` -error: aborting due to 15 previous errors +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:68:40 + | +LL | Vec::<u8>::new().extend((0..10).collect::<Vec<_>>()); + | ^^^^^^^^^^^^^^^^^^^^ help: remove this call + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:69:20 + | +LL | foo((0..10).collect::<Vec<_>>()); + | ^^^^^^^^^^^^^^^^^^^^ help: remove this call + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:70:49 + | +LL | bar((0..10).collect::<Vec<_>>(), (0..10).collect::<Vec<_>>()); + | ^^^^^^^^^^^^^^^^^^^^ help: remove this call + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:71:37 + | +LL | baz((0..10), (), ('a'..='z').collect::<Vec<_>>()) + | ^^^^^^^^^^^^^^^^^^^^ help: remove this call + +error: aborting due to 19 previous errors diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed index ee4e5007dc5..d49ae5d8636 100644 --- a/src/tools/clippy/tests/ui/needless_return.fixed +++ b/src/tools/clippy/tests/ui/needless_return.fixed @@ -231,8 +231,9 @@ fn needless_return_macro() -> String { } fn issue_9361() -> i32 { - #[allow(clippy::integer_arithmetic)] - return 1 + 2; + let n = 1; + #[allow(clippy::arithmetic_side_effects)] + return n + n; } fn issue8336(x: i32) -> bool { diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs index cd999db4f40..36763826174 100644 --- a/src/tools/clippy/tests/ui/needless_return.rs +++ b/src/tools/clippy/tests/ui/needless_return.rs @@ -239,8 +239,9 @@ fn needless_return_macro() -> String { } fn issue_9361() -> i32 { - #[allow(clippy::integer_arithmetic)] - return 1 + 2; + let n = 1; + #[allow(clippy::arithmetic_side_effects)] + return n + n; } fn issue8336(x: i32) -> bool { diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr index 87d0cd3e14c..05f6038cd25 100644 --- a/src/tools/clippy/tests/ui/needless_return.stderr +++ b/src/tools/clippy/tests/ui/needless_return.stderr @@ -328,7 +328,7 @@ LL | return format!("Hello {}", "world!"); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:249:9 + --> $DIR/needless_return.rs:250:9 | LL | return true; | ^^^^^^^^^^^ @@ -336,7 +336,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:251:9 + --> $DIR/needless_return.rs:252:9 | LL | return false; | ^^^^^^^^^^^^ @@ -344,7 +344,7 @@ LL | return false; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:258:13 + --> $DIR/needless_return.rs:259:13 | LL | return 10; | ^^^^^^^^^ @@ -352,7 +352,7 @@ LL | return 10; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:261:13 + --> $DIR/needless_return.rs:262:13 | LL | return 100; | ^^^^^^^^^^ @@ -360,7 +360,7 @@ LL | return 100; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:269:9 + --> $DIR/needless_return.rs:270:9 | LL | return 0; | ^^^^^^^^ @@ -368,7 +368,7 @@ LL | return 0; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:276:13 + --> $DIR/needless_return.rs:277:13 | LL | return *(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -376,7 +376,7 @@ LL | return *(x as *const isize); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:278:13 + --> $DIR/needless_return.rs:279:13 | LL | return !*(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -384,7 +384,7 @@ LL | return !*(x as *const isize); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:285:20 + --> $DIR/needless_return.rs:286:20 | LL | let _ = 42; | ____________________^ @@ -395,7 +395,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:292:20 + --> $DIR/needless_return.rs:293:20 | LL | let _ = 42; return; | ^^^^^^^ @@ -403,7 +403,7 @@ LL | let _ = 42; return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:304:9 + --> $DIR/needless_return.rs:305:9 | LL | return Ok(format!("ok!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -411,7 +411,7 @@ LL | return Ok(format!("ok!")); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:306:9 + --> $DIR/needless_return.rs:307:9 | LL | return Err(format!("err!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -419,7 +419,7 @@ LL | return Err(format!("err!")); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:312:9 + --> $DIR/needless_return.rs:313:9 | LL | return if true { 1 } else { 2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -427,7 +427,7 @@ LL | return if true { 1 } else { 2 }; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:316:9 + --> $DIR/needless_return.rs:317:9 | LL | return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg.fixed b/src/tools/clippy/tests/ui/non_minimal_cfg.fixed new file mode 100644 index 00000000000..430caafb33e --- /dev/null +++ b/src/tools/clippy/tests/ui/non_minimal_cfg.fixed @@ -0,0 +1,17 @@ +//@run-rustfix + +#![allow(unused)] + +#[cfg(windows)] +fn hermit() {} + +#[cfg(windows)] +fn wasi() {} + +#[cfg(all(unix, not(windows)))] +fn the_end() {} + +#[cfg(any())] +fn any() {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg.rs b/src/tools/clippy/tests/ui/non_minimal_cfg.rs new file mode 100644 index 00000000000..a38ce1c21d6 --- /dev/null +++ b/src/tools/clippy/tests/ui/non_minimal_cfg.rs @@ -0,0 +1,17 @@ +//@run-rustfix + +#![allow(unused)] + +#[cfg(all(windows))] +fn hermit() {} + +#[cfg(any(windows))] +fn wasi() {} + +#[cfg(all(any(unix), all(not(windows))))] +fn the_end() {} + +#[cfg(any())] +fn any() {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg.stderr b/src/tools/clippy/tests/ui/non_minimal_cfg.stderr new file mode 100644 index 00000000000..cdfd728aa61 --- /dev/null +++ b/src/tools/clippy/tests/ui/non_minimal_cfg.stderr @@ -0,0 +1,28 @@ +error: unneeded sub `cfg` when there is only one condition + --> $DIR/non_minimal_cfg.rs:5:7 + | +LL | #[cfg(all(windows))] + | ^^^^^^^^^^^^ help: try: `windows` + | + = note: `-D clippy::non-minimal-cfg` implied by `-D warnings` + +error: unneeded sub `cfg` when there is only one condition + --> $DIR/non_minimal_cfg.rs:8:7 + | +LL | #[cfg(any(windows))] + | ^^^^^^^^^^^^ help: try: `windows` + +error: unneeded sub `cfg` when there is only one condition + --> $DIR/non_minimal_cfg.rs:11:11 + | +LL | #[cfg(all(any(unix), all(not(windows))))] + | ^^^^^^^^^ help: try: `unix` + +error: unneeded sub `cfg` when there is only one condition + --> $DIR/non_minimal_cfg.rs:11:22 + | +LL | #[cfg(all(any(unix), all(not(windows))))] + | ^^^^^^^^^^^^^^^^^ help: try: `not(windows)` + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg2.rs b/src/tools/clippy/tests/ui/non_minimal_cfg2.rs new file mode 100644 index 00000000000..a4c6abce387 --- /dev/null +++ b/src/tools/clippy/tests/ui/non_minimal_cfg2.rs @@ -0,0 +1,6 @@ +#![allow(unused)] + +#[cfg(all())] +fn all() {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg2.stderr b/src/tools/clippy/tests/ui/non_minimal_cfg2.stderr new file mode 100644 index 00000000000..2a9a36fbcef --- /dev/null +++ b/src/tools/clippy/tests/ui/non_minimal_cfg2.stderr @@ -0,0 +1,10 @@ +error: unneeded sub `cfg` when there is no condition + --> $DIR/non_minimal_cfg2.rs:3:7 + | +LL | #[cfg(all())] + | ^^^^^ + | + = note: `-D clippy::non-minimal-cfg` implied by `-D warnings` + +error: aborting due to previous error + 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 57f341e0276..2b8ce5477cc 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.fixed +++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed @@ -92,6 +92,15 @@ fn pattern_to_vec(pattern: &str) -> Vec<String> { .collect::<Vec<_>>() } +// #10335 +fn test_result_impure_else(variable: Result<u32, &str>) { + variable.map_or_else(|_| { + println!("Err"); + }, |binding| { + println!("Ok {binding}"); + }) +} + enum DummyEnum { One(u8), Two, @@ -113,6 +122,7 @@ fn main() { unop_bad(&None, None); let _ = longer_body(None); test_map_or_else(None); + test_result_impure_else(Ok(42)); let _ = negative_tests(None); let _ = impure_else(None); 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 19f9f704517..cfbec8cb27d 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.rs +++ b/src/tools/clippy/tests/ui/option_if_let_else.rs @@ -115,6 +115,15 @@ fn pattern_to_vec(pattern: &str) -> Vec<String> { .collect::<Vec<_>>() } +// #10335 +fn test_result_impure_else(variable: Result<u32, &str>) { + if let Ok(binding) = variable { + println!("Ok {binding}"); + } else { + println!("Err"); + } +} + enum DummyEnum { One(u8), Two, @@ -136,6 +145,7 @@ fn main() { unop_bad(&None, None); let _ = longer_body(None); test_map_or_else(None); + test_result_impure_else(Ok(42)); let _ = negative_tests(None); let _ = impure_else(None); 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 f5e4affb672..91d52fc79b8 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.stderr +++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr @@ -152,14 +152,33 @@ LL | | vec![s.to_string()] 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 + --> $DIR/option_if_let_else.rs:120:5 + | +LL | / if let Ok(binding) = variable { +LL | | println!("Ok {binding}"); +LL | | } else { +LL | | println!("Err"); +LL | | } + | |_____^ + | +help: try + | +LL ~ variable.map_or_else(|_| { +LL + println!("Err"); +LL + }, |binding| { +LL + println!("Ok {binding}"); +LL + }) + | + error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:133:13 + --> $DIR/option_if_let_else.rs:142: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 - --> $DIR/option_if_let_else.rs:142:13 + --> $DIR/option_if_let_else.rs:152:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -181,13 +200,13 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:170:13 + --> $DIR/option_if_let_else.rs:180: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 - --> $DIR/option_if_let_else.rs:174:13 + --> $DIR/option_if_let_else.rs:184:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -207,7 +226,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:213:13 + --> $DIR/option_if_let_else.rs:223:13 | LL | let _ = match s { | _____________^ @@ -217,7 +236,7 @@ LL | | }; | |_____^ help: try: `s.map_or(1, |string| string.len())` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:217:13 + --> $DIR/option_if_let_else.rs:227:13 | LL | let _ = match Some(10) { | _____________^ @@ -227,7 +246,7 @@ LL | | }; | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:223:13 + --> $DIR/option_if_let_else.rs:233:13 | LL | let _ = match res { | _____________^ @@ -237,7 +256,7 @@ LL | | }; | |_____^ help: try: `res.map_or(1, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:227:13 + --> $DIR/option_if_let_else.rs:237:13 | LL | let _ = match res { | _____________^ @@ -247,10 +266,10 @@ LL | | }; | |_____^ help: try: `res.map_or(1, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:231:13 + --> $DIR/option_if_let_else.rs:241:13 | LL | let _ = if let Ok(a) = res { a + 1 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)` -error: aborting due to 20 previous errors +error: aborting due to 21 previous errors diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.fixed b/src/tools/clippy/tests/ui/partialeq_to_none.fixed index 81a716bd276..2df87a26d6d 100644 --- a/src/tools/clippy/tests/ui/partialeq_to_none.fixed +++ b/src/tools/clippy/tests/ui/partialeq_to_none.fixed @@ -1,5 +1,6 @@ //@run-rustfix #![warn(clippy::partialeq_to_none)] +#![allow(clippy::eq_op)] struct Foobar; diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.rs b/src/tools/clippy/tests/ui/partialeq_to_none.rs index f454715fa30..df6233b9afd 100644 --- a/src/tools/clippy/tests/ui/partialeq_to_none.rs +++ b/src/tools/clippy/tests/ui/partialeq_to_none.rs @@ -1,5 +1,6 @@ //@run-rustfix #![warn(clippy::partialeq_to_none)] +#![allow(clippy::eq_op)] struct Foobar; diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.stderr b/src/tools/clippy/tests/ui/partialeq_to_none.stderr index d06ab7aee55..4f84862a22b 100644 --- a/src/tools/clippy/tests/ui/partialeq_to_none.stderr +++ b/src/tools/clippy/tests/ui/partialeq_to_none.stderr @@ -1,5 +1,5 @@ error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:14:8 + --> $DIR/partialeq_to_none.rs:15:8 | LL | if f != None { "yay" } else { "nay" } | ^^^^^^^^^ help: use `Option::is_some()` instead: `f.is_some()` @@ -7,55 +7,55 @@ LL | if f != None { "yay" } else { "nay" } = note: `-D clippy::partialeq-to-none` implied by `-D warnings` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:44:13 + --> $DIR/partialeq_to_none.rs:45:13 | LL | let _ = x == None; | ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:45:13 + --> $DIR/partialeq_to_none.rs:46:13 | LL | let _ = x != None; | ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:46:13 + --> $DIR/partialeq_to_none.rs:47:13 | LL | let _ = None == x; | ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:47:13 + --> $DIR/partialeq_to_none.rs:48:13 | LL | let _ = None != x; | ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:49:8 + --> $DIR/partialeq_to_none.rs:50:8 | LL | if foobar() == None {} | ^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `foobar().is_none()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:51:8 + --> $DIR/partialeq_to_none.rs:52:8 | LL | if bar().ok() != None {} | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `bar().ok().is_some()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:53:13 + --> $DIR/partialeq_to_none.rs:54:13 | LL | let _ = Some(1 + 2) != None; | ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `Some(1 + 2).is_some()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:55:13 + --> $DIR/partialeq_to_none.rs:56:13 | LL | let _ = { Some(0) } == None; | ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `{ Some(0) }.is_none()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:57:13 + --> $DIR/partialeq_to_none.rs:58:13 | LL | let _ = { | _____________^ @@ -77,31 +77,31 @@ LL ~ }.is_some(); | error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:67:13 + --> $DIR/partialeq_to_none.rs:68:13 | LL | let _ = optref() == &&None; | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:68:13 + --> $DIR/partialeq_to_none.rs:69:13 | LL | let _ = &&None != optref(); | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:69:13 + --> $DIR/partialeq_to_none.rs:70:13 | LL | let _ = **optref() == None; | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:70:13 + --> $DIR/partialeq_to_none.rs:71:13 | LL | let _ = &None != *optref(); | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:73:13 + --> $DIR/partialeq_to_none.rs:74:13 | LL | let _ = None != *x; | ^^^^^^^^^^ help: use `Option::is_some()` instead: `(*x).is_some()` diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed index d62f7d26a35..accdf1da9dd 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed @@ -46,6 +46,7 @@ fn main() { let _ = if opt.is_some() { true } else { false }; issue6067(); + issue10726(); let _ = if gen_opt().is_some() { 1 @@ -88,3 +89,21 @@ fn issue7921() { if (&None::<()>).is_none() {} if (&None::<()>).is_none() {} } + +fn issue10726() { + let x = Some(42); + + x.is_some(); + + x.is_none(); + + x.is_none(); + + x.is_some(); + + // Don't lint + match x { + Some(21) => true, + _ => false, + }; +} diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs index d6429426573..ec684bdf71c 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs @@ -55,6 +55,7 @@ fn main() { let _ = if let Some(_) = opt { true } else { false }; issue6067(); + issue10726(); let _ = if let Some(_) = gen_opt() { 1 @@ -103,3 +104,33 @@ fn issue7921() { if let None = *(&None::<()>) {} if let None = *&None::<()> {} } + +fn issue10726() { + let x = Some(42); + + match x { + Some(_) => true, + _ => false, + }; + + match x { + None => true, + _ => false, + }; + + match x { + Some(_) => false, + _ => true, + }; + + match x { + None => false, + _ => true, + }; + + // Don't lint + match x { + Some(21) => true, + _ => false, + }; +} diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr index 7c5a047e455..a69eb390520 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr @@ -77,49 +77,49 @@ LL | let _ = if let Some(_) = opt { true } else { false }; | -------^^^^^^^------ help: try this: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:59:20 + --> $DIR/redundant_pattern_matching_option.rs:60:20 | LL | let _ = if let Some(_) = gen_opt() { | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:61:19 + --> $DIR/redundant_pattern_matching_option.rs:62:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try this: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:67:12 + --> $DIR/redundant_pattern_matching_option.rs:68:12 | LL | if let Some(..) = gen_opt() {} | -------^^^^^^^^------------ help: try this: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:82:12 + --> $DIR/redundant_pattern_matching_option.rs:83:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:84:12 + --> $DIR/redundant_pattern_matching_option.rs:85:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try this: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:86:15 + --> $DIR/redundant_pattern_matching_option.rs:87:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:88:15 + --> $DIR/redundant_pattern_matching_option.rs:89:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try this: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:90:5 + --> $DIR/redundant_pattern_matching_option.rs:91:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -128,7 +128,7 @@ LL | | }; | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:95:5 + --> $DIR/redundant_pattern_matching_option.rs:96:5 | LL | / match None::<()> { LL | | Some(_) => false, @@ -137,16 +137,52 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:103:12 + --> $DIR/redundant_pattern_matching_option.rs:104:12 | LL | if let None = *(&None::<()>) {} | -------^^^^----------------- help: try this: `if (&None::<()>).is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:104:12 + --> $DIR/redundant_pattern_matching_option.rs:105:12 | LL | if let None = *&None::<()> {} | -------^^^^--------------- help: try this: `if (&None::<()>).is_none()` -error: aborting due to 22 previous errors +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching_option.rs:111:5 + | +LL | / match x { +LL | | Some(_) => true, +LL | | _ => false, +LL | | }; + | |_____^ help: try this: `x.is_some()` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching_option.rs:116:5 + | +LL | / match x { +LL | | None => true, +LL | | _ => false, +LL | | }; + | |_____^ help: try this: `x.is_none()` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching_option.rs:121:5 + | +LL | / match x { +LL | | Some(_) => false, +LL | | _ => true, +LL | | }; + | |_____^ help: try this: `x.is_none()` + +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching_option.rs:126:5 + | +LL | / match x { +LL | | None => false, +LL | | _ => true, +LL | | }; + | |_____^ help: try this: `x.is_some()` + +error: aborting due to 26 previous errors diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed index c48d1522935..e4032ae44b7 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed @@ -43,6 +43,7 @@ fn main() { issue5504(); issue6067(); issue6065(); + issue10726(); let _ = if gen_res().is_ok() { 1 @@ -107,3 +108,28 @@ const fn issue6067() { Err::<i32, i32>(42).is_err(); } + +fn issue10726() { + // This is optional, but it makes the examples easier + let x: Result<i32, i32> = Ok(42); + + x.is_ok(); + + x.is_err(); + + x.is_err(); + + x.is_ok(); + + // Don't lint + match x { + Err(16) => false, + _ => true, + }; + + // Don't lint + match x { + Ok(16) => false, + _ => true, + }; +} diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs index 26f37d169fa..39eb10df878 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs @@ -55,6 +55,7 @@ fn main() { issue5504(); issue6067(); issue6065(); + issue10726(); let _ = if let Ok(_) = gen_res() { 1 @@ -125,3 +126,40 @@ const fn issue6067() { Err(_) => true, }; } + +fn issue10726() { + // This is optional, but it makes the examples easier + let x: Result<i32, i32> = Ok(42); + + match x { + Ok(_) => true, + _ => false, + }; + + match x { + Ok(_) => false, + _ => true, + }; + + match x { + Err(_) => true, + _ => false, + }; + + match x { + Err(_) => false, + _ => true, + }; + + // Don't lint + match x { + Err(16) => false, + _ => true, + }; + + // Don't lint + match x { + Ok(16) => false, + _ => true, + }; +} diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr index d6a46babb77..5893ae4dcc4 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr @@ -73,67 +73,67 @@ LL | let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false }; | -------^^^^^--------------------- help: try this: `if Ok::<usize, ()>(4).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:59:20 + --> $DIR/redundant_pattern_matching_result.rs:60:20 | LL | let _ = if let Ok(_) = gen_res() { | -------^^^^^------------ help: try this: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:61:19 + --> $DIR/redundant_pattern_matching_result.rs:62:19 | LL | } else if let Err(_) = gen_res() { | -------^^^^^^------------ help: try this: `if gen_res().is_err()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_result.rs:84:19 + --> $DIR/redundant_pattern_matching_result.rs:85:19 | LL | while let Some(_) = r#try!(result_opt()) {} | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_result.rs:85:16 + --> $DIR/redundant_pattern_matching_result.rs:86:16 | LL | if let Some(_) = r#try!(result_opt()) {} | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_result.rs:91:12 + --> $DIR/redundant_pattern_matching_result.rs:92:12 | LL | if let Some(_) = m!() {} | -------^^^^^^^------- help: try this: `if m!().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_result.rs:92:15 + --> $DIR/redundant_pattern_matching_result.rs:93:15 | LL | while let Some(_) = m!() {} | ----------^^^^^^^------- help: try this: `while m!().is_some()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:110:12 + --> $DIR/redundant_pattern_matching_result.rs:111:12 | LL | if let Ok(_) = Ok::<i32, i32>(42) {} | -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:112:12 + --> $DIR/redundant_pattern_matching_result.rs:113:12 | LL | if let Err(_) = Err::<i32, i32>(42) {} | -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:114:15 + --> $DIR/redundant_pattern_matching_result.rs:115:15 | LL | while let Ok(_) = Ok::<i32, i32>(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:116:15 + --> $DIR/redundant_pattern_matching_result.rs:117:15 | LL | while let Err(_) = Ok::<i32, i32>(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:118:5 + --> $DIR/redundant_pattern_matching_result.rs:119:5 | LL | / match Ok::<i32, i32>(42) { LL | | Ok(_) => true, @@ -142,7 +142,7 @@ LL | | }; | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:123:5 + --> $DIR/redundant_pattern_matching_result.rs:124:5 | LL | / match Err::<i32, i32>(42) { LL | | Ok(_) => false, @@ -150,5 +150,41 @@ LL | | Err(_) => true, LL | | }; | |_____^ help: try this: `Err::<i32, i32>(42).is_err()` -error: aborting due to 22 previous errors +error: redundant pattern matching, consider using `is_ok()` + --> $DIR/redundant_pattern_matching_result.rs:134:5 + | +LL | / match x { +LL | | Ok(_) => true, +LL | | _ => false, +LL | | }; + | |_____^ help: try this: `x.is_ok()` + +error: redundant pattern matching, consider using `is_err()` + --> $DIR/redundant_pattern_matching_result.rs:139:5 + | +LL | / match x { +LL | | Ok(_) => false, +LL | | _ => true, +LL | | }; + | |_____^ help: try this: `x.is_err()` + +error: redundant pattern matching, consider using `is_err()` + --> $DIR/redundant_pattern_matching_result.rs:144:5 + | +LL | / match x { +LL | | Err(_) => true, +LL | | _ => false, +LL | | }; + | |_____^ help: try this: `x.is_err()` + +error: redundant pattern matching, consider using `is_ok()` + --> $DIR/redundant_pattern_matching_result.rs:149:5 + | +LL | / match x { +LL | | Err(_) => false, +LL | | _ => true, +LL | | }; + | |_____^ help: try this: `x.is_ok()` + +error: aborting due to 26 previous errors diff --git a/src/tools/clippy/tests/ui/ref_patterns.rs b/src/tools/clippy/tests/ui/ref_patterns.rs new file mode 100644 index 00000000000..c51e0bc76ef --- /dev/null +++ b/src/tools/clippy/tests/ui/ref_patterns.rs @@ -0,0 +1,19 @@ +#![allow(unused)] +#![warn(clippy::ref_patterns)] + +fn use_in_pattern() { + let opt = Some(5); + match opt { + None => {}, + Some(ref opt) => {}, + } +} + +fn use_in_binding() { + let x = 5; + let ref y = x; +} + +fn use_in_parameter(ref x: i32) {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/ref_patterns.stderr b/src/tools/clippy/tests/ui/ref_patterns.stderr new file mode 100644 index 00000000000..aa007782683 --- /dev/null +++ b/src/tools/clippy/tests/ui/ref_patterns.stderr @@ -0,0 +1,27 @@ +error: usage of ref pattern + --> $DIR/ref_patterns.rs:8:14 + | +LL | Some(ref opt) => {}, + | ^^^^^^^ + | + = help: consider using `&` for clarity instead + = note: `-D clippy::ref-patterns` implied by `-D warnings` + +error: usage of ref pattern + --> $DIR/ref_patterns.rs:14:9 + | +LL | let ref y = x; + | ^^^^^ + | + = help: consider using `&` for clarity instead + +error: usage of ref pattern + --> $DIR/ref_patterns.rs:17:21 + | +LL | fn use_in_parameter(ref x: i32) {} + | ^^^^^ + | + = help: consider using `&` for clarity instead + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/regex.rs b/src/tools/clippy/tests/ui/regex.rs index ab8ac97a0e7..a5f79b139bc 100644 --- a/src/tools/clippy/tests/ui/regex.rs +++ b/src/tools/clippy/tests/ui/regex.rs @@ -34,8 +34,10 @@ fn syntax_error() { let set_error = RegexSet::new(&[OPENING_PAREN, r"[a-z]+\.(com|org|net)"]); let bset_error = BRegexSet::new(&[OPENING_PAREN, r"[a-z]+\.(com|org|net)"]); + // These following three cases are considering valid since regex-1.8.0 let raw_string_error = Regex::new(r"[...\/...]"); let raw_string_error = Regex::new(r#"[...\/...]"#); + let _ = Regex::new(r"(?<hi>hi)").unwrap(); let escaped_string_span = Regex::new("\\b\\c"); diff --git a/src/tools/clippy/tests/ui/regex.stderr b/src/tools/clippy/tests/ui/regex.stderr index c2440f39e0a..6b8a772e7f0 100644 --- a/src/tools/clippy/tests/ui/regex.stderr +++ b/src/tools/clippy/tests/ui/regex.stderr @@ -82,23 +82,11 @@ error: regex parse error: LL | let bset_error = BRegexSet::new(&[OPENING_PAREN, r"[a-z]+/.(com|org|net)"]); | ^^^^^^^^^^^^^ -error: regex syntax error: unrecognized escape sequence - --> $DIR/regex.rs:37:45 - | -LL | let raw_string_error = Regex::new(r"[...//...]"); - | ^^ - -error: regex syntax error: unrecognized escape sequence - --> $DIR/regex.rs:38:46 - | -LL | let raw_string_error = Regex::new(r#"[...//...]"#); - | ^^ - error: regex parse error: /b/c ^^ error: unrecognized escape sequence - --> $DIR/regex.rs:40:42 + --> $DIR/regex.rs:42:42 | LL | let escaped_string_span = Regex::new("/b/c"); | ^^^^^^^^ @@ -106,13 +94,13 @@ LL | let escaped_string_span = Regex::new("/b/c"); = help: consider using a raw string literal: `r".."` error: regex syntax error: duplicate flag - --> $DIR/regex.rs:42:34 + --> $DIR/regex.rs:44:34 | LL | let aux_span = Regex::new("(?ixi)"); | ^ ^ error: trivial regex - --> $DIR/regex.rs:46:33 + --> $DIR/regex.rs:48:33 | LL | let trivial_eq = Regex::new("^foobar$"); | ^^^^^^^^^^ @@ -120,7 +108,7 @@ LL | let trivial_eq = Regex::new("^foobar$"); = help: consider using `==` on `str`s error: trivial regex - --> $DIR/regex.rs:48:48 + --> $DIR/regex.rs:50:48 | LL | let trivial_eq_builder = RegexBuilder::new("^foobar$"); | ^^^^^^^^^^ @@ -128,7 +116,7 @@ LL | let trivial_eq_builder = RegexBuilder::new("^foobar$"); = help: consider using `==` on `str`s error: trivial regex - --> $DIR/regex.rs:50:42 + --> $DIR/regex.rs:52:42 | LL | let trivial_starts_with = Regex::new("^foobar"); | ^^^^^^^^^ @@ -136,7 +124,7 @@ LL | let trivial_starts_with = Regex::new("^foobar"); = help: consider using `str::starts_with` error: trivial regex - --> $DIR/regex.rs:52:40 + --> $DIR/regex.rs:54:40 | LL | let trivial_ends_with = Regex::new("foobar$"); | ^^^^^^^^^ @@ -144,7 +132,7 @@ LL | let trivial_ends_with = Regex::new("foobar$"); = help: consider using `str::ends_with` error: trivial regex - --> $DIR/regex.rs:54:39 + --> $DIR/regex.rs:56:39 | LL | let trivial_contains = Regex::new("foobar"); | ^^^^^^^^ @@ -152,7 +140,7 @@ LL | let trivial_contains = Regex::new("foobar"); = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:56:39 + --> $DIR/regex.rs:58:39 | LL | let trivial_contains = Regex::new(NOT_A_REAL_REGEX); | ^^^^^^^^^^^^^^^^ @@ -160,7 +148,7 @@ LL | let trivial_contains = Regex::new(NOT_A_REAL_REGEX); = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:58:40 + --> $DIR/regex.rs:60:40 | LL | let trivial_backslash = Regex::new("a/.b"); | ^^^^^^^ @@ -168,7 +156,7 @@ LL | let trivial_backslash = Regex::new("a/.b"); = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:61:36 + --> $DIR/regex.rs:63:36 | LL | let trivial_empty = Regex::new(""); | ^^ @@ -176,7 +164,7 @@ LL | let trivial_empty = Regex::new(""); = help: the regex is unlikely to be useful as it is error: trivial regex - --> $DIR/regex.rs:63:36 + --> $DIR/regex.rs:65:36 | LL | let trivial_empty = Regex::new("^"); | ^^^ @@ -184,7 +172,7 @@ LL | let trivial_empty = Regex::new("^"); = help: the regex is unlikely to be useful as it is error: trivial regex - --> $DIR/regex.rs:65:36 + --> $DIR/regex.rs:67:36 | LL | let trivial_empty = Regex::new("^$"); | ^^^^ @@ -192,12 +180,12 @@ LL | let trivial_empty = Regex::new("^$"); = help: consider using `str::is_empty` error: trivial regex - --> $DIR/regex.rs:67:44 + --> $DIR/regex.rs:69:44 | LL | let binary_trivial_empty = BRegex::new("^$"); | ^^^^ | = help: consider using `str::is_empty` -error: aborting due to 25 previous errors +error: aborting due to 23 previous errors diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed index 9036f892612..dfe45dec8a7 100644 --- a/src/tools/clippy/tests/ui/rename.fixed +++ b/src/tools/clippy/tests/ui/rename.fixed @@ -16,6 +16,7 @@ #![allow(clippy::mixed_read_write_in_expression)] #![allow(clippy::useless_conversion)] #![allow(clippy::match_result_ok)] +#![allow(clippy::arithmetic_side_effects)] #![allow(clippy::overly_complex_bool_expr)] #![allow(clippy::new_without_default)] #![allow(clippy::bind_instead_of_map)] @@ -29,11 +30,11 @@ #![allow(clippy::invisible_characters)] #![allow(suspicious_double_ref_op)] #![allow(drop_bounds)] -#![allow(drop_copy)] -#![allow(drop_ref)] +#![allow(dropping_copy_types)] +#![allow(dropping_references)] #![allow(for_loops_over_fallibles)] -#![allow(forget_copy)] -#![allow(forget_ref)] +#![allow(forgetting_copy_types)] +#![allow(forgetting_references)] #![allow(array_into_iter)] #![allow(invalid_atomic_ordering)] #![allow(invalid_value)] @@ -58,6 +59,7 @@ #![warn(clippy::mixed_read_write_in_expression)] #![warn(clippy::useless_conversion)] #![warn(clippy::match_result_ok)] +#![warn(clippy::arithmetic_side_effects)] #![warn(clippy::overly_complex_bool_expr)] #![warn(clippy::new_without_default)] #![warn(clippy::bind_instead_of_map)] @@ -75,13 +77,13 @@ #![warn(clippy::invisible_characters)] #![warn(suspicious_double_ref_op)] #![warn(drop_bounds)] -#![warn(drop_copy)] -#![warn(drop_ref)] +#![warn(dropping_copy_types)] +#![warn(dropping_references)] #![warn(for_loops_over_fallibles)] #![warn(for_loops_over_fallibles)] #![warn(for_loops_over_fallibles)] -#![warn(forget_copy)] -#![warn(forget_ref)] +#![warn(forgetting_copy_types)] +#![warn(forgetting_references)] #![warn(array_into_iter)] #![warn(invalid_atomic_ordering)] #![warn(invalid_value)] diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs index 43cabe810f3..ce8eca5a308 100644 --- a/src/tools/clippy/tests/ui/rename.rs +++ b/src/tools/clippy/tests/ui/rename.rs @@ -16,6 +16,7 @@ #![allow(clippy::mixed_read_write_in_expression)] #![allow(clippy::useless_conversion)] #![allow(clippy::match_result_ok)] +#![allow(clippy::arithmetic_side_effects)] #![allow(clippy::overly_complex_bool_expr)] #![allow(clippy::new_without_default)] #![allow(clippy::bind_instead_of_map)] @@ -29,11 +30,11 @@ #![allow(clippy::invisible_characters)] #![allow(suspicious_double_ref_op)] #![allow(drop_bounds)] -#![allow(drop_copy)] -#![allow(drop_ref)] +#![allow(dropping_copy_types)] +#![allow(dropping_references)] #![allow(for_loops_over_fallibles)] -#![allow(forget_copy)] -#![allow(forget_ref)] +#![allow(forgetting_copy_types)] +#![allow(forgetting_references)] #![allow(array_into_iter)] #![allow(invalid_atomic_ordering)] #![allow(invalid_value)] @@ -58,6 +59,7 @@ #![warn(clippy::eval_order_dependence)] #![warn(clippy::identity_conversion)] #![warn(clippy::if_let_some_result)] +#![warn(clippy::integer_arithmetic)] #![warn(clippy::logic_bug)] #![warn(clippy::new_without_default_derive)] #![warn(clippy::option_and_then_some)] diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr index 1ad7cf412c8..3fca60aa2eb 100644 --- a/src/tools/clippy/tests/ui/rename.stderr +++ b/src/tools/clippy/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` - --> $DIR/rename.rs:48:9 + --> $DIR/rename.rs:49:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -7,280 +7,286 @@ LL | #![warn(clippy::almost_complete_letter_range)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> $DIR/rename.rs:49:9 + --> $DIR/rename.rs:50:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:50:9 + --> $DIR/rename.rs:51:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::derive_hash_xor_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` +error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` + --> $DIR/rename.rs:62:9 + | +LL | #![warn(clippy::integer_arithmetic)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` + error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:71:9 + --> $DIR/rename.rs:73:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:72:9 + --> $DIR/rename.rs:74:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:73:9 + --> $DIR/rename.rs:75:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:74:9 + --> $DIR/rename.rs:76:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:75:9 + --> $DIR/rename.rs:77:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` - --> $DIR/rename.rs:76:9 + --> $DIR/rename.rs:78:9 | LL | #![warn(clippy::clone_double_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:77:9 + --> $DIR/rename.rs:79:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` -error: lint `clippy::drop_copy` has been renamed to `drop_copy` - --> $DIR/rename.rs:78:9 +error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` + --> $DIR/rename.rs:80:9 | LL | #![warn(clippy::drop_copy)] - | ^^^^^^^^^^^^^^^^^ help: use the new name: `drop_copy` + | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` -error: lint `clippy::drop_ref` has been renamed to `drop_ref` - --> $DIR/rename.rs:79:9 +error: lint `clippy::drop_ref` has been renamed to `dropping_references` + --> $DIR/rename.rs:81:9 | LL | #![warn(clippy::drop_ref)] - | ^^^^^^^^^^^^^^^^ help: use the new name: `drop_ref` + | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:80:9 + --> $DIR/rename.rs:82:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:81:9 + --> $DIR/rename.rs:83:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:82:9 + --> $DIR/rename.rs:84:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` -error: lint `clippy::forget_copy` has been renamed to `forget_copy` - --> $DIR/rename.rs:83:9 +error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` + --> $DIR/rename.rs:85:9 | LL | #![warn(clippy::forget_copy)] - | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forget_copy` + | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` -error: lint `clippy::forget_ref` has been renamed to `forget_ref` - --> $DIR/rename.rs:84:9 +error: lint `clippy::forget_ref` has been renamed to `forgetting_references` + --> $DIR/rename.rs:86:9 | LL | #![warn(clippy::forget_ref)] - | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forget_ref` + | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:85:9 + --> $DIR/rename.rs:87:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:86:9 + --> $DIR/rename.rs:88:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:87:9 + --> $DIR/rename.rs:89:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> $DIR/rename.rs:88:9 + --> $DIR/rename.rs:90:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:89:9 + --> $DIR/rename.rs:91:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:90:9 + --> $DIR/rename.rs:92:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> $DIR/rename.rs:91:9 + --> $DIR/rename.rs:93:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:92:9 + --> $DIR/rename.rs:94:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:93:9 + --> $DIR/rename.rs:95:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:94:9 + --> $DIR/rename.rs:96:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: aborting due to 47 previous errors +error: aborting due to 48 previous errors diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed index eef8024b131..fdac0e4cb1e 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed @@ -2,6 +2,8 @@ #![deny(clippy::trait_duplication_in_bounds)] #![allow(unused)] +use std::any::Any; + fn bad_foo<T: Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) { unimplemented!(); } @@ -109,4 +111,12 @@ fn qualified_path<T: std::clone::Clone + foo::Clone>(arg0: T) { unimplemented!(); } +fn good_trait_object(arg0: &(dyn Any + Send)) { + unimplemented!(); +} + +fn bad_trait_object(arg0: &(dyn Any + Send)) { + unimplemented!(); +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs index a7a1caf2880..a0300da5555 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs @@ -2,6 +2,8 @@ #![deny(clippy::trait_duplication_in_bounds)] #![allow(unused)] +use std::any::Any; + fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) { unimplemented!(); } @@ -109,4 +111,12 @@ fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) { unimplemented!(); } +fn good_trait_object(arg0: &(dyn Any + Send)) { + unimplemented!(); +} + +fn bad_trait_object(arg0: &(dyn Any + Send + Send)) { + unimplemented!(); +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr index af800ba7888..539b6114ca3 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr @@ -1,5 +1,5 @@ error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:5:15 + --> $DIR/trait_duplication_in_bounds.rs:7:15 | LL | fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` @@ -11,46 +11,52 @@ LL | #![deny(clippy::trait_duplication_in_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: these where clauses contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:11:8 + --> $DIR/trait_duplication_in_bounds.rs:13:8 | LL | T: Clone + Clone + Clone + Copy, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:39:26 + --> $DIR/trait_duplication_in_bounds.rs:41:26 | LL | trait BadSelfTraitBound: Clone + Clone + Clone { | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone` error: these where clauses contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:46:15 + --> $DIR/trait_duplication_in_bounds.rs:48:15 | LL | Self: Clone + Clone + Clone; | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:60:24 + --> $DIR/trait_duplication_in_bounds.rs:62:24 | LL | trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these where clauses contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:67:12 + --> $DIR/trait_duplication_in_bounds.rs:69:12 | LL | T: Clone + Clone + Clone + Copy, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:100:19 + --> $DIR/trait_duplication_in_bounds.rs:102:19 | LL | fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `GenericTrait<u64> + GenericTrait<u32>` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:108:22 + --> $DIR/trait_duplication_in_bounds.rs:110:22 | LL | fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::clone::Clone + foo::Clone` -error: aborting due to 8 previous errors +error: this trait bound is already specified in trait declaration + --> $DIR/trait_duplication_in_bounds.rs:118:33 + | +LL | fn bad_trait_object(arg0: &(dyn Any + Send + Send)) { + | ^^^^^^^^^^^^^^^^^ help: try: `Any + Send` + +error: aborting due to 9 previous errors diff --git a/src/tools/clippy/tests/ui/useless_conversion.fixed b/src/tools/clippy/tests/ui/useless_conversion.fixed index 01eb6c5b080..c16caa38fe9 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.fixed +++ b/src/tools/clippy/tests/ui/useless_conversion.fixed @@ -33,6 +33,11 @@ fn test_issue_3913() -> Result<(), std::io::Error> { Ok(()) } +fn dont_lint_on_type_alias() { + type A = i32; + _ = A::from(0i32); +} + fn dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr() { let text = "foo\r\nbar\n\nbaz\n"; let lines = text.lines(); @@ -106,6 +111,7 @@ fn main() { test_questionmark().unwrap(); test_issue_3913().unwrap(); + dont_lint_on_type_alias(); dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr(); lint_into_iter_on_mutable_local_implementing_iterator_in_expr(); lint_into_iter_on_expr_implementing_iterator(); diff --git a/src/tools/clippy/tests/ui/useless_conversion.rs b/src/tools/clippy/tests/ui/useless_conversion.rs index 34b43a6299b..c75a2bce4ca 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.rs +++ b/src/tools/clippy/tests/ui/useless_conversion.rs @@ -33,6 +33,11 @@ fn test_issue_3913() -> Result<(), std::io::Error> { Ok(()) } +fn dont_lint_on_type_alias() { + type A = i32; + _ = A::from(0i32); +} + fn dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr() { let text = "foo\r\nbar\n\nbaz\n"; let lines = text.lines(); @@ -106,6 +111,7 @@ fn main() { test_questionmark().unwrap(); test_issue_3913().unwrap(); + dont_lint_on_type_alias(); dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr(); lint_into_iter_on_mutable_local_implementing_iterator_in_expr(); lint_into_iter_on_expr_implementing_iterator(); diff --git a/src/tools/clippy/tests/ui/useless_conversion.stderr b/src/tools/clippy/tests/ui/useless_conversion.stderr index be067c6843a..4dca3aac533 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.stderr +++ b/src/tools/clippy/tests/ui/useless_conversion.stderr @@ -23,97 +23,97 @@ LL | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` error: useless conversion to the same type: `std::str::Lines<'_>` - --> $DIR/useless_conversion.rs:45:22 + --> $DIR/useless_conversion.rs:50:22 | LL | if Some("ok") == lines.into_iter().next() {} | ^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `lines` error: useless conversion to the same type: `std::str::Lines<'_>` - --> $DIR/useless_conversion.rs:50:21 + --> $DIR/useless_conversion.rs:55:21 | LL | let mut lines = text.lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()` error: useless conversion to the same type: `std::str::Lines<'_>` - --> $DIR/useless_conversion.rs:56:22 + --> $DIR/useless_conversion.rs:61:22 | LL | if Some("ok") == text.lines().into_iter().next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()` error: useless conversion to the same type: `std::ops::Range<i32>` - --> $DIR/useless_conversion.rs:62:13 + --> $DIR/useless_conversion.rs:67:13 | LL | let _ = NUMBERS.into_iter().next(); | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` error: useless conversion to the same type: `std::ops::Range<i32>` - --> $DIR/useless_conversion.rs:67:17 + --> $DIR/useless_conversion.rs:72:17 | LL | let mut n = NUMBERS.into_iter(); | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:128:21 + --> $DIR/useless_conversion.rs:134:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:129:21 + --> $DIR/useless_conversion.rs:135:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:130:13 + --> $DIR/useless_conversion.rs:136:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:131:13 + --> $DIR/useless_conversion.rs:137:13 | LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` error: useless conversion to the same type: `std::str::Lines<'_>` - --> $DIR/useless_conversion.rs:132:13 + --> $DIR/useless_conversion.rs:138:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` error: useless conversion to the same type: `std::vec::IntoIter<i32>` - --> $DIR/useless_conversion.rs:133:13 + --> $DIR/useless_conversion.rs:139:13 | LL | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:134:21 + --> $DIR/useless_conversion.rs:140:21 | LL | let _: String = format!("Hello {}", "world").into(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")` error: useless conversion to the same type: `i32` - --> $DIR/useless_conversion.rs:139:13 + --> $DIR/useless_conversion.rs:145:13 | LL | let _ = i32::from(a + b) * 3; | ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)` error: useless conversion to the same type: `Foo<'a'>` - --> $DIR/useless_conversion.rs:145:23 + --> $DIR/useless_conversion.rs:151:23 | LL | let _: Foo<'a'> = s2.into(); | ^^^^^^^^^ help: consider removing `.into()`: `s2` error: useless conversion to the same type: `Foo<'a'>` - --> $DIR/useless_conversion.rs:147:13 + --> $DIR/useless_conversion.rs:153:13 | LL | let _ = Foo::<'a'>::from(s3); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing `Foo::<'a'>::from()`: `s3` error: useless conversion to the same type: `std::vec::IntoIter<Foo<'a'>>` - --> $DIR/useless_conversion.rs:149:13 + --> $DIR/useless_conversion.rs:155:13 | LL | let _ = vec![s4, s4, s4].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()` diff --git a/src/tools/clippy/tests/ui/wildcard_imports_cfgtest.rs b/src/tools/clippy/tests/ui/wildcard_imports_cfgtest.rs new file mode 100644 index 00000000000..203c4e15b50 --- /dev/null +++ b/src/tools/clippy/tests/ui/wildcard_imports_cfgtest.rs @@ -0,0 +1,19 @@ +//@compile-flags: --test + +#![warn(clippy::wildcard_imports)] +#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] + +// Test for #10580, the lint should ignore it because of the crate's cfg test flag. + +fn foofoo() {} + +mod outer { + mod inner { + use super::super::*; + fn barbar() { + let _ = foofoo(); + } + } +} + +fn main() {} diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml index 3f8f6a7b98c..c40b71f6ca7 100644 --- a/src/tools/clippy/triagebot.toml +++ b/src/tools/clippy/triagebot.toml @@ -17,9 +17,9 @@ contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIB [assign.owners] "/.github" = ["@flip1995"] +"/book" = ["@flip1995"] "/util/gh-pages" = ["@xFrednet"] "*" = [ - "@flip1995", "@Manishearth", "@llogiq", "@giraffate", diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 0d42504c7f4..e5297d41a61 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -20,6 +20,7 @@ once_cell = "1.16.0" walkdir = "2" glob = "0.3.0" lazycell = "1.3.0" +anyhow = "1" [target.'cfg(unix)'.dependencies] libc = "0.2" diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 4ede4603789..5bc4d164265 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -32,6 +32,7 @@ use std::process::{Child, Command, ExitStatus, Output, Stdio}; use std::str; use std::sync::Arc; +use anyhow::Context; use glob::glob; use once_cell::sync::Lazy; use tracing::*; @@ -131,7 +132,11 @@ pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) { } let cx = TestCx { config: &config, props: &props, testpaths, revision }; - create_dir_all(&cx.output_base_dir()).unwrap(); + create_dir_all(&cx.output_base_dir()) + .with_context(|| { + format!("failed to create output base directory {}", cx.output_base_dir().display()) + }) + .unwrap(); if props.incremental { cx.init_incremental_test(); } diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index 737423a2cd1..7bedb5d48f6 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -184,6 +184,16 @@ dependencies = [ ] [[package]] +name = "ctrlc" +version = "3.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbcf33c2a618cbe41ee43ae6e9f2e48368cd9f9db2896f10167d8d762679f639" +dependencies = [ + "nix", + "windows-sys 0.45.0", +] + +[[package]] name = "diff" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -421,6 +431,7 @@ name = "miri" version = "0.1.0" dependencies = [ "colored", + "ctrlc", "env_logger", "getrandom", "lazy_static", @@ -438,6 +449,18 @@ dependencies = [ ] [[package]] +name = "nix" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +dependencies = [ + "bitflags", + "cfg-if", + "libc", + "static_assertions", +] + +[[package]] name = "object" version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -714,6 +737,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] name = "syn" version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index 5987b0df8d6..683f99ca4de 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -29,6 +29,7 @@ smallvec = "1.7" # for more information. rustc-workspace-hack = "1.0.0" measureme = "10.0.0" +ctrlc = "3.2.5" [target.'cfg(unix)'.dependencies] libc = "0.2" diff --git a/src/tools/miri/cargo-miri/src/arg.rs b/src/tools/miri/cargo-miri/src/arg.rs index e8bac4625f7..d7216060358 100644 --- a/src/tools/miri/cargo-miri/src/arg.rs +++ b/src/tools/miri/cargo-miri/src/arg.rs @@ -40,7 +40,8 @@ impl<'s, I: Iterator<Item = Cow<'s, str>>> Iterator for ArgSplitFlagValue<'_, I> if arg == "--" { // Stop searching at `--`. self.args = None; - return None; + // But yield the `--` so that it does not get lost! + return Some(Err(Cow::Borrowed("--"))); } // These branches cannot be merged if we want to avoid the allocation in the `Borrowed` branch. match &arg { @@ -79,9 +80,8 @@ impl<'a, I: Iterator<Item = String> + 'a> ArgSplitFlagValue<'a, I> { ) -> impl Iterator<Item = Result<String, String>> + 'a { ArgSplitFlagValue::new(args.map(Cow::Owned), name).map(|x| { match x { - Ok(Cow::Owned(s)) => Ok(s), - Err(Cow::Owned(s)) => Err(s), - _ => panic!("iterator converted owned to borrowed"), + Ok(s) => Ok(s.into_owned()), + Err(s) => Err(s.into_owned()), } }) } diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index 37f66d0033f..465e4a1b2d2 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -113,30 +113,17 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) { }; let metadata = get_cargo_metadata(); let mut cmd = cargo(); - cmd.arg(cargo_cmd); - - // Forward all arguments before `--` other than `--target-dir` and its value to Cargo. - // (We want to *change* the target-dir value, so we must not forward it.) - let mut target_dir = None; - for arg in ArgSplitFlagValue::from_string_iter(&mut args, "--target-dir") { - match arg { - Ok(value) => { - if target_dir.is_some() { - show_error!("`--target-dir` is provided more than once"); - } - target_dir = Some(value.into()); - } - Err(arg) => { - cmd.arg(arg); - } - } + cmd.arg(&cargo_cmd); + // In nextest we have to also forward the main `verb`. + if cargo_cmd == "nextest" { + cmd.arg( + args.next() + .unwrap_or_else(|| show_error!("`cargo miri nextest` expects a verb (e.g. `run`)")), + ); } - // Detect the target directory if it's not specified via `--target-dir`. - // (`cargo metadata` does not support `--target-dir`, that's why we have to handle this ourselves.) - let target_dir = target_dir.get_or_insert_with(|| metadata.target_directory.clone()); - // Set `--target-dir` to `miri` inside the original target directory. - target_dir.push("miri"); - cmd.arg("--target-dir").arg(target_dir); + // We set the following flags *before* forwarding more arguments. + // This is needed to fix <https://github.com/rust-lang/miri/issues/2829>: cargo will stop + // interpreting things as flags when it sees the first positional argument. // Make sure the build target is explicitly set. // This is needed to make the `target.runner` settings do something, @@ -154,8 +141,23 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) { cmd.arg("--config") .arg(format!("target.'cfg(all())'.runner=[{cargo_miri_path_for_toml}, 'runner']")); - // Forward all further arguments after `--` to cargo. - cmd.arg("--").args(args); + // Set `--target-dir` to `miri` inside the original target directory. + let mut target_dir = match get_arg_flag_value("--target-dir") { + Some(dir) => PathBuf::from(dir), + None => metadata.target_directory.clone().into_std_path_buf(), + }; + target_dir.push("miri"); + cmd.arg("--target-dir").arg(target_dir); + + // *After* we set all the flags that need setting, forward everything else. Make sure to skip + // `--target-dir` (which would otherwise be set twice). + for arg in + ArgSplitFlagValue::from_string_iter(&mut args, "--target-dir").filter_map(Result::err) + { + cmd.arg(arg); + } + // Forward all further arguments (not consumed by `ArgSplitFlagValue`) to cargo. + cmd.args(args); // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index b450f986149..0bff100dc14 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -69fef92ab2f287f072b66fb7b4f62c8bb4acba43 +8b4b20836b832e91aa605a2faf5e2a55190202c8 diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index e9bbae4d504..d85cac7bcbb 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -3,6 +3,7 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; use std::num::TryFromIntError; +use std::sync::atomic::{AtomicBool, Ordering::Relaxed}; use std::task::Poll; use std::time::{Duration, SystemTime}; @@ -1012,8 +1013,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { /// Run the core interpreter loop. Returns only when an interrupt occurs (an error or program /// termination). fn run_threads(&mut self) -> InterpResult<'tcx, !> { + static SIGNALED: AtomicBool = AtomicBool::new(false); + ctrlc::set_handler(move || { + // Indicate that we have ben signaled to stop. If we were already signaled, exit + // immediately. In our interpreter loop we try to consult this value often, but if for + // whatever reason we don't get to that check or the cleanup we do upon finding that + // this bool has become true takes a long time, the exit here will promptly exit the + // process on the second Ctrl-C. + if SIGNALED.swap(true, Relaxed) { + std::process::exit(1); + } + }) + .unwrap(); let this = self.eval_context_mut(); loop { + if SIGNALED.load(Relaxed) { + this.machine.handle_abnormal_termination(); + std::process::exit(1); + } match this.machine.threads.schedule(&this.machine.clock)? { SchedulingAction::ExecuteStep => { if !this.step()? { diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 32717a0d28b..29f518fe58b 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -713,6 +713,15 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { let def_id = frame.instance.def_id(); def_id.is_local() || self.local_crates.contains(&def_id.krate) } + + /// Called when the interpreter is going to shut down abnormally, such as due to a Ctrl-C. + pub(crate) fn handle_abnormal_termination(&mut self) { + // All strings in the profile data are stored in a single string table which is not + // written to disk until the profiler is dropped. If the interpreter exits without dropping + // the profiler, it is not possible to interpret the profile data and all measureme tools + // will panic when given the file. + drop(self.profiler.take()); + } } impl VisitTags for MiriMachine<'_, '_> { diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index 1e4ab2f0f62..323991249d3 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -102,7 +102,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let ptr_layout = this.layout_of(ptr_ty)?; for (i, ptr) in ptrs.into_iter().enumerate() { - let offset = ptr_layout.size * i.try_into().unwrap(); + let offset = ptr_layout.size.checked_mul(i.try_into().unwrap(), this).unwrap(); let op_place = buf_place.offset(offset, ptr_layout, this)?; diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 44bca3796f9..aa0794c00be 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -166,7 +166,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { 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::integer_arithmetic)] + #[allow(clippy::arithmetic_side_effects)] (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1)) }), ) { @@ -707,7 +707,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { .position(|&c| c == val) { let idx = u64::try_from(idx).unwrap(); - #[allow(clippy::integer_arithmetic)] // idx < num, so this never wraps + #[allow(clippy::arithmetic_side_effects)] // idx < num, so this never wraps let new_ptr = ptr.offset(Size::from_bytes(num - idx - 1), this)?; this.write_pointer(new_ptr, dest)?; } else { @@ -916,10 +916,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let a = this.read_scalar(a)?.to_u64()?; let b = this.read_scalar(b)?.to_u64()?; - #[allow(clippy::integer_arithmetic)] + #[allow(clippy::arithmetic_side_effects)] // adding two u64 and a u8 cannot wrap in a u128 let wide_sum = u128::from(c_in) + u128::from(a) + u128::from(b); - #[allow(clippy::integer_arithmetic)] // it's a u128, we can shift by 64 + #[allow(clippy::arithmetic_side_effects)] // it's a u128, we can shift by 64 let (c_out, sum) = ((wide_sum >> 64).truncate::<u8>(), wide_sum.truncate::<u64>()); let c_out_field = this.place_field(dest, 0)?; diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs index 114c66253f7..1995db715e8 100644 --- a/src/tools/miri/src/shims/intrinsics/simd.rs +++ b/src/tools/miri/src/shims/intrinsics/simd.rs @@ -563,7 +563,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let (op, op_len) = this.operand_to_simd(op)?; let bitmask_len = op_len.max(8); - assert!(dest.layout.ty.is_integral()); + // Returns either an unsigned integer or array of `u8`. + assert!( + dest.layout.ty.is_integral() + || matches!(dest.layout.ty.kind(), ty::Array(elemty, _) if elemty == &this.tcx.types.u8) + ); assert!(bitmask_len <= 64); assert_eq!(bitmask_len, dest.layout.size.bits()); let op_len = u32::try_from(op_len).unwrap(); @@ -577,7 +581,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { .unwrap(); } } - this.write_int(res, dest)?; + // We have to force the place type to be an int so that we can write `res` into it. + let mut dest = this.force_allocation(dest)?; + dest.layout = this.machine.layouts.uint(dest.layout.size).unwrap(); + this.write_int(res, &dest.into())?; } name => throw_unsup_format!("unimplemented intrinsic: `simd_{name}`"), @@ -605,7 +612,7 @@ fn simd_bitmask_index(idx: u32, vec_len: u32, endianness: Endian) -> u32 { assert!(idx < vec_len); match endianness { Endian::Little => idx, - #[allow(clippy::integer_arithmetic)] // idx < vec_len + #[allow(clippy::arithmetic_side_effects)] // idx < vec_len Endian::Big => vec_len - 1 - idx, // reverse order of bits } } diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs index 918efda3777..a423a0786b7 100644 --- a/src/tools/miri/src/shims/mod.rs +++ b/src/tools/miri/src/shims/mod.rs @@ -1,4 +1,4 @@ -#![warn(clippy::integer_arithmetic)] +#![warn(clippy::arithmetic_side_effects)] mod backtrace; #[cfg(target_os = "linux")] diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index 2f24c00ce14..756dec1beca 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -108,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(0) } - #[allow(non_snake_case, clippy::integer_arithmetic)] + #[allow(non_snake_case, clippy::arithmetic_side_effects)] fn GetSystemTimeAsFileTime( &mut self, LPFILETIME_op: &OpTy<'tcx, Provenance>, diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs index 685feeaf892..62bd087e7e8 100644 --- a/src/tools/miri/src/shims/tls.rs +++ b/src/tools/miri/src/shims/tls.rs @@ -56,7 +56,7 @@ impl<'tcx> Default for TlsData<'tcx> { impl<'tcx> TlsData<'tcx> { /// Generate a new TLS key with the given destructor. /// `max_size` determines the integer size the key has to fit in. - #[allow(clippy::integer_arithmetic)] + #[allow(clippy::arithmetic_side_effects)] pub fn create_tls_key( &mut self, dtor: Option<ty::Instance<'tcx>>, diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index abec782b4f0..d1b09cd7b55 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -458,7 +458,7 @@ pub struct DirHandler { } impl DirHandler { - #[allow(clippy::integer_arithmetic)] + #[allow(clippy::arithmetic_side_effects)] fn insert_new(&mut self, read_dir: ReadDir) -> u64 { let id = self.next_id; self.next_id += 1; diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs index ffe3ca69c58..6889c430042 100644 --- a/src/tools/miri/src/shims/unix/linux/sync.rs +++ b/src/tools/miri/src/shims/unix/linux/sync.rs @@ -247,7 +247,7 @@ pub fn futex<'tcx>( // before doing the syscall. this.atomic_fence(AtomicFenceOrd::SeqCst)?; let mut n = 0; - #[allow(clippy::integer_arithmetic)] + #[allow(clippy::arithmetic_side_effects)] for _ in 0..val { if let Some(thread) = this.futex_wake(addr_usize, bitset) { this.unblock_thread(thread); diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index f72ba5cca7a..b8bb7f62452 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -219,7 +219,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { .copied() .scan(Size::ZERO, |a, x| { let res = Some(*a); - *a += x; + *a = a.checked_add(x, this).unwrap(); res }) .collect(); diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs index 8bffa9991c7..d9ae1b22409 100644 --- a/src/tools/miri/src/shims/windows/handle.rs +++ b/src/tools/miri/src/shims/windows/handle.rs @@ -62,7 +62,7 @@ impl Handle { let floor_log2 = variant_count.ilog2(); // we need to add one for non powers of two to compensate for the difference - #[allow(clippy::integer_arithmetic)] // cannot overflow + #[allow(clippy::arithmetic_side_effects)] // cannot overflow if variant_count.is_power_of_two() { floor_log2 } else { floor_log2 + 1 } } @@ -87,7 +87,7 @@ impl Handle { // packs the data into the lower `data_size` bits // and packs the discriminant right above the data - #[allow(clippy::integer_arithmetic)] // cannot overflow + #[allow(clippy::arithmetic_side_effects)] // cannot overflow return discriminant << data_size | data; } @@ -106,11 +106,11 @@ impl Handle { let data_size = u32::BITS.checked_sub(disc_size).unwrap(); // the lower `data_size` bits of this mask are 1 - #[allow(clippy::integer_arithmetic)] // cannot overflow + #[allow(clippy::arithmetic_side_effects)] // cannot overflow let data_mask = 2u32.pow(data_size) - 1; // the discriminant is stored right above the lower `data_size` bits - #[allow(clippy::integer_arithmetic)] // cannot overflow + #[allow(clippy::arithmetic_side_effects)] // cannot overflow let discriminant = handle >> data_size; // the data is stored in the lower `data_size` bits diff --git a/src/tools/miri/test-cargo-miri/run-test.py b/src/tools/miri/test-cargo-miri/run-test.py index 46b3afa70e5..9df90c725e4 100755 --- a/src/tools/miri/test-cargo-miri/run-test.py +++ b/src/tools/miri/test-cargo-miri/run-test.py @@ -108,8 +108,9 @@ def test_cargo_miri_run(): env={'MIRITESTVAR': "wrongval"}, # changing the env var causes a rebuild (re-runs build.rs), # so keep it set ) + # This also covers passing arguments without `--`: Cargo will forward unused positional arguments to the program. test("`cargo miri run` (with arguments and target)", - cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"', r'he\\llo\"world'], + cargo_miri("run") + ["--bin", "cargo-miri-test", "hello world", '"hello world"', r'he\\llo\"world'], "run.args.stdout.ref", "run.args.stderr.ref", ) test("`cargo miri r` (subcrate, no isolation)", diff --git a/src/tools/miri/tests/fail/never_say_never.rs b/src/tools/miri/tests/fail/never_say_never.rs index f6d3dc790bf..fd082e367a8 100644 --- a/src/tools/miri/tests/fail/never_say_never.rs +++ b/src/tools/miri/tests/fail/never_say_never.rs @@ -6,10 +6,8 @@ fn main() { let y = &5; - let x: ! = unsafe { - *(y as *const _ as *const !) //~ ERROR: entering unreachable code - }; - f(x) + let x: ! = unsafe { *(y as *const _ as *const !) }; + f(x) //~ ERROR: entering unreachable code } fn f(x: !) -> ! { diff --git a/src/tools/miri/tests/fail/never_say_never.stderr b/src/tools/miri/tests/fail/never_say_never.stderr index a2a63b8baf5..9d3a8df525a 100644 --- a/src/tools/miri/tests/fail/never_say_never.stderr +++ b/src/tools/miri/tests/fail/never_say_never.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: entering unreachable code --> $DIR/never_say_never.rs:LL:CC | -LL | *(y as *const _ as *const !) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code +LL | f(x) + | ^^^^ entering unreachable code | = 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 diff --git a/src/tools/miri/tests/fail/stacked_borrows/illegal_write2.rs b/src/tools/miri/tests/fail/stacked_borrows/illegal_write2.rs index bf4204c61fd..a5a1930ed65 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_write2.rs +++ b/src/tools/miri/tests/fail/stacked_borrows/illegal_write2.rs @@ -1,4 +1,4 @@ -#![allow(drop_ref)] +#![allow(dropping_references)] fn main() { let target = &mut 42; diff --git a/src/tools/miri/tests/fail/uninit_buffer.rs b/src/tools/miri/tests/fail/uninit_buffer.rs index 8a330058375..d622b2fa7d8 100644 --- a/src/tools/miri/tests/fail/uninit_buffer.rs +++ b/src/tools/miri/tests/fail/uninit_buffer.rs @@ -1,6 +1,6 @@ //@error-in-other-file: memory is uninitialized at [0x4..0x10] -#![allow(drop_copy)] +#![allow(dropping_copy_types)] use std::alloc::{alloc, dealloc, Layout}; use std::slice::from_raw_parts; diff --git a/src/tools/miri/tests/fail/uninit_buffer_with_provenance.rs b/src/tools/miri/tests/fail/uninit_buffer_with_provenance.rs index 443f481c087..ca825901372 100644 --- a/src/tools/miri/tests/fail/uninit_buffer_with_provenance.rs +++ b/src/tools/miri/tests/fail/uninit_buffer_with_provenance.rs @@ -1,7 +1,7 @@ //@error-in-other-file: memory is uninitialized at [0x4..0x8] //@normalize-stderr-test: "a[0-9]+" -> "ALLOC" #![feature(strict_provenance)] -#![allow(drop_copy)] +#![allow(dropping_copy_types)] // Test printing allocations that contain single-byte provenance. diff --git a/src/tools/miri/tests/pass/portable-simd.rs b/src/tools/miri/tests/pass/portable-simd.rs index 173ac654b03..ee67a65a4f9 100644 --- a/src/tools/miri/tests/pass/portable-simd.rs +++ b/src/tools/miri/tests/pass/portable-simd.rs @@ -2,6 +2,10 @@ #![feature(portable_simd, platform_intrinsics)] use std::simd::*; +extern "platform-intrinsic" { + pub(crate) fn simd_bitmask<T, U>(x: T) -> U; +} + fn simd_ops_f32() { let a = f32x4::splat(10.0); let b = f32x4::from_array([1.0, 2.0, 3.0, -4.0]); @@ -208,11 +212,40 @@ fn simd_mask() { assert_eq!(bitmask, 0b1010001101001001); assert_eq!(Mask::<i64, 16>::from_bitmask(bitmask), mask); + // Also directly call intrinsic, to test both kinds of return types. + unsafe { + let bitmask1: u16 = simd_bitmask(mask.to_int()); + let bitmask2: [u8; 2] = simd_bitmask(mask.to_int()); + if cfg!(target_endian = "little") { + assert_eq!(bitmask1, 0b1010001101001001); + assert_eq!(bitmask2, [0b01001001, 0b10100011]); + } else { + // All the bitstrings are reversed compared to above, but the array elements are in the + // same order. + assert_eq!(bitmask1, 0b1001001011000101); + assert_eq!(bitmask2, [0b10010010, 0b11000101]); + } + } + + // Mask less than 8 bits long, which is a special case (padding with 0s). let values = [false, false, false, true]; let mask = Mask::<i64, 4>::from_array(values); let bitmask = mask.to_bitmask(); assert_eq!(bitmask, 0b1000); assert_eq!(Mask::<i64, 4>::from_bitmask(bitmask), mask); + + // Also directly call intrinsic, to test both kinds of return types. + unsafe { + let bitmask1: u8 = simd_bitmask(mask.to_int()); + let bitmask2: [u8; 1] = simd_bitmask(mask.to_int()); + if cfg!(target_endian = "little") { + assert_eq!(bitmask1, 0b1000); + assert_eq!(bitmask2, [0b1000]); + } else { + assert_eq!(bitmask1, 0b0001); + assert_eq!(bitmask2, [0b0001]); + } + } } fn simd_cast() { diff --git a/src/tools/miri/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs b/src/tools/miri/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs index 9f743f0b566..6e13a9ea836 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs +++ b/src/tools/miri/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs @@ -1,7 +1,7 @@ //@compile-flags: -Zmiri-retag-fields // Checks that the test does not run forever (which relies on a fast path). -#![allow(drop_copy)] +#![allow(dropping_copy_types)] fn main() { let array = [(); usize::MAX]; diff --git a/src/tools/replace-version-placeholder/src/main.rs b/src/tools/replace-version-placeholder/src/main.rs index 0aebfc4aad2..5c9c18b9b36 100644 --- a/src/tools/replace-version-placeholder/src/main.rs +++ b/src/tools/replace-version-placeholder/src/main.rs @@ -8,15 +8,13 @@ fn main() { let version_path = root_path.join("src").join("version"); let version_str = t!(std::fs::read_to_string(&version_path), version_path); let version_str = version_str.trim(); - walk::walk( - &root_path, + walk::walk_many( + &[&root_path.join("compiler"), &root_path.join("library")], |path, _is_dir| { walk::filter_dirs(path) // We exempt these as they require the placeholder // for their operation || path.ends_with("compiler/rustc_attr/src/builtin.rs") - || path.ends_with("src/tools/tidy/src/features/version.rs") - || path.ends_with("src/tools/replace-version-placeholder") }, &mut |entry, contents| { if !contents.contains(VERSION_PLACEHOLDER) { diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index e1004c796c5..2e778110931 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -117,6 +117,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "autocfg", "bitflags", "block-buffer", + "byteorder", // via ruzstd in object in thorin-dwp "cc", "cfg-if", "chalk-derive", @@ -217,6 +218,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "rustc-rayon", "rustc-rayon-core", "rustc_version", + "ruzstd", // via object in thorin-dwp "ryu", "scoped-tls", "scopeguard", diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index ee12f4acb10..be3a5d3aa0f 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -35,6 +35,7 @@ const EXTENSION_EXCEPTION_PATHS: &[&str] = &[ "tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment", // more include "tests/ui/unused-crate-deps/test.mk", // why would you use make "tests/ui/proc-macro/auxiliary/included-file.txt", // more include + "tests/ui/invalid/foo.natvis.xml", // sample debugger visualizer ]; fn check_entries(tests_path: &Path, bad: &mut bool) { diff --git a/tests/assembly/option-nonzero-eq.rs b/tests/assembly/option-nonzero-eq.rs new file mode 100644 index 00000000000..f5d88de76dd --- /dev/null +++ b/tests/assembly/option-nonzero-eq.rs @@ -0,0 +1,28 @@ +// revisions: WIN LIN +// [WIN] only-windows +// [LIN] only-linux +// assembly-output: emit-asm +// compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel +// only-x86_64 +// ignore-sgx +// ignore-debug + +use std::cmp::Ordering; + +// CHECK-lABEL: ordering_eq: +#[no_mangle] +pub fn ordering_eq(l: Option<Ordering>, r: Option<Ordering>) -> bool { + // Linux (System V): first two arguments are rdi then rsi + // Windows: first two arguments are rcx then rdx + // Both use rax for the return value. + + // CHECK-NOT: mov + // CHECK-NOT: test + // CHECK-NOT: cmp + + // LIN: cmp dil, sil + // WIN: cmp cl, dl + // CHECK-NEXT: sete al + // CHECK-NEXT: ret + l == r +} diff --git a/tests/codegen/drop-in-place-noalias.rs b/tests/codegen/drop-in-place-noalias.rs new file mode 100644 index 00000000000..725e6fc048d --- /dev/null +++ b/tests/codegen/drop-in-place-noalias.rs @@ -0,0 +1,38 @@ +// compile-flags: -O -C no-prepopulate-passes + +// Tests that the compiler can apply `noalias` and other &mut attributes to `drop_in_place`. +// Note that non-Unpin types should not get `noalias`, matching &mut behavior. + +#![crate_type="lib"] + +use std::marker::PhantomPinned; + +// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructUnpin{{.*}}({{.*\*|ptr}} noalias noundef align 4 dereferenceable(12) %{{.+}}) + +// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructNotUnpin{{.*}}({{.*\*|ptr}} noundef nonnull align 4 %{{.+}}) + +pub struct StructUnpin { + a: i32, + b: i32, + c: i32, +} + +impl Drop for StructUnpin { + fn drop(&mut self) {} +} + +pub struct StructNotUnpin { + a: i32, + b: i32, + c: i32, + p: PhantomPinned, +} + +impl Drop for StructNotUnpin { + fn drop(&mut self) {} +} + +pub unsafe fn main(x: StructUnpin, y: StructNotUnpin) { + drop(x); + drop(y); +} diff --git a/tests/codegen/issues/issue-111603.rs b/tests/codegen/issues/issue-111603.rs new file mode 100644 index 00000000000..90b3c314d2f --- /dev/null +++ b/tests/codegen/issues/issue-111603.rs @@ -0,0 +1,28 @@ +// compile-flags: -O + +#![crate_type = "lib"] +#![feature(get_mut_unchecked, new_uninit)] + +use std::sync::Arc; + +// CHECK-LABEL: @new_uninit +#[no_mangle] +pub fn new_uninit(x: u64) -> Arc<[u64; 1000]> { + // CHECK: call alloc::sync::arcinner_layout_for_value_layout + // CHECK-NOT: call alloc::sync::arcinner_layout_for_value_layout + let mut arc = Arc::new_uninit(); + unsafe { Arc::get_mut_unchecked(&mut arc) }.write([x; 1000]); + unsafe { arc.assume_init() } +} + +// CHECK-LABEL: @new_uninit_slice +#[no_mangle] +pub fn new_uninit_slice(x: u64) -> Arc<[u64]> { + // CHECK: call alloc::sync::arcinner_layout_for_value_layout + // CHECK-NOT: call alloc::sync::arcinner_layout_for_value_layout + let mut arc = Arc::new_uninit_slice(1000); + for elem in unsafe { Arc::get_mut_unchecked(&mut arc) } { + elem.write(x); + } + unsafe { arc.assume_init() } +} diff --git a/tests/codegen/noalias-box-off.rs b/tests/codegen/noalias-box-off.rs index afd17c7c160..c82c53b2a48 100644 --- a/tests/codegen/noalias-box-off.rs +++ b/tests/codegen/noalias-box-off.rs @@ -4,5 +4,8 @@ // CHECK-LABEL: @box_should_not_have_noalias_if_disabled( // CHECK-NOT: noalias +// CHECK-SAME: %foo) #[no_mangle] -pub fn box_should_not_have_noalias_if_disabled(_b: Box<u8>) {} +pub fn box_should_not_have_noalias_if_disabled(foo: Box<u8>) { + drop(foo); +} diff --git a/tests/codegen/option-nonzero-eq.rs b/tests/codegen/option-nonzero-eq.rs index 835decd3e5f..a394695f3bd 100644 --- a/tests/codegen/option-nonzero-eq.rs +++ b/tests/codegen/option-nonzero-eq.rs @@ -7,6 +7,9 @@ use core::cmp::Ordering; use core::num::{NonZeroU32, NonZeroI64}; use core::ptr::NonNull; +// See also tests/assembly/option-nonzero-eq.rs, for cases with `assume`s in the +// LLVM and thus don't optimize down clearly here, but do in assembly. + // CHECK-lABEL: @non_zero_eq #[no_mangle] pub fn non_zero_eq(l: Option<NonZeroU32>, r: Option<NonZeroU32>) -> bool { @@ -33,12 +36,3 @@ pub fn non_null_eq(l: Option<NonNull<u8>>, r: Option<NonNull<u8>>) -> bool { // CHECK-NEXT: ret i1 l == r } - -// CHECK-lABEL: @ordering_eq -#[no_mangle] -pub fn ordering_eq(l: Option<Ordering>, r: Option<Ordering>) -> bool { - // CHECK: start: - // CHECK-NEXT: icmp eq i8 - // CHECK-NEXT: ret i1 - l == r -} diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs b/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs index 71e26e3fe8a..ebb26cd35c0 100644 --- a/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs +++ b/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs @@ -44,7 +44,7 @@ impl<T> Trait1<T> for i32 { } // Trait implementation -impl<T> Trait1<T> for Struct1<T> { +impl<T, U> Trait1<T> for Struct1<U> { fn foo(&self) { } } @@ -536,15 +536,15 @@ pub fn foo149(_: Type14<Bar>, _: Type14<Bar>, _: Type14<Bar>) { } // CHECK: ![[TYPE93]] = !{i64 0, !"_ZTSFvPFu3i32S_EE"} // CHECK: ![[TYPE94]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_E"} // CHECK: ![[TYPE95]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_S0_E"} -// CHECK: ![[TYPE96]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} -// CHECK: ![[TYPE97]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} -// CHECK: ![[TYPE98]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} -// CHECK: ![[TYPE99]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} -// CHECK: ![[TYPE100]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} -// CHECK: ![[TYPE101]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} -// CHECK: ![[TYPE102]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} -// CHECK: ![[TYPE103]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} -// CHECK: ![[TYPE104]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} +// CHECK: ![[TYPE96]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5paramEu6regionEEE"} +// CHECK: ![[TYPE97]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5paramEu6regionEES3_E"} +// CHECK: ![[TYPE98]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5paramEu6regionEES3_S3_E"} +// CHECK: ![[TYPE99]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5paramEu6regionEEE"} +// CHECK: ![[TYPE100]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5paramEu6regionEES3_E"} +// CHECK: ![[TYPE101]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5paramEu6regionEES3_S3_E"} +// CHECK: ![[TYPE102]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5paramEu6regionEEE"} +// CHECK: ![[TYPE103]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5paramEu6regionEES3_E"} +// CHECK: ![[TYPE104]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5paramEu6regionEES3_S3_E"} // CHECK: ![[TYPE105]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"} // CHECK: ![[TYPE106]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_E"} // CHECK: ![[TYPE107]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_S2_E"} @@ -566,9 +566,9 @@ pub fn foo149(_: Type14<Bar>, _: Type14<Bar>, _: Type14<Bar>) { } // CHECK: ![[TYPE123]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32EE"} // CHECK: ![[TYPE124]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_E"} // CHECK: ![[TYPE125]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_S0_E"} -// CHECK: ![[TYPE126]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_EE"} -// CHECK: ![[TYPE127]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_ES3_E"} -// CHECK: ![[TYPE128]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_ES3_S3_E"} +// CHECK: ![[TYPE126]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu5paramEu6regionEu3i32EE"} +// CHECK: ![[TYPE127]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu5paramEu6regionEu3i32ES4_E"} +// CHECK: ![[TYPE128]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu5paramEu6regionEu3i32ES4_S4_E"} // CHECK: ![[TYPE129]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_EE"} // CHECK: ![[TYPE130]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_ES0_E"} // CHECK: ![[TYPE131]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_ES0_S0_E"} diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-trait-objects.rs b/tests/codegen/sanitizer-cfi-emit-type-metadata-trait-objects.rs index ab5dcec7936..0f79adab7bd 100644 --- a/tests/codegen/sanitizer-cfi-emit-type-metadata-trait-objects.rs +++ b/tests/codegen/sanitizer-cfi-emit-type-metadata-trait-objects.rs @@ -1,44 +1,120 @@ // Verifies that type metadata identifiers for trait objects are emitted correctly. // // needs-sanitizer-cfi -// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi +// compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Ctarget-feature=-crt-static -Zsanitizer=cfi #![crate_type="lib"] -trait Trait1 { +pub trait Trait1 { fn foo(&self); } -struct Type1; +#[derive(Clone, Copy)] +pub struct Type1; impl Trait1 for Type1 { fn foo(&self) { } } -pub fn foo() { - let a = Type1; +pub trait Trait2<T> { + fn bar(&self); +} + +pub struct Type2; + +impl Trait2<i32> for Type2 { + fn bar(&self) { + } +} + +pub trait Trait3<T> { + fn baz(&self, _: &T); +} + +pub struct Type3; + +impl<T, U> Trait3<U> for T { + fn baz(&self, _: &U) { + } +} + +pub trait Trait4<'a, T> { + type Output: 'a; + fn qux(&self, _: &T) -> Self::Output; +} + +pub struct Type4; + +impl<'a, T, U> Trait4<'a, U> for T { + type Output = &'a i32; + fn qux(&self, _: &U) -> Self::Output { + &0 + } +} + +pub fn foo1(a: &dyn Trait1) { a.foo(); - // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} - // CHECK: call <sanitizer_cfi_emit_type_metadata_trait_objects::Type1 as sanitizer_cfi_emit_type_metadata_trait_objects::Trait1>::foo + // CHECK-LABEL: define{{.*}}4foo1{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE1:[[:print:]]+]]") } -pub fn bar() { +pub fn bar1() { let a = Type1; let b = &a as &dyn Trait1; b.foo(); - // CHECK-LABEL: define{{.*}}bar{{.*}}!type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0|%1}}, metadata !"[[TYPE1:[[:print:]]+]]") + // CHECK-LABEL: define{{.*}}4bar1{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]") } -pub fn baz() { - let a = Type1; - let b = &a as &dyn Trait1; - a.foo(); - b.foo(); - // CHECK-LABEL: define{{.*}}baz{{.*}}!type !{{[0-9]+}} - // CHECK: call <sanitizer_cfi_emit_type_metadata_trait_objects::Type1 as sanitizer_cfi_emit_type_metadata_trait_objects::Trait1>::foo - // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0|%1}}, metadata !"[[TYPE1:[[:print:]]+]]") +pub fn foo2<T>(a: &dyn Trait2<T>) { + a.bar(); + // CHECK-LABEL: define{{.*}}4foo2{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]") +} + +pub fn bar2() { + let a = Type2; + foo2(&a); + let b = &a as &dyn Trait2<i32>; + b.bar(); + // CHECK-LABEL: define{{.*}}4bar2{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]") +} + +pub fn foo3(a: &dyn Trait3<Type3>) { + let b = Type3; + a.baz(&b); + // CHECK-LABEL: define{{.*}}4foo3{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE3:[[:print:]]+]]") +} + +pub fn bar3() { + let a = Type3; + foo3(&a); + let b = &a as &dyn Trait3<Type3>; + b.baz(&a); + // CHECK-LABEL: define{{.*}}4bar3{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE3:[[:print:]]+]]") +} + +pub fn foo4<'a>(a: &dyn Trait4<'a, Type4, Output = &'a i32>) { + let b = Type4; + a.qux(&b); + // CHECK-LABEL: define{{.*}}4foo4{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE4:[[:print:]]+]]") +} + +pub fn bar4<'a>() { + let a = Type4; + foo4(&a); + let b = &a as &dyn Trait4<'a, Type4, Output = &'a i32>; + b.qux(&a); + // CHECK-LABEL: define{{.*}}4bar4{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE4:[[:print:]]+]]") } // CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE1]]"} +// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE2]]"} +// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE3]]"} +// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE4]]"} diff --git a/tests/codegen/sanitizer-kcfi-emit-type-metadata-trait-objects.rs b/tests/codegen/sanitizer-kcfi-emit-type-metadata-trait-objects.rs index 81e0d9344f7..004a67e7df2 100644 --- a/tests/codegen/sanitizer-kcfi-emit-type-metadata-trait-objects.rs +++ b/tests/codegen/sanitizer-kcfi-emit-type-metadata-trait-objects.rs @@ -30,40 +30,115 @@ trait Freeze { } #[lang="drop_in_place"] fn drop_in_place_fn<T>() { } -trait Trait1 { +pub trait Trait1 { fn foo(&self); } -struct Type1; +pub struct Type1; impl Trait1 for Type1 { fn foo(&self) { } } -pub fn foo() { - let a = Type1; +pub trait Trait2<T> { + fn bar(&self); +} + +pub struct Type2; + +impl Trait2<i32> for Type2 { + fn bar(&self) { + } +} + +pub trait Trait3<T> { + fn baz(&self, _: &T); +} + +pub struct Type3; + +impl<T, U> Trait3<U> for T { + fn baz(&self, _: &U) { + } +} + +pub trait Trait4<'a, T> { + type Output: 'a; + fn qux(&self, _: &T) -> Self::Output; +} + +pub struct Type4; + +impl<'a, T, U> Trait4<'a, U> for T { + type Output = &'a i32; + fn qux(&self, _: &U) -> Self::Output { + &0 + } +} + +pub fn foo1(a: &dyn Trait1) { a.foo(); - // CHECK-LABEL: define{{.*}}foo{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} - // CHECK: call <sanitizer_kcfi_emit_type_metadata_trait_objects::Type1 as sanitizer_kcfi_emit_type_metadata_trait_objects::Trait1>::foo + // CHECK-LABEL: define{{.*}}4foo1{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} + // CHECK: call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ] } -pub fn bar() { +pub fn bar1() { let a = Type1; let b = &a as &dyn Trait1; b.foo(); - // CHECK-LABEL: define{{.*}}bar{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} - // CHECK: call void %0({{\{\}\*|ptr}} align 1 {{%b\.0|%_1}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ] + // CHECK-LABEL: define{{.*}}4bar1{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} + // CHECK: call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ] } -pub fn baz() { - let a = Type1; - let b = &a as &dyn Trait1; - a.foo(); - b.foo(); - // CHECK-LABEL: define{{.*}}baz{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} - // CHECK: call <sanitizer_kcfi_emit_type_metadata_trait_objects::Type1 as sanitizer_kcfi_emit_type_metadata_trait_objects::Trait1>::foo - // CHECK: call void %0({{\{\}\*|ptr}} align 1 {{%b\.0|%_1}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ] +pub fn foo2<T>(a: &dyn Trait2<T>) { + a.bar(); + // CHECK-LABEL: define{{.*}}4foo2{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} + // CHECK: call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE2:[[:print:]]+]]) ] +} + +pub fn bar2() { + let a = Type2; + foo2(&a); + let b = &a as &dyn Trait2<i32>; + b.bar(); + // CHECK-LABEL: define{{.*}}4bar2{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} + // CHECK: call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE2:[[:print:]]+]]) ] +} + +pub fn foo3(a: &dyn Trait3<Type3>) { + let b = Type3; + a.baz(&b); + // CHECK-LABEL: define{{.*}}4foo3{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} + // CHECK: call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}, {{\{\}\*|ptr|%Type3\*}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE3:[[:print:]]+]]) ] +} + +pub fn bar3() { + let a = Type3; + foo3(&a); + let b = &a as &dyn Trait3<Type3>; + b.baz(&a); + // CHECK-LABEL: define{{.*}}4bar3{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} + // CHECK: call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}, {{\{\}\*|ptr|%Type3\*}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE3:[[:print:]]+]]) ] +} + +pub fn foo4<'a>(a: &dyn Trait4<'a, Type4, Output = &'a i32>) { + let b = Type4; + a.qux(&b); + // CHECK-LABEL: define{{.*}}4foo4{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} + // CHECK: call align 4 {{ptr|i32\*}} %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}, {{\{\}\*|ptr|%Type4\*}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE4:[[:print:]]+]]) ] +} + +pub fn bar4<'a>() { + let a = Type4; + foo4(&a); + let b = &a as &dyn Trait4<'a, Type4, Output = &'a i32>; + b.qux(&a); + // CHECK-LABEL: define{{.*}}4bar4{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} + // CHECK: call align 4 {{ptr|i32\*}} %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}, {{\{\}\*|ptr|%Type4\*}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE4:[[:print:]]+]]) ] } // CHECK: !{{[0-9]+}} = !{i32 [[TYPE1]]} +// CHECK: !{{[0-9]+}} = !{i32 [[TYPE2]]} +// CHECK: !{{[0-9]+}} = !{i32 [[TYPE3]]} +// CHECK: !{{[0-9]+}} = !{i32 [[TYPE4]]} diff --git a/tests/codegen/tied-features-strength.rs b/tests/codegen/tied-features-strength.rs new file mode 100644 index 00000000000..51334c12158 --- /dev/null +++ b/tests/codegen/tied-features-strength.rs @@ -0,0 +1,29 @@ +// ignore-tidy-linelength +// revisions: ENABLE_SVE DISABLE_SVE DISABLE_NEON ENABLE_NEON +// compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu +// needs-llvm-components: aarch64 + +// The "+v8a" feature is matched as optional as it isn't added when we +// are targeting older LLVM versions. Once the min supported version +// is LLVM-14 we can remove the optional regex matching for this feature. + +// [ENABLE_SVE] compile-flags: -C target-feature=+sve +// ENABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)?|(\+sve,?)|(\+neon,?))*}}" } + +// [DISABLE_SVE] compile-flags: -C target-feature=-sve +// DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)?|(-sve,?)|(\+neon,?))*}}" } + +// [DISABLE_NEON] compile-flags: -C target-feature=-neon +// DISABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)?|(-fp-armv8,?)|(-neon,?))*}}" } + +// [ENABLE_NEON] compile-flags: -C target-feature=+neon +// ENABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)?|(\+fp-armv8,?)|(\+neon,?))*}}" } + + +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +pub fn test() {} diff --git a/tests/incremental/const-generic-type-cycle.rs b/tests/incremental/const-generic-type-cycle.rs new file mode 100644 index 00000000000..ca7b12e9e62 --- /dev/null +++ b/tests/incremental/const-generic-type-cycle.rs @@ -0,0 +1,17 @@ +// Verify that we do not ICE when we try to overwrite an anon-const's type because of a trait +// cycle. +// +// compile-flags: -Zincremental-ignore-spans +// revisions: cpass cfail +// error-pattern: cycle detected when computing type of `Bar::N` + +#![feature(trait_alias)] +#![crate_type="lib"] + +#[cfg(cpass)] +trait Bar<const N: usize> {} + +#[cfg(cfail)] +trait Bar<const N: dyn BB> {} + +trait BB = Bar<{ 2 + 1 }>; diff --git a/tests/mir-opt/building/enum_cast.bar.built.after.mir b/tests/mir-opt/building/enum_cast.bar.built.after.mir index 0746e0b498e..9f14c028465 100644 --- a/tests/mir-opt/building/enum_cast.bar.built.after.mir +++ b/tests/mir-opt/building/enum_cast.bar.built.after.mir @@ -5,17 +5,16 @@ fn bar(_1: Bar) -> usize { let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:+0:21: +0:26 let _2: Bar; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8 let mut _3: isize; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8 - let mut _4: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 + let mut _4: u8; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 let mut _5: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 bb0: { StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8 _2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8 _3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 - _4 = Ge(const 1_isize, _3); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 - assume(_4); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 - _5 = Le(const 0_isize, _3); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 - assume(_5); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 + _4 = _3 as u8 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 + _5 = Le(_4, const 1_u8); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 + assume(move _5); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 _0 = move _3 as usize (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:16: +1:17 return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2 diff --git a/tests/mir-opt/building/enum_cast.boo.built.after.mir b/tests/mir-opt/building/enum_cast.boo.built.after.mir index 699c876b01a..715dedcf24d 100644 --- a/tests/mir-opt/building/enum_cast.boo.built.after.mir +++ b/tests/mir-opt/building/enum_cast.boo.built.after.mir @@ -5,17 +5,16 @@ fn boo(_1: Boo) -> usize { let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:+0:21: +0:26 let _2: Boo; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8 let mut _3: u8; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8 - let mut _4: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 + let mut _4: u8; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 let mut _5: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 bb0: { StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8 _2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8 _3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 - _4 = Ge(const 1_u8, _3); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 - assume(_4); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 - _5 = Le(const 0_u8, _3); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 - assume(_5); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 + _4 = _3 as u8 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 + _5 = Le(_4, const 1_u8); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 + assume(move _5); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 _0 = move _3 as usize (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:16: +1:17 return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2 diff --git a/tests/mir-opt/building/enum_cast.droppy.built.after.mir b/tests/mir-opt/building/enum_cast.droppy.built.after.mir index 1112177fbbf..6c177c61eca 100644 --- a/tests/mir-opt/building/enum_cast.droppy.built.after.mir +++ b/tests/mir-opt/building/enum_cast.droppy.built.after.mir @@ -6,7 +6,7 @@ fn droppy() -> () { let _2: Droppy; // in scope 0 at $DIR/enum_cast.rs:+2:13: +2:14 let _4: Droppy; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:18 let mut _5: isize; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:18 - let mut _6: bool; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:27 + let mut _6: u8; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:27 let mut _7: bool; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:27 let _8: Droppy; // in scope 0 at $DIR/enum_cast.rs:+7:9: +7:10 scope 1 { @@ -31,10 +31,9 @@ fn droppy() -> () { StorageLive(_4); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:18 _4 = move _2; // scope 3 at $DIR/enum_cast.rs:+5:17: +5:18 _5 = discriminant(_4); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27 - _6 = Ge(const 2_isize, _5); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27 - assume(_6); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27 - _7 = Le(const 0_isize, _5); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27 - assume(_7); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27 + _6 = _5 as u8 (IntToInt); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27 + _7 = Le(_6, const 2_u8); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27 + assume(move _7); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27 _3 = move _5 as usize (IntToInt); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27 drop(_4) -> [return: bb1, unwind: bb4]; // scope 3 at $DIR/enum_cast.rs:+5:26: +5:27 } diff --git a/tests/mir-opt/building/enum_cast.far.built.after.mir b/tests/mir-opt/building/enum_cast.far.built.after.mir new file mode 100644 index 00000000000..ab8129ca01c --- /dev/null +++ b/tests/mir-opt/building/enum_cast.far.built.after.mir @@ -0,0 +1,22 @@ +// MIR for `far` after built + +fn far(_1: Far) -> isize { + debug far => _1; // in scope 0 at $DIR/enum_cast.rs:+0:8: +0:11 + let mut _0: isize; // return place in scope 0 at $DIR/enum_cast.rs:+0:21: +0:26 + let _2: Far; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8 + let mut _3: i16; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8 + let mut _4: u16; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 + let mut _5: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8 + _2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8 + _3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 + _4 = _3 as u16 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 + _5 = Le(_4, const 1_u16); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 + assume(move _5); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 + _0 = move _3 as isize (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 + StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:16: +1:17 + return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2 + } +} diff --git a/tests/mir-opt/building/enum_cast.offsetty.built.after.mir b/tests/mir-opt/building/enum_cast.offsetty.built.after.mir new file mode 100644 index 00000000000..7b2b583f20f --- /dev/null +++ b/tests/mir-opt/building/enum_cast.offsetty.built.after.mir @@ -0,0 +1,26 @@ +// MIR for `offsetty` after built + +fn offsetty(_1: NotStartingAtZero) -> u32 { + debug x => _1; // in scope 0 at $DIR/enum_cast.rs:+0:13: +0:14 + let mut _0: u32; // return place in scope 0 at $DIR/enum_cast.rs:+0:38: +0:41 + let _2: NotStartingAtZero; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:6 + let mut _3: isize; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:6 + let mut _4: u8; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + let mut _5: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + let mut _6: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + let mut _7: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:6 + _2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:6 + _3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + _4 = _3 as u8 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + _5 = Ge(_4, const 4_u8); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + _6 = Le(_4, const 8_u8); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + _7 = BitAnd(move _5, move _6); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + assume(move _7); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + _0 = move _3 as u32 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:12: +1:13 + return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2 + } +} diff --git a/tests/mir-opt/building/enum_cast.rs b/tests/mir-opt/building/enum_cast.rs index 98fd5acfb14..431b5c708b9 100644 --- a/tests/mir-opt/building/enum_cast.rs +++ b/tests/mir-opt/building/enum_cast.rs @@ -1,6 +1,7 @@ // EMIT_MIR enum_cast.foo.built.after.mir // EMIT_MIR enum_cast.bar.built.after.mir // EMIT_MIR enum_cast.boo.built.after.mir +// EMIT_MIR enum_cast.far.built.after.mir enum Foo { A @@ -15,6 +16,11 @@ enum Boo { A, B } +#[repr(i16)] +enum Far { + A, B +} + fn foo(foo: Foo) -> usize { foo as usize } @@ -27,6 +33,10 @@ fn boo(boo: Boo) -> usize { boo as usize } +fn far(far: Far) -> isize { + far as isize +} + // EMIT_MIR enum_cast.droppy.built.after.mir enum Droppy { A, B, C @@ -46,5 +56,37 @@ fn droppy() { let z = Droppy::B; } +#[repr(i16)] +enum SignedAroundZero { + A = -2, + B = 0, + C = 2, +} + +#[repr(u16)] +enum UnsignedAroundZero { + A = 65535, + B = 0, + C = 1, +} + +// EMIT_MIR enum_cast.signy.built.after.mir +fn signy(x: SignedAroundZero) -> i16 { + x as i16 +} + +// EMIT_MIR enum_cast.unsigny.built.after.mir +fn unsigny(x: UnsignedAroundZero) -> u16 { + // FIXME: This doesn't get an around-the-end range today, sadly. + x as u16 +} + +enum NotStartingAtZero { A = 4, B = 6, C = 8 } + +// EMIT_MIR enum_cast.offsetty.built.after.mir +fn offsetty(x: NotStartingAtZero) -> u32 { + x as u32 +} + fn main() { } diff --git a/tests/mir-opt/building/enum_cast.signy.built.after.mir b/tests/mir-opt/building/enum_cast.signy.built.after.mir new file mode 100644 index 00000000000..ef4fea604ec --- /dev/null +++ b/tests/mir-opt/building/enum_cast.signy.built.after.mir @@ -0,0 +1,26 @@ +// MIR for `signy` after built + +fn signy(_1: SignedAroundZero) -> i16 { + debug x => _1; // in scope 0 at $DIR/enum_cast.rs:+0:10: +0:11 + let mut _0: i16; // return place in scope 0 at $DIR/enum_cast.rs:+0:34: +0:37 + let _2: SignedAroundZero; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:6 + let mut _3: i16; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:6 + let mut _4: u16; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + let mut _5: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + let mut _6: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + let mut _7: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:6 + _2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:6 + _3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + _4 = _3 as u16 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + _5 = Ge(_4, const 65534_u16); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + _6 = Le(_4, const 2_u16); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + _7 = BitOr(move _5, move _6); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + assume(move _7); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + _0 = move _3 as i16 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13 + StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:12: +1:13 + return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2 + } +} diff --git a/tests/mir-opt/building/enum_cast.unsigny.built.after.mir b/tests/mir-opt/building/enum_cast.unsigny.built.after.mir new file mode 100644 index 00000000000..7ca147b1596 --- /dev/null +++ b/tests/mir-opt/building/enum_cast.unsigny.built.after.mir @@ -0,0 +1,17 @@ +// MIR for `unsigny` after built + +fn unsigny(_1: UnsignedAroundZero) -> u16 { + debug x => _1; // in scope 0 at $DIR/enum_cast.rs:+0:12: +0:13 + let mut _0: u16; // return place in scope 0 at $DIR/enum_cast.rs:+0:38: +0:41 + let _2: UnsignedAroundZero; // in scope 0 at $DIR/enum_cast.rs:+2:5: +2:6 + let mut _3: u16; // in scope 0 at $DIR/enum_cast.rs:+2:5: +2:6 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+2:5: +2:6 + _2 = move _1; // scope 0 at $DIR/enum_cast.rs:+2:5: +2:6 + _3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+2:5: +2:13 + _0 = move _3 as u16 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+2:5: +2:13 + StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+2:12: +2:13 + return; // scope 0 at $DIR/enum_cast.rs:+3:2: +3:2 + } +} diff --git a/tests/mir-opt/combine_transmutes.adt_transmutes.InstSimplify.diff b/tests/mir-opt/combine_transmutes.adt_transmutes.InstSimplify.diff index c5907e7cf18..15117ea890e 100644 --- a/tests/mir-opt/combine_transmutes.adt_transmutes.InstSimplify.diff +++ b/tests/mir-opt/combine_transmutes.adt_transmutes.InstSimplify.diff @@ -4,59 +4,29 @@ fn adt_transmutes() -> () { let mut _0: (); // return place in scope 0 at $DIR/combine_transmutes.rs:+0:32: +0:32 let _1: u8; // in scope 0 at $DIR/combine_transmutes.rs:+1:9: +1:11 - let mut _2: EnumNoRepr; // in scope 0 at $DIR/combine_transmutes.rs:+1:28: +1:41 - let mut _4: EnumNoRepr; // in scope 0 at $DIR/combine_transmutes.rs:+2:28: +2:41 - let mut _6: EnumReprIsize; // in scope 0 at $DIR/combine_transmutes.rs:+3:31: +3:47 - let mut _8: EnumReprIsize; // in scope 0 at $DIR/combine_transmutes.rs:+4:31: +4:47 - let mut _10: std::cmp::Ordering; // in scope 0 at $DIR/combine_transmutes.rs:+5:28: +5:52 - let mut _12: std::cmp::Ordering; // in scope 0 at $DIR/combine_transmutes.rs:+6:28: +6:52 - let mut _14: std::option::Option<std::num::NonZeroU8>; // in scope 0 at $DIR/combine_transmutes.rs:+7:28: +7:58 - let mut _16: std::num::Wrapping<i16>; // in scope 0 at $DIR/combine_transmutes.rs:+8:29: +8:54 - let mut _18: std::num::Wrapping<i16>; // in scope 0 at $DIR/combine_transmutes.rs:+9:29: +9:54 - let mut _20: Union32; // in scope 0 at $DIR/combine_transmutes.rs:+10:29: +10:47 - let mut _22: Union32; // in scope 0 at $DIR/combine_transmutes.rs:+11:29: +11:47 - let mut _24: std::mem::MaybeUninit<std::string::String>; // in scope 0 at $DIR/combine_transmutes.rs:+12:46: +12:77 + let mut _2: std::option::Option<std::num::NonZeroU8>; // in scope 0 at $DIR/combine_transmutes.rs:+1:28: +1:58 + let mut _4: std::num::Wrapping<i16>; // in scope 0 at $DIR/combine_transmutes.rs:+2:29: +2:54 + let mut _6: std::num::Wrapping<i16>; // in scope 0 at $DIR/combine_transmutes.rs:+3:29: +3:54 + let mut _8: Union32; // in scope 0 at $DIR/combine_transmutes.rs:+4:29: +4:47 + let mut _10: Union32; // in scope 0 at $DIR/combine_transmutes.rs:+5:29: +5:47 + let mut _12: std::mem::MaybeUninit<std::string::String>; // in scope 0 at $DIR/combine_transmutes.rs:+6:46: +6:77 scope 1 { debug _a => _1; // in scope 1 at $DIR/combine_transmutes.rs:+1:9: +1:11 - let _3: i8; // in scope 1 at $DIR/combine_transmutes.rs:+2:9: +2:11 + let _3: i16; // in scope 1 at $DIR/combine_transmutes.rs:+2:9: +2:11 scope 2 { debug _a => _3; // in scope 2 at $DIR/combine_transmutes.rs:+2:9: +2:11 - let _5: usize; // in scope 2 at $DIR/combine_transmutes.rs:+3:9: +3:11 + let _5: u16; // in scope 2 at $DIR/combine_transmutes.rs:+3:9: +3:11 scope 3 { debug _a => _5; // in scope 3 at $DIR/combine_transmutes.rs:+3:9: +3:11 - let _7: isize; // in scope 3 at $DIR/combine_transmutes.rs:+4:9: +4:11 + let _7: u32; // in scope 3 at $DIR/combine_transmutes.rs:+4:9: +4:11 scope 4 { debug _a => _7; // in scope 4 at $DIR/combine_transmutes.rs:+4:9: +4:11 - let _9: u8; // in scope 4 at $DIR/combine_transmutes.rs:+5:9: +5:11 + let _9: i32; // in scope 4 at $DIR/combine_transmutes.rs:+5:9: +5:11 scope 5 { debug _a => _9; // in scope 5 at $DIR/combine_transmutes.rs:+5:9: +5:11 - let _11: i8; // in scope 5 at $DIR/combine_transmutes.rs:+6:9: +6:11 + let _11: std::mem::ManuallyDrop<std::string::String>; // in scope 5 at $DIR/combine_transmutes.rs:+6:9: +6:11 scope 6 { debug _a => _11; // in scope 6 at $DIR/combine_transmutes.rs:+6:9: +6:11 - let _13: u8; // in scope 6 at $DIR/combine_transmutes.rs:+7:9: +7:11 - scope 7 { - debug _a => _13; // in scope 7 at $DIR/combine_transmutes.rs:+7:9: +7:11 - let _15: i16; // in scope 7 at $DIR/combine_transmutes.rs:+8:9: +8:11 - scope 8 { - debug _a => _15; // in scope 8 at $DIR/combine_transmutes.rs:+8:9: +8:11 - let _17: u16; // in scope 8 at $DIR/combine_transmutes.rs:+9:9: +9:11 - scope 9 { - debug _a => _17; // in scope 9 at $DIR/combine_transmutes.rs:+9:9: +9:11 - let _19: u32; // in scope 9 at $DIR/combine_transmutes.rs:+10:9: +10:11 - scope 10 { - debug _a => _19; // in scope 10 at $DIR/combine_transmutes.rs:+10:9: +10:11 - let _21: i32; // in scope 10 at $DIR/combine_transmutes.rs:+11:9: +11:11 - scope 11 { - debug _a => _21; // in scope 11 at $DIR/combine_transmutes.rs:+11:9: +11:11 - let _23: std::mem::ManuallyDrop<std::string::String>; // in scope 11 at $DIR/combine_transmutes.rs:+12:9: +12:11 - scope 12 { - debug _a => _23; // in scope 12 at $DIR/combine_transmutes.rs:+12:9: +12:11 - } - } - } - } - } - } } } } @@ -66,93 +36,55 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/combine_transmutes.rs:+1:9: +1:11 - StorageLive(_2); // scope 0 at $DIR/combine_transmutes.rs:+1:28: +1:41 - _2 = EnumNoRepr::A; // scope 0 at $DIR/combine_transmutes.rs:+1:28: +1:41 - _1 = move _2 as u8 (Transmute); // scope 0 at $DIR/combine_transmutes.rs:+1:18: +1:42 - StorageDead(_2); // scope 0 at $DIR/combine_transmutes.rs:+1:41: +1:42 + StorageLive(_2); // scope 0 at $DIR/combine_transmutes.rs:+1:28: +1:58 + _2 = Option::<NonZeroU8>::Some(const _); // scope 0 at $DIR/combine_transmutes.rs:+1:28: +1:58 + // mir::Constant + // + span: $DIR/combine_transmutes.rs:35:33: 35:57 + // + literal: Const { ty: NonZeroU8, val: Unevaluated(NonZeroU8::MAX, [], None) } + _1 = move _2 as u8 (Transmute); // scope 0 at $DIR/combine_transmutes.rs:+1:18: +1:59 + StorageDead(_2); // scope 0 at $DIR/combine_transmutes.rs:+1:58: +1:59 StorageLive(_3); // scope 1 at $DIR/combine_transmutes.rs:+2:9: +2:11 - StorageLive(_4); // scope 1 at $DIR/combine_transmutes.rs:+2:28: +2:41 - _4 = EnumNoRepr::B; // scope 1 at $DIR/combine_transmutes.rs:+2:28: +2:41 - _3 = move _4 as i8 (Transmute); // scope 1 at $DIR/combine_transmutes.rs:+2:18: +2:42 - StorageDead(_4); // scope 1 at $DIR/combine_transmutes.rs:+2:41: +2:42 + StorageLive(_4); // scope 1 at $DIR/combine_transmutes.rs:+2:29: +2:54 + _4 = Wrapping::<i16>(const 0_i16); // scope 1 at $DIR/combine_transmutes.rs:+2:29: +2:54 +- _3 = move _4 as i16 (Transmute); // scope 1 at $DIR/combine_transmutes.rs:+2:19: +2:55 ++ _3 = move (_4.0: i16); // scope 1 at $DIR/combine_transmutes.rs:+2:19: +2:55 + StorageDead(_4); // scope 1 at $DIR/combine_transmutes.rs:+2:54: +2:55 StorageLive(_5); // scope 2 at $DIR/combine_transmutes.rs:+3:9: +3:11 - StorageLive(_6); // scope 2 at $DIR/combine_transmutes.rs:+3:31: +3:47 - _6 = EnumReprIsize::A; // scope 2 at $DIR/combine_transmutes.rs:+3:31: +3:47 - _5 = move _6 as usize (Transmute); // scope 2 at $DIR/combine_transmutes.rs:+3:21: +3:48 - StorageDead(_6); // scope 2 at $DIR/combine_transmutes.rs:+3:47: +3:48 + StorageLive(_6); // scope 2 at $DIR/combine_transmutes.rs:+3:29: +3:54 + _6 = Wrapping::<i16>(const 0_i16); // scope 2 at $DIR/combine_transmutes.rs:+3:29: +3:54 + _5 = move _6 as u16 (Transmute); // scope 2 at $DIR/combine_transmutes.rs:+3:19: +3:55 + StorageDead(_6); // scope 2 at $DIR/combine_transmutes.rs:+3:54: +3:55 StorageLive(_7); // scope 3 at $DIR/combine_transmutes.rs:+4:9: +4:11 - StorageLive(_8); // scope 3 at $DIR/combine_transmutes.rs:+4:31: +4:47 - _8 = EnumReprIsize::B; // scope 3 at $DIR/combine_transmutes.rs:+4:31: +4:47 -- _7 = move _8 as isize (Transmute); // scope 3 at $DIR/combine_transmutes.rs:+4:21: +4:48 -+ _7 = discriminant(_8); // scope 3 at $DIR/combine_transmutes.rs:+4:21: +4:48 + StorageLive(_8); // scope 3 at $DIR/combine_transmutes.rs:+4:29: +4:47 + _8 = Union32 { u32: const 0_i32 }; // scope 3 at $DIR/combine_transmutes.rs:+4:29: +4:47 + _7 = move _8 as u32 (Transmute); // scope 3 at $DIR/combine_transmutes.rs:+4:19: +4:48 StorageDead(_8); // scope 3 at $DIR/combine_transmutes.rs:+4:47: +4:48 StorageLive(_9); // scope 4 at $DIR/combine_transmutes.rs:+5:9: +5:11 - StorageLive(_10); // scope 4 at $DIR/combine_transmutes.rs:+5:28: +5:52 - _10 = Less; // scope 4 at $DIR/combine_transmutes.rs:+5:28: +5:52 - _9 = move _10 as u8 (Transmute); // scope 4 at $DIR/combine_transmutes.rs:+5:18: +5:53 - StorageDead(_10); // scope 4 at $DIR/combine_transmutes.rs:+5:52: +5:53 + StorageLive(_10); // scope 4 at $DIR/combine_transmutes.rs:+5:29: +5:47 + _10 = Union32 { u32: const 0_u32 }; // scope 4 at $DIR/combine_transmutes.rs:+5:29: +5:47 + _9 = move _10 as i32 (Transmute); // scope 4 at $DIR/combine_transmutes.rs:+5:19: +5:48 + StorageDead(_10); // scope 4 at $DIR/combine_transmutes.rs:+5:47: +5:48 StorageLive(_11); // scope 5 at $DIR/combine_transmutes.rs:+6:9: +6:11 - StorageLive(_12); // scope 5 at $DIR/combine_transmutes.rs:+6:28: +6:52 - _12 = Less; // scope 5 at $DIR/combine_transmutes.rs:+6:28: +6:52 -- _11 = move _12 as i8 (Transmute); // scope 5 at $DIR/combine_transmutes.rs:+6:18: +6:53 -+ _11 = discriminant(_12); // scope 5 at $DIR/combine_transmutes.rs:+6:18: +6:53 - StorageDead(_12); // scope 5 at $DIR/combine_transmutes.rs:+6:52: +6:53 - StorageLive(_13); // scope 6 at $DIR/combine_transmutes.rs:+7:9: +7:11 - StorageLive(_14); // scope 6 at $DIR/combine_transmutes.rs:+7:28: +7:58 - _14 = Option::<NonZeroU8>::Some(const _); // scope 6 at $DIR/combine_transmutes.rs:+7:28: +7:58 - // mir::Constant - // + span: $DIR/combine_transmutes.rs:41:33: 41:57 - // + literal: Const { ty: NonZeroU8, val: Unevaluated(NonZeroU8::MAX, [], None) } - _13 = move _14 as u8 (Transmute); // scope 6 at $DIR/combine_transmutes.rs:+7:18: +7:59 - StorageDead(_14); // scope 6 at $DIR/combine_transmutes.rs:+7:58: +7:59 - StorageLive(_15); // scope 7 at $DIR/combine_transmutes.rs:+8:9: +8:11 - StorageLive(_16); // scope 7 at $DIR/combine_transmutes.rs:+8:29: +8:54 - _16 = Wrapping::<i16>(const 0_i16); // scope 7 at $DIR/combine_transmutes.rs:+8:29: +8:54 -- _15 = move _16 as i16 (Transmute); // scope 7 at $DIR/combine_transmutes.rs:+8:19: +8:55 -+ _15 = move (_16.0: i16); // scope 7 at $DIR/combine_transmutes.rs:+8:19: +8:55 - StorageDead(_16); // scope 7 at $DIR/combine_transmutes.rs:+8:54: +8:55 - StorageLive(_17); // scope 8 at $DIR/combine_transmutes.rs:+9:9: +9:11 - StorageLive(_18); // scope 8 at $DIR/combine_transmutes.rs:+9:29: +9:54 - _18 = Wrapping::<i16>(const 0_i16); // scope 8 at $DIR/combine_transmutes.rs:+9:29: +9:54 - _17 = move _18 as u16 (Transmute); // scope 8 at $DIR/combine_transmutes.rs:+9:19: +9:55 - StorageDead(_18); // scope 8 at $DIR/combine_transmutes.rs:+9:54: +9:55 - StorageLive(_19); // scope 9 at $DIR/combine_transmutes.rs:+10:9: +10:11 - StorageLive(_20); // scope 9 at $DIR/combine_transmutes.rs:+10:29: +10:47 - _20 = Union32 { u32: const 0_i32 }; // scope 9 at $DIR/combine_transmutes.rs:+10:29: +10:47 - _19 = move _20 as u32 (Transmute); // scope 9 at $DIR/combine_transmutes.rs:+10:19: +10:48 - StorageDead(_20); // scope 9 at $DIR/combine_transmutes.rs:+10:47: +10:48 - StorageLive(_21); // scope 10 at $DIR/combine_transmutes.rs:+11:9: +11:11 - StorageLive(_22); // scope 10 at $DIR/combine_transmutes.rs:+11:29: +11:47 - _22 = Union32 { u32: const 0_u32 }; // scope 10 at $DIR/combine_transmutes.rs:+11:29: +11:47 - _21 = move _22 as i32 (Transmute); // scope 10 at $DIR/combine_transmutes.rs:+11:19: +11:48 - StorageDead(_22); // scope 10 at $DIR/combine_transmutes.rs:+11:47: +11:48 - StorageLive(_23); // scope 11 at $DIR/combine_transmutes.rs:+12:9: +12:11 - StorageLive(_24); // scope 11 at $DIR/combine_transmutes.rs:+12:46: +12:77 - _24 = MaybeUninit::<String>::uninit() -> [return: bb1, unwind unreachable]; // scope 11 at $DIR/combine_transmutes.rs:+12:46: +12:77 + StorageLive(_12); // scope 5 at $DIR/combine_transmutes.rs:+6:46: +6:77 + _12 = MaybeUninit::<String>::uninit() -> [return: bb1, unwind unreachable]; // scope 5 at $DIR/combine_transmutes.rs:+6:46: +6:77 // mir::Constant - // + span: $DIR/combine_transmutes.rs:46:46: 46:75 - // + user_ty: UserType(23) + // + span: $DIR/combine_transmutes.rs:40:46: 40:75 + // + user_ty: UserType(11) // + literal: Const { ty: fn() -> MaybeUninit<String> {MaybeUninit::<String>::uninit}, val: Value(<ZST>) } } bb1: { -- _23 = move _24 as std::mem::ManuallyDrop<std::string::String> (Transmute); // scope 11 at $DIR/combine_transmutes.rs:+12:36: +12:78 -+ _23 = move (_24.1: std::mem::ManuallyDrop<std::string::String>); // scope 11 at $DIR/combine_transmutes.rs:+12:36: +12:78 - StorageDead(_24); // scope 11 at $DIR/combine_transmutes.rs:+12:77: +12:78 - _0 = const (); // scope 0 at $DIR/combine_transmutes.rs:+0:32: +13:2 - StorageDead(_23); // scope 11 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_21); // scope 10 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_19); // scope 9 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_17); // scope 8 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_15); // scope 7 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_13); // scope 6 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_11); // scope 5 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_9); // scope 4 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_7); // scope 3 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_5); // scope 2 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_3); // scope 1 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_1); // scope 0 at $DIR/combine_transmutes.rs:+13:1: +13:2 - return; // scope 0 at $DIR/combine_transmutes.rs:+13:2: +13:2 +- _11 = move _12 as std::mem::ManuallyDrop<std::string::String> (Transmute); // scope 5 at $DIR/combine_transmutes.rs:+6:36: +6:78 ++ _11 = move (_12.1: std::mem::ManuallyDrop<std::string::String>); // scope 5 at $DIR/combine_transmutes.rs:+6:36: +6:78 + StorageDead(_12); // scope 5 at $DIR/combine_transmutes.rs:+6:77: +6:78 + _0 = const (); // scope 0 at $DIR/combine_transmutes.rs:+0:32: +7:2 + StorageDead(_11); // scope 5 at $DIR/combine_transmutes.rs:+7:1: +7:2 + StorageDead(_9); // scope 4 at $DIR/combine_transmutes.rs:+7:1: +7:2 + StorageDead(_7); // scope 3 at $DIR/combine_transmutes.rs:+7:1: +7:2 + StorageDead(_5); // scope 2 at $DIR/combine_transmutes.rs:+7:1: +7:2 + StorageDead(_3); // scope 1 at $DIR/combine_transmutes.rs:+7:1: +7:2 + StorageDead(_1); // scope 0 at $DIR/combine_transmutes.rs:+7:1: +7:2 + return; // scope 0 at $DIR/combine_transmutes.rs:+7:2: +7:2 } } diff --git a/tests/mir-opt/combine_transmutes.rs b/tests/mir-opt/combine_transmutes.rs index 7088488c1b8..403f9356ce2 100644 --- a/tests/mir-opt/combine_transmutes.rs +++ b/tests/mir-opt/combine_transmutes.rs @@ -32,12 +32,6 @@ pub unsafe fn integer_transmutes() { // EMIT_MIR combine_transmutes.adt_transmutes.InstSimplify.diff pub unsafe fn adt_transmutes() { - let _a: u8 = transmute(EnumNoRepr::A); - let _a: i8 = transmute(EnumNoRepr::B); - let _a: usize = transmute(EnumReprIsize::A); - let _a: isize = transmute(EnumReprIsize::B); - let _a: u8 = transmute(std::cmp::Ordering::Less); - let _a: i8 = transmute(std::cmp::Ordering::Less); let _a: u8 = transmute(Some(std::num::NonZeroU8::MAX)); let _a: i16 = transmute(std::num::Wrapping(0_i16)); let _a: u16 = transmute(std::num::Wrapping(0_i16)); @@ -46,20 +40,4 @@ pub unsafe fn adt_transmutes() { let _a: ManuallyDrop<String> = transmute(MaybeUninit::<String>::uninit()); } -#[inline(always)] -#[custom_mir(dialect = "runtime", phase = "initial")] -const unsafe fn mir_transmute<T, U>(x: T) -> U { - mir!{ - { - RET = CastTransmute(x); - Return() - } - } -} - -pub enum EnumNoRepr { A, B, C } - -#[repr(isize)] -pub enum EnumReprIsize { A, B, C } - pub union Union32 { u32: u32, i32: i32 } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.32bit.diff index bc41b5d0813..5258d75bdf7 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.32bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.32bit.diff @@ -3,24 +3,20 @@ fn unreachable_box() -> ! { let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 - let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 - let _2: std::boxed::Box<Never>; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 - let mut _3: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + let _1: std::boxed::Box<Never>; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 scope 1 { - debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 } scope 2 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 - StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 -- _2 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 -+ _2 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 +- _1 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 ++ _1 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + // mir::Constant + // + span: no-location + // + literal: Const { ty: Box<Never>, val: Value(Scalar(0x00000001)) } - StorageLive(_3); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 } } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.64bit.diff index c4376e6e17a..7e57e06a5cf 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.64bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.64bit.diff @@ -3,24 +3,20 @@ fn unreachable_box() -> ! { let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 - let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 - let _2: std::boxed::Box<Never>; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 - let mut _3: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + let _1: std::boxed::Box<Never>; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 scope 1 { - debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 } scope 2 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 - StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 -- _2 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 -+ _2 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 +- _1 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 ++ _1 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + // mir::Constant + // + span: no-location + // + literal: Const { ty: Box<Never>, val: Value(Scalar(0x0000000000000001)) } - StorageLive(_3); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 } } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.32bit.diff index 81b7b368993..032681f230b 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.32bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.32bit.diff @@ -3,22 +3,19 @@ fn unreachable_direct() -> ! { let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:39: +0:40 - let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:41: +3:2 - let _2: Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 - let mut _3: (); // in scope 0 at $DIR/transmute.rs:+1:39: +1:41 - let mut _4: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:15 + let _1: Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 + let mut _2: (); // in scope 0 at $DIR/transmute.rs:+1:39: +1:41 scope 1 { - debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 } scope 2 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:41: +3:2 - StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 - StorageLive(_3); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 - _3 = (); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 - _2 = move _3 as Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:29: +1:42 + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 + StorageLive(_2); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 + _2 = (); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 + _1 = move _2 as Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:29: +1:42 unreachable; // scope 2 at $DIR/transmute.rs:+1:29: +1:42 } } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.64bit.diff index 81b7b368993..032681f230b 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.64bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.64bit.diff @@ -3,22 +3,19 @@ fn unreachable_direct() -> ! { let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:39: +0:40 - let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:41: +3:2 - let _2: Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 - let mut _3: (); // in scope 0 at $DIR/transmute.rs:+1:39: +1:41 - let mut _4: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:15 + let _1: Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 + let mut _2: (); // in scope 0 at $DIR/transmute.rs:+1:39: +1:41 scope 1 { - debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 } scope 2 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:41: +3:2 - StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 - StorageLive(_3); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 - _3 = (); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 - _2 = move _3 as Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:29: +1:42 + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 + StorageLive(_2); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 + _2 = (); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 + _1 = move _2 as Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:29: +1:42 unreachable; // scope 2 at $DIR/transmute.rs:+1:29: +1:42 } } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.32bit.diff index 47f023cd93d..ec8a62bd62c 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.32bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.32bit.diff @@ -3,28 +3,24 @@ fn unreachable_mut() -> ! { let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 - let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 - let _2: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 - let mut _3: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:34: +1:52 - let mut _4: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + let _1: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 + let mut _2: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:34: +1:52 scope 1 { - debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 } scope 2 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 - StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 - StorageLive(_3); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 -- _3 = const 1_usize as &mut Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 -+ _3 = const {0x1 as &mut Never}; // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 + StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 +- _2 = const 1_usize as &mut Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 ++ _2 = const {0x1 as &mut Never}; // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + // mir::Constant + // + span: no-location + // + literal: Const { ty: &mut Never, val: Value(Scalar(0x00000001)) } - _2 = &mut (*_3); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 - StorageDead(_3); // scope 0 at $DIR/transmute.rs:+1:54: +1:55 - StorageLive(_4); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 + _1 = &mut (*_2); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 + StorageDead(_2); // scope 0 at $DIR/transmute.rs:+1:54: +1:55 unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 } } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.64bit.diff index 62300d2e313..288da6e56c5 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.64bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.64bit.diff @@ -3,28 +3,24 @@ fn unreachable_mut() -> ! { let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 - let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 - let _2: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 - let mut _3: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:34: +1:52 - let mut _4: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + let _1: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 + let mut _2: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:34: +1:52 scope 1 { - debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 } scope 2 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 - StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 - StorageLive(_3); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 -- _3 = const 1_usize as &mut Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 -+ _3 = const {0x1 as &mut Never}; // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 + StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 +- _2 = const 1_usize as &mut Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 ++ _2 = const {0x1 as &mut Never}; // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + // mir::Constant + // + span: no-location + // + literal: Const { ty: &mut Never, val: Value(Scalar(0x0000000000000001)) } - _2 = &mut (*_3); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 - StorageDead(_3); // scope 0 at $DIR/transmute.rs:+1:54: +1:55 - StorageLive(_4); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 + _1 = &mut (*_2); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 + StorageDead(_2); // scope 0 at $DIR/transmute.rs:+1:54: +1:55 unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 } } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.32bit.diff index 8578f898a7e..dcca0fca619 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.32bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.32bit.diff @@ -3,24 +3,20 @@ fn unreachable_ref() -> ! { let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 - let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 - let _2: &Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 - let mut _3: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + let _1: &Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 scope 1 { - debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 } scope 2 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 - StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 -- _2 = const 1_usize as &Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:30: +1:48 -+ _2 = const {0x1 as &Never}; // scope 2 at $DIR/transmute.rs:+1:30: +1:48 + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 +- _1 = const 1_usize as &Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:30: +1:48 ++ _1 = const {0x1 as &Never}; // scope 2 at $DIR/transmute.rs:+1:30: +1:48 + // mir::Constant + // + span: no-location + // + literal: Const { ty: &Never, val: Value(Scalar(0x00000001)) } - StorageLive(_3); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 } } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.64bit.diff index 8b11cea9365..3a0b967e66f 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.64bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.64bit.diff @@ -3,24 +3,20 @@ fn unreachable_ref() -> ! { let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 - let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 - let _2: &Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 - let mut _3: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + let _1: &Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 scope 1 { - debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 } scope 2 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 - StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 -- _2 = const 1_usize as &Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:30: +1:48 -+ _2 = const {0x1 as &Never}; // scope 2 at $DIR/transmute.rs:+1:30: +1:48 + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 +- _1 = const 1_usize as &Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:30: +1:48 ++ _1 = const {0x1 as &Never}; // scope 2 at $DIR/transmute.rs:+1:30: +1:48 + // mir::Constant + // + span: no-location + // + literal: Const { ty: &Never, val: Value(Scalar(0x0000000000000001)) } - StorageLive(_3); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 } } diff --git a/tests/mir-opt/inline/unsized_argument.caller.Inline.diff b/tests/mir-opt/inline/unsized_argument.caller.Inline.diff new file mode 100644 index 00000000000..745f2bb193a --- /dev/null +++ b/tests/mir-opt/inline/unsized_argument.caller.Inline.diff @@ -0,0 +1,50 @@ +- // MIR for `caller` before Inline ++ // MIR for `caller` after Inline + + fn caller(_1: Box<[i32]>) -> () { + debug x => _1; // in scope 0 at $DIR/unsized_argument.rs:+0:11: +0:12 + let mut _0: (); // return place in scope 0 at $DIR/unsized_argument.rs:+0:26: +0:26 + let _2: (); // in scope 0 at $DIR/unsized_argument.rs:+1:5: +1:15 + let mut _3: std::boxed::Box<[i32]>; // in scope 0 at $DIR/unsized_argument.rs:+1:13: +1:14 + let mut _4: (); // in scope 0 at $DIR/unsized_argument.rs:+1:14: +1:15 + let mut _5: (); // in scope 0 at $DIR/unsized_argument.rs:+1:14: +1:15 + let mut _6: (); // in scope 0 at $DIR/unsized_argument.rs:+1:14: +1:15 + let mut _7: *const [i32]; // in scope 0 at $DIR/unsized_argument.rs:+1:13: +1:14 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/unsized_argument.rs:+1:5: +1:15 + StorageLive(_3); // scope 0 at $DIR/unsized_argument.rs:+1:13: +1:14 + _3 = move _1; // scope 0 at $DIR/unsized_argument.rs:+1:13: +1:14 + _7 = (((_3.0: std::ptr::Unique<[i32]>).0: std::ptr::NonNull<[i32]>).0: *const [i32]); // scope 0 at $DIR/unsized_argument.rs:+1:5: +1:15 + _2 = callee(move (*_7)) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/unsized_argument.rs:+1:5: +1:15 + // mir::Constant + // + span: $DIR/unsized_argument.rs:9:5: 9:11 + // + literal: Const { ty: fn([i32]) {callee}, val: Value(<ZST>) } + } + + bb1: { + StorageDead(_3); // scope 0 at $DIR/unsized_argument.rs:+1:14: +1:15 + StorageDead(_2); // scope 0 at $DIR/unsized_argument.rs:+1:15: +1:16 + _0 = const (); // scope 0 at $DIR/unsized_argument.rs:+0:26: +2:2 + return; // scope 0 at $DIR/unsized_argument.rs:+2:2: +2:2 + } + + bb2 (cleanup): { + resume; // scope 0 at $DIR/unsized_argument.rs:+0:1: +2:2 + } + + bb3: { + _4 = alloc::alloc::box_free::<[i32], std::alloc::Global>(move (_3.0: std::ptr::Unique<[i32]>), move (_3.1: std::alloc::Global)) -> bb1; // scope 0 at $DIR/unsized_argument.rs:+1:14: +1:15 + // mir::Constant + // + span: $DIR/unsized_argument.rs:9:14: 9:15 + // + literal: Const { ty: unsafe fn(Unique<[i32]>, std::alloc::Global) {alloc::alloc::box_free::<[i32], std::alloc::Global>}, val: Value(<ZST>) } + } + + bb4 (cleanup): { + _6 = alloc::alloc::box_free::<[i32], std::alloc::Global>(move (_3.0: std::ptr::Unique<[i32]>), move (_3.1: std::alloc::Global)) -> [return: bb2, unwind terminate]; // scope 0 at $DIR/unsized_argument.rs:+1:14: +1:15 + // mir::Constant + // + span: $DIR/unsized_argument.rs:9:14: 9:15 + // + literal: Const { ty: unsafe fn(Unique<[i32]>, std::alloc::Global) {alloc::alloc::box_free::<[i32], std::alloc::Global>}, val: Value(<ZST>) } + } + } + diff --git a/tests/mir-opt/inline/unsized_argument.rs b/tests/mir-opt/inline/unsized_argument.rs new file mode 100644 index 00000000000..b2c51407fd5 --- /dev/null +++ b/tests/mir-opt/inline/unsized_argument.rs @@ -0,0 +1,15 @@ +// needs-unwind +#![feature(unsized_fn_params)] + +#[inline(always)] +fn callee(y: [i32]) {} + +// EMIT_MIR unsized_argument.caller.Inline.diff +fn caller(x: Box<[i32]>) { + callee(*x); +} + +fn main() { + let b = Box::new([1]); + caller(b); +} diff --git a/tests/mir-opt/issue_72181_1.f.built.after.mir b/tests/mir-opt/issue_72181_1.f.built.after.mir index 4086da52011..25f47225113 100644 --- a/tests/mir-opt/issue_72181_1.f.built.after.mir +++ b/tests/mir-opt/issue_72181_1.f.built.after.mir @@ -3,27 +3,13 @@ fn f(_1: Void) -> ! { debug v => _1; // in scope 0 at $DIR/issue_72181_1.rs:+0:6: +0:7 let mut _0: !; // return place in scope 0 at $DIR/issue_72181_1.rs:+0:18: +0:19 - let mut _2: !; // in scope 0 at $DIR/issue_72181_1.rs:+0:20: +2:2 - let mut _3: !; // in scope 0 at $DIR/issue_72181_1.rs:+1:5: +1:15 bb0: { - StorageLive(_2); // scope 0 at $DIR/issue_72181_1.rs:+0:20: +2:2 - StorageLive(_3); // scope 0 at $DIR/issue_72181_1.rs:+1:5: +1:15 FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/issue_72181_1.rs:+1:11: +1:12 unreachable; // scope 0 at $DIR/issue_72181_1.rs:+1:11: +1:12 } bb1: { - unreachable; // scope 0 at $DIR/issue_72181_1.rs:+1:5: +1:15 - } - - bb2: { - StorageDead(_3); // scope 0 at $DIR/issue_72181_1.rs:+1:14: +1:15 - unreachable; // scope 0 at $DIR/issue_72181_1.rs:+0:20: +2:2 - } - - bb3: { - StorageDead(_2); // scope 0 at $DIR/issue_72181_1.rs:+2:1: +2:2 return; // scope 0 at $DIR/issue_72181_1.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff index 8735a750060..aa5d9619d10 100644 --- a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff @@ -3,26 +3,22 @@ fn transmute_to_box_uninhabited() -> ! { let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50 - let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 - let _2: std::boxed::Box<Never>; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 - let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + let _1: std::boxed::Box<Never>; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 scope 1 { - debug x => _2; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 - StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 -- _2 = transmute::<usize, Box<Never>>(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 +- _1 = transmute::<usize, Box<Never>>(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:70:25: 70:44 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> Box<Never> {transmute::<usize, Box<Never>>}, val: Value(<ZST>) } -+ _2 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 ++ _1 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 } bb1: { - StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16 unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13 } } diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff index a772132770c..5fafd45fe85 100644 --- a/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff @@ -3,26 +3,22 @@ fn transmute_to_mut_uninhabited() -> ! { let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50 - let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 - let _2: &mut Never; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 - let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + let _1: &mut Never; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 scope 1 { - debug x => _2; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 - StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 -- _2 = transmute::<usize, &mut Never>(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 +- _1 = transmute::<usize, &mut Never>(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:64:25: 64:44 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> &mut Never {transmute::<usize, &mut Never>}, val: Value(<ZST>) } -+ _2 = const 1_usize as &mut Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 ++ _1 = const 1_usize as &mut Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 } bb1: { - StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16 unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13 } } diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff index c4d53d4e8c7..08dead13211 100644 --- a/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff @@ -3,26 +3,22 @@ fn transmute_to_ref_uninhabited() -> ! { let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50 - let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 - let _2: &Never; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 - let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + let _1: &Never; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 scope 1 { - debug x => _2; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 - StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 -- _2 = transmute::<usize, &Never>(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 +- _1 = transmute::<usize, &Never>(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:58:21: 58:40 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> &Never {transmute::<usize, &Never>}, val: Value(<ZST>) } -+ _2 = const 1_usize as &Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 ++ _1 = const 1_usize as &Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 } bb1: { - StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16 unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13 } } diff --git a/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff index c0cc698c481..28e45909c33 100644 --- a/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff @@ -3,16 +3,15 @@ fn unreachable() -> ! { let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:25: +0:26 - let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:27: +2:2 - let _2: (); // in scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:45 - let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:45 + let _1: (); // in scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:45 + let mut _2: !; // in scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:45 scope 1 { } bb0: { - StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:47 - StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45 -- _3 = std::intrinsics::unreachable() -> unwind unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45 + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:47 + StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45 +- _2 = std::intrinsics::unreachable() -> unwind unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:31:14: 31:43 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn() -> ! {std::intrinsics::unreachable}, val: Value(<ZST>) } diff --git a/tests/run-make-fulldeps/obtain-borrowck/driver.rs b/tests/run-make-fulldeps/obtain-borrowck/driver.rs index 12cbb5a5f12..d342b2ff6d9 100644 --- a/tests/run-make-fulldeps/obtain-borrowck/driver.rs +++ b/tests/run-make-fulldeps/obtain-borrowck/driver.rs @@ -24,7 +24,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_interface::interface::Compiler; use rustc_interface::{Config, Queries}; -use rustc_middle::query::query_values::mir_borrowck; +use rustc_middle::query::queries::mir_borrowck::ProvidedValue; use rustc_middle::query::{ExternProviders, Providers}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -126,7 +126,7 @@ thread_local! { RefCell::new(HashMap::new()); } -fn mir_borrowck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> mir_borrowck<'tcx> { +fn mir_borrowck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ProvidedValue<'tcx> { let body_with_facts = rustc_borrowck::consumers::get_body_with_borrowck_facts(tcx, def_id); // SAFETY: The reader casts the 'static lifetime to 'tcx before using it. let body_with_facts: BodyWithBorrowckFacts<'static> = diff --git a/tests/run-make/CURRENT_RUSTC_VERSION/Makefile b/tests/run-make/CURRENT_RUSTC_VERSION/Makefile new file mode 100644 index 00000000000..7940dae207b --- /dev/null +++ b/tests/run-make/CURRENT_RUSTC_VERSION/Makefile @@ -0,0 +1,6 @@ +include ../tools.mk + +all: + $(RUSTC) --emit=metadata --crate-type lib stable.rs + $(RUSTC) --emit=metadata --extern stable=$(TMPDIR)/libstable.rmeta main.rs 2>&1 >/dev/null \ + | $(CGREP) -e "stable since $$(cat $(S)/src/version)(-[a-zA-Z]+)?" diff --git a/tests/run-make/CURRENT_RUSTC_VERSION/main.rs b/tests/run-make/CURRENT_RUSTC_VERSION/main.rs new file mode 100644 index 00000000000..466aaa82bd4 --- /dev/null +++ b/tests/run-make/CURRENT_RUSTC_VERSION/main.rs @@ -0,0 +1,4 @@ +#![feature(foo)] +extern crate stable; + +fn main() {} diff --git a/tests/run-make/CURRENT_RUSTC_VERSION/stable.rs b/tests/run-make/CURRENT_RUSTC_VERSION/stable.rs new file mode 100644 index 00000000000..2fd09aded60 --- /dev/null +++ b/tests/run-make/CURRENT_RUSTC_VERSION/stable.rs @@ -0,0 +1,5 @@ +#![feature(staged_api)] +#![stable(since = "1.0.0", feature = "rust1")] + +#[stable(since = "CURRENT_RUSTC_VERSION", feature = "foo")] +pub fn foo() {} diff --git a/tests/run-make/debugger-visualizer-dep-info/Makefile b/tests/run-make/debugger-visualizer-dep-info/Makefile new file mode 100644 index 00000000000..0877998a74f --- /dev/null +++ b/tests/run-make/debugger-visualizer-dep-info/Makefile @@ -0,0 +1,9 @@ +include ../tools.mk + +# This test makes sure that files referenced via #[debugger_visualizer] are +# included in `--emit dep-info` output. + +all: + $(RUSTC) --emit dep-info main.rs + $(CGREP) "foo.py" < $(TMPDIR)/main.d + $(CGREP) "my_visualizers/bar.natvis" < $(TMPDIR)/main.d diff --git a/tests/run-make/debugger-visualizer-dep-info/foo.py b/tests/run-make/debugger-visualizer-dep-info/foo.py new file mode 100644 index 00000000000..1bb8bf6d7fd --- /dev/null +++ b/tests/run-make/debugger-visualizer-dep-info/foo.py @@ -0,0 +1 @@ +# empty diff --git a/tests/run-make/debugger-visualizer-dep-info/main.rs b/tests/run-make/debugger-visualizer-dep-info/main.rs new file mode 100644 index 00000000000..3aede2215ea --- /dev/null +++ b/tests/run-make/debugger-visualizer-dep-info/main.rs @@ -0,0 +1,12 @@ +#![debugger_visualizer(gdb_script_file = "foo.py")] + +fn main() { + const _UNUSED: u32 = { + mod inner { + #![debugger_visualizer(natvis_file = "my_visualizers/bar.natvis")] + pub const XYZ: u32 = 123; + } + + inner::XYZ + 1 + }; +} diff --git a/tests/run-make/debugger-visualizer-dep-info/my_visualizers/bar.natvis b/tests/run-make/debugger-visualizer-dep-info/my_visualizers/bar.natvis new file mode 100644 index 00000000000..c341a403902 --- /dev/null +++ b/tests/run-make/debugger-visualizer-dep-info/my_visualizers/bar.natvis @@ -0,0 +1 @@ +<!-- empty --> diff --git a/tests/run-make/incremental-debugger-visualizer/Makefile b/tests/run-make/incremental-debugger-visualizer/Makefile new file mode 100644 index 00000000000..8cfe41597ad --- /dev/null +++ b/tests/run-make/incremental-debugger-visualizer/Makefile @@ -0,0 +1,49 @@ +include ../tools.mk + +# This test makes sure that changes to files referenced via #[debugger_visualizer] +# are picked up when compiling incrementally. + +# We have to copy the source to $(TMPDIR) because Github CI mounts the source +# directory as readonly. We need to apply modifications to some of the source +# file. +SRC_DIR := $(TMPDIR)/src +INCR_CACHE_DIR := $(TMPDIR)/incremental + +all: + rm -rf $(TMPDIR)/* + mkdir $(SRC_DIR) + cp ./foo.rs $(SRC_DIR) + echo "GDB script v1" > $(SRC_DIR)/foo.py + echo "Natvis v1" > $(SRC_DIR)/foo.natvis + $(RUSTC) $(SRC_DIR)/foo.rs \ + --crate-type=rlib \ + --emit metadata \ + -C incremental=$(INCR_CACHE_DIR) \ + -Z incremental-verify-ich + $(CGREP) "GDB script v1" < $(TMPDIR)/libfoo.rmeta + $(CGREP) "Natvis v1" < $(TMPDIR)/libfoo.rmeta + + # Change only the GDB script and check that the change has been picked up + echo "GDB script v2" > $(SRC_DIR)/foo.py + $(RUSTC) $(SRC_DIR)/foo.rs \ + --crate-type=rlib \ + --emit metadata \ + -C incremental=$(INCR_CACHE_DIR) \ + -Z incremental-verify-ich + + $(CGREP) "GDB script v2" < $(TMPDIR)/libfoo.rmeta + $(CGREP) -v "GDB script v1" < $(TMPDIR)/libfoo.rmeta + $(CGREP) "Natvis v1" < $(TMPDIR)/libfoo.rmeta + + # Now change the Natvis version and check that the change has been picked up + echo "Natvis v2" > $(SRC_DIR)/foo.natvis + $(RUSTC) $(SRC_DIR)/foo.rs \ + --crate-type=rlib \ + --emit metadata \ + -C incremental=$(INCR_CACHE_DIR) \ + -Z incremental-verify-ich + + $(CGREP) "GDB script v2" < $(TMPDIR)/libfoo.rmeta + $(CGREP) -v "GDB script v1" < $(TMPDIR)/libfoo.rmeta + $(CGREP) "Natvis v2" < $(TMPDIR)/libfoo.rmeta + $(CGREP) -v "Natvis v1" < $(TMPDIR)/libfoo.rmeta diff --git a/tests/run-make/incremental-debugger-visualizer/foo.rs b/tests/run-make/incremental-debugger-visualizer/foo.rs new file mode 100644 index 00000000000..8daa36a12d3 --- /dev/null +++ b/tests/run-make/incremental-debugger-visualizer/foo.rs @@ -0,0 +1,6 @@ +#![debugger_visualizer(natvis_file = "./foo.natvis")] +#![debugger_visualizer(gdb_script_file = "./foo.py")] + +pub struct Foo { + pub x: u32, +} diff --git a/tests/run-make/issue-83045/Makefile b/tests/run-make/issue-83045/Makefile index 7053da00f6b..b76e184b610 100644 --- a/tests/run-make/issue-83045/Makefile +++ b/tests/run-make/issue-83045/Makefile @@ -29,5 +29,5 @@ all: --crate-type=rlib \ --edition=2018 \ c.rs 2>&1 | tee $(TMPDIR)/output.txt || exit 0 - $(CGREP) E0519 < $(TMPDIR)/output.txt + $(CGREP) E0463 < $(TMPDIR)/output.txt $(CGREP) -v "internal compiler error" < $(TMPDIR)/output.txt diff --git a/tests/run-make/print-native-static-libs/Makefile b/tests/run-make/print-native-static-libs/Makefile new file mode 100644 index 00000000000..98e72d7696f --- /dev/null +++ b/tests/run-make/print-native-static-libs/Makefile @@ -0,0 +1,15 @@ +include ../tools.mk + +# ignore-cross-compile +# ignore-wasm + +all: + $(RUSTC) --crate-type rlib -lbar_cli bar.rs + $(RUSTC) foo.rs -lfoo_cli --crate-type staticlib --print native-static-libs 2>&1 \ + | grep 'note: native-static-libs: ' \ + | sed 's/note: native-static-libs: \(.*\)/\1/' > $(TMPDIR)/libs.txt + + cat $(TMPDIR)/libs.txt | grep -F "glib-2.0" # in bar.rs + cat $(TMPDIR)/libs.txt | grep -F "systemd" # in foo.rs + cat $(TMPDIR)/libs.txt | grep -F "bar_cli" + cat $(TMPDIR)/libs.txt | grep -F "foo_cli" diff --git a/tests/run-make/print-native-static-libs/bar.rs b/tests/run-make/print-native-static-libs/bar.rs new file mode 100644 index 00000000000..a563bbc2a22 --- /dev/null +++ b/tests/run-make/print-native-static-libs/bar.rs @@ -0,0 +1,13 @@ +#[no_mangle] +pub extern "C" fn my_bar_add(left: i32, right: i32) -> i32 { + // Obviously makes no sense but... + unsafe { + g_free(std::ptr::null_mut()); + } + left + right +} + +#[link(name = "glib-2.0")] +extern "C" { + fn g_free(p: *mut ()); +} diff --git a/tests/run-make/print-native-static-libs/foo.rs b/tests/run-make/print-native-static-libs/foo.rs new file mode 100644 index 00000000000..6acaee20ed4 --- /dev/null +++ b/tests/run-make/print-native-static-libs/foo.rs @@ -0,0 +1,15 @@ +extern crate bar; + +#[no_mangle] +pub extern "C" fn my_foo_add(left: i32, right: i32) -> i32 { + // Obviously makes no sense but... + unsafe { + init(std::ptr::null_mut()); + } + bar::my_bar_add(left, right) +} + +#[link(name = "systemd")] +extern "C" { + fn init(p: *mut ()); +} diff --git a/tests/run-make/short-ice/Makefile b/tests/run-make/short-ice/Makefile new file mode 100644 index 00000000000..4f33d590237 --- /dev/null +++ b/tests/run-make/short-ice/Makefile @@ -0,0 +1,9 @@ +include ../tools.mk + +# ignore-windows + +export RUSTC := $(RUSTC_ORIGINAL) +export TMPDIR := $(TMPDIR) + +all: + bash check.sh diff --git a/tests/run-make/short-ice/check.sh b/tests/run-make/short-ice/check.sh new file mode 100644 index 00000000000..96cd8fe86bc --- /dev/null +++ b/tests/run-make/short-ice/check.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +RUST_BACKTRACE=1 $RUSTC src/lib.rs -Z treat-err-as-bug=1 1>$TMPDIR/rust-test-1.log 2>&1 +RUST_BACKTRACE=full $RUSTC src/lib.rs -Z treat-err-as-bug=1 1>$TMPDIR/rust-test-2.log 2>&1 + +short=$(cat $TMPDIR/rust-test-1.log | wc -l) +full=$(cat $TMPDIR/rust-test-2.log | wc -l) +rustc_query_count=$(cat $TMPDIR/rust-test-1.log | grep rustc_query_ | wc -l) +rustc_query_count_full=$(cat $TMPDIR/rust-test-2.log | grep rustc_query_ | wc -l) + +begin_count=$(cat $TMPDIR/rust-test-2.log | grep __rust_begin_short_backtrace | wc -l) +end_count=$(cat $TMPDIR/rust-test-2.log | grep __rust_end_short_backtrace | wc -l) + +cat $TMPDIR/rust-test-1.log +echo "=====================" +cat $TMPDIR/rust-test-2.log +echo "=====================" + +echo "short backtrace: $short" +echo "full backtrace: $full" +echo "begin_count: $begin_count" +echo "end_count : $end_count" +echo "rustc_query_count: $rustc_query_count" +echo "rustc_query_count_full: $rustc_query_count_full" + +## backtraces to vary a bit depending on platform and configuration options, +## here we make sure that the short backtrace of rustc_query is shorter than the full, +## and marks are in pairs. +if [ $short -lt $full ] && + [ $begin_count -eq $end_count ] && + [ $(($rustc_query_count + 10)) -lt $rustc_query_count_full ] && + [ $rustc_query_count_full -gt 10 ]; then + exit 0 +else + exit 1 +fi diff --git a/tests/run-make/short-ice/src/lib.rs b/tests/run-make/short-ice/src/lib.rs new file mode 100644 index 00000000000..b23b7f830d7 --- /dev/null +++ b/tests/run-make/short-ice/src/lib.rs @@ -0,0 +1,7 @@ +fn func(s: &str) { + println!("{}", s); +} + +fn main() { + func(1); +} diff --git a/tests/rustdoc-gui/anchors.goml b/tests/rustdoc-gui/anchors.goml index 0904aa90e1b..e9b77296917 100644 --- a/tests/rustdoc-gui/anchors.goml +++ b/tests/rustdoc-gui/anchors.goml @@ -75,35 +75,35 @@ call-function: ( "check-colors", { "theme": "ayu", - "main_color": "rgb(197, 197, 197)", - "title_color": "rgb(255, 255, 255)", - "main_heading_color": "rgb(255, 255, 255)", - "main_heading_type_color": "rgb(255, 160, 165)", - "src_link_color": "rgb(57, 175, 215)", - "sidebar_link_color": "rgb(83, 177, 219)", + "main_color": "#c5c5c5", + "title_color": "#fff", + "main_heading_color": "#fff", + "main_heading_type_color": "#ffa0a5", + "src_link_color": "#39afd7", + "sidebar_link_color": "#53b1db", }, ) call-function: ( "check-colors", { "theme": "dark", - "main_color": "rgb(221, 221, 221)", - "title_color": "rgb(221, 221, 221)", - "main_heading_color": "rgb(221, 221, 221)", - "main_heading_type_color": "rgb(45, 191, 184)", - "src_link_color": "rgb(210, 153, 29)", - "sidebar_link_color": "rgb(253, 191, 53)", + "main_color": "#ddd", + "title_color": "#ddd", + "main_heading_color": "#ddd", + "main_heading_type_color": "#2dbfb8", + "src_link_color": "#d2991d", + "sidebar_link_color": "#fdbf35", }, ) call-function: ( "check-colors", { "theme": "light", - "main_color": "rgb(0, 0, 0)", - "title_color": "rgb(0, 0, 0)", - "main_heading_color": "rgb(0, 0, 0)", - "main_heading_type_color": "rgb(173, 55, 138)", - "src_link_color": "rgb(56, 115, 173)", - "sidebar_link_color": "rgb(53, 109, 164)", + "main_color": "black", + "title_color": "black", + "main_heading_color": "black", + "main_heading_type_color": "#ad378a", + "src_link_color": "#3873ad", + "sidebar_link_color": "#356da4", }, ) diff --git a/tests/rustdoc-gui/codeblock-tooltip.goml b/tests/rustdoc-gui/codeblock-tooltip.goml index 2ed0579d314..e1c81ed79e4 100644 --- a/tests/rustdoc-gui/codeblock-tooltip.goml +++ b/tests/rustdoc-gui/codeblock-tooltip.goml @@ -109,19 +109,19 @@ define-function: ( call-function: ("check-colors", { "theme": "ayu", - "background": "rgb(15, 20, 25)", - "color": "rgb(197, 197, 197)", - "border": "rgb(92, 103, 115)", + "background": "#0f1419", + "color": "#c5c5c5", + "border": "#5c6773", }) call-function: ("check-colors", { "theme": "dark", - "background": "rgb(53, 53, 53)", - "color": "rgb(221, 221, 221)", - "border": "rgb(224, 224, 224)", + "background": "#353535", + "color": "#ddd", + "border": "#e0e0e0", }) call-function: ("check-colors", { "theme": "light", - "background": "rgb(255, 255, 255)", - "color": "rgb(0, 0, 0)", - "border": "rgb(224, 224, 224)", + "background": "white", + "color": "black", + "border": "#e0e0e0", }) diff --git a/tests/rustdoc-gui/jump-to-def-background.goml b/tests/rustdoc-gui/jump-to-def-background.goml index 3a7d48284d7..6adc36b0edb 100644 --- a/tests/rustdoc-gui/jump-to-def-background.goml +++ b/tests/rustdoc-gui/jump-to-def-background.goml @@ -17,6 +17,6 @@ define-function: ( }, ) -call-function: ("check-background-color", ("ayu", "rgb(51, 51, 51)")) -call-function: ("check-background-color", ("dark", "rgb(51, 51, 51)")) -call-function: ("check-background-color", ("light", "rgb(238, 238, 238)")) +call-function: ("check-background-color", ("ayu", "#333")) +call-function: ("check-background-color", ("dark", "#333")) +call-function: ("check-background-color", ("light", "#eee")) diff --git a/tests/rustdoc-gui/scrape-examples-color.goml b/tests/rustdoc-gui/scrape-examples-color.goml index 8ddb06fccfc..0052d18dc56 100644 --- a/tests/rustdoc-gui/scrape-examples-color.goml +++ b/tests/rustdoc-gui/scrape-examples-color.goml @@ -33,30 +33,30 @@ define-function: ( call-function: ("check-colors", { "theme": "ayu", - "highlight": "rgb(91, 59, 1)", - "highlight_focus": "rgb(124, 75, 15)", - "help_border": "rgb(170, 170, 170)", - "help_color": "rgb(238, 238, 238)", - "help_hover_border": "rgb(255, 255, 255)", - "help_hover_color": "rgb(255, 255, 255)", + "highlight": "#5b3b01", + "highlight_focus": "#7c4b0f", + "help_border": "#aaa", + "help_color": "#eee", + "help_hover_border": "#fff", + "help_hover_color": "#fff", }) call-function: ("check-colors", { "theme": "dark", - "highlight": "rgb(91, 59, 1)", - "highlight_focus": "rgb(124, 75, 15)", - "help_border": "rgb(170, 170, 170)", - "help_color": "rgb(238, 238, 238)", - "help_hover_border": "rgb(255, 255, 255)", - "help_hover_color": "rgb(255, 255, 255)", + "highlight": "#5b3b01", + "highlight_focus": "#7c4b0f", + "help_border": "#aaa", + "help_color": "#eee", + "help_hover_border": "#fff", + "help_hover_color": "#fff", }) call-function: ("check-colors", { "theme": "light", - "highlight": "rgb(252, 255, 214)", - "highlight_focus": "rgb(246, 253, 176)", - "help_border": "rgb(85, 85, 85)", - "help_color": "rgb(51, 51, 51)", - "help_hover_border": "rgb(0, 0, 0)", - "help_hover_color": "rgb(0, 0, 0)", + "highlight": "#fcffd6", + "highlight_focus": "#f6fdb0", + "help_border": "#555", + "help_color": "#333", + "help_hover_border": "#000", + "help_hover_color": "#000", }) // Now testing the top and bottom background in case there is only one scraped examples. @@ -81,16 +81,16 @@ define-function: ( call-function: ("check-background", { "theme": "ayu", - "background_color_start": "rgb(15, 20, 25)", + "background_color_start": "rgba(15, 20, 25, 1)", "background_color_end": "rgba(15, 20, 25, 0)", }) call-function: ("check-background", { "theme": "dark", - "background_color_start": "rgb(53, 53, 53)", + "background_color_start": "rgba(53, 53, 53, 1)", "background_color_end": "rgba(53, 53, 53, 0)", }) call-function: ("check-background", { "theme": "light", - "background_color_start": "rgb(255, 255, 255)", + "background_color_start": "rgba(255, 255, 255, 1)", "background_color_end": "rgba(255, 255, 255, 0)", }) diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml index bf1fe7be910..c37d969324c 100644 --- a/tests/rustdoc-gui/settings.goml +++ b/tests/rustdoc-gui/settings.goml @@ -301,7 +301,7 @@ wait-for-css: ("#help-button .popover", {"display": "block"}) // Now we go to the settings page to check that the CSS is loaded as expected. go-to: "file://" + |DOC_PATH| + "/settings.html" wait-for: "#settings" -assert-css: (".setting-line", {"position": "relative"}) +assert-css: (".setting-radio", {"cursor": "pointer"}) assert-attribute-false: ("#settings", {"class": "popover"}, CONTAINS) compare-elements-position: (".sub form", "#settings", ("x")) @@ -322,4 +322,4 @@ reload: set-window-size: (300, 1000) click: "#settings-menu" wait-for: "#settings" -assert-css: (".setting-line", {"position": "relative"}) +assert-css: (".setting-radio", {"cursor": "pointer"}) diff --git a/tests/rustdoc-gui/source-code-page.goml b/tests/rustdoc-gui/source-code-page.goml index 5c795928bdc..d5dd511b1d3 100644 --- a/tests/rustdoc-gui/source-code-page.goml +++ b/tests/rustdoc-gui/source-code-page.goml @@ -40,24 +40,24 @@ define-function: ( call-function: ("check-colors", { "theme": "ayu", - "color": "rgb(92, 103, 115)", - "background_color": "rgba(0, 0, 0, 0)", - "highlight_color": "rgb(112, 128, 144)", + "color": "#5c6773", + "background_color": "transparent", + "highlight_color": "#708090", "highlight_background_color": "rgba(255, 236, 164, 0.06)", }) call-function: ("check-colors", { "theme": "dark", - "color": "rgb(59, 145, 226)", - "background_color": "rgba(0, 0, 0, 0)", - "highlight_color": "rgb(59, 145, 226)", - "highlight_background_color": "rgb(10, 4, 47)", + "color": "#3b91e2", + "background_color": "transparent", + "highlight_color": "#3b91e2", + "highlight_background_color": "#0a042f", }) call-function: ("check-colors", { "theme": "light", - "color": "rgb(198, 126, 45)", - "background_color": "rgba(0, 0, 0, 0)", - "highlight_color": "rgb(198, 126, 45)", - "highlight_background_color": "rgb(253, 255, 211)", + "color": "#c67e2d", + "background_color": "transparent", + "highlight_color": "#c67e2d", + "highlight_background_color": "#fdffd3", }) // This is to ensure that the content is correctly align with the line numbers. diff --git a/tests/rustdoc-json/assoc_items.rs b/tests/rustdoc-json/assoc_items.rs index 6d7f6bb969f..05c2d428393 100644 --- a/tests/rustdoc-json/assoc_items.rs +++ b/tests/rustdoc-json/assoc_items.rs @@ -3,35 +3,32 @@ pub struct Simple; impl Simple { - // @is "$.index[*][?(@.name=='CONSTANT')].kind" \"assoc_const\" + // @has "$.index[*][?(@.name=='CONSTANT')].inner.assoc_const" pub const CONSTANT: usize = 0; } pub trait EasyToImpl { - // @is "$.index[*][?(@.docs=='ToDeclare trait')].kind" \"assoc_type\" - // @is "$.index[*][?(@.docs=='ToDeclare trait')].inner.default" null - // @is "$.index[*][?(@.docs=='ToDeclare trait')].inner.bounds" [] + // @has "$.index[*][?(@.docs=='ToDeclare trait')].inner.assoc_type" + // @is "$.index[*][?(@.docs=='ToDeclare trait')].inner.assoc_type.default" null + // @is "$.index[*][?(@.docs=='ToDeclare trait')].inner.assoc_type.bounds" [] /// ToDeclare trait type ToDeclare; - // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].kind" \"assoc_const\" - // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.default" null - // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.type.kind" '"primitive"' - // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.type.inner" '"usize"' + // @has "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const" + // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const.default" null + // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const.type.primitive" '"usize"' /// AN_ATTRIBUTE trait const AN_ATTRIBUTE: usize; } impl EasyToImpl for Simple { - // @is "$.index[*][?(@.docs=='ToDeclare impl')].kind" '"assoc_type"' - // @is "$.index[*][?(@.docs=='ToDeclare impl')].inner.default.kind" \"primitive\" - // @is "$.index[*][?(@.docs=='ToDeclare impl')].inner.default.inner" \"usize\" + // @has "$.index[*][?(@.docs=='ToDeclare impl')].inner.assoc_type" + // @is "$.index[*][?(@.docs=='ToDeclare impl')].inner.assoc_type.default.primitive" \"usize\" /// ToDeclare impl type ToDeclare = usize; - // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].kind" '"assoc_const"' - // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.type.kind" \"primitive\" - // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.type.inner" \"usize\" - // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.default" \"12\" + // @has "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const" + // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const.type.primitive" \"usize\" + // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const.default" \"12\" /// AN_ATTRIBUTE impl const AN_ATTRIBUTE: usize = 12; } diff --git a/tests/rustdoc-json/blanket_impls.rs b/tests/rustdoc-json/blanket_impls.rs index c5cc87ca1eb..a2a5c4a7146 100644 --- a/tests/rustdoc-json/blanket_impls.rs +++ b/tests/rustdoc-json/blanket_impls.rs @@ -2,7 +2,7 @@ #![no_std] -// @has "$.index[*][?(@.name=='Error')].kind" \"assoc_type\" -// @has "$.index[*][?(@.name=='Error')].inner.default.kind" \"resolved_path\" -// @has "$.index[*][?(@.name=='Error')].inner.default.inner.name" \"Infallible\" +// @has "$.index[*][?(@.name=='Error')].inner.assoc_type" +// @has "$.index[*][?(@.name=='Error')].inner.assoc_type.default.resolved_path" +// @has "$.index[*][?(@.name=='Error')].inner.assoc_type.default.resolved_path.name" \"Infallible\" pub struct ForBlanketTryFromImpl; diff --git a/tests/rustdoc-json/enums/discriminant/basic.rs b/tests/rustdoc-json/enums/discriminant/basic.rs index 06906df3b2c..dbfc5c2cf6b 100644 --- a/tests/rustdoc-json/enums/discriminant/basic.rs +++ b/tests/rustdoc-json/enums/discriminant/basic.rs @@ -1,12 +1,12 @@ #[repr(i8)] pub enum Ordering { - // @is "$.index[*][?(@.name=='Less')].inner.discriminant.expr" '"-1"' - // @is "$.index[*][?(@.name=='Less')].inner.discriminant.value" '"-1"' + // @is "$.index[*][?(@.name=='Less')].inner.variant.discriminant.expr" '"-1"' + // @is "$.index[*][?(@.name=='Less')].inner.variant.discriminant.value" '"-1"' Less = -1, - // @is "$.index[*][?(@.name=='Equal')].inner.discriminant.expr" '"0"' - // @is "$.index[*][?(@.name=='Equal')].inner.discriminant.value" '"0"' + // @is "$.index[*][?(@.name=='Equal')].inner.variant.discriminant.expr" '"0"' + // @is "$.index[*][?(@.name=='Equal')].inner.variant.discriminant.value" '"0"' Equal = 0, - // @is "$.index[*][?(@.name=='Greater')].inner.discriminant.expr" '"1"' - // @is "$.index[*][?(@.name=='Greater')].inner.discriminant.value" '"1"' + // @is "$.index[*][?(@.name=='Greater')].inner.variant.discriminant.expr" '"1"' + // @is "$.index[*][?(@.name=='Greater')].inner.variant.discriminant.value" '"1"' Greater = 1, } diff --git a/tests/rustdoc-json/enums/discriminant/expr.rs b/tests/rustdoc-json/enums/discriminant/expr.rs index e639965e79b..ddcad58a550 100644 --- a/tests/rustdoc-json/enums/discriminant/expr.rs +++ b/tests/rustdoc-json/enums/discriminant/expr.rs @@ -1,30 +1,30 @@ pub enum Foo { - // @is "$.index[*][?(@.name=='Addition')].inner.discriminant.value" '"0"' - // @is "$.index[*][?(@.name=='Addition')].inner.discriminant.expr" '"{ _ }"' + // @is "$.index[*][?(@.name=='Addition')].inner.variant.discriminant.value" '"0"' + // @is "$.index[*][?(@.name=='Addition')].inner.variant.discriminant.expr" '"{ _ }"' Addition = 0 + 0, - // @is "$.index[*][?(@.name=='Bin')].inner.discriminant.value" '"1"' - // @is "$.index[*][?(@.name=='Bin')].inner.discriminant.expr" '"0b1"' + // @is "$.index[*][?(@.name=='Bin')].inner.variant.discriminant.value" '"1"' + // @is "$.index[*][?(@.name=='Bin')].inner.variant.discriminant.expr" '"0b1"' Bin = 0b1, - // @is "$.index[*][?(@.name=='Oct')].inner.discriminant.value" '"2"' - // @is "$.index[*][?(@.name=='Oct')].inner.discriminant.expr" '"0o2"' + // @is "$.index[*][?(@.name=='Oct')].inner.variant.discriminant.value" '"2"' + // @is "$.index[*][?(@.name=='Oct')].inner.variant.discriminant.expr" '"0o2"' Oct = 0o2, - // @is "$.index[*][?(@.name=='PubConst')].inner.discriminant.value" '"3"' - // @is "$.index[*][?(@.name=='PubConst')].inner.discriminant.expr" '"THREE"' + // @is "$.index[*][?(@.name=='PubConst')].inner.variant.discriminant.value" '"3"' + // @is "$.index[*][?(@.name=='PubConst')].inner.variant.discriminant.expr" '"THREE"' PubConst = THREE, - // @is "$.index[*][?(@.name=='Hex')].inner.discriminant.value" '"4"' - // @is "$.index[*][?(@.name=='Hex')].inner.discriminant.expr" '"0x4"' + // @is "$.index[*][?(@.name=='Hex')].inner.variant.discriminant.value" '"4"' + // @is "$.index[*][?(@.name=='Hex')].inner.variant.discriminant.expr" '"0x4"' Hex = 0x4, - // @is "$.index[*][?(@.name=='Cast')].inner.discriminant.value" '"5"' - // @is "$.index[*][?(@.name=='Cast')].inner.discriminant.expr" '"{ _ }"' + // @is "$.index[*][?(@.name=='Cast')].inner.variant.discriminant.value" '"5"' + // @is "$.index[*][?(@.name=='Cast')].inner.variant.discriminant.expr" '"{ _ }"' Cast = 5 as isize, - // @is "$.index[*][?(@.name=='PubCall')].inner.discriminant.value" '"6"' - // @is "$.index[*][?(@.name=='PubCall')].inner.discriminant.expr" '"{ _ }"' + // @is "$.index[*][?(@.name=='PubCall')].inner.variant.discriminant.value" '"6"' + // @is "$.index[*][?(@.name=='PubCall')].inner.variant.discriminant.expr" '"{ _ }"' PubCall = six(), - // @is "$.index[*][?(@.name=='PrivCall')].inner.discriminant.value" '"7"' - // @is "$.index[*][?(@.name=='PrivCall')].inner.discriminant.expr" '"{ _ }"' + // @is "$.index[*][?(@.name=='PrivCall')].inner.variant.discriminant.value" '"7"' + // @is "$.index[*][?(@.name=='PrivCall')].inner.variant.discriminant.expr" '"{ _ }"' PrivCall = seven(), - // @is "$.index[*][?(@.name=='PrivConst')].inner.discriminant.value" '"8"' - // @is "$.index[*][?(@.name=='PrivConst')].inner.discriminant.expr" '"EIGHT"' + // @is "$.index[*][?(@.name=='PrivConst')].inner.variant.discriminant.value" '"8"' + // @is "$.index[*][?(@.name=='PrivConst')].inner.variant.discriminant.expr" '"EIGHT"' PrivConst = EIGHT, } diff --git a/tests/rustdoc-json/enums/discriminant/limits.rs b/tests/rustdoc-json/enums/discriminant/limits.rs index e56d5594f2f..47fb7040896 100644 --- a/tests/rustdoc-json/enums/discriminant/limits.rs +++ b/tests/rustdoc-json/enums/discriminant/limits.rs @@ -4,40 +4,40 @@ #[repr(u64)] pub enum U64 { - // @is "$.index[*][?(@.name=='U64Min')].inner.discriminant.value" '"0"' - // @is "$.index[*][?(@.name=='U64Min')].inner.discriminant.expr" '"u64::MIN"' + // @is "$.index[*][?(@.name=='U64Min')].inner.variant.discriminant.value" '"0"' + // @is "$.index[*][?(@.name=='U64Min')].inner.variant.discriminant.expr" '"u64::MIN"' U64Min = u64::MIN, - // @is "$.index[*][?(@.name=='U64Max')].inner.discriminant.value" '"18446744073709551615"' - // @is "$.index[*][?(@.name=='U64Max')].inner.discriminant.expr" '"u64::MAX"' + // @is "$.index[*][?(@.name=='U64Max')].inner.variant.discriminant.value" '"18446744073709551615"' + // @is "$.index[*][?(@.name=='U64Max')].inner.variant.discriminant.expr" '"u64::MAX"' U64Max = u64::MAX, } #[repr(i64)] pub enum I64 { - // @is "$.index[*][?(@.name=='I64Min')].inner.discriminant.value" '"-9223372036854775808"' - // @is "$.index[*][?(@.name=='I64Min')].inner.discriminant.expr" '"i64::MIN"' + // @is "$.index[*][?(@.name=='I64Min')].inner.variant.discriminant.value" '"-9223372036854775808"' + // @is "$.index[*][?(@.name=='I64Min')].inner.variant.discriminant.expr" '"i64::MIN"' I64Min = i64::MIN, - // @is "$.index[*][?(@.name=='I64Max')].inner.discriminant.value" '"9223372036854775807"' - // @is "$.index[*][?(@.name=='I64Max')].inner.discriminant.expr" '"i64::MAX"' + // @is "$.index[*][?(@.name=='I64Max')].inner.variant.discriminant.value" '"9223372036854775807"' + // @is "$.index[*][?(@.name=='I64Max')].inner.variant.discriminant.expr" '"i64::MAX"' I64Max = i64::MAX, } #[repr(u128)] pub enum U128 { - // @is "$.index[*][?(@.name=='U128Min')].inner.discriminant.value" '"0"' - // @is "$.index[*][?(@.name=='U128Min')].inner.discriminant.expr" '"u128::MIN"' + // @is "$.index[*][?(@.name=='U128Min')].inner.variant.discriminant.value" '"0"' + // @is "$.index[*][?(@.name=='U128Min')].inner.variant.discriminant.expr" '"u128::MIN"' U128Min = u128::MIN, - // @is "$.index[*][?(@.name=='U128Max')].inner.discriminant.value" '"340282366920938463463374607431768211455"' - // @is "$.index[*][?(@.name=='U128Max')].inner.discriminant.expr" '"u128::MAX"' + // @is "$.index[*][?(@.name=='U128Max')].inner.variant.discriminant.value" '"340282366920938463463374607431768211455"' + // @is "$.index[*][?(@.name=='U128Max')].inner.variant.discriminant.expr" '"u128::MAX"' U128Max = u128::MAX, } #[repr(i128)] pub enum I128 { - // @is "$.index[*][?(@.name=='I128Min')].inner.discriminant.value" '"-170141183460469231731687303715884105728"' - // @is "$.index[*][?(@.name=='I128Min')].inner.discriminant.expr" '"i128::MIN"' + // @is "$.index[*][?(@.name=='I128Min')].inner.variant.discriminant.value" '"-170141183460469231731687303715884105728"' + // @is "$.index[*][?(@.name=='I128Min')].inner.variant.discriminant.expr" '"i128::MIN"' I128Min = i128::MIN, - // @is "$.index[*][?(@.name=='I128Max')].inner.discriminant.value" '"170141183460469231731687303715884105727"' - // @is "$.index[*][?(@.name=='I128Max')].inner.discriminant.expr" '"i128::MAX"' + // @is "$.index[*][?(@.name=='I128Max')].inner.variant.discriminant.value" '"170141183460469231731687303715884105727"' + // @is "$.index[*][?(@.name=='I128Max')].inner.variant.discriminant.expr" '"i128::MAX"' I128Max = i128::MAX, } diff --git a/tests/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs b/tests/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs index 6889b305ffb..9c3db81c663 100644 --- a/tests/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs +++ b/tests/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs @@ -1,15 +1,17 @@ +// ignore-tidy-linelength + #[repr(u32)] pub enum Foo { - // @is "$.index[*][?(@.name=='Basic')].inner.discriminant.value" '"0"' - // @is "$.index[*][?(@.name=='Basic')].inner.discriminant.expr" '"0"' + // @is "$.index[*][?(@.name=='Basic')].inner.variant.discriminant.value" '"0"' + // @is "$.index[*][?(@.name=='Basic')].inner.variant.discriminant.expr" '"0"' Basic = 0, - // @is "$.index[*][?(@.name=='Suffix')].inner.discriminant.value" '"10"' - // @is "$.index[*][?(@.name=='Suffix')].inner.discriminant.expr" '"10u32"' + // @is "$.index[*][?(@.name=='Suffix')].inner.variant.discriminant.value" '"10"' + // @is "$.index[*][?(@.name=='Suffix')].inner.variant.discriminant.expr" '"10u32"' Suffix = 10u32, - // @is "$.index[*][?(@.name=='Underscore')].inner.discriminant.value" '"100"' - // @is "$.index[*][?(@.name=='Underscore')].inner.discriminant.expr" '"1_0_0"' + // @is "$.index[*][?(@.name=='Underscore')].inner.variant.discriminant.value" '"100"' + // @is "$.index[*][?(@.name=='Underscore')].inner.variant.discriminant.expr" '"1_0_0"' Underscore = 1_0_0, - // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.discriminant.value" '"1000"' - // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.discriminant.expr" '"1_0_0_0u32"' + // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant.discriminant.value" '"1000"' + // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant.discriminant.expr" '"1_0_0_0u32"' SuffixUnderscore = 1_0_0_0u32, } diff --git a/tests/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs b/tests/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs index 6a4f54de617..38ba1caf140 100644 --- a/tests/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs +++ b/tests/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs @@ -1,10 +1,12 @@ +// ignore-tidy-linelength + pub enum Foo { - // @is "$.index[*][?(@.name=='Has')].inner.discriminant" '{"expr":"0", "value":"0"}' + // @is "$.index[*][?(@.name=='Has')].inner.variant.discriminant" '{"expr":"0", "value":"0"}' Has = 0, - // @is "$.index[*][?(@.name=='Doesnt')].inner.discriminant" null + // @is "$.index[*][?(@.name=='Doesnt')].inner.variant.discriminant" null Doesnt, - // @is "$.index[*][?(@.name=='AlsoDoesnt')].inner.discriminant" null + // @is "$.index[*][?(@.name=='AlsoDoesnt')].inner.variant.discriminant" null AlsoDoesnt, - // @is "$.index[*][?(@.name=='AlsoHas')].inner.discriminant" '{"expr":"44", "value":"44"}' + // @is "$.index[*][?(@.name=='AlsoHas')].inner.variant.discriminant" '{"expr":"44", "value":"44"}' AlsoHas = 44, } diff --git a/tests/rustdoc-json/enums/discriminant/struct.rs b/tests/rustdoc-json/enums/discriminant/struct.rs index e91a632a3b3..c4b087c3635 100644 --- a/tests/rustdoc-json/enums/discriminant/struct.rs +++ b/tests/rustdoc-json/enums/discriminant/struct.rs @@ -3,13 +3,13 @@ #[repr(i32)] // @is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(i32)]"]' pub enum Foo { - // @is "$.index[*][?(@.name=='Struct')].inner.discriminant" null - // @count "$.index[*][?(@.name=='Struct')].inner.kind.struct.fields[*]" 0 + // @is "$.index[*][?(@.name=='Struct')].inner.variant.discriminant" null + // @count "$.index[*][?(@.name=='Struct')].inner.variant.kind.struct.fields[*]" 0 Struct {}, - // @is "$.index[*][?(@.name=='StructWithDiscr')].inner.discriminant" '{"expr": "42", "value": "42"}' - // @count "$.index[*][?(@.name=='StructWithDiscr')].inner.kind.struct.fields[*]" 1 + // @is "$.index[*][?(@.name=='StructWithDiscr')].inner.variant.discriminant" '{"expr": "42", "value": "42"}' + // @count "$.index[*][?(@.name=='StructWithDiscr')].inner.variant.kind.struct.fields[*]" 1 StructWithDiscr { x: i32 } = 42, - // @is "$.index[*][?(@.name=='StructWithHexDiscr')].inner.discriminant" '{"expr": "0x42", "value": "66"}' - // @count "$.index[*][?(@.name=='StructWithHexDiscr')].inner.kind.struct.fields[*]" 2 + // @is "$.index[*][?(@.name=='StructWithHexDiscr')].inner.variant.discriminant" '{"expr": "0x42", "value": "66"}' + // @count "$.index[*][?(@.name=='StructWithHexDiscr')].inner.variant.kind.struct.fields[*]" 2 StructWithHexDiscr { x: i32, y: bool } = 0x42, } diff --git a/tests/rustdoc-json/enums/discriminant/tuple.rs b/tests/rustdoc-json/enums/discriminant/tuple.rs index b94d5739eab..7da82ec8ea4 100644 --- a/tests/rustdoc-json/enums/discriminant/tuple.rs +++ b/tests/rustdoc-json/enums/discriminant/tuple.rs @@ -3,13 +3,13 @@ #[repr(u32)] // @is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(u32)]"]' pub enum Foo { - // @is "$.index[*][?(@.name=='Tuple')].inner.discriminant" null - // @count "$.index[*][?(@.name=='Tuple')].inner.kind.tuple[*]" 0 + // @is "$.index[*][?(@.name=='Tuple')].inner.variant.discriminant" null + // @count "$.index[*][?(@.name=='Tuple')].inner.variant.kind.tuple[*]" 0 Tuple(), - // @is "$.index[*][?(@.name=='TupleWithDiscr')].inner.discriminant" '{"expr": "1", "value": "1"}' - // @count "$.index[*][?(@.name=='TupleWithDiscr')].inner.kind.tuple[*]" 1 + // @is "$.index[*][?(@.name=='TupleWithDiscr')].inner.variant.discriminant" '{"expr": "1", "value": "1"}' + // @count "$.index[*][?(@.name=='TupleWithDiscr')].inner.variant.kind.tuple[*]" 1 TupleWithDiscr(i32) = 1, - // @is "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.discriminant" '{"expr": "0b10", "value": "2"}' - // @count "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.kind.tuple[*]" 2 + // @is "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.variant.discriminant" '{"expr": "0b10", "value": "2"}' + // @count "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.variant.kind.tuple[*]" 2 TupleWithBinDiscr(i32, i32) = 0b10, } diff --git a/tests/rustdoc-json/enums/doc_link_to_foreign_variant.rs b/tests/rustdoc-json/enums/doc_link_to_foreign_variant.rs index 470b195a292..b00156124fc 100644 --- a/tests/rustdoc-json/enums/doc_link_to_foreign_variant.rs +++ b/tests/rustdoc-json/enums/doc_link_to_foreign_variant.rs @@ -5,7 +5,7 @@ extern crate color; use color::Color::Red; -// @set red = "$.index[*][?(@.inner.is_crate == true)].links.Red" +// @set red = "$.index[*][?(@.inner.module.is_crate)].links.Red" // @!has "$.index[*][?(@.name == 'Red')]" // @!has "$.index[*][?(@.name == 'Color')]" diff --git a/tests/rustdoc-json/enums/field_hidden.rs b/tests/rustdoc-json/enums/field_hidden.rs index 78a05431472..5c0d0ffd3df 100644 --- a/tests/rustdoc-json/enums/field_hidden.rs +++ b/tests/rustdoc-json/enums/field_hidden.rs @@ -5,8 +5,8 @@ // @has "$.index[*][?(@.name=='ParseError')]" // @has "$.index[*][?(@.name=='UnexpectedEndTag')]" -// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.kind.tuple" [null] -// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.discriminant" null +// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant.kind.tuple" [null] +// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant.discriminant" null pub enum ParseError { UnexpectedEndTag(#[doc(hidden)] u32), diff --git a/tests/rustdoc-json/enums/kind.rs b/tests/rustdoc-json/enums/kind.rs index 1787a859c8b..e283c074006 100644 --- a/tests/rustdoc-json/enums/kind.rs +++ b/tests/rustdoc-json/enums/kind.rs @@ -5,28 +5,28 @@ pub enum Foo { // @set Unit = "$.index[*][?(@.name=='Unit')].id" - // @is "$.index[*][?(@.name=='Unit')].inner.kind" '"plain"' + // @is "$.index[*][?(@.name=='Unit')].inner.variant.kind" '"plain"' Unit, // @set Named = "$.index[*][?(@.name=='Named')].id" - // @is "$.index[*][?(@.name=='Named')].inner.kind.struct" '{"fields": [], "fields_stripped": false}' + // @is "$.index[*][?(@.name=='Named')].inner.variant.kind.struct" '{"fields": [], "fields_stripped": false}' Named {}, // @set Tuple = "$.index[*][?(@.name=='Tuple')].id" - // @is "$.index[*][?(@.name=='Tuple')].inner.kind.tuple" [] + // @is "$.index[*][?(@.name=='Tuple')].inner.variant.kind.tuple" [] Tuple(), // @set NamedField = "$.index[*][?(@.name=='NamedField')].id" - // @set x = "$.index[*][?(@.name=='x' && @.kind=='struct_field')].id" - // @is "$.index[*][?(@.name=='NamedField')].inner.kind.struct.fields[*]" $x - // @is "$.index[*][?(@.name=='NamedField')].inner.kind.struct.fields_stripped" false + // @set x = "$.index[*][?(@.name=='x' && @.inner.struct_field)].id" + // @is "$.index[*][?(@.name=='NamedField')].inner.variant.kind.struct.fields[*]" $x + // @is "$.index[*][?(@.name=='NamedField')].inner.variant.kind.struct.fields_stripped" false NamedField { x: i32 }, // @set TupleField = "$.index[*][?(@.name=='TupleField')].id" - // @set tup_field = "$.index[*][?(@.name=='0' && @.kind=='struct_field')].id" - // @is "$.index[*][?(@.name=='TupleField')].inner.kind.tuple[*]" $tup_field + // @set tup_field = "$.index[*][?(@.name=='0' && @.inner.struct_field)].id" + // @is "$.index[*][?(@.name=='TupleField')].inner.variant.kind.tuple[*]" $tup_field TupleField(i32), } -// @is "$.index[*][?(@.name=='Foo')].inner.variants[0]" $Unit -// @is "$.index[*][?(@.name=='Foo')].inner.variants[1]" $Named -// @is "$.index[*][?(@.name=='Foo')].inner.variants[2]" $Tuple -// @is "$.index[*][?(@.name=='Foo')].inner.variants[3]" $NamedField -// @is "$.index[*][?(@.name=='Foo')].inner.variants[4]" $TupleField -// @count "$.index[*][?(@.name=='Foo')].inner.variants[*]" 5 +// @is "$.index[*][?(@.name=='Foo')].inner.enum.variants[0]" $Unit +// @is "$.index[*][?(@.name=='Foo')].inner.enum.variants[1]" $Named +// @is "$.index[*][?(@.name=='Foo')].inner.enum.variants[2]" $Tuple +// @is "$.index[*][?(@.name=='Foo')].inner.enum.variants[3]" $NamedField +// @is "$.index[*][?(@.name=='Foo')].inner.enum.variants[4]" $TupleField +// @count "$.index[*][?(@.name=='Foo')].inner.enum.variants[*]" 5 diff --git a/tests/rustdoc-json/enums/struct_field_hidden.rs b/tests/rustdoc-json/enums/struct_field_hidden.rs index de939cde2e7..2676c4e4157 100644 --- a/tests/rustdoc-json/enums/struct_field_hidden.rs +++ b/tests/rustdoc-json/enums/struct_field_hidden.rs @@ -9,8 +9,8 @@ pub enum Foo { // @set y = "$.index[*][?(@.name=='y')].id" y: i32, }, - // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields_stripped" true - // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[0]" $b - // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[1]" $y - // @count "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[*]" 2 + // @is "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields_stripped" true + // @is "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields[0]" $b + // @is "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields[1]" $y + // @count "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields[*]" 2 } diff --git a/tests/rustdoc-json/enums/tuple_fields_hidden.rs b/tests/rustdoc-json/enums/tuple_fields_hidden.rs index 70bfbb81826..3aeb0356420 100644 --- a/tests/rustdoc-json/enums/tuple_fields_hidden.rs +++ b/tests/rustdoc-json/enums/tuple_fields_hidden.rs @@ -14,47 +14,47 @@ // @set 3.3.1 = "$.index[*][?(@.docs=='3.3.1')].id" pub enum EnumWithStrippedTupleVariants { - // @count "$.index[*][?(@.name=='None')].inner.kind.tuple[*]" 0 + // @count "$.index[*][?(@.name=='None')].inner.variant.kind.tuple[*]" 0 None(), - // @count "$.index[*][?(@.name=='One')].inner.kind.tuple[*]" 1 - // @is "$.index[*][?(@.name=='One')].inner.kind.tuple[0]" $1.1.0 + // @count "$.index[*][?(@.name=='One')].inner.variant.kind.tuple[*]" 1 + // @is "$.index[*][?(@.name=='One')].inner.variant.kind.tuple[0]" $1.1.0 One(/** 1.1.0*/ bool), - // @count "$.index[*][?(@.name=='OneHidden')].inner.kind.tuple[*]" 1 - // @is "$.index[*][?(@.name=='OneHidden')].inner.kind.tuple[0]" null + // @count "$.index[*][?(@.name=='OneHidden')].inner.variant.kind.tuple[*]" 1 + // @is "$.index[*][?(@.name=='OneHidden')].inner.variant.kind.tuple[0]" null OneHidden(#[doc(hidden)] bool), - // @count "$.index[*][?(@.name=='Two')].inner.kind.tuple[*]" 2 - // @is "$.index[*][?(@.name=='Two')].inner.kind.tuple[0]" $2.1.0 - // @is "$.index[*][?(@.name=='Two')].inner.kind.tuple[1]" $2.1.1 + // @count "$.index[*][?(@.name=='Two')].inner.variant.kind.tuple[*]" 2 + // @is "$.index[*][?(@.name=='Two')].inner.variant.kind.tuple[0]" $2.1.0 + // @is "$.index[*][?(@.name=='Two')].inner.variant.kind.tuple[1]" $2.1.1 Two(/** 2.1.0*/ bool, /** 2.1.1*/ bool), - // @count "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[*]" 2 - // @is "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[0]" null - // @is "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[1]" $2.2.1 + // @count "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant.kind.tuple[*]" 2 + // @is "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant.kind.tuple[0]" null + // @is "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant.kind.tuple[1]" $2.2.1 TwoLeftHidden(#[doc(hidden)] bool, /** 2.2.1*/ bool), - // @count "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[*]" 2 - // @is "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[0]" $2.3.0 - // @is "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[1]" null + // @count "$.index[*][?(@.name=='TwoRightHidden')].inner.variant.kind.tuple[*]" 2 + // @is "$.index[*][?(@.name=='TwoRightHidden')].inner.variant.kind.tuple[0]" $2.3.0 + // @is "$.index[*][?(@.name=='TwoRightHidden')].inner.variant.kind.tuple[1]" null TwoRightHidden(/** 2.3.0*/ bool, #[doc(hidden)] bool), - // @count "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[*]" 2 - // @is "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[0]" null - // @is "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[1]" null + // @count "$.index[*][?(@.name=='TwoBothHidden')].inner.variant.kind.tuple[*]" 2 + // @is "$.index[*][?(@.name=='TwoBothHidden')].inner.variant.kind.tuple[0]" null + // @is "$.index[*][?(@.name=='TwoBothHidden')].inner.variant.kind.tuple[1]" null TwoBothHidden(#[doc(hidden)] bool, #[doc(hidden)] bool), - // @count "$.index[*][?(@.name=='Three1')].inner.kind.tuple[*]" 3 - // @is "$.index[*][?(@.name=='Three1')].inner.kind.tuple[0]" null - // @is "$.index[*][?(@.name=='Three1')].inner.kind.tuple[1]" $3.1.1 - // @is "$.index[*][?(@.name=='Three1')].inner.kind.tuple[2]" $3.1.2 + // @count "$.index[*][?(@.name=='Three1')].inner.variant.kind.tuple[*]" 3 + // @is "$.index[*][?(@.name=='Three1')].inner.variant.kind.tuple[0]" null + // @is "$.index[*][?(@.name=='Three1')].inner.variant.kind.tuple[1]" $3.1.1 + // @is "$.index[*][?(@.name=='Three1')].inner.variant.kind.tuple[2]" $3.1.2 Three1(#[doc(hidden)] bool, /** 3.1.1*/ bool, /** 3.1.2*/ bool), - // @count "$.index[*][?(@.name=='Three2')].inner.kind.tuple[*]" 3 - // @is "$.index[*][?(@.name=='Three2')].inner.kind.tuple[0]" $3.2.0 - // @is "$.index[*][?(@.name=='Three2')].inner.kind.tuple[1]" null - // @is "$.index[*][?(@.name=='Three2')].inner.kind.tuple[2]" $3.2.2 + // @count "$.index[*][?(@.name=='Three2')].inner.variant.kind.tuple[*]" 3 + // @is "$.index[*][?(@.name=='Three2')].inner.variant.kind.tuple[0]" $3.2.0 + // @is "$.index[*][?(@.name=='Three2')].inner.variant.kind.tuple[1]" null + // @is "$.index[*][?(@.name=='Three2')].inner.variant.kind.tuple[2]" $3.2.2 Three2(/** 3.2.0*/ bool, #[doc(hidden)] bool, /** 3.2.2*/ bool), - // @count "$.index[*][?(@.name=='Three3')].inner.kind.tuple[*]" 3 - // @is "$.index[*][?(@.name=='Three3')].inner.kind.tuple[0]" $3.3.0 - // @is "$.index[*][?(@.name=='Three3')].inner.kind.tuple[1]" $3.3.1 - // @is "$.index[*][?(@.name=='Three3')].inner.kind.tuple[2]" null + // @count "$.index[*][?(@.name=='Three3')].inner.variant.kind.tuple[*]" 3 + // @is "$.index[*][?(@.name=='Three3')].inner.variant.kind.tuple[0]" $3.3.0 + // @is "$.index[*][?(@.name=='Three3')].inner.variant.kind.tuple[1]" $3.3.1 + // @is "$.index[*][?(@.name=='Three3')].inner.variant.kind.tuple[2]" null Three3(/** 3.3.0*/ bool, /** 3.3.1*/ bool, #[doc(hidden)] bool), } @@ -70,14 +70,14 @@ pub enum EnumWithStrippedTupleVariants { // @is "$.index[*][?(@.docs=='3.3.0')].name" '"0"' // @is "$.index[*][?(@.docs=='3.3.1')].name" '"1"' -// @is "$.index[*][?(@.docs=='1.1.0')].inner" '{"kind": "primitive", "inner": "bool"}' -// @is "$.index[*][?(@.docs=='2.1.0')].inner" '{"kind": "primitive", "inner": "bool"}' -// @is "$.index[*][?(@.docs=='2.1.1')].inner" '{"kind": "primitive", "inner": "bool"}' -// @is "$.index[*][?(@.docs=='2.2.1')].inner" '{"kind": "primitive", "inner": "bool"}' -// @is "$.index[*][?(@.docs=='2.3.0')].inner" '{"kind": "primitive", "inner": "bool"}' -// @is "$.index[*][?(@.docs=='3.1.1')].inner" '{"kind": "primitive", "inner": "bool"}' -// @is "$.index[*][?(@.docs=='3.1.2')].inner" '{"kind": "primitive", "inner": "bool"}' -// @is "$.index[*][?(@.docs=='3.2.0')].inner" '{"kind": "primitive", "inner": "bool"}' -// @is "$.index[*][?(@.docs=='3.2.2')].inner" '{"kind": "primitive", "inner": "bool"}' -// @is "$.index[*][?(@.docs=='3.3.0')].inner" '{"kind": "primitive", "inner": "bool"}' -// @is "$.index[*][?(@.docs=='3.3.1')].inner" '{"kind": "primitive", "inner": "bool"}' +// @is "$.index[*][?(@.docs=='1.1.0')].inner.struct_field" '{"primitive": "bool"}' +// @is "$.index[*][?(@.docs=='2.1.0')].inner.struct_field" '{"primitive": "bool"}' +// @is "$.index[*][?(@.docs=='2.1.1')].inner.struct_field" '{"primitive": "bool"}' +// @is "$.index[*][?(@.docs=='2.2.1')].inner.struct_field" '{"primitive": "bool"}' +// @is "$.index[*][?(@.docs=='2.3.0')].inner.struct_field" '{"primitive": "bool"}' +// @is "$.index[*][?(@.docs=='3.1.1')].inner.struct_field" '{"primitive": "bool"}' +// @is "$.index[*][?(@.docs=='3.1.2')].inner.struct_field" '{"primitive": "bool"}' +// @is "$.index[*][?(@.docs=='3.2.0')].inner.struct_field" '{"primitive": "bool"}' +// @is "$.index[*][?(@.docs=='3.2.2')].inner.struct_field" '{"primitive": "bool"}' +// @is "$.index[*][?(@.docs=='3.3.0')].inner.struct_field" '{"primitive": "bool"}' +// @is "$.index[*][?(@.docs=='3.3.1')].inner.struct_field" '{"primitive": "bool"}' diff --git a/tests/rustdoc-json/enums/use_glob.rs b/tests/rustdoc-json/enums/use_glob.rs index 62b8b832afd..49990ec5331 100644 --- a/tests/rustdoc-json/enums/use_glob.rs +++ b/tests/rustdoc-json/enums/use_glob.rs @@ -10,9 +10,9 @@ pub enum Color { Blue, } -// @set use_Color = "$.index[*][?(@.kind == 'import')].id" -// @is "$.index[*][?(@.kind == 'import')].inner.id" $Color -// @is "$.index[*][?(@.kind == 'import')].inner.glob" true +// @set use_Color = "$.index[*][?(@.inner.import)].id" +// @is "$.index[*][?(@.inner.import)].inner.import.id" $Color +// @is "$.index[*][?(@.inner.import)].inner.import.glob" true pub use Color::*; -// @ismany "$.index[*][?(@.name == 'use_glob')].inner.items[*]" $Color $use_Color +// @ismany "$.index[*][?(@.name == 'use_glob')].inner.module.items[*]" $Color $use_Color diff --git a/tests/rustdoc-json/enums/use_variant.rs b/tests/rustdoc-json/enums/use_variant.rs index 5f0d2b9b1ec..8190e1cbe81 100644 --- a/tests/rustdoc-json/enums/use_variant.rs +++ b/tests/rustdoc-json/enums/use_variant.rs @@ -6,10 +6,10 @@ pub enum AlwaysNone { // @set None = "$.index[*][?(@.name == 'None')].id" None, } -// @is "$.index[*][?(@.name == 'AlwaysNone')].inner.variants[*]" $None +// @is "$.index[*][?(@.name == 'AlwaysNone')].inner.enum.variants[*]" $None -// @set use_None = "$.index[*][?(@.kind == 'import')].id" -// @is "$.index[*][?(@.kind == 'import')].inner.id" $None +// @set use_None = "$.index[*][?(@.inner.import)].id" +// @is "$.index[*][?(@.inner.import)].inner.import.id" $None pub use AlwaysNone::None; -// @ismany "$.index[*][?(@.name == 'use_variant')].inner.items[*]" $AlwaysNone $use_None +// @ismany "$.index[*][?(@.name == 'use_variant')].inner.module.items[*]" $AlwaysNone $use_None diff --git a/tests/rustdoc-json/enums/use_variant_foreign.rs b/tests/rustdoc-json/enums/use_variant_foreign.rs index 11bb6ce1f3a..a79e899d85f 100644 --- a/tests/rustdoc-json/enums/use_variant_foreign.rs +++ b/tests/rustdoc-json/enums/use_variant_foreign.rs @@ -2,7 +2,7 @@ extern crate color; -// @is "$.index[*][?(@.inner.name == 'Red')].kind" '"import"' +// @has "$.index[*].inner.import[?(@.name == 'Red')]" pub use color::Color::Red; // @!has "$.index[*][?(@.name == 'Red')]" diff --git a/tests/rustdoc-json/enums/variant_struct.rs b/tests/rustdoc-json/enums/variant_struct.rs index bc870c502a0..fe40f1a5d5d 100644 --- a/tests/rustdoc-json/enums/variant_struct.rs +++ b/tests/rustdoc-json/enums/variant_struct.rs @@ -1,10 +1,10 @@ // @is "$.index[*][?(@.name=='EnumStruct')].visibility" \"public\" -// @is "$.index[*][?(@.name=='EnumStruct')].kind" \"enum\" +// @has "$.index[*][?(@.name=='EnumStruct')].inner.enum" pub enum EnumStruct { - // @is "$.index[*][?(@.name=='x')].kind" \"struct_field\" + // @has "$.index[*][?(@.name=='x')].inner.struct_field" // @set x = "$.index[*][?(@.name=='x')].id" - // @is "$.index[*][?(@.name=='y')].kind" \"struct_field\" + // @has "$.index[*][?(@.name=='y')].inner.struct_field" // @set y = "$.index[*][?(@.name=='y')].id" - // @ismany "$.index[*][?(@.name=='VariantS')].inner.kind.struct.fields[*]" $x $y + // @ismany "$.index[*][?(@.name=='VariantS')].inner.variant.kind.struct.fields[*]" $x $y VariantS { x: u32, y: String }, } diff --git a/tests/rustdoc-json/enums/variant_tuple_struct.rs b/tests/rustdoc-json/enums/variant_tuple_struct.rs index d1207bbfb18..358fc1079cb 100644 --- a/tests/rustdoc-json/enums/variant_tuple_struct.rs +++ b/tests/rustdoc-json/enums/variant_tuple_struct.rs @@ -1,10 +1,10 @@ // @is "$.index[*][?(@.name=='EnumTupleStruct')].visibility" \"public\" -// @is "$.index[*][?(@.name=='EnumTupleStruct')].kind" \"enum\" +// @has "$.index[*][?(@.name=='EnumTupleStruct')].inner.enum" pub enum EnumTupleStruct { - // @is "$.index[*][?(@.name=='0')].kind" \"struct_field\" + // @has "$.index[*][?(@.name=='0')].inner.struct_field" // @set f0 = "$.index[*][?(@.name=='0')].id" - // @is "$.index[*][?(@.name=='1')].kind" \"struct_field\" + // @has "$.index[*][?(@.name=='1')].inner.struct_field" // @set f1 = "$.index[*][?(@.name=='1')].id" - // @ismany "$.index[*][?(@.name=='VariantA')].inner.kind.tuple[*]" $f0 $f1 + // @ismany "$.index[*][?(@.name=='VariantA')].inner.variant.kind.tuple[*]" $f0 $f1 VariantA(u32, String), } diff --git a/tests/rustdoc-json/fn_pointer/abi.rs b/tests/rustdoc-json/fn_pointer/abi.rs index 6a30acc2cc3..77c0e82330f 100644 --- a/tests/rustdoc-json/fn_pointer/abi.rs +++ b/tests/rustdoc-json/fn_pointer/abi.rs @@ -2,23 +2,23 @@ #![feature(abi_vectorcall)] -// @is "$.index[*][?(@.name=='AbiRust')].inner.type.inner.header.abi" \"Rust\" +// @is "$.index[*][?(@.name=='AbiRust')].inner.typedef.type.function_pointer.header.abi" \"Rust\" pub type AbiRust = fn(); -// @is "$.index[*][?(@.name=='AbiC')].inner.type.inner.header.abi" '{"C": {"unwind": false}}' +// @is "$.index[*][?(@.name=='AbiC')].inner.typedef.type.function_pointer.header.abi" '{"C": {"unwind": false}}' pub type AbiC = extern "C" fn(); -// @is "$.index[*][?(@.name=='AbiSystem')].inner.type.inner.header.abi" '{"System": {"unwind": false}}' +// @is "$.index[*][?(@.name=='AbiSystem')].inner.typedef.type.function_pointer.header.abi" '{"System": {"unwind": false}}' pub type AbiSystem = extern "system" fn(); -// @is "$.index[*][?(@.name=='AbiCUnwind')].inner.type.inner.header.abi" '{"C": {"unwind": true}}' +// @is "$.index[*][?(@.name=='AbiCUnwind')].inner.typedef.type.function_pointer.header.abi" '{"C": {"unwind": true}}' pub type AbiCUnwind = extern "C-unwind" fn(); -// @is "$.index[*][?(@.name=='AbiSystemUnwind')].inner.type.inner.header.abi" '{"System": {"unwind": true}}' +// @is "$.index[*][?(@.name=='AbiSystemUnwind')].inner.typedef.type.function_pointer.header.abi" '{"System": {"unwind": true}}' pub type AbiSystemUnwind = extern "system-unwind" fn(); -// @is "$.index[*][?(@.name=='AbiVecorcall')].inner.type.inner.header.abi.Other" '"\"vectorcall\""' +// @is "$.index[*][?(@.name=='AbiVecorcall')].inner.typedef.type.function_pointer.header.abi.Other" '"\"vectorcall\""' pub type AbiVecorcall = extern "vectorcall" fn(); -// @is "$.index[*][?(@.name=='AbiVecorcallUnwind')].inner.type.inner.header.abi.Other" '"\"vectorcall-unwind\""' +// @is "$.index[*][?(@.name=='AbiVecorcallUnwind')].inner.typedef.type.function_pointer.header.abi.Other" '"\"vectorcall-unwind\""' pub type AbiVecorcallUnwind = extern "vectorcall-unwind" fn(); diff --git a/tests/rustdoc-json/fn_pointer/generics.rs b/tests/rustdoc-json/fn_pointer/generics.rs index a93b01ac2c4..48672f12da1 100644 --- a/tests/rustdoc-json/fn_pointer/generics.rs +++ b/tests/rustdoc-json/fn_pointer/generics.rs @@ -3,12 +3,11 @@ #![feature(no_core)] #![no_core] -// @count "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.decl.inputs[*]" 1 -// @is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.decl.inputs[0][0]" '"val"' -// @is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.decl.inputs[0][1].kind" '"borrowed_ref"' -// @is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.decl.inputs[0][1].inner.lifetime" \"\'c\" -// @is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.decl.output" '{ "kind": "primitive", "inner": "i32" }' -// @count "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.generic_params[*]" 1 -// @is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.generic_params[0].name" \"\'c\" -// @is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }' +// @count "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.typedef.type.function_pointer.decl.inputs[*]" 1 +// @is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.typedef.type.function_pointer.decl.inputs[0][0]" '"val"' +// @is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.typedef.type.function_pointer.decl.inputs[0][1].borrowed_ref.lifetime" \"\'c\" +// @is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.typedef.type.function_pointer.decl.output.primitive" \"i32\" +// @count "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.typedef.type.function_pointer.generic_params[*]" 1 +// @is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.typedef.type.function_pointer.generic_params[0].name" \"\'c\" +// @is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.typedef.type.function_pointer.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }' pub type WithHigherRankTraitBounds = for<'c> fn(val: &'c i32) -> i32; diff --git a/tests/rustdoc-json/fn_pointer/qualifiers.rs b/tests/rustdoc-json/fn_pointer/qualifiers.rs index bd65bb3eefe..0ab776c21ed 100644 --- a/tests/rustdoc-json/fn_pointer/qualifiers.rs +++ b/tests/rustdoc-json/fn_pointer/qualifiers.rs @@ -1,9 +1,11 @@ -// @is "$.index[*][?(@.name=='FnPointer')].inner.type.inner.header.unsafe" false -// @is "$.index[*][?(@.name=='FnPointer')].inner.type.inner.header.const" false -// @is "$.index[*][?(@.name=='FnPointer')].inner.type.inner.header.async" false +// ignore-tidy-linelength + +// @is "$.index[*][?(@.name=='FnPointer')].inner.typedef.type.function_pointer.header.unsafe" false +// @is "$.index[*][?(@.name=='FnPointer')].inner.typedef.type.function_pointer.header.const" false +// @is "$.index[*][?(@.name=='FnPointer')].inner.typedef.type.function_pointer.header.async" false pub type FnPointer = fn(); -// @is "$.index[*][?(@.name=='UnsafePointer')].inner.type.inner.header.unsafe" true -// @is "$.index[*][?(@.name=='UnsafePointer')].inner.type.inner.header.const" false -// @is "$.index[*][?(@.name=='UnsafePointer')].inner.type.inner.header.async" false +// @is "$.index[*][?(@.name=='UnsafePointer')].inner.typedef.type.function_pointer.header.unsafe" true +// @is "$.index[*][?(@.name=='UnsafePointer')].inner.typedef.type.function_pointer.header.const" false +// @is "$.index[*][?(@.name=='UnsafePointer')].inner.typedef.type.function_pointer.header.async" false pub type UnsafePointer = unsafe fn(); diff --git a/tests/rustdoc-json/fns/abi.rs b/tests/rustdoc-json/fns/abi.rs index 7a5dbee730c..d7b98b5924b 100644 --- a/tests/rustdoc-json/fns/abi.rs +++ b/tests/rustdoc-json/fns/abi.rs @@ -2,23 +2,23 @@ #![feature(abi_vectorcall)] -// @is "$.index[*][?(@.name=='abi_rust')].inner.header.abi" \"Rust\" +// @is "$.index[*][?(@.name=='abi_rust')].inner.function.header.abi" \"Rust\" pub fn abi_rust() {} -// @is "$.index[*][?(@.name=='abi_c')].inner.header.abi" '{"C": {"unwind": false}}' +// @is "$.index[*][?(@.name=='abi_c')].inner.function.header.abi" '{"C": {"unwind": false}}' pub extern "C" fn abi_c() {} -// @is "$.index[*][?(@.name=='abi_system')].inner.header.abi" '{"System": {"unwind": false}}' +// @is "$.index[*][?(@.name=='abi_system')].inner.function.header.abi" '{"System": {"unwind": false}}' pub extern "system" fn abi_system() {} -// @is "$.index[*][?(@.name=='abi_c_unwind')].inner.header.abi" '{"C": {"unwind": true}}' +// @is "$.index[*][?(@.name=='abi_c_unwind')].inner.function.header.abi" '{"C": {"unwind": true}}' pub extern "C-unwind" fn abi_c_unwind() {} -// @is "$.index[*][?(@.name=='abi_system_unwind')].inner.header.abi" '{"System": {"unwind": true}}' +// @is "$.index[*][?(@.name=='abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' pub extern "system-unwind" fn abi_system_unwind() {} -// @is "$.index[*][?(@.name=='abi_vectorcall')].inner.header.abi.Other" '"\"vectorcall\""' +// @is "$.index[*][?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' pub extern "vectorcall" fn abi_vectorcall() {} -// @is "$.index[*][?(@.name=='abi_vectorcall_unwind')].inner.header.abi.Other" '"\"vectorcall-unwind\""' +// @is "$.index[*][?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {} diff --git a/tests/rustdoc-json/fns/async_return.rs b/tests/rustdoc-json/fns/async_return.rs index b89781ca92d..8192f2e6ae6 100644 --- a/tests/rustdoc-json/fns/async_return.rs +++ b/tests/rustdoc-json/fns/async_return.rs @@ -5,32 +5,30 @@ use std::future::Future; -// @is "$.index[*][?(@.name=='get_int')].inner.decl.output" '{"inner": "i32", "kind": "primitive"}' -// @is "$.index[*][?(@.name=='get_int')].inner.header.async" false +// @is "$.index[*][?(@.name=='get_int')].inner.function.decl.output.primitive" \"i32\" +// @is "$.index[*][?(@.name=='get_int')].inner.function.header.async" false pub fn get_int() -> i32 { 42 } -// @is "$.index[*][?(@.name=='get_int_async')].inner.decl.output" '{"inner": "i32", "kind": "primitive"}' -// @is "$.index[*][?(@.name=='get_int_async')].inner.header.async" true +// @is "$.index[*][?(@.name=='get_int_async')].inner.function.decl.output.primitive" \"i32\" +// @is "$.index[*][?(@.name=='get_int_async')].inner.function.header.async" true pub async fn get_int_async() -> i32 { 42 } -// @is "$.index[*][?(@.name=='get_int_future')].inner.decl.output.kind" '"impl_trait"' -// @is "$.index[*][?(@.name=='get_int_future')].inner.decl.output.inner[0].trait_bound.trait.name" '"Future"' -// @is "$.index[*][?(@.name=='get_int_future')].inner.decl.output.inner[0].trait_bound.trait.args.angle_bracketed.bindings[0].name" '"Output"' -// @is "$.index[*][?(@.name=='get_int_future')].inner.decl.output.inner[0].trait_bound.trait.args.angle_bracketed.bindings[0].binding.equality.type" '{"inner": "i32", "kind": "primitive"}' -// @is "$.index[*][?(@.name=='get_int_future')].inner.header.async" false +// @is "$.index[*][?(@.name=='get_int_future')].inner.function.decl.output.impl_trait[0].trait_bound.trait.name" '"Future"' +// @is "$.index[*][?(@.name=='get_int_future')].inner.function.decl.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.bindings[0].name" '"Output"' +// @is "$.index[*][?(@.name=='get_int_future')].inner.function.decl.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.bindings[0].binding.equality.type.primitive" \"i32\" +// @is "$.index[*][?(@.name=='get_int_future')].inner.function.header.async" false pub fn get_int_future() -> impl Future<Output = i32> { async { 42 } } -// @is "$.index[*][?(@.name=='get_int_future_async')].inner.decl.output.kind" '"impl_trait"' -// @is "$.index[*][?(@.name=='get_int_future_async')].inner.decl.output.inner[0].trait_bound.trait.name" '"Future"' -// @is "$.index[*][?(@.name=='get_int_future_async')].inner.decl.output.inner[0].trait_bound.trait.args.angle_bracketed.bindings[0].name" '"Output"' -// @is "$.index[*][?(@.name=='get_int_future_async')].inner.decl.output.inner[0].trait_bound.trait.args.angle_bracketed.bindings[0].binding.equality.type" '{"inner": "i32", "kind": "primitive"}' -// @is "$.index[*][?(@.name=='get_int_future_async')].inner.header.async" true +// @is "$.index[*][?(@.name=='get_int_future_async')].inner.function.decl.output.impl_trait[0].trait_bound.trait.name" '"Future"' +// @is "$.index[*][?(@.name=='get_int_future_async')].inner.function.decl.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.bindings[0].name" '"Output"' +// @is "$.index[*][?(@.name=='get_int_future_async')].inner.function.decl.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.bindings[0].binding.equality.type.primitive" \"i32\" +// @is "$.index[*][?(@.name=='get_int_future_async')].inner.function.header.async" true pub async fn get_int_future_async() -> impl Future<Output = i32> { async { 42 } } diff --git a/tests/rustdoc-json/fns/extern_c_variadic.rs b/tests/rustdoc-json/fns/extern_c_variadic.rs index 33bebbab5e0..d6ea343b991 100644 --- a/tests/rustdoc-json/fns/extern_c_variadic.rs +++ b/tests/rustdoc-json/fns/extern_c_variadic.rs @@ -2,8 +2,8 @@ #![no_core] extern "C" { - // @is "$.index[*][?(@.name == 'not_variadic')].inner.decl.c_variadic" false + // @is "$.index[*][?(@.name == 'not_variadic')].inner.function.decl.c_variadic" false pub fn not_variadic(_: i32); - // @is "$.index[*][?(@.name == 'variadic')].inner.decl.c_variadic" true + // @is "$.index[*][?(@.name == 'variadic')].inner.function.decl.c_variadic" true pub fn variadic(_: i32, ...); } diff --git a/tests/rustdoc-json/fns/generic_args.rs b/tests/rustdoc-json/fns/generic_args.rs index eec295efec0..539d17f831e 100644 --- a/tests/rustdoc-json/fns/generic_args.rs +++ b/tests/rustdoc-json/fns/generic_args.rs @@ -9,59 +9,55 @@ pub trait Foo {} // @set generic_foo = "$.index[*][?(@.name=='GenericFoo')].id" pub trait GenericFoo<'a> {} -// @is "$.index[*][?(@.name=='generics')].inner.generics.where_predicates" "[]" -// @count "$.index[*][?(@.name=='generics')].inner.generics.params[*]" 1 -// @is "$.index[*][?(@.name=='generics')].inner.generics.params[0].name" '"F"' -// @is "$.index[*][?(@.name=='generics')].inner.generics.params[0].kind.type.default" 'null' -// @count "$.index[*][?(@.name=='generics')].inner.generics.params[0].kind.type.bounds[*]" 1 -// @is "$.index[*][?(@.name=='generics')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" '$foo' -// @count "$.index[*][?(@.name=='generics')].inner.decl.inputs[*]" 1 -// @is "$.index[*][?(@.name=='generics')].inner.decl.inputs[0][0]" '"f"' -// @is "$.index[*][?(@.name=='generics')].inner.decl.inputs[0][1].kind" '"generic"' -// @is "$.index[*][?(@.name=='generics')].inner.decl.inputs[0][1].inner" '"F"' +// @is "$.index[*][?(@.name=='generics')].inner.function.generics.where_predicates" "[]" +// @count "$.index[*][?(@.name=='generics')].inner.function.generics.params[*]" 1 +// @is "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].name" '"F"' +// @is "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].kind.type.default" 'null' +// @count "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].kind.type.bounds[*]" 1 +// @is "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" '$foo' +// @count "$.index[*][?(@.name=='generics')].inner.function.decl.inputs[*]" 1 +// @is "$.index[*][?(@.name=='generics')].inner.function.decl.inputs[0][0]" '"f"' +// @is "$.index[*][?(@.name=='generics')].inner.function.decl.inputs[0][1].generic" '"F"' pub fn generics<F: Foo>(f: F) {} -// @is "$.index[*][?(@.name=='impl_trait')].inner.generics.where_predicates" "[]" -// @count "$.index[*][?(@.name=='impl_trait')].inner.generics.params[*]" 1 -// @is "$.index[*][?(@.name=='impl_trait')].inner.generics.params[0].name" '"impl Foo"' -// @is "$.index[*][?(@.name=='impl_trait')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $foo -// @count "$.index[*][?(@.name=='impl_trait')].inner.decl.inputs[*]" 1 -// @is "$.index[*][?(@.name=='impl_trait')].inner.decl.inputs[0][0]" '"f"' -// @is "$.index[*][?(@.name=='impl_trait')].inner.decl.inputs[0][1].kind" '"impl_trait"' -// @count "$.index[*][?(@.name=='impl_trait')].inner.decl.inputs[0][1].inner[*]" 1 -// @is "$.index[*][?(@.name=='impl_trait')].inner.decl.inputs[0][1].inner[0].trait_bound.trait.id" $foo +// @is "$.index[*][?(@.name=='impl_trait')].inner.function.generics.where_predicates" "[]" +// @count "$.index[*][?(@.name=='impl_trait')].inner.function.generics.params[*]" 1 +// @is "$.index[*][?(@.name=='impl_trait')].inner.function.generics.params[0].name" '"impl Foo"' +// @is "$.index[*][?(@.name=='impl_trait')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $foo +// @count "$.index[*][?(@.name=='impl_trait')].inner.function.decl.inputs[*]" 1 +// @is "$.index[*][?(@.name=='impl_trait')].inner.function.decl.inputs[0][0]" '"f"' +// @count "$.index[*][?(@.name=='impl_trait')].inner.function.decl.inputs[0][1].impl_trait[*]" 1 +// @is "$.index[*][?(@.name=='impl_trait')].inner.function.decl.inputs[0][1].impl_trait[0].trait_bound.trait.id" $foo pub fn impl_trait(f: impl Foo) {} -// @count "$.index[*][?(@.name=='where_clase')].inner.generics.params[*]" 3 -// @is "$.index[*][?(@.name=='where_clase')].inner.generics.params[0].name" '"F"' -// @is "$.index[*][?(@.name=='where_clase')].inner.generics.params[0].kind" '{"type": {"bounds": [], "default": null, "synthetic": false}}' -// @count "$.index[*][?(@.name=='where_clase')].inner.decl.inputs[*]" 3 -// @is "$.index[*][?(@.name=='where_clase')].inner.decl.inputs[0][0]" '"f"' -// @is "$.index[*][?(@.name=='where_clase')].inner.decl.inputs[0][1].kind" '"generic"' -// @is "$.index[*][?(@.name=='where_clase')].inner.decl.inputs[0][1].inner" '"F"' -// @count "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[*]" 3 +// @count "$.index[*][?(@.name=='where_clase')].inner.function.generics.params[*]" 3 +// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.params[0].name" '"F"' +// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.params[0].kind" '{"type": {"bounds": [], "default": null, "synthetic": false}}' +// @count "$.index[*][?(@.name=='where_clase')].inner.function.decl.inputs[*]" 3 +// @is "$.index[*][?(@.name=='where_clase')].inner.function.decl.inputs[0][0]" '"f"' +// @is "$.index[*][?(@.name=='where_clase')].inner.function.decl.inputs[0][1].generic" '"F"' +// @count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[*]" 3 -// @is "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[0].bound_predicate.type" '{"inner": "F", "kind": "generic"}' -// @count "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[0].bound_predicate.bounds[*]" 1 -// @is "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[0].bound_predicate.bounds[0].trait_bound.trait.id" $foo +// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[0].bound_predicate.type.generic" \"F\" +// @count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[0].bound_predicate.bounds[*]" 1 +// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[0].bound_predicate.bounds[0].trait_bound.trait.id" $foo -// @is "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.type" '{"inner": "G", "kind": "generic"}' -// @count "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.bounds[*]" 1 -// @is "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.trait.id" $generic_foo -// @count "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[*]" 1 -// @is "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[0].name" \"\'a\" -// @is "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }' -// @is "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.generic_params" "[]" +// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.type.generic" \"G\" +// @count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[*]" 1 +// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.trait.id" $generic_foo +// @count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[*]" 1 +// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[0].name" \"\'a\" +// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[0].kind.lifetime.outlives" "[]" +// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.generic_params" "[]" -// @is "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.type.kind" '"borrowed_ref"' -// @is "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.type.inner.lifetime" \"\'b\" -// @is "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.type.inner.type" '{"inner": "H", "kind": "generic"}' -// @count "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.bounds[*]" 1 -// @is "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.bounds[0].trait_bound.trait.id" $foo -// @is "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.bounds[0].trait_bound.generic_params" "[]" -// @count "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.generic_params[*]" 1 -// @is "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.generic_params[0].name" \"\'b\" -// @is "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }' +// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.type.borrowed_ref.lifetime" \"\'b\" +// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.type.borrowed_ref.type.generic" \"H\" +// @count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.bounds[*]" 1 +// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.bounds[0].trait_bound.trait.id" $foo +// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.bounds[0].trait_bound.generic_params" "[]" +// @count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.generic_params[*]" 1 +// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.generic_params[0].name" \"\'b\" +// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.generic_params[0].kind.lifetime.outlives" "[]" pub fn where_clase<F, G, H>(f: F, g: G, h: H) where F: Foo, diff --git a/tests/rustdoc-json/fns/generic_returns.rs b/tests/rustdoc-json/fns/generic_returns.rs index a9bc2d5d727..27d842066f4 100644 --- a/tests/rustdoc-json/fns/generic_returns.rs +++ b/tests/rustdoc-json/fns/generic_returns.rs @@ -3,15 +3,14 @@ #![feature(no_core)] #![no_core] -// @count "$.index[*][?(@.name=='generic_returns')].inner.items[*]" 2 +// @count "$.index[*][?(@.name=='generic_returns')].inner.module.items[*]" 2 // @set foo = "$.index[*][?(@.name=='Foo')].id" pub trait Foo {} -// @is "$.index[*][?(@.name=='get_foo')].inner.decl.inputs" [] -// @is "$.index[*][?(@.name=='get_foo')].inner.decl.output.kind" '"impl_trait"' -// @count "$.index[*][?(@.name=='get_foo')].inner.decl.output.inner[*]" 1 -// @is "$.index[*][?(@.name=='get_foo')].inner.decl.output.inner[0].trait_bound.trait.id" $foo +// @is "$.index[*][?(@.name=='get_foo')].inner.function.decl.inputs" [] +// @count "$.index[*][?(@.name=='get_foo')].inner.function.decl.output.impl_trait[*]" 1 +// @is "$.index[*][?(@.name=='get_foo')].inner.function.decl.output.impl_trait[0].trait_bound.trait.id" $foo pub fn get_foo() -> impl Foo { Fooer {} } diff --git a/tests/rustdoc-json/fns/generics.rs b/tests/rustdoc-json/fns/generics.rs index 7b70ff1df6b..5239a6f21f5 100644 --- a/tests/rustdoc-json/fns/generics.rs +++ b/tests/rustdoc-json/fns/generics.rs @@ -6,21 +6,20 @@ // @set wham_id = "$.index[*][?(@.name=='Wham')].id" pub trait Wham {} -// @is "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.where_predicates" [] -// @count "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[*]" 1 -// @is "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[0].name" '"T"' -// @is "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[0].kind.type.synthetic" false -// @is "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $wham_id -// @is "$.index[*][?(@.name=='one_generic_param_fn')].inner.decl.inputs" '[["w", {"inner": "T", "kind": "generic"}]]' +// @is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.where_predicates" [] +// @count "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[*]" 1 +// @is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].name" '"T"' +// @is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].kind.type.synthetic" false +// @is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $wham_id +// @is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.decl.inputs" '[["w", {"generic": "T"}]]' pub fn one_generic_param_fn<T: Wham>(w: T) {} -// @is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.where_predicates" [] -// @count "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[*]" 1 -// @is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[0].name" '"impl Wham"' -// @is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[0].kind.type.synthetic" true -// @is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $wham_id -// @count "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[*]" 1 -// @is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[0][0]" '"w"' -// @is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[0][1].kind" '"impl_trait"' -// @is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[0][1].inner[0].trait_bound.trait.id" $wham_id +// @is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.where_predicates" [] +// @count "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[*]" 1 +// @is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].name" '"impl Wham"' +// @is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].kind.type.synthetic" true +// @is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $wham_id +// @count "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.decl.inputs[*]" 1 +// @is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.decl.inputs[0][0]" '"w"' +// @is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.decl.inputs[0][1].impl_trait[0].trait_bound.trait.id" $wham_id pub fn one_synthetic_generic_param_fn(w: impl Wham) {} diff --git a/tests/rustdoc-json/fns/pattern_arg.rs b/tests/rustdoc-json/fns/pattern_arg.rs index 32b7da0fae4..55f24797ac0 100644 --- a/tests/rustdoc-json/fns/pattern_arg.rs +++ b/tests/rustdoc-json/fns/pattern_arg.rs @@ -1,7 +1,7 @@ -// @is "$.index[*][?(@.name=='fst')].inner.decl.inputs[0][0]" '"(x, _)"' +// @is "$.index[*][?(@.name=='fst')].inner.function.decl.inputs[0][0]" '"(x, _)"' pub fn fst<X, Y>((x, _): (X, Y)) -> X { x } -// @is "$.index[*][?(@.name=='drop_int')].inner.decl.inputs[0][0]" '"_"' +// @is "$.index[*][?(@.name=='drop_int')].inner.function.decl.inputs[0][0]" '"_"' pub fn drop_int(_: i32) {} diff --git a/tests/rustdoc-json/fns/qualifiers.rs b/tests/rustdoc-json/fns/qualifiers.rs index 7ff54290042..643865a3f07 100644 --- a/tests/rustdoc-json/fns/qualifiers.rs +++ b/tests/rustdoc-json/fns/qualifiers.rs @@ -1,33 +1,33 @@ // edition:2018 -// @is "$.index[*][?(@.name=='nothing_fn')].inner.header.async" false -// @is "$.index[*][?(@.name=='nothing_fn')].inner.header.const" false -// @is "$.index[*][?(@.name=='nothing_fn')].inner.header.unsafe" false +// @is "$.index[*][?(@.name=='nothing_fn')].inner.function.header.async" false +// @is "$.index[*][?(@.name=='nothing_fn')].inner.function.header.const" false +// @is "$.index[*][?(@.name=='nothing_fn')].inner.function.header.unsafe" false pub fn nothing_fn() {} -// @is "$.index[*][?(@.name=='unsafe_fn')].inner.header.async" false -// @is "$.index[*][?(@.name=='unsafe_fn')].inner.header.const" false -// @is "$.index[*][?(@.name=='unsafe_fn')].inner.header.unsafe" true +// @is "$.index[*][?(@.name=='unsafe_fn')].inner.function.header.async" false +// @is "$.index[*][?(@.name=='unsafe_fn')].inner.function.header.const" false +// @is "$.index[*][?(@.name=='unsafe_fn')].inner.function.header.unsafe" true pub unsafe fn unsafe_fn() {} -// @is "$.index[*][?(@.name=='const_fn')].inner.header.async" false -// @is "$.index[*][?(@.name=='const_fn')].inner.header.const" true -// @is "$.index[*][?(@.name=='const_fn')].inner.header.unsafe" false +// @is "$.index[*][?(@.name=='const_fn')].inner.function.header.async" false +// @is "$.index[*][?(@.name=='const_fn')].inner.function.header.const" true +// @is "$.index[*][?(@.name=='const_fn')].inner.function.header.unsafe" false pub const fn const_fn() {} -// @is "$.index[*][?(@.name=='async_fn')].inner.header.async" true -// @is "$.index[*][?(@.name=='async_fn')].inner.header.const" false -// @is "$.index[*][?(@.name=='async_fn')].inner.header.unsafe" false +// @is "$.index[*][?(@.name=='async_fn')].inner.function.header.async" true +// @is "$.index[*][?(@.name=='async_fn')].inner.function.header.const" false +// @is "$.index[*][?(@.name=='async_fn')].inner.function.header.unsafe" false pub async fn async_fn() {} -// @is "$.index[*][?(@.name=='async_unsafe_fn')].inner.header.async" true -// @is "$.index[*][?(@.name=='async_unsafe_fn')].inner.header.const" false -// @is "$.index[*][?(@.name=='async_unsafe_fn')].inner.header.unsafe" true +// @is "$.index[*][?(@.name=='async_unsafe_fn')].inner.function.header.async" true +// @is "$.index[*][?(@.name=='async_unsafe_fn')].inner.function.header.const" false +// @is "$.index[*][?(@.name=='async_unsafe_fn')].inner.function.header.unsafe" true pub async unsafe fn async_unsafe_fn() {} -// @is "$.index[*][?(@.name=='const_unsafe_fn')].inner.header.async" false -// @is "$.index[*][?(@.name=='const_unsafe_fn')].inner.header.const" true -// @is "$.index[*][?(@.name=='const_unsafe_fn')].inner.header.unsafe" true +// @is "$.index[*][?(@.name=='const_unsafe_fn')].inner.function.header.async" false +// @is "$.index[*][?(@.name=='const_unsafe_fn')].inner.function.header.const" true +// @is "$.index[*][?(@.name=='const_unsafe_fn')].inner.function.header.unsafe" true pub const unsafe fn const_unsafe_fn() {} // It's impossible for a function to be both const and async, so no test for that diff --git a/tests/rustdoc-json/fns/return_type_alias.rs b/tests/rustdoc-json/fns/return_type_alias.rs index 2578bb49ad3..e8a7dce8b0a 100644 --- a/tests/rustdoc-json/fns/return_type_alias.rs +++ b/tests/rustdoc-json/fns/return_type_alias.rs @@ -3,8 +3,7 @@ /// @set foo = "$.index[*][?(@.name=='Foo')].id" pub type Foo = i32; -// @is "$.index[*][?(@.name=='demo')].inner.decl.output.kind" '"resolved_path"' -// @is "$.index[*][?(@.name=='demo')].inner.decl.output.inner.id" $foo +// @is "$.index[*][?(@.name=='demo')].inner.function.decl.output.resolved_path.id" $foo pub fn demo() -> Foo { 42 } diff --git a/tests/rustdoc-json/generic-associated-types/gats.rs b/tests/rustdoc-json/generic-associated-types/gats.rs index e5809783aec..99c57ff6540 100644 --- a/tests/rustdoc-json/generic-associated-types/gats.rs +++ b/tests/rustdoc-json/generic-associated-types/gats.rs @@ -9,34 +9,32 @@ pub trait Sized {} pub trait Display {} pub trait LendingIterator { - // @count "$.index[*][?(@.name=='LendingItem')].inner.generics.params[*]" 1 - // @is "$.index[*][?(@.name=='LendingItem')].inner.generics.params[*].name" \"\'a\" - // @count "$.index[*][?(@.name=='LendingItem')].inner.generics.where_predicates[*]" 1 - // @is "$.index[*][?(@.name=='LendingItem')].inner.generics.where_predicates[*].bound_predicate.type.inner" \"Self\" - // @is "$.index[*][?(@.name=='LendingItem')].inner.generics.where_predicates[*].bound_predicate.bounds[*].outlives" \"\'a\" - // @count "$.index[*][?(@.name=='LendingItem')].inner.bounds[*]" 1 + // @count "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.generics.params[*]" 1 + // @is "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.generics.params[*].name" \"\'a\" + // @count "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.generics.where_predicates[*]" 1 + // @is "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.generics.where_predicates[*].bound_predicate.type.generic" \"Self\" + // @is "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.generics.where_predicates[*].bound_predicate.bounds[*].outlives" \"\'a\" + // @count "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.bounds[*]" 1 type LendingItem<'a>: Display where Self: 'a; - // @is "$.index[*][?(@.name=='lending_next')].inner.decl.output.kind" \"qualified_path\" - // @count "$.index[*][?(@.name=='lending_next')].inner.decl.output.inner.args.angle_bracketed.args[*]" 1 - // @count "$.index[*][?(@.name=='lending_next')].inner.decl.output.inner.args.angle_bracketed.bindings[*]" 0 - // @is "$.index[*][?(@.name=='lending_next')].inner.decl.output.inner.self_type.inner" \"Self\" - // @is "$.index[*][?(@.name=='lending_next')].inner.decl.output.inner.name" \"LendingItem\" + // @count "$.index[*][?(@.name=='lending_next')].inner.function.decl.output.qualified_path.args.angle_bracketed.args[*]" 1 + // @count "$.index[*][?(@.name=='lending_next')].inner.function.decl.output.qualified_path.args.angle_bracketed.bindings[*]" 0 + // @is "$.index[*][?(@.name=='lending_next')].inner.function.decl.output.qualified_path.self_type.generic" \"Self\" + // @is "$.index[*][?(@.name=='lending_next')].inner.function.decl.output.qualified_path.name" \"LendingItem\" fn lending_next<'a>(&'a self) -> Self::LendingItem<'a>; } pub trait Iterator { - // @count "$.index[*][?(@.name=='Item')].inner.generics.params[*]" 0 - // @count "$.index[*][?(@.name=='Item')].inner.generics.where_predicates[*]" 0 - // @count "$.index[*][?(@.name=='Item')].inner.bounds[*]" 1 + // @count "$.index[*][?(@.name=='Item')].inner.assoc_type.generics.params[*]" 0 + // @count "$.index[*][?(@.name=='Item')].inner.assoc_type.generics.where_predicates[*]" 0 + // @count "$.index[*][?(@.name=='Item')].inner.assoc_type.bounds[*]" 1 type Item: Display; - // @is "$.index[*][?(@.name=='next')].inner.decl.output.kind" \"qualified_path\" - // @count "$.index[*][?(@.name=='next')].inner.decl.output.inner.args.angle_bracketed.args[*]" 0 - // @count "$.index[*][?(@.name=='next')].inner.decl.output.inner.args.angle_bracketed.bindings[*]" 0 - // @is "$.index[*][?(@.name=='next')].inner.decl.output.inner.self_type.inner" \"Self\" - // @is "$.index[*][?(@.name=='next')].inner.decl.output.inner.name" \"Item\" + // @count "$.index[*][?(@.name=='next')].inner.function.decl.output.qualified_path.args.angle_bracketed.args[*]" 0 + // @count "$.index[*][?(@.name=='next')].inner.function.decl.output.qualified_path.args.angle_bracketed.bindings[*]" 0 + // @is "$.index[*][?(@.name=='next')].inner.function.decl.output.qualified_path.self_type.generic" \"Self\" + // @is "$.index[*][?(@.name=='next')].inner.function.decl.output.qualified_path.name" \"Item\" fn next<'a>(&'a self) -> Self::Item; } diff --git a/tests/rustdoc-json/glob_import.rs b/tests/rustdoc-json/glob_import.rs index 00051b12199..f37ce0abb41 100644 --- a/tests/rustdoc-json/glob_import.rs +++ b/tests/rustdoc-json/glob_import.rs @@ -5,7 +5,7 @@ #![no_core] // @has "$.index[*][?(@.name=='glob')]" -// @has "$.index[*][?(@.kind=='import')].inner.name" \"*\" +// @has "$.index[*][?(@.inner.import)].inner.import.name" \"*\" mod m1 { diff --git a/tests/rustdoc-json/impls/auto.rs b/tests/rustdoc-json/impls/auto.rs index 50d85241427..ace37e5b3df 100644 --- a/tests/rustdoc-json/impls/auto.rs +++ b/tests/rustdoc-json/impls/auto.rs @@ -12,7 +12,8 @@ impl Foo { } // Testing spans, so all tests below code -// @is "$.index[*][?(@.kind=='impl' && @.inner.synthetic==true)].span" null // @is "$.index[*][?(@.docs=='has span')].span.begin" "[10, 0]" // @is "$.index[*][?(@.docs=='has span')].span.end" "[12, 1]" +// FIXME: this doesn't work due to https://github.com/freestrings/jsonpath/issues/91 +// is "$.index[*][?(@.inner.impl.synthetic==true)].span" null pub struct Foo; diff --git a/tests/rustdoc-json/impls/foreign_for_local.rs b/tests/rustdoc-json/impls/foreign_for_local.rs index 290c2d571e8..20e1cecd778 100644 --- a/tests/rustdoc-json/impls/foreign_for_local.rs +++ b/tests/rustdoc-json/impls/foreign_for_local.rs @@ -3,7 +3,7 @@ extern crate foreign_trait; /// ForeignTrait id hack pub use foreign_trait::ForeignTrait as _; -// @set ForeignTrait = "$.index[*][?(@.docs=='ForeignTrait id hack')].inner.id" +// @set ForeignTrait = "$.index[*][?(@.docs=='ForeignTrait id hack')].inner.import.id" pub struct LocalStruct; // @set LocalStruct = "$.index[*][?(@.name=='LocalStruct')].id" @@ -12,7 +12,7 @@ pub struct LocalStruct; impl foreign_trait::ForeignTrait for LocalStruct {} // @set impl = "$.index[*][?(@.docs=='foreign for local')].id" -// @is "$.index[*][?(@.docs=='foreign for local')].inner.for.inner.id" $LocalStruct -// @is "$.index[*][?(@.docs=='foreign for local')].inner.trait.id" $ForeignTrait +// @is "$.index[*][?(@.docs=='foreign for local')].inner.impl.for.resolved_path.id" $LocalStruct +// @is "$.index[*][?(@.docs=='foreign for local')].inner.impl.trait.id" $ForeignTrait -// @has "$.index[*][?(@.name=='LocalStruct')].inner.impls[*]" $impl +// @has "$.index[*][?(@.name=='LocalStruct')].inner.struct.impls[*]" $impl diff --git a/tests/rustdoc-json/impls/impl_item_visibility.rs b/tests/rustdoc-json/impls/impl_item_visibility.rs new file mode 100644 index 00000000000..efa54d91dca --- /dev/null +++ b/tests/rustdoc-json/impls/impl_item_visibility.rs @@ -0,0 +1,26 @@ +#![feature(no_core)] +#![no_core] + +pub struct Foo; + +/// impl Foo priv +impl Foo { + fn baz() {} +} +// @!has '$.index[*][?(@.docs=="impl Foo priv")]' + + +/// impl Foo pub +impl Foo { + pub fn qux() {} +} +// @is '$.index[*][?(@.docs=="impl Foo pub")].visibility' '"default"' + + +/// impl Foo hidden +impl Foo { + #[doc(hidden)] + pub fn __quazl(){} +} +// FIXME(#111564): Is this the right behaviour? +// @is '$.index[*][?(@.docs=="impl Foo hidden")].visibility' '"default"' diff --git a/tests/rustdoc-json/impls/impl_item_visibility_show_hidden.rs b/tests/rustdoc-json/impls/impl_item_visibility_show_hidden.rs new file mode 100644 index 00000000000..3c6fefc4ca2 --- /dev/null +++ b/tests/rustdoc-json/impls/impl_item_visibility_show_hidden.rs @@ -0,0 +1,28 @@ +// compile-flags: --document-hidden-items +#![feature(no_core)] +#![no_core] + +pub struct Foo; + +/// impl Foo priv +impl Foo { + fn baz() {} +} +// FIXME(#111564): Is this the right behaviour? +// @is '$.index[*][?(@.docs=="impl Foo priv")].visibility' '"default"' + + +/// impl Foo pub +impl Foo { + pub fn qux() {} +} +// @is '$.index[*][?(@.docs=="impl Foo pub")].visibility' '"default"' + + +/// impl Foo hidden +impl Foo { + #[doc(hidden)] + pub fn __quazl(){} +} +// FIXME(#111564): Is this the right behaviour? +// @is '$.index[*][?(@.docs=="impl Foo hidden")].visibility' '"default"' diff --git a/tests/rustdoc-json/impls/impl_item_visibility_show_private.rs b/tests/rustdoc-json/impls/impl_item_visibility_show_private.rs new file mode 100644 index 00000000000..b98d1e4167c --- /dev/null +++ b/tests/rustdoc-json/impls/impl_item_visibility_show_private.rs @@ -0,0 +1,27 @@ +// compile-flags: --document-private-items +#![feature(no_core)] +#![no_core] + +pub struct Foo; + +/// impl Foo priv +impl Foo { + fn baz() {} +} +// @is '$.index[*][?(@.docs=="impl Foo priv")].visibility' '"default"' + + +/// impl Foo pub +impl Foo { + pub fn qux() {} +} +// @is '$.index[*][?(@.docs=="impl Foo pub")].visibility' '"default"' + + +/// impl Foo hidden +impl Foo { + #[doc(hidden)] + pub fn __quazl(){} +} +// FIXME(#111564): Is this the right behaviour? +// @is '$.index[*][?(@.docs=="impl Foo hidden")].visibility' '"default"' diff --git a/tests/rustdoc-json/impls/import_from_private.rs b/tests/rustdoc-json/impls/import_from_private.rs index fa88b6113a5..d2b0665dcaf 100644 --- a/tests/rustdoc-json/impls/import_from_private.rs +++ b/tests/rustdoc-json/impls/import_from_private.rs @@ -4,19 +4,19 @@ #![no_core] mod bar { - // @set baz = "$.index[*][?(@.kind=='struct')].id" + // @set baz = "$.index[*][?(@.inner.struct)].id" pub struct Baz; - // @set impl = "$.index[*][?(@.kind=='impl')].id" + // @set impl = "$.index[*][?(@.inner.impl)].id" impl Baz { - // @set doit = "$.index[*][?(@.kind=='function')].id" + // @set doit = "$.index[*][?(@.inner.function)].id" pub fn doit() {} } } -// @set import = "$.index[*][?(@.kind=='import')].id" +// @set import = "$.index[*][?(@.inner.import)].id" pub use bar::Baz; -// @is "$.index[*][?(@.kind=='module')].inner.items[*]" $import -// @is "$.index[*][?(@.kind=='import')].inner.id" $baz -// @is "$.index[*][?(@.kind=='struct')].inner.impls[*]" $impl -// @is "$.index[*][?(@.kind=='impl')].inner.items[*]" $doit +// @is "$.index[*].inner.module.items[*]" $import +// @is "$.index[*].inner.import.id" $baz +// @is "$.index[*].inner.struct.impls[*]" $impl +// @is "$.index[*].inner.impl.items[*]" $doit diff --git a/tests/rustdoc-json/impls/local_for_foreign.rs b/tests/rustdoc-json/impls/local_for_foreign.rs index 74f2f08b5a4..72352ce88da 100644 --- a/tests/rustdoc-json/impls/local_for_foreign.rs +++ b/tests/rustdoc-json/impls/local_for_foreign.rs @@ -3,7 +3,7 @@ extern crate foreign_struct; /// ForeignStruct id hack pub use foreign_struct::ForeignStruct as _; -// @set ForeignStruct = "$.index[*][?(@.docs=='ForeignStruct id hack')].inner.id" +// @set ForeignStruct = "$.index[*][?(@.docs=='ForeignStruct id hack')].inner.import.id" pub trait LocalTrait {} // @set LocalTrait = "$.index[*][?(@.name=='LocalTrait')].id" @@ -12,7 +12,7 @@ pub trait LocalTrait {} impl LocalTrait for foreign_struct::ForeignStruct {} // @set impl = "$.index[*][?(@.docs=='local for foreign')].id" -// @is "$.index[*][?(@.docs=='local for foreign')].inner.trait.id" $LocalTrait -// @is "$.index[*][?(@.docs=='local for foreign')].inner.for.inner.id" $ForeignStruct +// @is "$.index[*][?(@.docs=='local for foreign')].inner.impl.trait.id" $LocalTrait +// @is "$.index[*][?(@.docs=='local for foreign')].inner.impl.for.resolved_path.id" $ForeignStruct -// @is "$.index[*][?(@.name=='LocalTrait')].inner.implementations[*]" $impl +// @is "$.index[*][?(@.name=='LocalTrait')].inner.trait.implementations[*]" $impl diff --git a/tests/rustdoc-json/impls/local_for_local.rs b/tests/rustdoc-json/impls/local_for_local.rs index 93dedb7ec92..37a72000329 100644 --- a/tests/rustdoc-json/impls/local_for_local.rs +++ b/tests/rustdoc-json/impls/local_for_local.rs @@ -9,7 +9,7 @@ pub trait Trait {} /// impl impl Trait for Struct {} -// @is "$.index[*][?(@.name=='Struct')].inner.impls[*]" $impl -// @is "$.index[*][?(@.name=='Trait')].inner.implementations[*]" $impl -// @is "$.index[*][?(@.docs=='impl')].inner.trait.id" $trait -// @is "$.index[*][?(@.docs=='impl')].inner.for.inner.id" $struct +// @is "$.index[*][?(@.name=='Struct')].inner.struct.impls[*]" $impl +// @is "$.index[*][?(@.name=='Trait')].inner.trait.implementations[*]" $impl +// @is "$.index[*][?(@.docs=='impl')].inner.impl.trait.id" $trait +// @is "$.index[*][?(@.docs=='impl')].inner.impl.for.resolved_path.id" $struct diff --git a/tests/rustdoc-json/impls/local_for_local_primitive.rs b/tests/rustdoc-json/impls/local_for_local_primitive.rs index 8383dcc0482..769dd3f0a2c 100644 --- a/tests/rustdoc-json/impls/local_for_local_primitive.rs +++ b/tests/rustdoc-json/impls/local_for_local_primitive.rs @@ -5,14 +5,13 @@ // @set Local = "$.index[*][?(@.name=='Local')].id" pub trait Local {} -// @is "$.index[*][?(@.docs=='Local for bool')].inner.trait.id" $Local -// @is "$.index[*][?(@.docs=='Local for bool')].inner.for.kind" '"primitive"' -// @is "$.index[*][?(@.docs=='Local for bool')].inner.for.inner" '"bool"' +// @is "$.index[*][?(@.docs=='Local for bool')].inner.impl.trait.id" $Local +// @is "$.index[*][?(@.docs=='Local for bool')].inner.impl.for.primitive" '"bool"' /// Local for bool impl Local for bool {} // @set impl = "$.index[*][?(@.docs=='Local for bool')].id" -// @is "$.index[*][?(@.name=='Local')].inner.implementations[*]" $impl +// @is "$.index[*][?(@.name=='Local')].inner.trait.implementations[*]" $impl // FIXME(#101695): Test bool's `impls` include "Local for bool" // @has "$.index[*][?(@.name=='bool')]" diff --git a/tests/rustdoc-json/impls/local_for_primitive.rs b/tests/rustdoc-json/impls/local_for_primitive.rs index 7702a526fd8..85278c0e08c 100644 --- a/tests/rustdoc-json/impls/local_for_primitive.rs +++ b/tests/rustdoc-json/impls/local_for_primitive.rs @@ -2,6 +2,6 @@ pub trait Local {} // @set impl = "$.index[*][?(@.docs=='local for bool')].id" -// @is "$.index[*][?(@.name=='Local')].inner.implementations[*]" $impl +// @is "$.index[*][?(@.name=='Local')].inner.trait.implementations[*]" $impl /// local for bool impl Local for bool {} diff --git a/tests/rustdoc-json/lifetime/longest.rs b/tests/rustdoc-json/lifetime/longest.rs index 326dab8e57a..dc28258a8b6 100644 --- a/tests/rustdoc-json/lifetime/longest.rs +++ b/tests/rustdoc-json/lifetime/longest.rs @@ -3,30 +3,27 @@ #![feature(no_core)] #![no_core] -// @is "$.index[*][?(@.name=='longest')].inner.generics.params[0].name" \"\'a\" -// @is "$.index[*][?(@.name=='longest')].inner.generics.params[0].kind" '{"lifetime": {"outlives": []}}' -// @is "$.index[*][?(@.name=='longest')].inner.generics.params[0].kind" '{"lifetime": {"outlives": []}}' -// @count "$.index[*][?(@.name=='longest')].inner.generics.params[*]" 1 -// @is "$.index[*][?(@.name=='longest')].inner.generics.where_predicates" [] +// @is "$.index[*][?(@.name=='longest')].inner.function.generics.params[0].name" \"\'a\" +// @is "$.index[*][?(@.name=='longest')].inner.function.generics.params[0].kind" '{"lifetime": {"outlives": []}}' +// @is "$.index[*][?(@.name=='longest')].inner.function.generics.params[0].kind" '{"lifetime": {"outlives": []}}' +// @count "$.index[*][?(@.name=='longest')].inner.function.generics.params[*]" 1 +// @is "$.index[*][?(@.name=='longest')].inner.function.generics.where_predicates" [] -// @count "$.index[*][?(@.name=='longest')].inner.decl.inputs[*]" 2 -// @is "$.index[*][?(@.name=='longest')].inner.decl.inputs[0][0]" '"l"' -// @is "$.index[*][?(@.name=='longest')].inner.decl.inputs[1][0]" '"r"' +// @count "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[*]" 2 +// @is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[0][0]" '"l"' +// @is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[1][0]" '"r"' -// @is "$.index[*][?(@.name=='longest')].inner.decl.inputs[0][1].kind" '"borrowed_ref"' -// @is "$.index[*][?(@.name=='longest')].inner.decl.inputs[0][1].inner.lifetime" \"\'a\" -// @is "$.index[*][?(@.name=='longest')].inner.decl.inputs[0][1].inner.mutable" false -// @is "$.index[*][?(@.name=='longest')].inner.decl.inputs[0][1].inner.type" '{"inner": "str", "kind": "primitive"}' +// @is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[0][1].borrowed_ref.lifetime" \"\'a\" +// @is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[0][1].borrowed_ref.mutable" false +// @is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[0][1].borrowed_ref.type.primitive" \"str\" -// @is "$.index[*][?(@.name=='longest')].inner.decl.inputs[1][1].kind" '"borrowed_ref"' -// @is "$.index[*][?(@.name=='longest')].inner.decl.inputs[1][1].inner.lifetime" \"\'a\" -// @is "$.index[*][?(@.name=='longest')].inner.decl.inputs[1][1].inner.mutable" false -// @is "$.index[*][?(@.name=='longest')].inner.decl.inputs[1][1].inner.type" '{"inner": "str", "kind": "primitive"}' +// @is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[1][1].borrowed_ref.lifetime" \"\'a\" +// @is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[1][1].borrowed_ref.mutable" false +// @is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[1][1].borrowed_ref.type.primitive" \"str\" -// @is "$.index[*][?(@.name=='longest')].inner.decl.output.kind" '"borrowed_ref"' -// @is "$.index[*][?(@.name=='longest')].inner.decl.output.inner.lifetime" \"\'a\" -// @is "$.index[*][?(@.name=='longest')].inner.decl.output.inner.mutable" false -// @is "$.index[*][?(@.name=='longest')].inner.decl.output.inner.type" '{"inner": "str", "kind": "primitive"}' +// @is "$.index[*][?(@.name=='longest')].inner.function.decl.output.borrowed_ref.lifetime" \"\'a\" +// @is "$.index[*][?(@.name=='longest')].inner.function.decl.output.borrowed_ref.mutable" false +// @is "$.index[*][?(@.name=='longest')].inner.function.decl.output.borrowed_ref.type.primitive" \"str\" pub fn longest<'a>(l: &'a str, r: &'a str) -> &'a str { if l.len() > r.len() { l } else { r } diff --git a/tests/rustdoc-json/lifetime/outlives.rs b/tests/rustdoc-json/lifetime/outlives.rs index e15a533efdc..6e105b382b0 100644 --- a/tests/rustdoc-json/lifetime/outlives.rs +++ b/tests/rustdoc-json/lifetime/outlives.rs @@ -3,21 +3,19 @@ #![feature(no_core)] #![no_core] -// @count "$.index[*][?(@.name=='foo')].inner.generics.params[*]" 3 -// @is "$.index[*][?(@.name=='foo')].inner.generics.where_predicates" [] -// @is "$.index[*][?(@.name=='foo')].inner.generics.params[0].name" \"\'a\" -// @is "$.index[*][?(@.name=='foo')].inner.generics.params[1].name" \"\'b\" -// @is "$.index[*][?(@.name=='foo')].inner.generics.params[2].name" '"T"' -// @is "$.index[*][?(@.name=='foo')].inner.generics.params[0].kind.lifetime.outlives" [] -// @is "$.index[*][?(@.name=='foo')].inner.generics.params[1].kind.lifetime.outlives" [\"\'a\"] -// @is "$.index[*][?(@.name=='foo')].inner.generics.params[2].kind.type.default" null -// @count "$.index[*][?(@.name=='foo')].inner.generics.params[2].kind.type.bounds[*]" 1 -// @is "$.index[*][?(@.name=='foo')].inner.generics.params[2].kind.type.bounds[0].outlives" \"\'b\" -// @is "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].kind" '"borrowed_ref"' -// @is "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].inner.lifetime" \"\'a\" -// @is "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].inner.mutable" false -// @is "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].inner.type.kind" '"borrowed_ref"' -// @is "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].inner.type.inner.lifetime" \"\'b\" -// @is "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].inner.type.inner.mutable" false -// @is "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].inner.type.inner.type" '{"inner": "T", "kind": "generic"}' +// @count "$.index[*][?(@.name=='foo')].inner.function.generics.params[*]" 3 +// @is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates" [] +// @is "$.index[*][?(@.name=='foo')].inner.function.generics.params[0].name" \"\'a\" +// @is "$.index[*][?(@.name=='foo')].inner.function.generics.params[1].name" \"\'b\" +// @is "$.index[*][?(@.name=='foo')].inner.function.generics.params[2].name" '"T"' +// @is "$.index[*][?(@.name=='foo')].inner.function.generics.params[0].kind.lifetime.outlives" [] +// @is "$.index[*][?(@.name=='foo')].inner.function.generics.params[1].kind.lifetime.outlives" [\"\'a\"] +// @is "$.index[*][?(@.name=='foo')].inner.function.generics.params[2].kind.type.default" null +// @count "$.index[*][?(@.name=='foo')].inner.function.generics.params[2].kind.type.bounds[*]" 1 +// @is "$.index[*][?(@.name=='foo')].inner.function.generics.params[2].kind.type.bounds[0].outlives" \"\'b\" +// @is "$.index[*][?(@.name=='foo')].inner.function.decl.inputs[0][1].borrowed_ref.lifetime" \"\'a\" +// @is "$.index[*][?(@.name=='foo')].inner.function.decl.inputs[0][1].borrowed_ref.mutable" false +// @is "$.index[*][?(@.name=='foo')].inner.function.decl.inputs[0][1].borrowed_ref.type.borrowed_ref.lifetime" \"\'b\" +// @is "$.index[*][?(@.name=='foo')].inner.function.decl.inputs[0][1].borrowed_ref.type.borrowed_ref.mutable" false +// @is "$.index[*][?(@.name=='foo')].inner.function.decl.inputs[0][1].borrowed_ref.type.borrowed_ref.type.generic" \"T\" pub fn foo<'a, 'b: 'a, T: 'b>(_: &'a &'b T) {} diff --git a/tests/rustdoc-json/methods/abi.rs b/tests/rustdoc-json/methods/abi.rs index fd03d92d65b..b8279298c1e 100644 --- a/tests/rustdoc-json/methods/abi.rs +++ b/tests/rustdoc-json/methods/abi.rs @@ -8,47 +8,47 @@ pub struct Foo; impl Foo { - // @is "$.index[*][?(@.name=='abi_rust')].inner.header.abi" \"Rust\" + // @is "$.index[*][?(@.name=='abi_rust')].inner.function.header.abi" \"Rust\" pub fn abi_rust() {} - // @is "$.index[*][?(@.name=='abi_c')].inner.header.abi" '{"C": {"unwind": false}}' + // @is "$.index[*][?(@.name=='abi_c')].inner.function.header.abi" '{"C": {"unwind": false}}' pub extern "C" fn abi_c() {} - // @is "$.index[*][?(@.name=='abi_system')].inner.header.abi" '{"System": {"unwind": false}}' + // @is "$.index[*][?(@.name=='abi_system')].inner.function.header.abi" '{"System": {"unwind": false}}' pub extern "system" fn abi_system() {} - // @is "$.index[*][?(@.name=='abi_c_unwind')].inner.header.abi" '{"C": {"unwind": true}}' + // @is "$.index[*][?(@.name=='abi_c_unwind')].inner.function.header.abi" '{"C": {"unwind": true}}' pub extern "C-unwind" fn abi_c_unwind() {} - // @is "$.index[*][?(@.name=='abi_system_unwind')].inner.header.abi" '{"System": {"unwind": true}}' + // @is "$.index[*][?(@.name=='abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' pub extern "system-unwind" fn abi_system_unwind() {} - // @is "$.index[*][?(@.name=='abi_vectorcall')].inner.header.abi.Other" '"\"vectorcall\""' + // @is "$.index[*][?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' pub extern "vectorcall" fn abi_vectorcall() {} - // @is "$.index[*][?(@.name=='abi_vectorcall_unwind')].inner.header.abi.Other" '"\"vectorcall-unwind\""' + // @is "$.index[*][?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {} } pub trait Bar { - // @is "$.index[*][?(@.name=='trait_abi_rust')].inner.header.abi" \"Rust\" + // @is "$.index[*][?(@.name=='trait_abi_rust')].inner.function.header.abi" \"Rust\" fn trait_abi_rust() {} - // @is "$.index[*][?(@.name=='trait_abi_c')].inner.header.abi" '{"C": {"unwind": false}}' + // @is "$.index[*][?(@.name=='trait_abi_c')].inner.function.header.abi" '{"C": {"unwind": false}}' extern "C" fn trait_abi_c() {} - // @is "$.index[*][?(@.name=='trait_abi_system')].inner.header.abi" '{"System": {"unwind": false}}' + // @is "$.index[*][?(@.name=='trait_abi_system')].inner.function.header.abi" '{"System": {"unwind": false}}' extern "system" fn trait_abi_system() {} - // @is "$.index[*][?(@.name=='trait_abi_c_unwind')].inner.header.abi" '{"C": {"unwind": true}}' + // @is "$.index[*][?(@.name=='trait_abi_c_unwind')].inner.function.header.abi" '{"C": {"unwind": true}}' extern "C-unwind" fn trait_abi_c_unwind() {} - // @is "$.index[*][?(@.name=='trait_abi_system_unwind')].inner.header.abi" '{"System": {"unwind": true}}' + // @is "$.index[*][?(@.name=='trait_abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' extern "system-unwind" fn trait_abi_system_unwind() {} - // @is "$.index[*][?(@.name=='trait_abi_vectorcall')].inner.header.abi.Other" '"\"vectorcall\""' + // @is "$.index[*][?(@.name=='trait_abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' extern "vectorcall" fn trait_abi_vectorcall() {} - // @is "$.index[*][?(@.name=='trait_abi_vectorcall_unwind')].inner.header.abi.Other" '"\"vectorcall-unwind\""' + // @is "$.index[*][?(@.name=='trait_abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' extern "vectorcall-unwind" fn trait_abi_vectorcall_unwind() {} } diff --git a/tests/rustdoc-json/methods/qualifiers.rs b/tests/rustdoc-json/methods/qualifiers.rs index b9a5e56012e..65977bc826f 100644 --- a/tests/rustdoc-json/methods/qualifiers.rs +++ b/tests/rustdoc-json/methods/qualifiers.rs @@ -3,34 +3,34 @@ pub struct Foo; impl Foo { - // @is "$.index[*][?(@.name=='const_meth')].inner.header.async" false - // @is "$.index[*][?(@.name=='const_meth')].inner.header.const" true - // @is "$.index[*][?(@.name=='const_meth')].inner.header.unsafe" false + // @is "$.index[*][?(@.name=='const_meth')].inner.function.header.async" false + // @is "$.index[*][?(@.name=='const_meth')].inner.function.header.const" true + // @is "$.index[*][?(@.name=='const_meth')].inner.function.header.unsafe" false pub const fn const_meth() {} - // @is "$.index[*][?(@.name=='nothing_meth')].inner.header.async" false - // @is "$.index[*][?(@.name=='nothing_meth')].inner.header.const" false - // @is "$.index[*][?(@.name=='nothing_meth')].inner.header.unsafe" false + // @is "$.index[*][?(@.name=='nothing_meth')].inner.function.header.async" false + // @is "$.index[*][?(@.name=='nothing_meth')].inner.function.header.const" false + // @is "$.index[*][?(@.name=='nothing_meth')].inner.function.header.unsafe" false pub fn nothing_meth() {} - // @is "$.index[*][?(@.name=='unsafe_meth')].inner.header.async" false - // @is "$.index[*][?(@.name=='unsafe_meth')].inner.header.const" false - // @is "$.index[*][?(@.name=='unsafe_meth')].inner.header.unsafe" true + // @is "$.index[*][?(@.name=='unsafe_meth')].inner.function.header.async" false + // @is "$.index[*][?(@.name=='unsafe_meth')].inner.function.header.const" false + // @is "$.index[*][?(@.name=='unsafe_meth')].inner.function.header.unsafe" true pub unsafe fn unsafe_meth() {} - // @is "$.index[*][?(@.name=='async_meth')].inner.header.async" true - // @is "$.index[*][?(@.name=='async_meth')].inner.header.const" false - // @is "$.index[*][?(@.name=='async_meth')].inner.header.unsafe" false + // @is "$.index[*][?(@.name=='async_meth')].inner.function.header.async" true + // @is "$.index[*][?(@.name=='async_meth')].inner.function.header.const" false + // @is "$.index[*][?(@.name=='async_meth')].inner.function.header.unsafe" false pub async fn async_meth() {} - // @is "$.index[*][?(@.name=='async_unsafe_meth')].inner.header.async" true - // @is "$.index[*][?(@.name=='async_unsafe_meth')].inner.header.const" false - // @is "$.index[*][?(@.name=='async_unsafe_meth')].inner.header.unsafe" true + // @is "$.index[*][?(@.name=='async_unsafe_meth')].inner.function.header.async" true + // @is "$.index[*][?(@.name=='async_unsafe_meth')].inner.function.header.const" false + // @is "$.index[*][?(@.name=='async_unsafe_meth')].inner.function.header.unsafe" true pub async unsafe fn async_unsafe_meth() {} - // @is "$.index[*][?(@.name=='const_unsafe_meth')].inner.header.async" false - // @is "$.index[*][?(@.name=='const_unsafe_meth')].inner.header.const" true - // @is "$.index[*][?(@.name=='const_unsafe_meth')].inner.header.unsafe" true + // @is "$.index[*][?(@.name=='const_unsafe_meth')].inner.function.header.async" false + // @is "$.index[*][?(@.name=='const_unsafe_meth')].inner.function.header.const" true + // @is "$.index[*][?(@.name=='const_unsafe_meth')].inner.function.header.unsafe" true pub const unsafe fn const_unsafe_meth() {} // It's impossible for a method to be both const and async, so no test for that diff --git a/tests/rustdoc-json/nested.rs b/tests/rustdoc-json/nested.rs index ee2d2efa960..e012cfc5014 100644 --- a/tests/rustdoc-json/nested.rs +++ b/tests/rustdoc-json/nested.rs @@ -2,30 +2,31 @@ // compile-flags: --crate-version 1.0.0 // @is "$.crate_version" \"1.0.0\" -// @is "$.index[*][?(@.name=='nested')].kind" \"module\" -// @is "$.index[*][?(@.name=='nested')].inner.is_crate" true +// @has "$.index[*][?(@.name=='nested')].inner.module" +// @is "$.index[*][?(@.name=='nested')].inner.module.is_crate" true // @set l1_id = "$.index[*][?(@.name=='l1')].id" -// @ismany "$.index[*][?(@.name=='nested')].inner.items[*]" $l1_id +// @ismany "$.index[*][?(@.name=='nested')].inner.module.items[*]" $l1_id -// @is "$.index[*][?(@.name=='l1')].kind" \"module\" -// @is "$.index[*][?(@.name=='l1')].inner.is_crate" false +// @has "$.index[*][?(@.name=='l1')].inner.module" +// @is "$.index[*][?(@.name=='l1')].inner.module.is_crate" false pub mod l1 { - // @is "$.index[*][?(@.name=='l3')].kind" \"module\" - // @is "$.index[*][?(@.name=='l3')].inner.is_crate" false + // @has "$.index[*][?(@.name=='l3')].inner.module" + // @is "$.index[*][?(@.name=='l3')].inner.module.is_crate" false // @set l3_id = "$.index[*][?(@.name=='l3')].id" pub mod l3 { - // @is "$.index[*][?(@.name=='L4')].kind" \"struct\" - // @is "$.index[*][?(@.name=='L4')].inner.kind" \"unit\" + // @has "$.index[*][?(@.name=='L4')].inner.struct" + // @is "$.index[*][?(@.name=='L4')].inner.struct.kind" '"unit"' // @set l4_id = "$.index[*][?(@.name=='L4')].id" - // @ismany "$.index[*][?(@.name=='l3')].inner.items[*]" $l4_id + // @ismany "$.index[*][?(@.name=='l3')].inner.module.items[*]" $l4_id pub struct L4; } - // @is "$.index[*][?(@.inner.source=='l3::L4')].kind" \"import\" - // @is "$.index[*][?(@.inner.source=='l3::L4')].inner.glob" false - // @is "$.index[*][?(@.inner.source=='l3::L4')].inner.id" $l4_id - // @set l4_use_id = "$.index[*][?(@.inner.source=='l3::L4')].id" + // @is "$.index[*][?(@.inner.import)].inner.import.glob" false + // @is "$.index[*][?(@.inner.import)].inner.import.source" '"l3::L4"' + // @is "$.index[*][?(@.inner.import)].inner.import.glob" false + // @is "$.index[*][?(@.inner.import)].inner.import.id" $l4_id + // @set l4_use_id = "$.index[*][?(@.inner.import)].id" pub use l3::L4; } -// @ismany "$.index[*][?(@.name=='l1')].inner.items[*]" $l3_id $l4_use_id +// @ismany "$.index[*][?(@.name=='l1')].inner.module.items[*]" $l3_id $l4_use_id diff --git a/tests/rustdoc-json/non_lifetime_binders.rs b/tests/rustdoc-json/non_lifetime_binders.rs index ca5a008344a..cabee0b1caa 100644 --- a/tests/rustdoc-json/non_lifetime_binders.rs +++ b/tests/rustdoc-json/non_lifetime_binders.rs @@ -16,9 +16,9 @@ struct PhantomData<T_>; pub struct Wrapper<T_>(PhantomData<T_>); -// @count "$.index[*][?(@.name=='foo')].inner.generics.where_predicates[0].bound_predicate.generic_params[*]" 2 -// @is "$.index[*][?(@.name=='foo')].inner.generics.where_predicates[0].bound_predicate.generic_params[0].name" \"\'a\" -// @is "$.index[*][?(@.name=='foo')].inner.generics.where_predicates[0].bound_predicate.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }' -// @is "$.index[*][?(@.name=='foo')].inner.generics.where_predicates[0].bound_predicate.generic_params[1].name" \"T\" -// @is "$.index[*][?(@.name=='foo')].inner.generics.where_predicates[0].bound_predicate.generic_params[1].kind" '{ "type": { "bounds": [], "default": null, "synthetic": false } }' +// @count "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[*]" 2 +// @is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[0].name" \"\'a\" +// @is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }' +// @is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[1].name" \"T\" +// @is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[1].kind" '{ "type": { "bounds": [], "default": null, "synthetic": false } }' pub fn foo() where for<'a, T> &'a Wrapper<T>: Trait {} diff --git a/tests/rustdoc-json/primitives/local_primitive.rs b/tests/rustdoc-json/primitives/local_primitive.rs index 0cf479faf29..562c7e4d79b 100644 --- a/tests/rustdoc-json/primitives/local_primitive.rs +++ b/tests/rustdoc-json/primitives/local_primitive.rs @@ -14,7 +14,7 @@ mod prim_i32 {} // @set local_i32 = "$.index[*][?(@.name=='i32')].id" // @has "$.index[*][?(@.name=='local_primitive')]" -// @ismany "$.index[*][?(@.name=='local_primitive')].inner.items[*]" $local_i32 +// @ismany "$.index[*][?(@.name=='local_primitive')].inner.module.items[*]" $local_i32 // @is "$.index[*][?(@.name=='local_primitive')].links['prim@i32']" $local_i32 // Let's ensure the `prim_i32` module isn't present in the output JSON: diff --git a/tests/rustdoc-json/primitives/primitive_impls.rs b/tests/rustdoc-json/primitives/primitive_impls.rs index 85d179ee45f..4b7b7646b89 100644 --- a/tests/rustdoc-json/primitives/primitive_impls.rs +++ b/tests/rustdoc-json/primitives/primitive_impls.rs @@ -15,7 +15,7 @@ impl i32 { self } - // @is "$.index[*][?(@.docs=='Only core can do this')].inner.items[*]" $identity + // @is "$.index[*][?(@.docs=='Only core can do this')].inner.impl.items[*]" $identity } // @set Trait = "$.index[*][?(@.name=='Trait')].id" @@ -30,5 +30,5 @@ mod prim_i32 {} // @set i32 = "$.index[*][?(@.docs=='i32')].id" // @is "$.index[*][?(@.docs=='i32')].name" '"i32"' -// @is "$.index[*][?(@.docs=='i32')].inner.name" '"i32"' -// @ismany "$.index[*][?(@.docs=='i32')].inner.impls[*]" $impl_i32 $impl_trait_for_i32 +// @is "$.index[*][?(@.docs=='i32')].inner.primitive.name" '"i32"' +// @ismany "$.index[*][?(@.docs=='i32')].inner.primitive.impls[*]" $impl_i32 $impl_trait_for_i32 diff --git a/tests/rustdoc-json/primitives/primitive_type.rs b/tests/rustdoc-json/primitives/primitive_type.rs index 8024044bc05..5f251b3b890 100644 --- a/tests/rustdoc-json/primitives/primitive_type.rs +++ b/tests/rustdoc-json/primitives/primitive_type.rs @@ -1,22 +1,17 @@ #![feature(never_type)] // @is "$.index[*][?(@.name=='PrimNever')].visibility" \"public\" -// @is "$.index[*][?(@.name=='PrimNever')].inner.type.kind" \"primitive\" -// @is "$.index[*][?(@.name=='PrimNever')].inner.type.inner" \"never\" +// @is "$.index[*][?(@.name=='PrimNever')].inner.typedef.type.primitive" \"never\" pub type PrimNever = !; -// @is "$.index[*][?(@.name=='PrimStr')].inner.type.kind" \"primitive\" -// @is "$.index[*][?(@.name=='PrimStr')].inner.type.inner" \"str\" +// @is "$.index[*][?(@.name=='PrimStr')].inner.typedef.type.primitive" \"str\" pub type PrimStr = str; -// @is "$.index[*][?(@.name=='PrimBool')].inner.type.kind" \"primitive\" -// @is "$.index[*][?(@.name=='PrimBool')].inner.type.inner" \"bool\" +// @is "$.index[*][?(@.name=='PrimBool')].inner.typedef.type.primitive" \"bool\" pub type PrimBool = bool; -// @is "$.index[*][?(@.name=='PrimChar')].inner.type.kind" \"primitive\" -// @is "$.index[*][?(@.name=='PrimChar')].inner.type.inner" \"char\" +// @is "$.index[*][?(@.name=='PrimChar')].inner.typedef.type.primitive" \"char\" pub type PrimChar = char; -// @is "$.index[*][?(@.name=='PrimU8')].inner.type.kind" \"primitive\" -// @is "$.index[*][?(@.name=='PrimU8')].inner.type.inner" \"u8\" +// @is "$.index[*][?(@.name=='PrimU8')].inner.typedef.type.primitive" \"u8\" pub type PrimU8 = u8; diff --git a/tests/rustdoc-json/primitives/use_primitive.rs b/tests/rustdoc-json/primitives/use_primitive.rs index 5180a804f07..f8118b82094 100644 --- a/tests/rustdoc-json/primitives/use_primitive.rs +++ b/tests/rustdoc-json/primitives/use_primitive.rs @@ -13,8 +13,8 @@ mod usize {} // @!is "$.index[*][?(@.name=='checked_add')]" $local_crate_id // @!has "$.index[*][?(@.name=='is_ascii_uppercase')]" -// @is "$.index[*][?(@.kind=='import' && @.inner.name=='my_i32')].inner.id" null +// @is "$.index[*].inner.import[?(@.name=='my_i32')].id" null pub use i32 as my_i32; -// @is "$.index[*][?(@.kind=='import' && @.inner.name=='u32')].inner.id" null +// @is "$.index[*].inner.import[?(@.name=='u32')].id" null pub use u32; diff --git a/tests/rustdoc-json/reexport/doc_inline_external_crate.rs b/tests/rustdoc-json/reexport/doc_inline_external_crate.rs index 40b681d7dbb..1c5fed8c6b2 100644 --- a/tests/rustdoc-json/reexport/doc_inline_external_crate.rs +++ b/tests/rustdoc-json/reexport/doc_inline_external_crate.rs @@ -1,10 +1,11 @@ // Regression Test for https://github.com/rust-lang/rust/issues/110138 // aux-build: enum_with_discriminant.rs +// ignore-tidy-linelength #[doc(inline)] pub extern crate enum_with_discriminant; // @!has '$.index[*][?(@.docs == "Should not be inlined")]' -// @is '$.index[*][?(@.name == "enum_with_discriminant")].kind' '"extern_crate"' +// @has '$.index[*][?(@.name == "enum_with_discriminant")].inner.extern_crate' // @set enum_with_discriminant = '$.index[*][?(@.name == "enum_with_discriminant")].id' -// @is '$.index[*][?(@.name == "doc_inline_external_crate")].inner.items[*]' $enum_with_discriminant +// @is '$.index[*][?(@.name == "doc_inline_external_crate")].inner.module.items[*]' $enum_with_discriminant diff --git a/tests/rustdoc-json/reexport/export_extern_crate_as_self.rs b/tests/rustdoc-json/reexport/export_extern_crate_as_self.rs index f076feb7185..37ca279b352 100644 --- a/tests/rustdoc-json/reexport/export_extern_crate_as_self.rs +++ b/tests/rustdoc-json/reexport/export_extern_crate_as_self.rs @@ -7,5 +7,5 @@ // ignore-tidy-linelength -// @is "$.index[*][?(@.kind=='module')].name" \"export_extern_crate_as_self\" +// @is "$.index[*][?(@.inner.module)].name" \"export_extern_crate_as_self\" pub extern crate self as export_extern_crate_as_self; // Must be the same name as the crate already has diff --git a/tests/rustdoc-json/reexport/extern_crate_glob.rs b/tests/rustdoc-json/reexport/extern_crate_glob.rs index 8efb94fd3f1..553ee79b44e 100644 --- a/tests/rustdoc-json/reexport/extern_crate_glob.rs +++ b/tests/rustdoc-json/reexport/extern_crate_glob.rs @@ -6,5 +6,6 @@ extern crate enum_with_discriminant; pub use enum_with_discriminant::*; // @!has '$.index[*][?(@.docs == "Should not be inlined")]' -// @set use = '$.index[*][?(@.inner.name == "enum_with_discriminant")].id' -// @is '$.index[*][?(@.name == "extern_crate_glob")].inner.items[*]' $use +// @is '$.index[*][?(@.inner.import)].inner.import.name' \"enum_with_discriminant\" +// @set use = '$.index[*][?(@.inner.import)].id' +// @is '$.index[*][?(@.name == "extern_crate_glob")].inner.module.items[*]' $use diff --git a/tests/rustdoc-json/reexport/glob_collision.rs b/tests/rustdoc-json/reexport/glob_collision.rs index f91144dbfad..dee35ba78dc 100644 --- a/tests/rustdoc-json/reexport/glob_collision.rs +++ b/tests/rustdoc-json/reexport/glob_collision.rs @@ -3,26 +3,28 @@ #![feature(no_core)] #![no_core] -// @set m1 = "$.index[*][?(@.name == 'm1' && @.kind == 'module')].id" -// @is "$.index[*][?(@.name == 'm1' && @.kind == 'module')].inner.items" [] -// @is "$.index[*][?(@.name == 'm1' && @.kind == 'module')].inner.is_stripped" true +// @set m1 = "$.index[*][?(@.name == 'm1' && @.inner.module)].id" +// @is "$.index[*][?(@.name == 'm1')].inner.module.items" [] +// @is "$.index[*][?(@.name == 'm1')].inner.module.is_stripped" true mod m1 { pub fn f() {} } -// @set m2 = "$.index[*][?(@.name == 'm2' && @.kind == 'module')].id" -// @is "$.index[*][?(@.name == 'm2' && @.kind == 'module')].inner.items" [] -// @is "$.index[*][?(@.name == 'm2' && @.kind == 'module')].inner.is_stripped" true +// @set m2 = "$.index[*][?(@.name == 'm2' && @.inner.module)].id" +// @is "$.index[*][?(@.name == 'm2')].inner.module.items" [] +// @is "$.index[*][?(@.name == 'm2')].inner.module.is_stripped" true mod m2 { pub fn f(_: u8) {} } -// @set m1_use = "$.index[*][?(@.inner.name=='m1')].id" -// @is "$.index[*][?(@.inner.name=='m1')].inner.id" $m1 -// @is "$.index[*][?(@.inner.name=='m1')].inner.glob" true +// @set m1_use = "$.index[*][?(@.docs=='m1 re-export')].id" +// @is "$.index[*].inner.import[?(@.name=='m1')].id" $m1 +// @is "$.index[*].inner.import[?(@.name=='m1')].glob" true +/// m1 re-export pub use m1::*; -// @set m2_use = "$.index[*][?(@.inner.name=='m2')].id" -// @is "$.index[*][?(@.inner.name=='m2')].inner.id" $m2 -// @is "$.index[*][?(@.inner.name=='m2')].inner.glob" true +// @set m2_use = "$.index[*][?(@.docs=='m2 re-export')].id" +// @is "$.index[*].inner.import[?(@.name=='m2')].id" $m2 +// @is "$.index[*].inner.import[?(@.name=='m2')].glob" true +/// m2 re-export pub use m2::*; -// @ismany "$.index[*][?(@.inner.is_crate==true)].inner.items[*]" $m1_use $m2_use +// @ismany "$.index[*].inner.module[?(@.is_crate==true)].items[*]" $m1_use $m2_use diff --git a/tests/rustdoc-json/reexport/glob_empty_mod.rs b/tests/rustdoc-json/reexport/glob_empty_mod.rs index da68228352c..8b7150c8fd7 100644 --- a/tests/rustdoc-json/reexport/glob_empty_mod.rs +++ b/tests/rustdoc-json/reexport/glob_empty_mod.rs @@ -1,8 +1,8 @@ // Regression test for https://github.com/rust-lang/rust/issues/100973 -// @is "$.index[*][?(@.name=='m1' && @.kind == 'module')].inner.is_stripped" true +// @is "$.index[*][?(@.name=='m1' && @.inner.module)].inner.module.is_stripped" true // @set m1 = "$.index[*][?(@.name=='m1')].id" mod m1 {} -// @is "$.index[*][?(@.inner.name=='m1' && @.kind=='import')].inner.id" $m1 +// @is "$.index[*][?(@.inner.import)].inner.import.id" $m1 pub use m1::*; diff --git a/tests/rustdoc-json/reexport/glob_extern.rs b/tests/rustdoc-json/reexport/glob_extern.rs index 7a1e8c11ffa..78edfaf0aa8 100644 --- a/tests/rustdoc-json/reexport/glob_extern.rs +++ b/tests/rustdoc-json/reexport/glob_extern.rs @@ -3,8 +3,7 @@ #![no_core] #![feature(no_core)] -// @is "$.index[*][?(@.name=='mod1')].kind" \"module\" -// @is "$.index[*][?(@.name=='mod1')].inner.is_stripped" "true" +// @is "$.index[*][?(@.name=='mod1')].inner.module.is_stripped" "true" mod mod1 { extern "C" { // @set public_fn_id = "$.index[*][?(@.name=='public_fn')].id" @@ -12,12 +11,12 @@ mod mod1 { // @!has "$.index[*][?(@.name=='private_fn')]" fn private_fn(); } - // @ismany "$.index[*][?(@.name=='mod1')].inner.items[*]" $public_fn_id + // @ismany "$.index[*][?(@.name=='mod1')].inner.module.items[*]" $public_fn_id // @set mod1_id = "$.index[*][?(@.name=='mod1')].id" } -// @is "$.index[*][?(@.kind=='import')].inner.glob" true -// @is "$.index[*][?(@.kind=='import')].inner.id" $mod1_id -// @set use_id = "$.index[*][?(@.kind=='import')].id" -// @ismany "$.index[*][?(@.name=='glob_extern')].inner.items[*]" $use_id +// @is "$.index[*][?(@.inner.import)].inner.import.glob" true +// @is "$.index[*][?(@.inner.import)].inner.import.id" $mod1_id +// @set use_id = "$.index[*][?(@.inner.import)].id" +// @ismany "$.index[*][?(@.name=='glob_extern')].inner.module.items[*]" $use_id pub use mod1::*; diff --git a/tests/rustdoc-json/reexport/glob_private.rs b/tests/rustdoc-json/reexport/glob_private.rs index 3a83a20818b..ae4e87d23bc 100644 --- a/tests/rustdoc-json/reexport/glob_private.rs +++ b/tests/rustdoc-json/reexport/glob_private.rs @@ -3,11 +3,9 @@ #![no_core] #![feature(no_core)] -// @is "$.index[*][?(@.name=='mod1')].kind" \"module\" -// @is "$.index[*][?(@.name=='mod1')].inner.is_stripped" "true" +// @is "$.index[*][?(@.name=='mod1')].inner.module.is_stripped" "true" mod mod1 { - // @is "$.index[*][?(@.name=='mod2')].kind" \"module\" - // @is "$.index[*][?(@.name=='mod2')].inner.is_stripped" "true" + // @is "$.index[*][?(@.name=='mod2')].inner.module.is_stripped" "true" mod mod2 { // @set m2pub_id = "$.index[*][?(@.name=='Mod2Public')].id" pub struct Mod2Public; @@ -16,7 +14,9 @@ mod mod1 { struct Mod2Private; } - // @set mod2_use_id = "$.index[*][?(@.kind=='import' && @.inner.name=='mod2')].id" + // @set mod2_use_id = "$.index[*][?(@.docs=='Mod2 re-export')].id" + // @is "$.index[*][?(@.docs=='Mod2 re-export')].inner.import.name" \"mod2\" + /// Mod2 re-export pub use self::mod2::*; // @set m1pub_id = "$.index[*][?(@.name=='Mod1Public')].id" @@ -25,9 +25,11 @@ mod mod1 { struct Mod1Private; } -// @set mod1_use_id = "$.index[*][?(@.kind=='import' && @.inner.name=='mod1')].id" +// @set mod1_use_id = "$.index[*][?(@.docs=='Mod1 re-export')].id" +// @is "$.index[*][?(@.docs=='Mod1 re-export')].inner.import.name" \"mod1\" +/// Mod1 re-export pub use mod1::*; -// @ismany "$.index[*][?(@.name=='mod2')].inner.items[*]" $m2pub_id -// @ismany "$.index[*][?(@.name=='mod1')].inner.items[*]" $m1pub_id $mod2_use_id -// @ismany "$.index[*][?(@.name=='glob_private')].inner.items[*]" $mod1_use_id +// @ismany "$.index[*][?(@.name=='mod2')].inner.module.items[*]" $m2pub_id +// @ismany "$.index[*][?(@.name=='mod1')].inner.module.items[*]" $m1pub_id $mod2_use_id +// @ismany "$.index[*][?(@.name=='glob_private')].inner.module.items[*]" $mod1_use_id diff --git a/tests/rustdoc-json/reexport/in_root_and_mod.rs b/tests/rustdoc-json/reexport/in_root_and_mod.rs index 7b97ebf2129..f81445bd48d 100644 --- a/tests/rustdoc-json/reexport/in_root_and_mod.rs +++ b/tests/rustdoc-json/reexport/in_root_and_mod.rs @@ -7,10 +7,10 @@ mod foo { pub struct Foo; } -// @has "$.index[*][?(@.kind=='import' && @.inner.source=='foo::Foo')]" +// @has "$.index[*].inner[?(@.import.source=='foo::Foo')]" pub use foo::Foo; pub mod bar { - // @has "$.index[*][?(@.kind=='import' && @.inner.source=='crate::foo::Foo')]" + // @has "$.index[*].inner[?(@.import.source=='crate::foo::Foo')]" pub use crate::foo::Foo; } diff --git a/tests/rustdoc-json/reexport/in_root_and_mod_pub.rs b/tests/rustdoc-json/reexport/in_root_and_mod_pub.rs index f6d932d927b..c5c41b25f7e 100644 --- a/tests/rustdoc-json/reexport/in_root_and_mod_pub.rs +++ b/tests/rustdoc-json/reexport/in_root_and_mod_pub.rs @@ -3,18 +3,20 @@ pub mod foo { // @set bar_id = "$.index[*][?(@.name=='Bar')].id" - // @ismany "$.index[*][?(@.name=='foo')].inner.items[*]" $bar_id + // @ismany "$.index[*][?(@.name=='foo')].inner.module.items[*]" $bar_id pub struct Bar; } -// @set root_import_id = "$.index[*][?(@.inner.source=='foo::Bar')].id" -// @is "$.index[*][?(@.inner.source=='foo::Bar')].inner.id" $bar_id -// @has "$.index[*][?(@.name=='in_root_and_mod_pub')].inner.items[*]" $root_import_id +// @set root_import_id = "$.index[*][?(@.docs=='Outer re-export')].id" +// @is "$.index[*].inner[?(@.import.source=='foo::Bar')].import.id" $bar_id +// @has "$.index[*][?(@.name=='in_root_and_mod_pub')].inner.module.items[*]" $root_import_id +/// Outer re-export pub use foo::Bar; pub mod baz { - // @set baz_import_id = "$.index[*][?(@.inner.source=='crate::foo::Bar')].id" - // @is "$.index[*][?(@.inner.source=='crate::foo::Bar')].inner.id" $bar_id - // @ismany "$.index[*][?(@.name=='baz')].inner.items[*]" $baz_import_id + // @set baz_import_id = "$.index[*][?(@.docs=='Inner re-export')].id" + // @is "$.index[*].inner[?(@.import.source=='crate::foo::Bar')].import.id" $bar_id + // @ismany "$.index[*][?(@.name=='baz')].inner.module.items[*]" $baz_import_id + /// Inner re-export pub use crate::foo::Bar; } diff --git a/tests/rustdoc-json/reexport/macro.rs b/tests/rustdoc-json/reexport/macro.rs index b4882100f06..ac0632b98a9 100644 --- a/tests/rustdoc-json/reexport/macro.rs +++ b/tests/rustdoc-json/reexport/macro.rs @@ -9,7 +9,8 @@ macro_rules! repro { () => {}; } -// @set repro2_id = "$.index[*][?(@.inner.name=='repro2')].id" +// @set repro2_id = "$.index[*][?(@.docs=='Re-export')].id" +/// Re-export pub use crate::repro as repro2; -// @ismany "$.index[*][?(@.name=='macro')].inner.items[*]" $repro_id $repro2_id +// @ismany "$.index[*][?(@.name=='macro')].inner.module.items[*]" $repro_id $repro2_id diff --git a/tests/rustdoc-json/reexport/mod_not_included.rs b/tests/rustdoc-json/reexport/mod_not_included.rs index 7b7600ef20f..1c49f213d1a 100644 --- a/tests/rustdoc-json/reexport/mod_not_included.rs +++ b/tests/rustdoc-json/reexport/mod_not_included.rs @@ -9,6 +9,6 @@ mod m1 { pub use m1::x; -// @has "$.index[*][?(@.name=='x' && @.kind=='function')]" -// @has "$.index[*][?(@.kind=='import' && @.inner.name=='x')].inner.source" '"m1::x"' +// @has "$.index[*][?(@.name=='x' && @.inner.function)]" +// @has "$.index[*].inner[?(@.import.name=='x')].import.source" '"m1::x"' // @!has "$.index[*][?(@.name=='m1')]" diff --git a/tests/rustdoc-json/reexport/private_twice_one_inline.rs b/tests/rustdoc-json/reexport/private_twice_one_inline.rs index 687a3b2ac8b..8c8152bd16c 100644 --- a/tests/rustdoc-json/reexport/private_twice_one_inline.rs +++ b/tests/rustdoc-json/reexport/private_twice_one_inline.rs @@ -11,18 +11,18 @@ extern crate pub_struct as foo; #[doc(inline)] // @set crate_use_id = "$.index[*][?(@.docs=='Hack A')].id" -// @set foo_id = "$.index[*][?(@.docs=='Hack A')].inner.id" +// @set foo_id = "$.index[*][?(@.docs=='Hack A')].inner.import.id" /// Hack A pub use foo::Foo; // @set bar_id = "$.index[*][?(@.name=='bar')].id" pub mod bar { - // @is "$.index[*][?(@.docs=='Hack B')].inner.id" $foo_id + // @is "$.index[*][?(@.docs=='Hack B')].inner.import.id" $foo_id // @set bar_use_id = "$.index[*][?(@.docs=='Hack B')].id" - // @ismany "$.index[*][?(@.name=='bar')].inner.items[*]" $bar_use_id + // @ismany "$.index[*][?(@.name=='bar')].inner.module.items[*]" $bar_use_id /// Hack B pub use foo::Foo; } -// @ismany "$.index[*][?(@.kind=='import')].id" $crate_use_id $bar_use_id -// @ismany "$.index[*][?(@.name=='private_twice_one_inline')].inner.items[*]" $bar_id $crate_use_id +// @ismany "$.index[*][?(@.inner.import)].id" $crate_use_id $bar_use_id +// @ismany "$.index[*][?(@.name=='private_twice_one_inline')].inner.module.items[*]" $bar_id $crate_use_id diff --git a/tests/rustdoc-json/reexport/private_two_names.rs b/tests/rustdoc-json/reexport/private_two_names.rs index 9858538a9d0..cdcbf2a2bc8 100644 --- a/tests/rustdoc-json/reexport/private_two_names.rs +++ b/tests/rustdoc-json/reexport/private_two_names.rs @@ -8,15 +8,19 @@ // @!has "$.index[*][?(@.name=='style')]" mod style { - // @set color_struct_id = "$.index[*][?(@.kind=='struct' && @.name=='Color')].id" + // @set color_struct_id = "$.index[*][?(@.inner.struct && @.name=='Color')].id" pub struct Color; } -// @is "$.index[*][?(@.kind=='import' && @.inner.name=='Color')].inner.id" $color_struct_id -// @set color_export_id = "$.index[*][?(@.kind=='import' && @.inner.name=='Color')].id" +// @is "$.index[*][?(@.docs=='First re-export')].inner.import.id" $color_struct_id +// @is "$.index[*][?(@.docs=='First re-export')].inner.import.name" \"Color\" +// @set color_export_id = "$.index[*][?(@.docs=='First re-export')].id" +/// First re-export pub use style::Color; -// @is "$.index[*][?(@.kind=='import' && @.inner.name=='Colour')].inner.id" $color_struct_id -// @set colour_export_id = "$.index[*][?(@.kind=='import' && @.inner.name=='Colour')].id" +// @is "$.index[*][?(@.docs=='Second re-export')].inner.import.id" $color_struct_id +// @is "$.index[*][?(@.docs=='Second re-export')].inner.import.name" \"Colour\" +// @set colour_export_id = "$.index[*][?(@.docs=='Second re-export')].id" +/// Second re-export pub use style::Color as Colour; -// @ismany "$.index[*][?(@.name=='private_two_names')].inner.items[*]" $color_export_id $colour_export_id +// @ismany "$.index[*][?(@.name=='private_two_names')].inner.module.items[*]" $color_export_id $colour_export_id diff --git a/tests/rustdoc-json/reexport/reexport_method_from_private_module.rs b/tests/rustdoc-json/reexport/reexport_method_from_private_module.rs index 239b1a23b43..61075088af9 100644 --- a/tests/rustdoc-json/reexport/reexport_method_from_private_module.rs +++ b/tests/rustdoc-json/reexport/reexport_method_from_private_module.rs @@ -1,9 +1,9 @@ // Regression test for <https://github.com/rust-lang/rust/issues/102583>. // @set impl_S = "$.index[*][?(@.docs=='impl S')].id" -// @has "$.index[*][?(@.name=='S')].inner.impls[*]" $impl_S +// @has "$.index[*][?(@.name=='S')].inner.struct.impls[*]" $impl_S // @set is_present = "$.index[*][?(@.name=='is_present')].id" -// @is "$.index[*][?(@.docs=='impl S')].inner.items[*]" $is_present +// @is "$.index[*][?(@.docs=='impl S')].inner.impl.items[*]" $is_present // @!has "$.index[*][?(@.name=='hidden_impl')]" // @!has "$.index[*][?(@.name=='hidden_fn')]" diff --git a/tests/rustdoc-json/reexport/rename_private.rs b/tests/rustdoc-json/reexport/rename_private.rs index 8fd850f9b13..9114460231d 100644 --- a/tests/rustdoc-json/reexport/rename_private.rs +++ b/tests/rustdoc-json/reexport/rename_private.rs @@ -3,11 +3,11 @@ #![no_core] #![feature(no_core)] -// @!has "$.index[*][?(@.kind=='inner')]" +// @!has "$.index[*][?(@.name=='inner')]" mod inner { // @has "$.index[*][?(@.name=='Public')]" pub struct Public; } -// @is "$.index[*][?(@.kind=='import')].inner.name" \"NewName\" +// @is "$.index[*][?(@.inner.import)].inner.import.name" \"NewName\" pub use inner::Public as NewName; diff --git a/tests/rustdoc-json/reexport/rename_public.rs b/tests/rustdoc-json/reexport/rename_public.rs index e30907fe256..d0fd314bd8c 100644 --- a/tests/rustdoc-json/reexport/rename_public.rs +++ b/tests/rustdoc-json/reexport/rename_public.rs @@ -6,12 +6,13 @@ // @set inner_id = "$.index[*][?(@.name=='inner')].id" pub mod inner { // @set public_id = "$.index[*][?(@.name=='Public')].id" - // @ismany "$.index[*][?(@.name=='inner')].inner.items[*]" $public_id + // @ismany "$.index[*][?(@.name=='inner')].inner.module.items[*]" $public_id pub struct Public; } -// @set import_id = "$.index[*][?(@.inner.name=='NewName')].id" -// @!has "$.index[*][?(@.inner.name=='Public')]" -// @is "$.index[*][?(@.inner.name=='NewName')].inner.source" \"inner::Public\" +// @set import_id = "$.index[*][?(@.docs=='Re-export')].id" +// @!has "$.index[*].inner[?(@.import.name=='Public')]" +// @is "$.index[*].inner[?(@.import.name=='NewName')].import.source" \"inner::Public\" +/// Re-export pub use inner::Public as NewName; -// @ismany "$.index[*][?(@.name=='rename_public')].inner.items[*]" $inner_id $import_id +// @ismany "$.index[*][?(@.name=='rename_public')].inner.module.items[*]" $inner_id $import_id diff --git a/tests/rustdoc-json/reexport/same_name_different_types.rs b/tests/rustdoc-json/reexport/same_name_different_types.rs index 2314a4eb909..6a765b73301 100644 --- a/tests/rustdoc-json/reexport/same_name_different_types.rs +++ b/tests/rustdoc-json/reexport/same_name_different_types.rs @@ -16,10 +16,10 @@ pub mod nested { pub fn Foo() {} } -// @ismany "$.index[*][?(@.inner.name == 'Foo' && @.kind == 'import')].inner.id" $foo_fn $foo_struct -// @ismany "$.index[*][?(@.inner.name == 'Bar' && @.kind == 'import')].inner.id" $foo_fn $foo_struct +// @ismany "$.index[*].inner[?(@.import.name == 'Foo')].import.id" $foo_fn $foo_struct +// @ismany "$.index[*].inner[?(@.import.name == 'Bar')].import.id" $foo_fn $foo_struct -// @count "$.index[*][?(@.inner.name == 'Foo' && @.kind == 'import')]" 2 +// @count "$.index[*].inner[?(@.import.name == 'Foo')]" 2 pub use nested::Foo; -// @count "$.index[*][?(@.inner.name == 'Bar' && @.kind == 'import')]" 2 +// @count "$.index[*].inner[?(@.import.name == 'Bar')]" 2 pub use Foo as Bar; diff --git a/tests/rustdoc-json/reexport/same_type_reexported_more_than_once.rs b/tests/rustdoc-json/reexport/same_type_reexported_more_than_once.rs index 880dbdc4416..a00547dc348 100644 --- a/tests/rustdoc-json/reexport/same_type_reexported_more_than_once.rs +++ b/tests/rustdoc-json/reexport/same_type_reexported_more_than_once.rs @@ -11,11 +11,13 @@ mod inner { pub trait Trait {} } -// @set export_id = "$.index[*][?(@.inner.name=='Trait')].id" -// @is "$.index[*][?(@.inner.name=='Trait')].inner.id" $trait_id +// @set export_id = "$.index[*][?(@.docs=='First re-export')].id" +// @is "$.index[*].inner[?(@.import.name=='Trait')].import.id" $trait_id +/// First re-export pub use inner::Trait; -// @set reexport_id = "$.index[*][?(@.inner.name=='Reexport')].id" -// @is "$.index[*][?(@.inner.name=='Reexport')].inner.id" $trait_id +// @set reexport_id = "$.index[*][?(@.docs=='Second re-export')].id" +// @is "$.index[*].inner[?(@.import.name=='Reexport')].import.id" $trait_id +/// Second re-export pub use inner::Trait as Reexport; -// @ismany "$.index[*][?(@.name=='same_type_reexported_more_than_once')].inner.items[*]" $reexport_id $export_id +// @ismany "$.index[*][?(@.name=='same_type_reexported_more_than_once')].inner.module.items[*]" $reexport_id $export_id diff --git a/tests/rustdoc-json/reexport/simple_private.rs b/tests/rustdoc-json/reexport/simple_private.rs index d058ce0598d..462efee51bf 100644 --- a/tests/rustdoc-json/reexport/simple_private.rs +++ b/tests/rustdoc-json/reexport/simple_private.rs @@ -8,9 +8,9 @@ mod inner { pub struct Public; } -// @is "$.index[*][?(@.kind=='import')].inner.name" \"Public\" -// @is "$.index[*][?(@.kind=='import')].inner.id" $pub_id -// @set use_id = "$.index[*][?(@.kind=='import')].id" +// @is "$.index[*][?(@.inner.import)].inner.import.name" \"Public\" +// @is "$.index[*][?(@.inner.import)].inner.import.id" $pub_id +// @set use_id = "$.index[*][?(@.inner.import)].id" pub use inner::Public; -// @ismany "$.index[*][?(@.name=='simple_private')].inner.items[*]" $use_id +// @ismany "$.index[*][?(@.name=='simple_private')].inner.module.items[*]" $use_id diff --git a/tests/rustdoc-json/reexport/simple_public.rs b/tests/rustdoc-json/reexport/simple_public.rs index e64a0dcb769..1373f96f87f 100644 --- a/tests/rustdoc-json/reexport/simple_public.rs +++ b/tests/rustdoc-json/reexport/simple_public.rs @@ -7,12 +7,13 @@ pub mod inner { // @set public_id = "$.index[*][?(@.name=='Public')].id" - // @ismany "$.index[*][?(@.name=='inner')].inner.items[*]" $public_id + // @ismany "$.index[*][?(@.name=='inner')].inner.module.items[*]" $public_id pub struct Public; } -// @set import_id = "$.index[*][?(@.inner.name=='Public')].id" -// @is "$.index[*][?(@.inner.name=='Public')].inner.source" \"inner::Public\" +// @set import_id = "$.index[*][?(@.docs=='Outer')].id" +// @is "$.index[*][?(@.docs=='Outer')].inner.import.source" \"inner::Public\" +/// Outer pub use inner::Public; -// @ismany "$.index[*][?(@.name=='simple_public')].inner.items[*]" $import_id $inner_id +// @ismany "$.index[*][?(@.name=='simple_public')].inner.module.items[*]" $import_id $inner_id diff --git a/tests/rustdoc-json/return_private.rs b/tests/rustdoc-json/return_private.rs index a8d1fae30df..0ce81b5e59f 100644 --- a/tests/rustdoc-json/return_private.rs +++ b/tests/rustdoc-json/return_private.rs @@ -8,8 +8,8 @@ mod secret { pub struct Secret; } -// @is "$.index[*][?(@.name=='get_secret')].kind" \"function\" -// @is "$.index[*][?(@.name=='get_secret')].inner.decl.output.inner.name" \"secret::Secret\" +// @has "$.index[*][?(@.name=='get_secret')].inner.function" +// @is "$.index[*][?(@.name=='get_secret')].inner.function.decl.output.resolved_path.name" \"secret::Secret\" pub fn get_secret() -> secret::Secret { secret::Secret } diff --git a/tests/rustdoc-json/structs/plain_all_pub.rs b/tests/rustdoc-json/structs/plain_all_pub.rs index b86ab93c264..777260100d6 100644 --- a/tests/rustdoc-json/structs/plain_all_pub.rs +++ b/tests/rustdoc-json/structs/plain_all_pub.rs @@ -5,7 +5,7 @@ pub struct Demo { // @set x = "$.index[*][?(@.name=='x')].id" // @set y = "$.index[*][?(@.name=='y')].id" -// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[0]" $x -// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[1]" $y -// @count "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[*]" 2 -// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields_stripped" false +// @is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[0]" $x +// @is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[1]" $y +// @count "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[*]" 2 +// @is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields_stripped" false diff --git a/tests/rustdoc-json/structs/plain_doc_hidden.rs b/tests/rustdoc-json/structs/plain_doc_hidden.rs index 7800b55a481..1ff4489ef6b 100644 --- a/tests/rustdoc-json/structs/plain_doc_hidden.rs +++ b/tests/rustdoc-json/structs/plain_doc_hidden.rs @@ -6,6 +6,6 @@ pub struct Demo { // @set x = "$.index[*][?(@.name=='x')].id" // @!has "$.index[*][?(@.name=='y')].id" -// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[0]" $x -// @count "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[*]" 1 -// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields_stripped" true +// @is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[0]" $x +// @count "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[*]" 1 +// @is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields_stripped" true diff --git a/tests/rustdoc-json/structs/plain_empty.rs b/tests/rustdoc-json/structs/plain_empty.rs index 1d01b8bc14a..c037c0251b9 100644 --- a/tests/rustdoc-json/structs/plain_empty.rs +++ b/tests/rustdoc-json/structs/plain_empty.rs @@ -1,5 +1,5 @@ // @is "$.index[*][?(@.name=='PlainEmpty')].visibility" \"public\" -// @is "$.index[*][?(@.name=='PlainEmpty')].kind" \"struct\" -// @is "$.index[*][?(@.name=='PlainEmpty')].inner.kind.plain.fields_stripped" false -// @is "$.index[*][?(@.name=='PlainEmpty')].inner.kind.plain.fields" [] +// @has "$.index[*][?(@.name=='PlainEmpty')].inner.struct" +// @is "$.index[*][?(@.name=='PlainEmpty')].inner.struct.kind.plain.fields_stripped" false +// @is "$.index[*][?(@.name=='PlainEmpty')].inner.struct.kind.plain.fields" [] pub struct PlainEmpty {} diff --git a/tests/rustdoc-json/structs/plain_pub_priv.rs b/tests/rustdoc-json/structs/plain_pub_priv.rs index 9b771224d97..ff061be62d1 100644 --- a/tests/rustdoc-json/structs/plain_pub_priv.rs +++ b/tests/rustdoc-json/structs/plain_pub_priv.rs @@ -4,6 +4,6 @@ pub struct Demo { } // @set x = "$.index[*][?(@.name=='x')].id" -// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[0]" $x -// @count "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[*]" 1 -// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields_stripped" true +// @is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[0]" $x +// @count "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[*]" 1 +// @is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields_stripped" true diff --git a/tests/rustdoc-json/structs/tuple.rs b/tests/rustdoc-json/structs/tuple.rs index 6bdb753ee01..16ab95ed271 100644 --- a/tests/rustdoc-json/structs/tuple.rs +++ b/tests/rustdoc-json/structs/tuple.rs @@ -1,4 +1,4 @@ // @is "$.index[*][?(@.name=='Tuple')].visibility" \"public\" -// @is "$.index[*][?(@.name=='Tuple')].kind" \"struct\" -// @is "$.index[*][?(@.name=='Tuple')].inner.kind.tuple" '[null, null]' +// @has "$.index[*][?(@.name=='Tuple')].inner.struct" +// @is "$.index[*][?(@.name=='Tuple')].inner.struct.kind.tuple" '[null, null]' pub struct Tuple(u32, String); diff --git a/tests/rustdoc-json/structs/tuple_empty.rs b/tests/rustdoc-json/structs/tuple_empty.rs index 0ad6a89547f..4d4af8558bb 100644 --- a/tests/rustdoc-json/structs/tuple_empty.rs +++ b/tests/rustdoc-json/structs/tuple_empty.rs @@ -1,2 +1,2 @@ -// @is "$.index[*][?(@.name=='TupleUnit')].inner.kind.tuple" [] +// @is "$.index[*][?(@.name=='TupleUnit')].inner.struct.kind.tuple" [] pub struct TupleUnit(); diff --git a/tests/rustdoc-json/structs/tuple_pub_priv.rs b/tests/rustdoc-json/structs/tuple_pub_priv.rs index 9d5a1d1c8be..a669ba1dfcc 100644 --- a/tests/rustdoc-json/structs/tuple_pub_priv.rs +++ b/tests/rustdoc-json/structs/tuple_pub_priv.rs @@ -7,7 +7,7 @@ pub struct Demo( // @set field = "$.index[*][?(@.docs=='field')].id" -// @is "$.index[*][?(@.name=='Demo')].inner.kind.tuple[0]" null -// @is "$.index[*][?(@.name=='Demo')].inner.kind.tuple[1]" $field -// @is "$.index[*][?(@.name=='Demo')].inner.kind.tuple[2]" null -// @count "$.index[*][?(@.name=='Demo')].inner.kind.tuple[*]" 3 +// @is "$.index[*][?(@.name=='Demo')].inner.struct.kind.tuple[0]" null +// @is "$.index[*][?(@.name=='Demo')].inner.struct.kind.tuple[1]" $field +// @is "$.index[*][?(@.name=='Demo')].inner.struct.kind.tuple[2]" null +// @count "$.index[*][?(@.name=='Demo')].inner.struct.kind.tuple[*]" 3 diff --git a/tests/rustdoc-json/structs/unit.rs b/tests/rustdoc-json/structs/unit.rs index 26570971721..640d3fb7865 100644 --- a/tests/rustdoc-json/structs/unit.rs +++ b/tests/rustdoc-json/structs/unit.rs @@ -1,4 +1,4 @@ // @is "$.index[*][?(@.name=='Unit')].visibility" \"public\" -// @is "$.index[*][?(@.name=='Unit')].kind" \"struct\" -// @is "$.index[*][?(@.name=='Unit')].inner.kind" \"unit\" +// @has "$.index[*][?(@.name=='Unit')].inner.struct" +// @is "$.index[*][?(@.name=='Unit')].inner.struct.kind" \"unit\" pub struct Unit; diff --git a/tests/rustdoc-json/structs/with_generics.rs b/tests/rustdoc-json/structs/with_generics.rs index 00474800a0e..d721cbdbe25 100644 --- a/tests/rustdoc-json/structs/with_generics.rs +++ b/tests/rustdoc-json/structs/with_generics.rs @@ -1,13 +1,13 @@ use std::collections::HashMap; // @is "$.index[*][?(@.name=='WithGenerics')].visibility" \"public\" -// @is "$.index[*][?(@.name=='WithGenerics')].kind" \"struct\" -// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].name" \"T\" -// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].kind.type.bounds" [] -// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].name" \"U\" -// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].kind.type.bounds" [] -// @is "$.index[*][?(@.name=='WithGenerics')].inner.kind.plain.fields_stripped" true -// @is "$.index[*][?(@.name=='WithGenerics')].inner.kind.plain.fields" [] +// @has "$.index[*][?(@.name=='WithGenerics')].inner.struct" +// @is "$.index[*][?(@.name=='WithGenerics')].inner.struct.generics.params[0].name" \"T\" +// @is "$.index[*][?(@.name=='WithGenerics')].inner.struct.generics.params[0].kind.type.bounds" [] +// @is "$.index[*][?(@.name=='WithGenerics')].inner.struct.generics.params[1].name" \"U\" +// @is "$.index[*][?(@.name=='WithGenerics')].inner.struct.generics.params[1].kind.type.bounds" [] +// @is "$.index[*][?(@.name=='WithGenerics')].inner.struct.kind.plain.fields_stripped" true +// @is "$.index[*][?(@.name=='WithGenerics')].inner.struct.kind.plain.fields" [] pub struct WithGenerics<T, U> { stuff: Vec<T>, things: HashMap<U, U>, diff --git a/tests/rustdoc-json/structs/with_primitives.rs b/tests/rustdoc-json/structs/with_primitives.rs index 9c5a37f3957..e0285a9e688 100644 --- a/tests/rustdoc-json/structs/with_primitives.rs +++ b/tests/rustdoc-json/structs/with_primitives.rs @@ -1,9 +1,11 @@ +// ignore-tidy-linelength + // @is "$.index[*][?(@.name=='WithPrimitives')].visibility" \"public\" -// @is "$.index[*][?(@.name=='WithPrimitives')].kind" \"struct\" -// @is "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].name" \"\'a\" -// @is "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].kind.lifetime.outlives" [] -// @is "$.index[*][?(@.name=='WithPrimitives')].inner.kind.plain.fields_stripped" true -// @is "$.index[*][?(@.name=='WithPrimitives')].inner.kind.plain.fields" [] +// @has "$.index[*][?(@.name=='WithPrimitives')].inner.struct" +// @is "$.index[*][?(@.name=='WithPrimitives')].inner.struct.generics.params[0].name" \"\'a\" +// @is "$.index[*][?(@.name=='WithPrimitives')].inner.struct.generics.params[0].kind.lifetime.outlives" [] +// @is "$.index[*][?(@.name=='WithPrimitives')].inner.struct.kind.plain.fields_stripped" true +// @is "$.index[*][?(@.name=='WithPrimitives')].inner.struct.kind.plain.fields" [] pub struct WithPrimitives<'a> { num: u32, s: &'a str, diff --git a/tests/rustdoc-json/traits/has_body.rs b/tests/rustdoc-json/traits/has_body.rs index a57cb97d4a6..219e2d9bc54 100644 --- a/tests/rustdoc-json/traits/has_body.rs +++ b/tests/rustdoc-json/traits/has_body.rs @@ -1,21 +1,21 @@ // @has "$.index[*][?(@.name=='Foo')]" pub trait Foo { - // @is "$.index[*][?(@.name=='no_self')].inner.has_body" false + // @is "$.index[*][?(@.name=='no_self')].inner.function.has_body" false fn no_self(); - // @is "$.index[*][?(@.name=='move_self')].inner.has_body" false + // @is "$.index[*][?(@.name=='move_self')].inner.function.has_body" false fn move_self(self); - // @is "$.index[*][?(@.name=='ref_self')].inner.has_body" false + // @is "$.index[*][?(@.name=='ref_self')].inner.function.has_body" false fn ref_self(&self); - // @is "$.index[*][?(@.name=='no_self_def')].inner.has_body" true + // @is "$.index[*][?(@.name=='no_self_def')].inner.function.has_body" true fn no_self_def() {} - // @is "$.index[*][?(@.name=='move_self_def')].inner.has_body" true + // @is "$.index[*][?(@.name=='move_self_def')].inner.function.has_body" true fn move_self_def(self) {} - // @is "$.index[*][?(@.name=='ref_self_def')].inner.has_body" true + // @is "$.index[*][?(@.name=='ref_self_def')].inner.function.has_body" true fn ref_self_def(&self) {} } pub trait Bar: Clone { - // @is "$.index[*][?(@.name=='method')].inner.has_body" false + // @is "$.index[*][?(@.name=='method')].inner.function.has_body" false fn method(&self, param: usize); } diff --git a/tests/rustdoc-json/traits/implementors.rs b/tests/rustdoc-json/traits/implementors.rs index db3fe5df739..7d351ad61be 100644 --- a/tests/rustdoc-json/traits/implementors.rs +++ b/tests/rustdoc-json/traits/implementors.rs @@ -2,18 +2,18 @@ #![no_core] // @set wham = "$.index[*][?(@.name=='Wham')].id" -// @count "$.index[*][?(@.name=='Wham')].inner.implementations[*]" 1 -// @set gmWham = "$.index[*][?(@.name=='Wham')].inner.implementations[0]" +// @count "$.index[*][?(@.name=='Wham')].inner.trait.implementations[*]" 1 +// @set gmWham = "$.index[*][?(@.name=='Wham')].inner.trait.implementations[0]" pub trait Wham {} -// @count "$.index[*][?(@.name=='GeorgeMichael')].inner.impls[*]" 1 -// @is "$.index[*][?(@.name=='GeorgeMichael')].inner.impls[0]" $gmWham +// @count "$.index[*][?(@.name=='GeorgeMichael')].inner.struct.impls[*]" 1 +// @is "$.index[*][?(@.name=='GeorgeMichael')].inner.struct.impls[0]" $gmWham // @set gm = "$.index[*][?(@.name=='Wham')].id" // jsonpath_lib isnt expressive enough (for now) to get the "impl" item, so we // just check it isn't pointing to the type, but when you port to jsondocck-ng // check what the impl item is -// @!is "$.index[*][?(@.name=='Wham')].inner.implementations[0]" $gm +// @!is "$.index[*][?(@.name=='Wham')].inner.trait.implementations[0]" $gm pub struct GeorgeMichael {} impl Wham for GeorgeMichael {} diff --git a/tests/rustdoc-json/traits/supertrait.rs b/tests/rustdoc-json/traits/supertrait.rs index 4048fdd74b4..2123ac40427 100644 --- a/tests/rustdoc-json/traits/supertrait.rs +++ b/tests/rustdoc-json/traits/supertrait.rs @@ -8,19 +8,19 @@ pub trait Loud {} // @set very_loud_id = "$.index[*][?(@.name=='VeryLoud')].id" -// @count "$.index[*][?(@.name=='VeryLoud')].inner.bounds[*]" 1 -// @is "$.index[*][?(@.name=='VeryLoud')].inner.bounds[0].trait_bound.trait.id" $loud_id +// @count "$.index[*][?(@.name=='VeryLoud')].inner.trait.bounds[*]" 1 +// @is "$.index[*][?(@.name=='VeryLoud')].inner.trait.bounds[0].trait_bound.trait.id" $loud_id pub trait VeryLoud: Loud {} // @set sounds_good_id = "$.index[*][?(@.name=='SoundsGood')].id" pub trait SoundsGood {} -// @count "$.index[*][?(@.name=='MetalBand')].inner.bounds[*]" 2 -// @is "$.index[*][?(@.name=='MetalBand')].inner.bounds[0].trait_bound.trait.id" $very_loud_id -// @is "$.index[*][?(@.name=='MetalBand')].inner.bounds[1].trait_bound.trait.id" $sounds_good_id +// @count "$.index[*][?(@.name=='MetalBand')].inner.trait.bounds[*]" 2 +// @is "$.index[*][?(@.name=='MetalBand')].inner.trait.bounds[0].trait_bound.trait.id" $very_loud_id +// @is "$.index[*][?(@.name=='MetalBand')].inner.trait.bounds[1].trait_bound.trait.id" $sounds_good_id pub trait MetalBand: VeryLoud + SoundsGood {} -// @count "$.index[*][?(@.name=='DnabLatem')].inner.bounds[*]" 2 -// @is "$.index[*][?(@.name=='DnabLatem')].inner.bounds[1].trait_bound.trait.id" $very_loud_id -// @is "$.index[*][?(@.name=='DnabLatem')].inner.bounds[0].trait_bound.trait.id" $sounds_good_id +// @count "$.index[*][?(@.name=='DnabLatem')].inner.trait.bounds[*]" 2 +// @is "$.index[*][?(@.name=='DnabLatem')].inner.trait.bounds[1].trait_bound.trait.id" $very_loud_id +// @is "$.index[*][?(@.name=='DnabLatem')].inner.trait.bounds[0].trait_bound.trait.id" $sounds_good_id pub trait DnabLatem: SoundsGood + VeryLoud {} diff --git a/tests/rustdoc-json/traits/trait_alias.rs b/tests/rustdoc-json/traits/trait_alias.rs index 35db9296cdd..4fcc26f7de2 100644 --- a/tests/rustdoc-json/traits/trait_alias.rs +++ b/tests/rustdoc-json/traits/trait_alias.rs @@ -4,24 +4,24 @@ #![feature(trait_alias)] // @set Orig = "$.index[*][?(@.name == 'Orig')].id" -// @is "$.index[*][?(@.name == 'Orig')].kind" '"trait"' +// @has "$.index[*][?(@.name == 'Orig')].inner.trait" pub trait Orig<T> {} // @set Alias = "$.index[*][?(@.name == 'Alias')].id" -// @is "$.index[*][?(@.name == 'Alias')].kind" '"trait_alias"' -// @is "$.index[*][?(@.name == 'Alias')].inner.generics" '{"params": [], "where_predicates": []}' -// @count "$.index[*][?(@.name == 'Alias')].inner.params[*]" 1 -// @is "$.index[*][?(@.name == 'Alias')].inner.params[0].trait_bound.trait.id" $Orig -// @is "$.index[*][?(@.name == 'Alias')].inner.params[0].trait_bound.trait.args.angle_bracketed.args[0].type.inner" '"i32"' +// @has "$.index[*][?(@.name == 'Alias')].inner.trait_alias" +// @is "$.index[*][?(@.name == 'Alias')].inner.trait_alias.generics" '{"params": [], "where_predicates": []}' +// @count "$.index[*][?(@.name == 'Alias')].inner.trait_alias.params[*]" 1 +// @is "$.index[*][?(@.name == 'Alias')].inner.trait_alias.params[0].trait_bound.trait.id" $Orig +// @is "$.index[*][?(@.name == 'Alias')].inner.trait_alias.params[0].trait_bound.trait.args.angle_bracketed.args[0].type.primitive" '"i32"' pub trait Alias = Orig<i32>; pub struct Struct; impl Orig<i32> for Struct {} -// @is "$.index[*][?(@.name=='takes_alias')].inner.decl.inputs[0][1].kind" '"impl_trait"' -// @is "$.index[*][?(@.name=='takes_alias')].inner.decl.inputs[0][1].inner[0].trait_bound.trait.id" $Alias -// @is "$.index[*][?(@.name=='takes_alias')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $Alias +// @has "$.index[*][?(@.name=='takes_alias')].inner.function.decl.inputs[0][1].impl_trait" +// @is "$.index[*][?(@.name=='takes_alias')].inner.function.decl.inputs[0][1].impl_trait[0].trait_bound.trait.id" $Alias +// @is "$.index[*][?(@.name=='takes_alias')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $Alias pub fn takes_alias(_: impl Alias) {} // FIXME: Should the trait be mentioned in both the decl and generics? diff --git a/tests/rustdoc-json/type/dyn.rs b/tests/rustdoc-json/type/dyn.rs index eaf249252e3..e5ee60fad59 100644 --- a/tests/rustdoc-json/type/dyn.rs +++ b/tests/rustdoc-json/type/dyn.rs @@ -1,46 +1,46 @@ // ignore-tidy-linelength use std::fmt::Debug; -// @count "$.index[*][?(@.name=='dyn')].inner.items[*]" 3 +// @count "$.index[*][?(@.name=='dyn')].inner.module.items[*]" 3 // @set sync_int_gen = "$.index[*][?(@.name=='SyncIntGen')].id" // @set ref_fn = "$.index[*][?(@.name=='RefFn')].id" // @set weird_order = "$.index[*][?(@.name=='WeirdOrder')].id" -// @ismany "$.index[*][?(@.name=='dyn')].inner.items[*]" $sync_int_gen $ref_fn $weird_order +// @ismany "$.index[*][?(@.name=='dyn')].inner.module.items[*]" $sync_int_gen $ref_fn $weird_order -// @is "$.index[*][?(@.name=='SyncIntGen')].kind" \"typedef\" -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.generics" '{"params": [], "where_predicates": []}' -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type.kind" \"resolved_path\" -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.name" \"Box\" -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.bindings" [] -// @count "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args" 1 -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"dyn_trait\" -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.lifetime" \"\'static\" -// @count "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[*]" 3 -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].generic_params" [] -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].generic_params" [] -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[2].generic_params" [] -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.name" '"Fn"' -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].trait.name" '"Send"' -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[2].trait.name" '"Sync"' -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}' +// @has "$.index[*][?(@.name=='SyncIntGen')].inner.typedef" +// @is "$.index[*][?(@.name=='SyncIntGen')].inner.typedef.generics" '{"params": [], "where_predicates": []}' +// @has "$.index[*][?(@.name=='SyncIntGen')].inner.typedef.type.resolved_path" +// @is "$.index[*][?(@.name=='SyncIntGen')].inner.typedef.type.resolved_path.name" \"Box\" +// @is "$.index[*][?(@.name=='SyncIntGen')].inner.typedef.type.resolved_path.args.angle_bracketed.bindings" [] +// @count "$.index[*][?(@.name=='SyncIntGen')].inner.typedef.type.resolved_path.args.angle_bracketed.args" 1 +// @has "$.index[*][?(@.name=='SyncIntGen')].inner.typedef.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait" +// @is "$.index[*][?(@.name=='SyncIntGen')].inner.typedef.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.lifetime" \"\'static\" +// @count "$.index[*][?(@.name=='SyncIntGen')].inner.typedef.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[*]" 3 +// @is "$.index[*][?(@.name=='SyncIntGen')].inner.typedef.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].generic_params" [] +// @is "$.index[*][?(@.name=='SyncIntGen')].inner.typedef.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].generic_params" [] +// @is "$.index[*][?(@.name=='SyncIntGen')].inner.typedef.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[2].generic_params" [] +// @is "$.index[*][?(@.name=='SyncIntGen')].inner.typedef.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.name" '"Fn"' +// @is "$.index[*][?(@.name=='SyncIntGen')].inner.typedef.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].trait.name" '"Send"' +// @is "$.index[*][?(@.name=='SyncIntGen')].inner.typedef.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[2].trait.name" '"Sync"' +// @is "$.index[*][?(@.name=='SyncIntGen')].inner.typedef.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.args" '{"parenthesized": {"inputs": [],"output": {"primitive": "i32"}}}' pub type SyncIntGen = Box<dyn Fn() -> i32 + Send + Sync + 'static>; -// @is "$.index[*][?(@.name=='RefFn')].kind" \"typedef\" -// @is "$.index[*][?(@.name=='RefFn')].inner.generics" '{"params": [{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"}],"where_predicates": []}' -// @is "$.index[*][?(@.name=='RefFn')].inner.type.kind" '"borrowed_ref"' -// @is "$.index[*][?(@.name=='RefFn')].inner.type.inner.mutable" 'false' -// @is "$.index[*][?(@.name=='RefFn')].inner.type.inner.lifetime" "\"'a\"" -// @is "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.kind" '"dyn_trait"' -// @is "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.lifetime" null -// @count "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[*]" 1 -// @is "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' -// @is "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.name" '"Fn"' -// @is "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.args.parenthesized.inputs[0].kind" '"borrowed_ref"' -// @is "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.args.parenthesized.inputs[0].inner.lifetime" "\"'b\"" -// @is "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.args.parenthesized.output.kind" '"borrowed_ref"' -// @is "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.args.parenthesized.output.inner.lifetime" "\"'b\"" +// @has "$.index[*][?(@.name=='RefFn')].inner.typedef" +// @is "$.index[*][?(@.name=='RefFn')].inner.typedef.generics" '{"params": [{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"}],"where_predicates": []}' +// @has "$.index[*][?(@.name=='RefFn')].inner.typedef.type.borrowed_ref" +// @is "$.index[*][?(@.name=='RefFn')].inner.typedef.type.borrowed_ref.mutable" 'false' +// @is "$.index[*][?(@.name=='RefFn')].inner.typedef.type.borrowed_ref.lifetime" "\"'a\"" +// @has "$.index[*][?(@.name=='RefFn')].inner.typedef.type.borrowed_ref.type.dyn_trait" +// @is "$.index[*][?(@.name=='RefFn')].inner.typedef.type.borrowed_ref.type.dyn_trait.lifetime" null +// @count "$.index[*][?(@.name=='RefFn')].inner.typedef.type.borrowed_ref.type.dyn_trait.traits[*]" 1 +// @is "$.index[*][?(@.name=='RefFn')].inner.typedef.type.borrowed_ref.type.dyn_trait.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' +// @is "$.index[*][?(@.name=='RefFn')].inner.typedef.type.borrowed_ref.type.dyn_trait.traits[0].trait.name" '"Fn"' +// @has "$.index[*][?(@.name=='RefFn')].inner.typedef.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.inputs[0].borrowed_ref" +// @is "$.index[*][?(@.name=='RefFn')].inner.typedef.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.inputs[0].borrowed_ref.lifetime" "\"'b\"" +// @has "$.index[*][?(@.name=='RefFn')].inner.typedef.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.output.borrowed_ref" +// @is "$.index[*][?(@.name=='RefFn')].inner.typedef.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.output.borrowed_ref.lifetime" "\"'b\"" pub type RefFn<'a> = &'a dyn for<'b> Fn(&'b i32) -> &'b i32; -// @is "$.index[*][?(@.name=='WeirdOrder')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.name" '"Send"' -// @is "$.index[*][?(@.name=='WeirdOrder')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].trait.name" '"Debug"' +// @is "$.index[*][?(@.name=='WeirdOrder')].inner.typedef.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.name" '"Send"' +// @is "$.index[*][?(@.name=='WeirdOrder')].inner.typedef.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].trait.name" '"Debug"' pub type WeirdOrder = Box<dyn Send + Debug>; diff --git a/tests/rustdoc-json/type/extern.rs b/tests/rustdoc-json/type/extern.rs index d287d5ebec5..c30146ce9e0 100644 --- a/tests/rustdoc-json/type/extern.rs +++ b/tests/rustdoc-json/type/extern.rs @@ -6,5 +6,4 @@ extern { } // @is "$.index[*][?(@.docs=='No inner information')].name" '"Foo"' -// @is "$.index[*][?(@.docs=='No inner information')].kind" '"foreign_type"' -// @!has "$.index[*][?(@.docs=='No inner information')].inner" +// @is "$.index[*][?(@.docs=='No inner information')].inner" \"foreign_type\" diff --git a/tests/rustdoc-json/type/fn_lifetime.rs b/tests/rustdoc-json/type/fn_lifetime.rs index d7216ec7675..424c5dce273 100644 --- a/tests/rustdoc-json/type/fn_lifetime.rs +++ b/tests/rustdoc-json/type/fn_lifetime.rs @@ -1,27 +1,26 @@ // ignore-tidy-linelength -// @is "$.index[*][?(@.name=='GenericFn')].kind" \"typedef\" +// @has "$.index[*][?(@.name=='GenericFn')].inner.typedef" -// @ismany "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].name" \"\'a\" -// @has "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].kind.lifetime" -// @count "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].kind.lifetime.outlives[*]" 0 -// @count "$.index[*][?(@.name=='GenericFn')].inner.generics.where_predicates[*]" 0 -// @is "$.index[*][?(@.name=='GenericFn')].inner.type.kind" \"function_pointer\" -// @count "$.index[*][?(@.name=='GenericFn')].inner.type.inner.generic_params[*]" 0 -// @count "$.index[*][?(@.name=='GenericFn')].inner.type.inner.decl.inputs[*]" 1 -// @is "$.index[*][?(@.name=='GenericFn')].inner.type.inner.decl.inputs[*][1].inner.lifetime" \"\'a\" -// @is "$.index[*][?(@.name=='GenericFn')].inner.type.inner.decl.output.inner.lifetime" \"\'a\" +// @ismany "$.index[*][?(@.name=='GenericFn')].inner.typedef.generics.params[*].name" \"\'a\" +// @has "$.index[*][?(@.name=='GenericFn')].inner.typedef.generics.params[*].kind.lifetime" +// @count "$.index[*][?(@.name=='GenericFn')].inner.typedef.generics.params[*].kind.lifetime.outlives[*]" 0 +// @count "$.index[*][?(@.name=='GenericFn')].inner.typedef.generics.where_predicates[*]" 0 +// @count "$.index[*][?(@.name=='GenericFn')].inner.typedef.type.function_pointer.generic_params[*]" 0 +// @count "$.index[*][?(@.name=='GenericFn')].inner.typedef.type.function_pointer.decl.inputs[*]" 1 +// @is "$.index[*][?(@.name=='GenericFn')].inner.typedef.type.function_pointer.decl.inputs[*][1].borrowed_ref.lifetime" \"\'a\" +// @is "$.index[*][?(@.name=='GenericFn')].inner.typedef.type.function_pointer.decl.output.borrowed_ref.lifetime" \"\'a\" pub type GenericFn<'a> = fn(&'a i32) -> &'a i32; -// @is "$.index[*][?(@.name=='ForAll')].kind" \"typedef\" -// @count "$.index[*][?(@.name=='ForAll')].inner.generics.params[*]" 0 -// @count "$.index[*][?(@.name=='ForAll')].inner.generics.where_predicates[*]" 0 -// @count "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*]" 1 -// @is "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*].name" \"\'a\" -// @has "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*].kind.lifetime" -// @count "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*].kind.lifetime.outlives[*]" 0 -// @count "$.index[*][?(@.name=='ForAll')].inner.type.inner.decl.inputs[*]" 1 -// @is "$.index[*][?(@.name=='ForAll')].inner.type.inner.decl.inputs[*][1].inner.lifetime" \"\'a\" -// @is "$.index[*][?(@.name=='ForAll')].inner.type.inner.decl.output.inner.lifetime" \"\'a\" +// @has "$.index[*][?(@.name=='ForAll')].inner.typedef" +// @count "$.index[*][?(@.name=='ForAll')].inner.typedef.generics.params[*]" 0 +// @count "$.index[*][?(@.name=='ForAll')].inner.typedef.generics.where_predicates[*]" 0 +// @count "$.index[*][?(@.name=='ForAll')].inner.typedef.type.function_pointer.generic_params[*]" 1 +// @is "$.index[*][?(@.name=='ForAll')].inner.typedef.type.function_pointer.generic_params[*].name" \"\'a\" +// @has "$.index[*][?(@.name=='ForAll')].inner.typedef.type.function_pointer.generic_params[*].kind.lifetime" +// @count "$.index[*][?(@.name=='ForAll')].inner.typedef.type.function_pointer.generic_params[*].kind.lifetime.outlives[*]" 0 +// @count "$.index[*][?(@.name=='ForAll')].inner.typedef.type.function_pointer.decl.inputs[*]" 1 +// @is "$.index[*][?(@.name=='ForAll')].inner.typedef.type.function_pointer.decl.inputs[*][1].borrowed_ref.lifetime" \"\'a\" +// @is "$.index[*][?(@.name=='ForAll')].inner.typedef.type.function_pointer.decl.output.borrowed_ref.lifetime" \"\'a\" pub type ForAll = for<'a> fn(&'a i32) -> &'a i32; diff --git a/tests/rustdoc-json/type/generic_default.rs b/tests/rustdoc-json/type/generic_default.rs index 9c6d4540bfb..b4642874532 100644 --- a/tests/rustdoc-json/type/generic_default.rs +++ b/tests/rustdoc-json/type/generic_default.rs @@ -9,25 +9,25 @@ pub enum Result<T, E> { // @set my_error = "$.index[*][?(@.name=='MyError')].id" pub struct MyError {} -// @is "$.index[*][?(@.name=='MyResult')].kind" \"typedef\" -// @count "$.index[*][?(@.name=='MyResult')].inner.generics.where_predicates[*]" 0 -// @count "$.index[*][?(@.name=='MyResult')].inner.generics.params[*]" 2 -// @is "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].name" \"T\" -// @is "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].name" \"E\" -// @has "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].kind.type" -// @has "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type" -// @count "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].kind.type.bounds[*]" 0 -// @count "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.bounds[*]" 0 -// @is "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].kind.type.default" null -// @is "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.default.kind" \"resolved_path\" -// @is "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.default.inner.id" $my_error -// @is "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.default.inner.name" \"MyError\" -// @is "$.index[*][?(@.name=='MyResult')].inner.type.kind" \"resolved_path\" -// @is "$.index[*][?(@.name=='MyResult')].inner.type.inner.id" $result -// @is "$.index[*][?(@.name=='MyResult')].inner.type.inner.name" \"Result\" -// @is "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.bindings" [] -// @is "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"generic\" -// @is "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[1].type.kind" \"generic\" -// @is "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[0].type.inner" \"T\" -// @is "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[1].type.inner" \"E\" +// @has "$.index[*][?(@.name=='MyResult')].inner.typedef" +// @count "$.index[*][?(@.name=='MyResult')].inner.typedef.generics.where_predicates[*]" 0 +// @count "$.index[*][?(@.name=='MyResult')].inner.typedef.generics.params[*]" 2 +// @is "$.index[*][?(@.name=='MyResult')].inner.typedef.generics.params[0].name" \"T\" +// @is "$.index[*][?(@.name=='MyResult')].inner.typedef.generics.params[1].name" \"E\" +// @has "$.index[*][?(@.name=='MyResult')].inner.typedef.generics.params[0].kind.type" +// @has "$.index[*][?(@.name=='MyResult')].inner.typedef.generics.params[1].kind.type" +// @count "$.index[*][?(@.name=='MyResult')].inner.typedef.generics.params[0].kind.type.bounds[*]" 0 +// @count "$.index[*][?(@.name=='MyResult')].inner.typedef.generics.params[1].kind.type.bounds[*]" 0 +// @is "$.index[*][?(@.name=='MyResult')].inner.typedef.generics.params[0].kind.type.default" null +// @has "$.index[*][?(@.name=='MyResult')].inner.typedef.generics.params[1].kind.type.default.resolved_path" +// @is "$.index[*][?(@.name=='MyResult')].inner.typedef.generics.params[1].kind.type.default.resolved_path.id" $my_error +// @is "$.index[*][?(@.name=='MyResult')].inner.typedef.generics.params[1].kind.type.default.resolved_path.name" \"MyError\" +// @has "$.index[*][?(@.name=='MyResult')].inner.typedef.type.resolved_path" +// @is "$.index[*][?(@.name=='MyResult')].inner.typedef.type.resolved_path.id" $result +// @is "$.index[*][?(@.name=='MyResult')].inner.typedef.type.resolved_path.name" \"Result\" +// @is "$.index[*][?(@.name=='MyResult')].inner.typedef.type.resolved_path.args.angle_bracketed.bindings" [] +// @has "$.index[*][?(@.name=='MyResult')].inner.typedef.type.resolved_path.args.angle_bracketed.args[0].type.generic" +// @has "$.index[*][?(@.name=='MyResult')].inner.typedef.type.resolved_path.args.angle_bracketed.args[1].type.generic" +// @is "$.index[*][?(@.name=='MyResult')].inner.typedef.type.resolved_path.args.angle_bracketed.args[0].type.generic" \"T\" +// @is "$.index[*][?(@.name=='MyResult')].inner.typedef.type.resolved_path.args.angle_bracketed.args[1].type.generic" \"E\" pub type MyResult<T, E = MyError> = Result<T, E>; diff --git a/tests/rustdoc-json/type/hrtb.rs b/tests/rustdoc-json/type/hrtb.rs index 2c4ee00d468..f7ac878ceaa 100644 --- a/tests/rustdoc-json/type/hrtb.rs +++ b/tests/rustdoc-json/type/hrtb.rs @@ -1,7 +1,7 @@ // ignore-tidy-linelength -// @is "$.index[*][?(@.name=='genfn')].inner.generics.where_predicates[0].bound_predicate.type" '{"inner": "F","kind": "generic"}' -// @is "$.index[*][?(@.name=='genfn')].inner.generics.where_predicates[0].bound_predicate.generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' +// @is "$.index[*][?(@.name=='genfn')].inner.function.generics.where_predicates[0].bound_predicate.type" '{"generic": "F"}' +// @is "$.index[*][?(@.name=='genfn')].inner.function.generics.where_predicates[0].bound_predicate.generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' pub fn genfn<F>(f: F) where for<'a, 'b> F: Fn(&'a i32, &'b i32), @@ -10,14 +10,12 @@ where f(&zero, &zero); } -// @is "$.index[*][?(@.name=='dynfn')].inner.generics" '{"params": [], "where_predicates": []}' -// @is "$.index[*][?(@.name=='dynfn')].inner.generics" '{"params": [], "where_predicates": []}' -// @is "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].kind" '"borrowed_ref"' -// @is "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.kind" '"dyn_trait"' -// @is "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.lifetime" null -// @count "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[*]" 1 -// @is "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' -// @is "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[0].trait.name" '"Fn"' +// @is "$.index[*][?(@.name=='dynfn')].inner.function.generics" '{"params": [], "where_predicates": []}' +// @is "$.index[*][?(@.name=='dynfn')].inner.function.generics" '{"params": [], "where_predicates": []}' +// @is "$.index[*][?(@.name=='dynfn')].inner.function.decl.inputs[0][1].borrowed_ref.type.dyn_trait.lifetime" null +// @count "$.index[*][?(@.name=='dynfn')].inner.function.decl.inputs[0][1].borrowed_ref.type.dyn_trait.traits[*]" 1 +// @is "$.index[*][?(@.name=='dynfn')].inner.function.decl.inputs[0][1].borrowed_ref.type.dyn_trait.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' +// @is "$.index[*][?(@.name=='dynfn')].inner.function.decl.inputs[0][1].borrowed_ref.type.dyn_trait.traits[0].trait.name" '"Fn"' pub fn dynfn(f: &dyn for<'a, 'b> Fn(&'a i32, &'b i32)) { let zero = 0; f(&zero, &zero); diff --git a/tests/rustdoc-json/type/inherent_associated_type.rs b/tests/rustdoc-json/type/inherent_associated_type.rs index ed63def93df..64c6c53ce47 100644 --- a/tests/rustdoc-json/type/inherent_associated_type.rs +++ b/tests/rustdoc-json/type/inherent_associated_type.rs @@ -12,11 +12,9 @@ pub struct Owner; pub fn create() -> Owner::Metadata { OwnerMetadata } -// @is '$.index[*][?(@.name=="create")].inner.decl.output.kind' '"qualified_path"' -// @is '$.index[*][?(@.name=="create")].inner.decl.output.inner.name' '"Metadata"' -// @is '$.index[*][?(@.name=="create")].inner.decl.output.inner.trait' null -// @is '$.index[*][?(@.name=="create")].inner.decl.output.inner.self_type.kind' '"resolved_path"' -// @is '$.index[*][?(@.name=="create")].inner.decl.output.inner.self_type.inner.id' $Owner +// @is '$.index[*][?(@.name=="create")].inner.function.decl.output.qualified_path.name' '"Metadata"' +// @is '$.index[*][?(@.name=="create")].inner.function.decl.output.qualified_path.trait' null +// @is '$.index[*][?(@.name=="create")].inner.function.decl.output.qualified_path.self_type.resolved_path.id' $Owner /// impl impl Owner { @@ -24,6 +22,5 @@ impl Owner { pub type Metadata = OwnerMetadata; } // @set iat = '$.index[*][?(@.docs=="iat")].id' -// @is '$.index[*][?(@.docs=="impl")].inner.items[*]' $iat -// @is '$.index[*][?(@.docs=="iat")].kind' '"assoc_type"' -// @is '$.index[*][?(@.docs=="iat")].inner.default.inner.id' $OwnerMetadata +// @is '$.index[*][?(@.docs=="impl")].inner.impl.items[*]' $iat +// @is '$.index[*][?(@.docs=="iat")].inner.assoc_type.default.resolved_path.id' $OwnerMetadata diff --git a/tests/rustdoc-json/type/inherent_associated_type_bound.rs b/tests/rustdoc-json/type/inherent_associated_type_bound.rs index a089600b692..2e9b13d0cac 100644 --- a/tests/rustdoc-json/type/inherent_associated_type_bound.rs +++ b/tests/rustdoc-json/type/inherent_associated_type_bound.rs @@ -5,14 +5,12 @@ // @set Carrier = '$.index[*][?(@.name=="Carrier")].id' pub struct Carrier<'a>(&'a ()); -// @is '$.index[*][?(@.name=="User")].inner.type.kind' '"function_pointer"' -// @is '$.index[*][?(@.name=="User")].inner.type.inner.generic_params[*].name' \""'b"\" -// @is '$.index[*][?(@.name=="User")].inner.type.inner.decl.inputs[0][1].kind' '"qualified_path"' -// @is '$.index[*][?(@.name=="User")].inner.type.inner.decl.inputs[0][1].inner.self_type.inner.id' $Carrier -// @is '$.index[*][?(@.name=="User")].inner.type.inner.decl.inputs[0][1].inner.self_type.inner.args.angle_bracketed.args[0].lifetime' \""'b"\" -// @is '$.index[*][?(@.name=="User")].inner.type.inner.decl.inputs[0][1].inner.name' '"Focus"' -// @is '$.index[*][?(@.name=="User")].inner.type.inner.decl.inputs[0][1].inner.trait' null -// @is '$.index[*][?(@.name=="User")].inner.type.inner.decl.inputs[0][1].inner.args.angle_bracketed.args[0].type.inner' '"i32"' +// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.generic_params[*].name' \""'b"\" +// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.id' $Carrier +// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].lifetime' \""'b"\" +// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.name' '"Focus"' +// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.trait' null +// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.args.angle_bracketed.args[0].type.primitive' '"i32"' pub type User = for<'b> fn(Carrier<'b>::Focus<i32>); diff --git a/tests/rustdoc-json/type/inherent_associated_type_projections.rs b/tests/rustdoc-json/type/inherent_associated_type_projections.rs index 30c68bfe56c..942e323efca 100644 --- a/tests/rustdoc-json/type/inherent_associated_type_projections.rs +++ b/tests/rustdoc-json/type/inherent_associated_type_projections.rs @@ -5,11 +5,10 @@ // @set Parametrized = '$.index[*][?(@.name=="Parametrized")].id' pub struct Parametrized<T>(T); -// @is '$.index[*][?(@.name=="Test")].inner.type.kind' '"qualified_path"' -// @is '$.index[*][?(@.name=="Test")].inner.type.inner.self_type.inner.id' $Parametrized -// @is '$.index[*][?(@.name=="Test")].inner.type.inner.self_type.inner.args.angle_bracketed.args[0].type' '{"inner": "i32", "kind": "primitive"}' -// @is '$.index[*][?(@.name=="Test")].inner.type.inner.name' '"Proj"' -// @is '$.index[*][?(@.name=="Test")].inner.type.inner.trait' null +// @is '$.index[*][?(@.name=="Test")].inner.typedef.type.qualified_path.self_type.resolved_path.id' $Parametrized +// @is '$.index[*][?(@.name=="Test")].inner.typedef.type.qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].type.primitive' \"i32\" +// @is '$.index[*][?(@.name=="Test")].inner.typedef.type.qualified_path.name' '"Proj"' +// @is '$.index[*][?(@.name=="Test")].inner.typedef.type.qualified_path.trait' null pub type Test = Parametrized<i32>::Proj; /// param_bool @@ -29,5 +28,5 @@ impl Parametrized<i32> { // @set param_bool_proj = '$.index[*][?(@.docs=="param_bool_proj")].id' // @set param_i32_proj = '$.index[*][?(@.docs=="param_i32_proj")].id' -// @is '$.index[*][?(@.docs=="param_bool")].inner.items[*]' $param_bool_proj -// @is '$.index[*][?(@.docs=="param_i32")].inner.items[*]' $param_i32_proj +// @is '$.index[*][?(@.docs=="param_bool")].inner.impl.items[*]' $param_bool_proj +// @is '$.index[*][?(@.docs=="param_i32")].inner.impl.items[*]' $param_i32_proj diff --git a/tests/rustdoc-json/unions/impl.rs b/tests/rustdoc-json/unions/impl.rs index 4454a69ecd1..7456892df1b 100644 --- a/tests/rustdoc-json/unions/impl.rs +++ b/tests/rustdoc-json/unions/impl.rs @@ -1,15 +1,15 @@ #![no_std] // @is "$.index[*][?(@.name=='Ux')].visibility" \"public\" -// @is "$.index[*][?(@.name=='Ux')].kind" \"union\" +// @has "$.index[*][?(@.name=='Ux')].inner.union" pub union Ux { a: u32, b: u64 } // @is "$.index[*][?(@.name=='Num')].visibility" \"public\" -// @is "$.index[*][?(@.name=='Num')].kind" \"trait\" +// @has "$.index[*][?(@.name=='Num')].inner.trait" pub trait Num {} -// @count "$.index[*][?(@.name=='Ux')].inner.impls" 1 +// @count "$.index[*][?(@.name=='Ux')].inner.union.impls" 1 impl Num for Ux {} diff --git a/tests/rustdoc-json/unions/union.rs b/tests/rustdoc-json/unions/union.rs index c9df2b81c4b..22b70e1ce8c 100644 --- a/tests/rustdoc-json/unions/union.rs +++ b/tests/rustdoc-json/unions/union.rs @@ -1,6 +1,6 @@ // @has "$.index[*][?(@.name=='Union')].visibility" \"public\" -// @has "$.index[*][?(@.name=='Union')].kind" \"union\" -// @!has "$.index[*][?(@.name=='Union')].inner.struct_type" +// @has "$.index[*][?(@.name=='Union')].inner.union" +// @!has "$.index[*][?(@.name=='Union')].inner.union.struct_type" // @set Union = "$.index[*][?(@.name=='Union')].id" pub union Union { int: i32, @@ -8,8 +8,8 @@ pub union Union { } -// @is "$.index[*][?(@.name=='make_int_union')].inner.decl.output.kind" '"resolved_path"' -// @is "$.index[*][?(@.name=='make_int_union')].inner.decl.output.inner.id" $Union +// @has "$.index[*][?(@.name=='make_int_union')].inner.function.decl.output.resolved_path" +// @is "$.index[*][?(@.name=='make_int_union')].inner.function.decl.output.resolved_path.id" $Union pub fn make_int_union(int: i32) -> Union { Union { int } } diff --git a/tests/rustdoc-ui/intra-doc/issue-111189-resolution-ice.rs b/tests/rustdoc-ui/intra-doc/issue-111189-resolution-ice.rs new file mode 100644 index 00000000000..4e74278dc7b --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/issue-111189-resolution-ice.rs @@ -0,0 +1,10 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/111189>. +// This test ensures that it doesn't crash. + +#![deny(warnings)] + +/// #[rustfmt::skip] +//~^ ERROR unresolved link to `rustfmt::skip` +/// #[clippy::whatever] +//~^ ERROR unresolved link to `clippy::whatever` +pub fn foo() {} diff --git a/tests/rustdoc-ui/intra-doc/issue-111189-resolution-ice.stderr b/tests/rustdoc-ui/intra-doc/issue-111189-resolution-ice.stderr new file mode 100644 index 00000000000..edd3dfa7d7e --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/issue-111189-resolution-ice.stderr @@ -0,0 +1,21 @@ +error: unresolved link to `rustfmt::skip` + --> $DIR/issue-111189-resolution-ice.rs:6:7 + | +LL | /// #[rustfmt::skip] + | ^^^^^^^^^^^^^ no item named `rustfmt` in scope + | +note: the lint level is defined here + --> $DIR/issue-111189-resolution-ice.rs:4:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]` + +error: unresolved link to `clippy::whatever` + --> $DIR/issue-111189-resolution-ice.rs:8:7 + | +LL | /// #[clippy::whatever] + | ^^^^^^^^^^^^^^^^ no item named `clippy` in scope + +error: aborting due to 2 previous errors + diff --git a/tests/rustdoc/strikethrough-in-summary.rs b/tests/rustdoc/strikethrough-in-summary.rs new file mode 100644 index 00000000000..cb6cd0e7ba6 --- /dev/null +++ b/tests/rustdoc/strikethrough-in-summary.rs @@ -0,0 +1,6 @@ +#![crate_name = "foo"] + +// @has foo/index.html '//del' 'strike' + +/// ~~strike~~ +pub fn strike() {} diff --git a/tests/ui/associated-inherent-types/inference.rs b/tests/ui/associated-inherent-types/inference.rs index 7d6d26003f6..ebd8e1d5594 100644 --- a/tests/ui/associated-inherent-types/inference.rs +++ b/tests/ui/associated-inherent-types/inference.rs @@ -3,7 +3,7 @@ #![feature(inherent_associated_types)] #![allow(incomplete_features)] -#![allow(drop_copy)] +#![allow(dropping_copy_types)] use std::convert::identity; diff --git a/tests/ui/associated-inherent-types/issue-111879-0.rs b/tests/ui/associated-inherent-types/issue-111879-0.rs new file mode 100644 index 00000000000..e37f7d34ab5 --- /dev/null +++ b/tests/ui/associated-inherent-types/issue-111879-0.rs @@ -0,0 +1,14 @@ +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +// Check that we don't crash when printing inherent projections in diagnostics. + +pub struct Carrier<'a>(&'a ()); + +pub type User = for<'b> fn(Carrier<'b>::Focus<i32>); + +impl<'a> Carrier<'a> { + pub type Focus<T> = &'a mut User; //~ ERROR overflow evaluating associated type +} + +fn main() {} diff --git a/tests/ui/associated-inherent-types/issue-111879-0.stderr b/tests/ui/associated-inherent-types/issue-111879-0.stderr new file mode 100644 index 00000000000..7bdbad44017 --- /dev/null +++ b/tests/ui/associated-inherent-types/issue-111879-0.stderr @@ -0,0 +1,8 @@ +error: overflow evaluating associated type `Carrier<'b>::Focus<i32>` + --> $DIR/issue-111879-0.rs:11:25 + | +LL | pub type Focus<T> = &'a mut User; + | ^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/associated-inherent-types/issue-111879-1.rs b/tests/ui/associated-inherent-types/issue-111879-1.rs new file mode 100644 index 00000000000..7acc4f94505 --- /dev/null +++ b/tests/ui/associated-inherent-types/issue-111879-1.rs @@ -0,0 +1,12 @@ +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +// Check that we don't crash when printing inherent projections in diagnostics. + +struct Foo<T>(T); + +impl<'a> Foo<fn(&'a ())> { + type Assoc = &'a (); +} + +fn main(_: for<'a> fn(Foo<fn(&'a ())>::Assoc)) {} //~ ERROR `main` function has wrong type diff --git a/tests/ui/associated-inherent-types/issue-111879-1.stderr b/tests/ui/associated-inherent-types/issue-111879-1.stderr new file mode 100644 index 00000000000..689b45e09aa --- /dev/null +++ b/tests/ui/associated-inherent-types/issue-111879-1.stderr @@ -0,0 +1,12 @@ +error[E0580]: `main` function has wrong type + --> $DIR/issue-111879-1.rs:12:1 + | +LL | fn main(_: for<'a> fn(Foo<fn(&'a ())>::Assoc)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters + | + = note: expected fn pointer `fn()` + found fn pointer `fn(for<'a> fn(Foo<fn(&'a ())>::Assoc))` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0580`. diff --git a/tests/ui/async-await/return-type-notation/supertrait-bound.rs b/tests/ui/async-await/return-type-notation/supertrait-bound.rs new file mode 100644 index 00000000000..19bcfe3046b --- /dev/null +++ b/tests/ui/async-await/return-type-notation/supertrait-bound.rs @@ -0,0 +1,11 @@ +// check-pass + +#![feature(return_position_impl_trait_in_trait, return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete and may not be safe to use + +trait IntFactory { + fn stream(&self) -> impl Iterator<Item = i32>; +} +trait SendIntFactory: IntFactory<stream(): Send> + Send {} + +fn main() {} diff --git a/tests/ui/async-await/return-type-notation/supertrait-bound.stderr b/tests/ui/async-await/return-type-notation/supertrait-bound.stderr new file mode 100644 index 00000000000..c8cec4946b4 --- /dev/null +++ b/tests/ui/async-await/return-type-notation/supertrait-bound.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/supertrait-bound.rs:3:49 + | +LL | #![feature(return_position_impl_trait_in_trait, return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/borrowck/borrowck-closures-slice-patterns-ok.rs b/tests/ui/borrowck/borrowck-closures-slice-patterns-ok.rs index 9163c8ed6fb..60128c9419d 100644 --- a/tests/ui/borrowck/borrowck-closures-slice-patterns-ok.rs +++ b/tests/ui/borrowck/borrowck-closures-slice-patterns-ok.rs @@ -1,7 +1,7 @@ // Check that closure captures for slice patterns are inferred correctly #![allow(unused_variables)] -#![allow(drop_ref)] +#![allow(dropping_references)] // run-pass diff --git a/tests/ui/borrowck/borrowck-field-sensitivity-rpass.rs b/tests/ui/borrowck/borrowck-field-sensitivity-rpass.rs index a88b323e0bf..78e965cc4bc 100644 --- a/tests/ui/borrowck/borrowck-field-sensitivity-rpass.rs +++ b/tests/ui/borrowck/borrowck-field-sensitivity-rpass.rs @@ -1,7 +1,7 @@ // run-pass #![allow(unused_mut)] #![allow(unused_variables)] -#![allow(drop_copy)] +#![allow(dropping_copy_types)] // pretty-expanded FIXME #23616 struct A { a: isize, b: Box<isize> } diff --git a/tests/ui/borrowck/borrowck-use-mut-borrow-rpass.rs b/tests/ui/borrowck/borrowck-use-mut-borrow-rpass.rs index 40c6bfeeb43..9acb1ec5e43 100644 --- a/tests/ui/borrowck/borrowck-use-mut-borrow-rpass.rs +++ b/tests/ui/borrowck/borrowck-use-mut-borrow-rpass.rs @@ -1,7 +1,7 @@ // run-pass // pretty-expanded FIXME #23616 -#![allow(drop_copy)] +#![allow(dropping_copy_types)] struct A { a: isize, b: Box<isize> } diff --git a/tests/ui/cfg/cfg-stmt-recovery.rs b/tests/ui/cfg/cfg-stmt-recovery.rs new file mode 100644 index 00000000000..2e0839d2a15 --- /dev/null +++ b/tests/ui/cfg/cfg-stmt-recovery.rs @@ -0,0 +1,13 @@ +// Verify that we do not ICE when failing to parse a statement in `cfg_eval`. + +#![feature(cfg_eval)] +#![feature(stmt_expr_attributes)] + +#[cfg_eval] +fn main() { + #[cfg_eval] + let _ = #[cfg(FALSE)] 0; + //~^ ERROR removing an expression is not supported in this position + //~| ERROR expected expression, found `;` + //~| ERROR removing an expression is not supported in this position +} diff --git a/tests/ui/cfg/cfg-stmt-recovery.stderr b/tests/ui/cfg/cfg-stmt-recovery.stderr new file mode 100644 index 00000000000..cb15e21fac6 --- /dev/null +++ b/tests/ui/cfg/cfg-stmt-recovery.stderr @@ -0,0 +1,20 @@ +error: removing an expression is not supported in this position + --> $DIR/cfg-stmt-recovery.rs:9:13 + | +LL | let _ = #[cfg(FALSE)] 0; + | ^^^^^^^^^^^^^ + +error: expected expression, found `;` + --> $DIR/cfg-stmt-recovery.rs:9:28 + | +LL | let _ = #[cfg(FALSE)] 0; + | ^ expected expression + +error: removing an expression is not supported in this position + --> $DIR/cfg-stmt-recovery.rs:9:13 + | +LL | let _ = #[cfg(FALSE)] 0; + | ^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.rs b/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.rs index bc7295a0826..98f8d5d4733 100644 --- a/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.rs +++ b/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.rs @@ -1,7 +1,7 @@ // run-pass #![warn(rust_2021_incompatible_closure_captures)] -#![allow(drop_ref, drop_copy)] +#![allow(dropping_references, dropping_copy_types)] fn main() { if let a = "" { diff --git a/tests/ui/closures/2229_closure_analysis/optimization/edge_case_run_pass.rs b/tests/ui/closures/2229_closure_analysis/optimization/edge_case_run_pass.rs index 0f15f664e75..5496d0e5fc7 100644 --- a/tests/ui/closures/2229_closure_analysis/optimization/edge_case_run_pass.rs +++ b/tests/ui/closures/2229_closure_analysis/optimization/edge_case_run_pass.rs @@ -3,7 +3,7 @@ #![allow(unused)] #![allow(dead_code)] -#![allow(drop_ref)] +#![allow(dropping_references)] struct Int(i32); struct B<'a>(&'a i32); diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.rs b/tests/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.rs index a097424a021..b5e97ec1c1b 100644 --- a/tests/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.rs +++ b/tests/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.rs @@ -2,7 +2,7 @@ // check-pass #![feature(rustc_attrs)] -#![allow(drop_ref)] +#![allow(dropping_references)] fn main() { let mut x = 1; diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs index a1b711a3024..87ae83dd966 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs @@ -11,6 +11,13 @@ struct S<T> { impl<T: ConstParamTy> ConstParamTy for S<T> {} +#[derive(PartialEq, Eq, ConstParamTy)] +struct D<T> { + field: u8, + gen: T, +} + + fn check<T: ConstParamTy + ?Sized>() {} fn main() { @@ -39,5 +46,8 @@ fn main() { check::<S<u8>>(); check::<S<[&[bool]; 8]>>(); + check::<D<u8>>(); + check::<D<[&[bool]; 8]>>(); + // FIXME: test tuples } diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs index 07fd243737e..74283a37afc 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs @@ -10,4 +10,8 @@ struct CantParam(NotParam); impl std::marker::ConstParamTy for CantParam {} //~^ error: the trait `ConstParamTy` cannot be implemented for this type +#[derive(std::marker::ConstParamTy, Eq, PartialEq)] +//~^ error: the trait `ConstParamTy` cannot be implemented for this type +struct CantParamDerive(NotParam); + fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr index c8e065848b1..52b65d6061a 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr @@ -7,6 +7,17 @@ LL | LL | impl std::marker::ConstParamTy for CantParam {} | ^^^^^^^^^ -error: aborting due to previous error +error[E0204]: the trait `ConstParamTy` cannot be implemented for this type + --> $DIR/const_param_ty_impl_bad_field.rs:13:10 + | +LL | #[derive(std::marker::ConstParamTy, Eq, PartialEq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | struct CantParamDerive(NotParam); + | -------- this field does not implement `ConstParamTy` + | + = note: this error originates in the derive macro `std::marker::ConstParamTy` (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 E0204`. diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs index 17ef396164e..37986de481f 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs @@ -10,6 +10,10 @@ struct CantParam(ImplementsConstParamTy); impl std::marker::ConstParamTy for CantParam {} //~^ error: the type `CantParam` does not `#[derive(Eq)]` +#[derive(std::marker::ConstParamTy)] +//~^ error: the type `CantParamDerive` does not `#[derive(Eq)]` +struct CantParamDerive(ImplementsConstParamTy); + fn check<T: std::marker::ConstParamTy>() {} fn main() { diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr index ca5abf5e254..52701d55914 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr @@ -7,6 +7,16 @@ LL | impl std::marker::ConstParamTy for CantParam {} note: required by a bound in `ConstParamTy` --> $SRC_DIR/core/src/marker.rs:LL:COL -error: aborting due to previous error +error[E0277]: the type `CantParamDerive` does not `#[derive(Eq)]` + --> $DIR/const_param_ty_impl_no_structural_eq.rs:13:10 + | +LL | #[derive(std::marker::ConstParamTy)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `StructuralEq` is not implemented for `CantParamDerive` + | +note: required by a bound in `ConstParamTy` + --> $SRC_DIR/core/src/marker.rs:LL:COL + = note: this error originates in the derive macro `std::marker::ConstParamTy` (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 E0277`. diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs new file mode 100644 index 00000000000..d70377a20c1 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs @@ -0,0 +1,33 @@ +#![allow(incomplete_features)] +#![feature(adt_const_params, structural_match)] + +union Union { + a: u8, +} + +impl PartialEq for Union { + fn eq(&self, other: &Union) -> bool { + true + } +} +impl Eq for Union {} +impl std::marker::StructuralEq for Union {} + +impl std::marker::ConstParamTy for Union {} + +#[derive(std::marker::ConstParamTy)] +//~^ ERROR this trait cannot be derived for unions +union UnionDerive { + a: u8, +} + +impl PartialEq for UnionDerive { + fn eq(&self, other: &UnionDerive) -> bool { + true + } +} +impl Eq for UnionDerive {} +impl std::marker::StructuralEq for UnionDerive {} + + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr new file mode 100644 index 00000000000..29370304605 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr @@ -0,0 +1,8 @@ +error: this trait cannot be derived for unions + --> $DIR/const_param_ty_impl_union.rs:18:10 + | +LL | #[derive(std::marker::ConstParamTy)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/consts/const_forget.rs b/tests/ui/consts/const_forget.rs index acdd6a54cf4..f06149f2cb9 100644 --- a/tests/ui/consts/const_forget.rs +++ b/tests/ui/consts/const_forget.rs @@ -1,6 +1,6 @@ // check-pass -#![allow(forget_copy)] +#![allow(forgetting_copy_types)] use std::mem::forget; diff --git a/tests/ui/consts/issue-104155.rs b/tests/ui/consts/issue-104155.rs index b3821f467b6..7b375dc0566 100644 --- a/tests/ui/consts/issue-104155.rs +++ b/tests/ui/consts/issue-104155.rs @@ -1,6 +1,6 @@ // check-pass -#![allow(forget_copy)] +#![allow(forgetting_copy_types)] const _: () = core::mem::forget(Box::<u32>::default); const _: () = core::mem::forget(|| Box::<u32>::default()); diff --git a/tests/ui/crate-leading-sep.rs b/tests/ui/crate-leading-sep.rs index 8d1d0b4fcdf..fce97d9ba23 100644 --- a/tests/ui/crate-leading-sep.rs +++ b/tests/ui/crate-leading-sep.rs @@ -1,7 +1,7 @@ // run-pass // pretty-expanded FIXME #23616 -#![allow(drop_copy)] +#![allow(dropping_copy_types)] fn main() { use ::std::mem; diff --git a/tests/ui/drop/issue-110682.rs b/tests/ui/drop/issue-110682.rs new file mode 100644 index 00000000000..35f9c7e8d9b --- /dev/null +++ b/tests/ui/drop/issue-110682.rs @@ -0,0 +1,92 @@ +// build-pass +// compile-flags: -Zmir-opt-level=3 + +use std::fmt::Debug; +use std::mem::ManuallyDrop; +use std::ptr; + +pub trait BitRegister {} + +macro_rules! register { + ($($t:ty),+ $(,)?) => { $( + impl BitRegister for $t { + } + )* }; +} + +register!(u8, u16, u32); + +pub trait BitStore: Sized + Debug { + /// The register type that the implementor describes. + type Mem: BitRegister + Into<Self>; +} + +macro_rules! store { + ($($t:ty),+ $(,)?) => { $( + impl BitStore for $t { + type Mem = Self; + } + )+ }; +} + +store!(u8, u16, u32,); + +#[repr(C)] +pub struct BitVec<T> +where + T: BitStore, +{ + /// Region pointer describing the live portion of the owned buffer. + pointer: ptr::NonNull<T>, + /// Allocated capacity, in elements `T`, of the owned buffer. + capacity: usize, +} + +impl<T> BitVec<T> +where + T: BitStore, +{ + pub fn new() -> Self { + let pointer = ptr::NonNull::<T>::new(ptr::null_mut()).unwrap(); + + BitVec { pointer, capacity: 10 } + } + + pub fn clear(&mut self) { + unsafe { + self.set_len(0); + } + } + + #[inline] + pub unsafe fn set_len(&mut self, new_len: usize) {} + + fn with_vec<F, R>(&mut self, func: F) -> R + where + F: FnOnce(&mut ManuallyDrop<Vec<T::Mem>>) -> R, + { + let cap = self.capacity; + let elts = 10; + let mut vec = ManuallyDrop::new(unsafe { Vec::from_raw_parts(ptr::null_mut(), elts, cap) }); + let out = func(&mut vec); + + out + } +} + +impl<T> Drop for BitVec<T> +where + T: BitStore, +{ + #[inline] + fn drop(&mut self) { + // The buffer elements do not have destructors. + self.clear(); + // Run the `Vec` destructor to deällocate the buffer. + self.with_vec(|vec| unsafe { ManuallyDrop::drop(vec) }); + } +} + +fn main() { + let bitvec = BitVec::<u32>::new(); +} diff --git a/tests/ui/drop/repeat-drop.rs b/tests/ui/drop/repeat-drop.rs index 659d35db657..0afb4bb11bc 100644 --- a/tests/ui/drop/repeat-drop.rs +++ b/tests/ui/drop/repeat-drop.rs @@ -1,7 +1,7 @@ // run-pass // needs-unwind -#![allow(drop_ref, drop_copy)] +#![allow(dropping_references, dropping_copy_types)] static mut CHECK: usize = 0; diff --git a/tests/ui/dyn-star/param-env-infer.current.stderr b/tests/ui/dyn-star/param-env-infer.current.stderr new file mode 100644 index 00000000000..d0785c887d8 --- /dev/null +++ b/tests/ui/dyn-star/param-env-infer.current.stderr @@ -0,0 +1,18 @@ +warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/param-env-infer.rs:5:12 + | +LL | #![feature(dyn_star, pointer_like_trait)] + | ^^^^^^^^ + | + = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0282]: type annotations needed + --> $DIR/param-env-infer.rs:12:10 + | +LL | t as _ + | ^ cannot infer type + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/dyn-star/param-env-infer.next.stderr b/tests/ui/dyn-star/param-env-infer.next.stderr new file mode 100644 index 00000000000..d0785c887d8 --- /dev/null +++ b/tests/ui/dyn-star/param-env-infer.next.stderr @@ -0,0 +1,18 @@ +warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/param-env-infer.rs:5:12 + | +LL | #![feature(dyn_star, pointer_like_trait)] + | ^^^^^^^^ + | + = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0282]: type annotations needed + --> $DIR/param-env-infer.rs:12:10 + | +LL | t as _ + | ^ cannot infer type + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/dyn-star/param-env-infer.rs b/tests/ui/dyn-star/param-env-infer.rs new file mode 100644 index 00000000000..9039dde5e93 --- /dev/null +++ b/tests/ui/dyn-star/param-env-infer.rs @@ -0,0 +1,16 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next +// incremental + +#![feature(dyn_star, pointer_like_trait)] +//~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes + +use std::fmt::Debug; +use std::marker::PointerLike; + +fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a { + t as _ + //~^ ERROR type annotations needed +} + +fn main() {} diff --git a/tests/ui/error-codes/E0746.fixed b/tests/ui/error-codes/E0746.fixed deleted file mode 100644 index ca8319aa020..00000000000 --- a/tests/ui/error-codes/E0746.fixed +++ /dev/null @@ -1,18 +0,0 @@ -// run-rustfix -#![allow(dead_code)] -struct Struct; -trait Trait {} -impl Trait for Struct {} -impl Trait for u32 {} - -fn foo() -> impl Trait { Struct } -//~^ ERROR E0746 - -fn bar() -> impl Trait { //~ ERROR E0746 - if true { - return 0; - } - 42 -} - -fn main() {} diff --git a/tests/ui/error-codes/E0746.rs b/tests/ui/error-codes/E0746.rs index bf5ba8fff56..86b5b7444d1 100644 --- a/tests/ui/error-codes/E0746.rs +++ b/tests/ui/error-codes/E0746.rs @@ -1,5 +1,5 @@ -// run-rustfix #![allow(dead_code)] + struct Struct; trait Trait {} impl Trait for Struct {} diff --git a/tests/ui/error-codes/E0746.stderr b/tests/ui/error-codes/E0746.stderr index 2153b59ad18..9fe90ab7bec 100644 --- a/tests/ui/error-codes/E0746.stderr +++ b/tests/ui/error-codes/E0746.stderr @@ -4,11 +4,14 @@ error[E0746]: return type cannot have an unboxed trait object LL | fn foo() -> dyn Trait { Struct } | ^^^^^^^^^ doesn't have a size known at compile-time | - = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> -help: use `impl Trait` as the return type, as all return paths are of type `Struct`, which implements `Trait` +help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type | LL | fn foo() -> impl Trait { Struct } - | ~~~~~~~~~~ + | ~~~~ +help: box the return type, and wrap all of the returned values in `Box::new` + | +LL | fn foo() -> Box<dyn Trait> { Box::new(Struct) } + | ++++ + +++++++++ + error[E0746]: return type cannot have an unboxed trait object --> $DIR/E0746.rs:11:13 @@ -16,11 +19,18 @@ error[E0746]: return type cannot have an unboxed trait object LL | fn bar() -> dyn Trait { | ^^^^^^^^^ doesn't have a size known at compile-time | - = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> -help: use `impl Trait` as the return type, as all return paths are of type `{integer}`, which implements `Trait` +help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type | LL | fn bar() -> impl Trait { - | ~~~~~~~~~~ + | ~~~~ +help: box the return type, and wrap all of the returned values in `Box::new` + | +LL ~ fn bar() -> Box<dyn Trait> { +LL | if true { +LL ~ return Box::new(0); +LL | } +LL ~ Box::new(42) + | error: aborting due to 2 previous errors diff --git a/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed b/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed index 0bc4feed329..bb093a4af4a 100644 --- a/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed +++ b/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed @@ -1,6 +1,6 @@ // run-rustfix -#![allow(drop_ref)] +#![allow(dropping_references)] struct Foo { x: isize diff --git a/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs b/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs index 26ae6698d66..1a9f89c054f 100644 --- a/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs +++ b/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs @@ -1,6 +1,6 @@ // run-rustfix -#![allow(drop_ref)] +#![allow(dropping_references)] struct Foo { x: isize diff --git a/tests/ui/generator/drop-env.rs b/tests/ui/generator/drop-env.rs index cb46953dac3..137a407931a 100644 --- a/tests/ui/generator/drop-env.rs +++ b/tests/ui/generator/drop-env.rs @@ -4,7 +4,7 @@ //[nomiropt]compile-flags: -Z mir-opt-level=0 #![feature(generators, generator_trait)] -#![allow(drop_copy)] +#![allow(dropping_copy_types)] use std::ops::Generator; use std::pin::Pin; diff --git a/tests/ui/generator/issue-57017.rs b/tests/ui/generator/issue-57017.rs index 918d233bf4e..381897c77a5 100644 --- a/tests/ui/generator/issue-57017.rs +++ b/tests/ui/generator/issue-57017.rs @@ -5,7 +5,7 @@ // [drop_tracking_mir] build-pass #![feature(generators, negative_impls)] -#![allow(drop_ref, drop_copy)] +#![allow(dropping_references, dropping_copy_types)] macro_rules! type_combinations { ( diff --git a/tests/ui/generator/non-static-is-unpin.rs b/tests/ui/generator/non-static-is-unpin.rs index adba800e25a..a5dde3912cc 100644 --- a/tests/ui/generator/non-static-is-unpin.rs +++ b/tests/ui/generator/non-static-is-unpin.rs @@ -3,7 +3,7 @@ // run-pass #![feature(generators, generator_trait)] -#![allow(drop_copy)] +#![allow(dropping_copy_types)] use std::marker::{PhantomPinned, Unpin}; diff --git a/tests/ui/generator/resume-arg-size.rs b/tests/ui/generator/resume-arg-size.rs index 19618f8d0aa..195166f975b 100644 --- a/tests/ui/generator/resume-arg-size.rs +++ b/tests/ui/generator/resume-arg-size.rs @@ -1,5 +1,5 @@ #![feature(generators)] -#![allow(drop_copy)] +#![allow(dropping_copy_types)] // run-pass diff --git a/tests/ui/hygiene/stdlib-prelude-from-opaque-late.rs b/tests/ui/hygiene/stdlib-prelude-from-opaque-late.rs index 214267372bf..721bb7281c0 100644 --- a/tests/ui/hygiene/stdlib-prelude-from-opaque-late.rs +++ b/tests/ui/hygiene/stdlib-prelude-from-opaque-late.rs @@ -1,7 +1,7 @@ // check-pass #![feature(decl_macro)] -#![allow(drop_copy)] +#![allow(dropping_copy_types)] macro mac() { mod m { diff --git a/tests/ui/illegal-ufcs-drop.fixed b/tests/ui/illegal-ufcs-drop.fixed index 8783682dec4..c088c82791b 100644 --- a/tests/ui/illegal-ufcs-drop.fixed +++ b/tests/ui/illegal-ufcs-drop.fixed @@ -1,6 +1,6 @@ // run-rustfix -#![allow(drop_ref)] +#![allow(dropping_references)] struct Foo; diff --git a/tests/ui/illegal-ufcs-drop.rs b/tests/ui/illegal-ufcs-drop.rs index 29774306ec6..1389b112188 100644 --- a/tests/ui/illegal-ufcs-drop.rs +++ b/tests/ui/illegal-ufcs-drop.rs @@ -1,6 +1,6 @@ // run-rustfix -#![allow(drop_ref)] +#![allow(dropping_references)] struct Foo; diff --git a/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.rs b/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.rs index cbf1daabe2b..af368203de0 100644 --- a/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.rs +++ b/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.rs @@ -26,7 +26,7 @@ fn bax() -> dyn Trait { //~ ERROR E0746 if true { Struct } else { - 42 //~ ERROR `if` and `else` have incompatible types + 42 } } fn bam() -> Box<dyn Trait> { diff --git a/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr index dc1e40ea560..ed9261d0de5 100644 --- a/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr +++ b/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr @@ -46,11 +46,10 @@ error[E0746]: return type cannot have an unboxed trait object LL | fn bap() -> Trait { Struct } | ^^^^^ doesn't have a size known at compile-time | - = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> -help: use `impl Trait` as the return type, as all return paths are of type `Struct`, which implements `Trait` +help: box the return type, and wrap all of the returned values in `Box::new` | -LL | fn bap() -> impl Trait { Struct } - | ~~~~~~~~~~ +LL | fn bap() -> Box<Trait> { Box::new(Struct) } + | ++++ + +++++++++ + error[E0746]: return type cannot have an unboxed trait object --> $DIR/dyn-trait-return-should-be-impl-trait.rs:15:13 @@ -58,11 +57,14 @@ error[E0746]: return type cannot have an unboxed trait object LL | fn ban() -> dyn Trait { Struct } | ^^^^^^^^^ doesn't have a size known at compile-time | - = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> -help: use `impl Trait` as the return type, as all return paths are of type `Struct`, which implements `Trait` +help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type | LL | fn ban() -> impl Trait { Struct } - | ~~~~~~~~~~ + | ~~~~ +help: box the return type, and wrap all of the returned values in `Box::new` + | +LL | fn ban() -> Box<dyn Trait> { Box::new(Struct) } + | ++++ + +++++++++ + error[E0746]: return type cannot have an unboxed trait object --> $DIR/dyn-trait-return-should-be-impl-trait.rs:17:13 @@ -70,14 +72,14 @@ error[E0746]: return type cannot have an unboxed trait object LL | fn bak() -> dyn Trait { unimplemented!() } | ^^^^^^^^^ doesn't have a size known at compile-time | -help: use `impl Trait` as the return type if all return paths have the same type but you want to expose only the trait in the signature +help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type | LL | fn bak() -> impl Trait { unimplemented!() } - | ~~~~~~~~~~ -help: use a boxed trait object if all return paths implement trait `Trait` + | ~~~~ +help: box the return type, and wrap all of the returned values in `Box::new` | -LL | fn bak() -> Box<dyn Trait> { unimplemented!() } - | ++++ + +LL | fn bak() -> Box<dyn Trait> { Box::new(unimplemented!()) } + | ++++ + +++++++++ + error[E0746]: return type cannot have an unboxed trait object --> $DIR/dyn-trait-return-should-be-impl-trait.rs:19:13 @@ -85,34 +87,18 @@ error[E0746]: return type cannot have an unboxed trait object LL | fn bal() -> dyn Trait { | ^^^^^^^^^ doesn't have a size known at compile-time | - = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types> - = note: if all the returned values were of the same type you could use `impl Trait` as the return type - = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> - = note: you can create a new `enum` with a variant for each returned type -help: return a boxed trait object instead +help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type | -LL | fn bal() -> Box<dyn Trait> { - | ++++ + -help: ... and box this value +LL | fn bal() -> impl Trait { + | ~~~~ +help: box the return type, and wrap all of the returned values in `Box::new` | -LL | return Box::new(Struct); - | +++++++++ + -help: ... and box this value +LL ~ fn bal() -> Box<dyn Trait> { +LL | if true { +LL ~ return Box::new(Struct); +LL | } +LL ~ Box::new(42) | -LL | Box::new(42) - | +++++++++ + - -error[E0308]: `if` and `else` have incompatible types - --> $DIR/dyn-trait-return-should-be-impl-trait.rs:29:9 - | -LL | / if true { -LL | | Struct - | | ------ expected because of this -LL | | } else { -LL | | 42 - | | ^^ expected `Struct`, found integer -LL | | } - | |_____- `if` and `else` have incompatible types error[E0746]: return type cannot have an unboxed trait object --> $DIR/dyn-trait-return-should-be-impl-trait.rs:25:13 @@ -120,22 +106,18 @@ error[E0746]: return type cannot have an unboxed trait object LL | fn bax() -> dyn Trait { | ^^^^^^^^^ doesn't have a size known at compile-time | - = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types> - = note: if all the returned values were of the same type you could use `impl Trait` as the return type - = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> - = note: you can create a new `enum` with a variant for each returned type -help: return a boxed trait object instead +help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type | -LL | fn bax() -> Box<dyn Trait> { - | ++++ + -help: ... and box this value +LL | fn bax() -> impl Trait { + | ~~~~ +help: box the return type, and wrap all of the returned values in `Box::new` | -LL | Box::new(Struct) - | +++++++++ + -help: ... and box this value +LL ~ fn bax() -> Box<dyn Trait> { +LL | if true { +LL ~ Box::new(Struct) +LL | } else { +LL ~ Box::new(42) | -LL | Box::new(42) - | +++++++++ + error[E0308]: mismatched types --> $DIR/dyn-trait-return-should-be-impl-trait.rs:34:16 @@ -279,11 +261,18 @@ error[E0746]: return type cannot have an unboxed trait object LL | fn bat() -> dyn Trait { | ^^^^^^^^^ doesn't have a size known at compile-time | - = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> -help: use `impl Trait` as the return type, as all return paths are of type `{integer}`, which implements `Trait` +help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type | LL | fn bat() -> impl Trait { - | ~~~~~~~~~~ + | ~~~~ +help: box the return type, and wrap all of the returned values in `Box::new` + | +LL ~ fn bat() -> Box<dyn Trait> { +LL | if true { +LL ~ return Box::new(0); +LL | } +LL ~ Box::new(42) + | error[E0746]: return type cannot have an unboxed trait object --> $DIR/dyn-trait-return-should-be-impl-trait.rs:66:13 @@ -291,13 +280,20 @@ error[E0746]: return type cannot have an unboxed trait object LL | fn bay() -> dyn Trait { | ^^^^^^^^^ doesn't have a size known at compile-time | - = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> -help: use `impl Trait` as the return type, as all return paths are of type `{integer}`, which implements `Trait` +help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type | LL | fn bay() -> impl Trait { - | ~~~~~~~~~~ + | ~~~~ +help: box the return type, and wrap all of the returned values in `Box::new` + | +LL ~ fn bay() -> Box<dyn Trait> { +LL | if true { +LL ~ Box::new(0) +LL | } else { +LL ~ Box::new(42) + | -error: aborting due to 20 previous errors +error: aborting due to 19 previous errors Some errors have detailed explanations: E0277, E0308, E0746. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.rs b/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.rs index fa7664a83ee..a8a6288eb56 100644 --- a/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.rs +++ b/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.rs @@ -77,7 +77,7 @@ fn hat() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed fn pug() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object match 13 { 0 => 0i32, - 1 => 1u32, //~ ERROR `match` arms have incompatible types + 1 => 1u32, _ => 2u32, } } @@ -86,7 +86,7 @@ fn man() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed if false { 0i32 } else { - 1u32 //~ ERROR `if` and `else` have incompatible types + 1u32 } } diff --git a/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr b/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr index 3c65fd998c5..9205d74504f 100644 --- a/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr +++ b/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr @@ -171,39 +171,20 @@ error[E0746]: return type cannot have an unboxed trait object LL | fn hat() -> dyn std::fmt::Display { | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types> - = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type - = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> - = note: you can create a new `enum` with a variant for each returned type -help: return a boxed trait object instead - | -LL | fn hat() -> Box<dyn std::fmt::Display> { - | ++++ + -help: ... and box this value - | -LL | return Box::new(0i32); - | +++++++++ + -help: ... and box this value - | -LL | Box::new(1u32) - | +++++++++ + - -error[E0308]: `match` arms have incompatible types - --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:80:14 +help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type | -LL | / match 13 { -LL | | 0 => 0i32, - | | ---- this is found to be of type `i32` -LL | | 1 => 1u32, - | | ^^^^ expected `i32`, found `u32` -LL | | _ => 2u32, -LL | | } - | |_____- `match` arms have incompatible types +LL | fn hat() -> impl std::fmt::Display { + | ~~~~ +help: box the return type, and wrap all of the returned values in `Box::new` | -help: change the type of the numeric literal from `u32` to `i32` +LL ~ fn hat() -> Box<dyn std::fmt::Display> { +LL | match 13 { +LL | 0 => { +LL ~ return Box::new(0i32); +LL | } +LL | _ => { +LL ~ Box::new(1u32) | -LL | 1 => 1i32, - | ~~~ error[E0746]: return type cannot have an unboxed trait object --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:77:13 @@ -211,43 +192,18 @@ error[E0746]: return type cannot have an unboxed trait object LL | fn pug() -> dyn std::fmt::Display { | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types> - = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type - = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> - = note: you can create a new `enum` with a variant for each returned type -help: return a boxed trait object instead - | -LL | fn pug() -> Box<dyn std::fmt::Display> { - | ++++ + -help: ... and box this value +help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type | -LL | 0 => Box::new(0i32), - | +++++++++ + -help: ... and box this value - | -LL | 1 => Box::new(1u32), - | +++++++++ + -help: ... and box this value - | -LL | _ => Box::new(2u32), - | +++++++++ + - -error[E0308]: `if` and `else` have incompatible types - --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:89:9 +LL | fn pug() -> impl std::fmt::Display { + | ~~~~ +help: box the return type, and wrap all of the returned values in `Box::new` | -LL | / if false { -LL | | 0i32 - | | ---- expected because of this -LL | | } else { -LL | | 1u32 - | | ^^^^ expected `i32`, found `u32` -LL | | } - | |_____- `if` and `else` have incompatible types - | -help: change the type of the numeric literal from `u32` to `i32` +LL ~ fn pug() -> Box<dyn std::fmt::Display> { +LL | match 13 { +LL ~ 0 => Box::new(0i32), +LL ~ 1 => Box::new(1u32), +LL ~ _ => Box::new(2u32), | -LL | 1i32 - | ~~~ error[E0746]: return type cannot have an unboxed trait object --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:85:13 @@ -255,24 +211,20 @@ error[E0746]: return type cannot have an unboxed trait object LL | fn man() -> dyn std::fmt::Display { | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types> - = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type - = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> - = note: you can create a new `enum` with a variant for each returned type -help: return a boxed trait object instead +help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type | -LL | fn man() -> Box<dyn std::fmt::Display> { - | ++++ + -help: ... and box this value +LL | fn man() -> impl std::fmt::Display { + | ~~~~ +help: box the return type, and wrap all of the returned values in `Box::new` | -LL | Box::new(0i32) - | +++++++++ + -help: ... and box this value +LL ~ fn man() -> Box<dyn std::fmt::Display> { +LL | if false { +LL ~ Box::new(0i32) +LL | } else { +LL ~ Box::new(1u32) | -LL | Box::new(1u32) - | +++++++++ + -error: aborting due to 14 previous errors +error: aborting due to 12 previous errors Some errors have detailed explanations: E0308, E0746. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/imports/issue-109148.rs b/tests/ui/imports/issue-109148.rs new file mode 100644 index 00000000000..694cb494a15 --- /dev/null +++ b/tests/ui/imports/issue-109148.rs @@ -0,0 +1,15 @@ +// edition: 2021 + +// https://github.com/rust-lang/rust/pull/111761#issuecomment-1557777314 +macro_rules! m { + () => { + extern crate core as std; + //~^ ERROR macro-expanded `extern crate` items cannot shadow names passed with `--extern` + } +} + +m!(); + +use std::mem; + +fn main() {} diff --git a/tests/ui/imports/issue-109148.stderr b/tests/ui/imports/issue-109148.stderr new file mode 100644 index 00000000000..6cc1221cfe9 --- /dev/null +++ b/tests/ui/imports/issue-109148.stderr @@ -0,0 +1,13 @@ +error: macro-expanded `extern crate` items cannot shadow names passed with `--extern` + --> $DIR/issue-109148.rs:6:9 + | +LL | extern crate core as std; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | m!(); + | ---- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/tests/ui/imports/issue-109343.rs b/tests/ui/imports/issue-109343.rs new file mode 100644 index 00000000000..0c10259bcd7 --- /dev/null +++ b/tests/ui/imports/issue-109343.rs @@ -0,0 +1,10 @@ +#![crate_type = "lib"] + +pub mod f {} +pub use unresolved::f; +//~^ ERROR unresolved import `unresolved` + +/// [g] +pub use f as g; + +fn main() {} diff --git a/tests/ui/imports/issue-109343.stderr b/tests/ui/imports/issue-109343.stderr new file mode 100644 index 00000000000..8d9a3aee980 --- /dev/null +++ b/tests/ui/imports/issue-109343.stderr @@ -0,0 +1,11 @@ +error[E0432]: unresolved import `unresolved` + --> $DIR/issue-109343.rs:4:9 + | +LL | pub use unresolved::f; + | ^^^^^^^^^^ maybe a missing crate `unresolved`? + | + = help: consider adding `extern crate unresolved` to use the `unresolved` crate + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/invalid/foo.natvis.xml b/tests/ui/invalid/foo.natvis.xml new file mode 100644 index 00000000000..c341a403902 --- /dev/null +++ b/tests/ui/invalid/foo.natvis.xml @@ -0,0 +1 @@ +<!-- empty --> diff --git a/tests/ui/invalid/invalid-debugger-visualizer-target.rs b/tests/ui/invalid/invalid-debugger-visualizer-target.rs index f9dd20dbfed..1efb9555c24 100644 --- a/tests/ui/invalid/invalid-debugger-visualizer-target.rs +++ b/tests/ui/invalid/invalid-debugger-visualizer-target.rs @@ -1,2 +1,2 @@ -#[debugger_visualizer(natvis_file = "../foo.natvis")] //~ ERROR attribute should be applied to a module +#[debugger_visualizer(natvis_file = "./foo.natvis.xml")] //~ ERROR attribute should be applied to a module fn main() {} diff --git a/tests/ui/invalid/invalid-debugger-visualizer-target.stderr b/tests/ui/invalid/invalid-debugger-visualizer-target.stderr index 7944f751859..c8a4d681379 100644 --- a/tests/ui/invalid/invalid-debugger-visualizer-target.stderr +++ b/tests/ui/invalid/invalid-debugger-visualizer-target.stderr @@ -1,8 +1,8 @@ error: attribute should be applied to a module --> $DIR/invalid-debugger-visualizer-target.rs:1:1 | -LL | #[debugger_visualizer(natvis_file = "../foo.natvis")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[debugger_visualizer(natvis_file = "./foo.natvis.xml")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/tests/ui/issues/issue-18107.stderr b/tests/ui/issues/issue-18107.stderr index 1669b550a9b..cf4e06316a7 100644 --- a/tests/ui/issues/issue-18107.stderr +++ b/tests/ui/issues/issue-18107.stderr @@ -4,14 +4,18 @@ error[E0746]: return type cannot have an unboxed trait object LL | dyn AbstractRenderer | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | -help: use `impl AbstractRenderer` as the return type if all return paths have the same type but you want to expose only the trait in the signature +help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type | LL | impl AbstractRenderer + | ~~~~ +help: box the return type, and wrap all of the returned values in `Box::new` | -help: use a boxed trait object if all return paths implement trait `AbstractRenderer` +LL ~ Box<dyn AbstractRenderer> +LL | +LL | { +LL | match 0 { +LL ~ _ => Box::new(unimplemented!()) | -LL | Box<dyn AbstractRenderer> - | ++++ + error: aborting due to previous error diff --git a/tests/ui/iterators/collect-into-slice.rs b/tests/ui/iterators/collect-into-slice.rs index 5a8aacb1a6d..045d40a6f71 100644 --- a/tests/ui/iterators/collect-into-slice.rs +++ b/tests/ui/iterators/collect-into-slice.rs @@ -14,4 +14,10 @@ fn main() { //~| NOTE doesn't have a size known at compile-time //~| NOTE doesn't have a size known at compile-time process_slice(&some_generated_vec); + + let some_generated_vec = (0..10).collect(); + //~^ ERROR a slice of type `&[i32]` cannot be built since we need to store the elements somewhere + //~| NOTE try explicitly collecting into a `Vec<{integer}>` + //~| NOTE required by a bound in `collect` + process_slice(some_generated_vec); } diff --git a/tests/ui/iterators/collect-into-slice.stderr b/tests/ui/iterators/collect-into-slice.stderr index 29fff8c51c6..07dc561f06a 100644 --- a/tests/ui/iterators/collect-into-slice.stderr +++ b/tests/ui/iterators/collect-into-slice.stderr @@ -28,6 +28,16 @@ LL | let some_generated_vec = (0..10).collect(); note: required by a bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL -error: aborting due to 3 previous errors +error[E0277]: a slice of type `&[i32]` cannot be built since we need to store the elements somewhere + --> $DIR/collect-into-slice.rs:18:38 + | +LL | let some_generated_vec = (0..10).collect(); + | ^^^^^^^ try explicitly collecting into a `Vec<{integer}>` + | + = help: the trait `FromIterator<{integer}>` is not implemented for `&[i32]` +note: required by a bound in `collect` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/lint/drop_copy.rs b/tests/ui/lint/dropping_copy_types.rs index 0adcd34505f..2937320e5d8 100644 --- a/tests/ui/lint/drop_copy.rs +++ b/tests/ui/lint/dropping_copy_types.rs @@ -1,6 +1,6 @@ // check-pass -#![warn(drop_copy)] +#![warn(dropping_copy_types)] use std::mem::drop; use std::vec::Vec; diff --git a/tests/ui/lint/drop_copy.stderr b/tests/ui/lint/dropping_copy_types.stderr index db8e89ad295..b6291aa5ed6 100644 --- a/tests/ui/lint/drop_copy.stderr +++ b/tests/ui/lint/dropping_copy_types.stderr @@ -1,5 +1,5 @@ warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing - --> $DIR/drop_copy.rs:34:5 + --> $DIR/dropping_copy_types.rs:34:5 | LL | drop(s1); | ^^^^^--^ @@ -8,13 +8,13 @@ LL | drop(s1); | = note: use `let _ = ...` to ignore the expression or result note: the lint level is defined here - --> $DIR/drop_copy.rs:3:9 + --> $DIR/dropping_copy_types.rs:3:9 | -LL | #![warn(drop_copy)] - | ^^^^^^^^^ +LL | #![warn(dropping_copy_types)] + | ^^^^^^^^^^^^^^^^^^^ warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing - --> $DIR/drop_copy.rs:35:5 + --> $DIR/dropping_copy_types.rs:35:5 | LL | drop(s2); | ^^^^^--^ @@ -24,7 +24,7 @@ LL | drop(s2); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing - --> $DIR/drop_copy.rs:36:5 + --> $DIR/dropping_copy_types.rs:36:5 | LL | drop(s3); | ^^^^^--^ @@ -32,10 +32,10 @@ LL | drop(s3); | argument has type `&SomeStruct` | = note: use `let _ = ...` to ignore the expression or result - = note: `#[warn(drop_ref)]` on by default + = note: `#[warn(dropping_references)]` on by default warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing - --> $DIR/drop_copy.rs:37:5 + --> $DIR/dropping_copy_types.rs:37:5 | LL | drop(s4); | ^^^^^--^ @@ -45,7 +45,7 @@ LL | drop(s4); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing - --> $DIR/drop_copy.rs:38:5 + --> $DIR/dropping_copy_types.rs:38:5 | LL | drop(s5); | ^^^^^--^ @@ -55,7 +55,7 @@ LL | drop(s5); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing - --> $DIR/drop_copy.rs:50:5 + --> $DIR/dropping_copy_types.rs:50:5 | LL | drop(a2); | ^^^^^--^ @@ -65,7 +65,7 @@ LL | drop(a2); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing - --> $DIR/drop_copy.rs:52:5 + --> $DIR/dropping_copy_types.rs:52:5 | LL | drop(a4); | ^^^^^--^ @@ -75,7 +75,7 @@ LL | drop(a4); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing - --> $DIR/drop_copy.rs:71:13 + --> $DIR/dropping_copy_types.rs:71:13 | LL | drop(println_and(13)); | ^^^^^---------------^ @@ -85,7 +85,7 @@ LL | drop(println_and(13)); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing - --> $DIR/drop_copy.rs:74:14 + --> $DIR/dropping_copy_types.rs:74:14 | LL | 3 if drop(println_and(14)) == () => (), | ^^^^^---------------^ @@ -95,7 +95,7 @@ LL | 3 if drop(println_and(14)) == () => (), = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing - --> $DIR/drop_copy.rs:76:14 + --> $DIR/dropping_copy_types.rs:76:14 | LL | 4 => drop(2), | ^^^^^-^ diff --git a/tests/ui/lint/drop_ref.rs b/tests/ui/lint/dropping_references.rs index db4f7569f6f..0d5d484f451 100644 --- a/tests/ui/lint/drop_ref.rs +++ b/tests/ui/lint/dropping_references.rs @@ -1,6 +1,6 @@ // check-pass -#![warn(drop_ref)] +#![warn(dropping_references)] struct SomeStruct; diff --git a/tests/ui/lint/drop_ref.stderr b/tests/ui/lint/dropping_references.stderr index 04c988fe99d..7e25a46216e 100644 --- a/tests/ui/lint/drop_ref.stderr +++ b/tests/ui/lint/dropping_references.stderr @@ -1,5 +1,5 @@ warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing - --> $DIR/drop_ref.rs:8:5 + --> $DIR/dropping_references.rs:8:5 | LL | drop(&SomeStruct); | ^^^^^-----------^ @@ -8,13 +8,13 @@ LL | drop(&SomeStruct); | = note: use `let _ = ...` to ignore the expression or result note: the lint level is defined here - --> $DIR/drop_ref.rs:3:9 + --> $DIR/dropping_references.rs:3:9 | -LL | #![warn(drop_ref)] - | ^^^^^^^^ +LL | #![warn(dropping_references)] + | ^^^^^^^^^^^^^^^^^^^ warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing - --> $DIR/drop_ref.rs:11:5 + --> $DIR/dropping_references.rs:11:5 | LL | drop(&owned1); | ^^^^^-------^ @@ -24,7 +24,7 @@ LL | drop(&owned1); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing - --> $DIR/drop_ref.rs:12:5 + --> $DIR/dropping_references.rs:12:5 | LL | drop(&&owned1); | ^^^^^--------^ @@ -34,7 +34,7 @@ LL | drop(&&owned1); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing - --> $DIR/drop_ref.rs:13:5 + --> $DIR/dropping_references.rs:13:5 | LL | drop(&mut owned1); | ^^^^^-----------^ @@ -44,7 +44,7 @@ LL | drop(&mut owned1); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing - --> $DIR/drop_ref.rs:17:5 + --> $DIR/dropping_references.rs:17:5 | LL | drop(reference1); | ^^^^^----------^ @@ -54,7 +54,7 @@ LL | drop(reference1); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing - --> $DIR/drop_ref.rs:20:5 + --> $DIR/dropping_references.rs:20:5 | LL | drop(reference2); | ^^^^^----------^ @@ -64,7 +64,7 @@ LL | drop(reference2); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing - --> $DIR/drop_ref.rs:23:5 + --> $DIR/dropping_references.rs:23:5 | LL | drop(reference3); | ^^^^^----------^ @@ -74,7 +74,7 @@ LL | drop(reference3); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing - --> $DIR/drop_ref.rs:28:5 + --> $DIR/dropping_references.rs:28:5 | LL | drop(&val); | ^^^^^----^ @@ -84,7 +84,7 @@ LL | drop(&val); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing - --> $DIR/drop_ref.rs:36:5 + --> $DIR/dropping_references.rs:36:5 | LL | std::mem::drop(&SomeStruct); | ^^^^^^^^^^^^^^^-----------^ @@ -94,7 +94,7 @@ LL | std::mem::drop(&SomeStruct); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing - --> $DIR/drop_ref.rs:91:13 + --> $DIR/dropping_references.rs:91:13 | LL | drop(println_and(&13)); | ^^^^^----------------^ @@ -104,7 +104,7 @@ LL | drop(println_and(&13)); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing - --> $DIR/drop_ref.rs:94:14 + --> $DIR/dropping_references.rs:94:14 | LL | 3 if drop(println_and(&14)) == () => (), | ^^^^^----------------^ @@ -114,7 +114,7 @@ LL | 3 if drop(println_and(&14)) == () => (), = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing - --> $DIR/drop_ref.rs:96:14 + --> $DIR/dropping_references.rs:96:14 | LL | 4 => drop(&2), | ^^^^^--^ diff --git a/tests/ui/lint/forget_copy.rs b/tests/ui/lint/forgetting_copy_types.rs index a6b17b76971..224c7bcd5f6 100644 --- a/tests/ui/lint/forget_copy.rs +++ b/tests/ui/lint/forgetting_copy_types.rs @@ -1,6 +1,6 @@ // check-pass -#![warn(forget_copy)] +#![warn(forgetting_copy_types)] use std::mem::forget; use std::vec::Vec; diff --git a/tests/ui/lint/forget_copy.stderr b/tests/ui/lint/forgetting_copy_types.stderr index 37bc8a8854e..36d1ef5c53e 100644 --- a/tests/ui/lint/forget_copy.stderr +++ b/tests/ui/lint/forgetting_copy_types.stderr @@ -1,5 +1,5 @@ warning: calls to `std::mem::forget` with a value that implements `Copy` does nothing - --> $DIR/forget_copy.rs:34:5 + --> $DIR/forgetting_copy_types.rs:34:5 | LL | forget(s1); | ^^^^^^^--^ @@ -8,13 +8,13 @@ LL | forget(s1); | = note: use `let _ = ...` to ignore the expression or result note: the lint level is defined here - --> $DIR/forget_copy.rs:3:9 + --> $DIR/forgetting_copy_types.rs:3:9 | -LL | #![warn(forget_copy)] - | ^^^^^^^^^^^ +LL | #![warn(forgetting_copy_types)] + | ^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::mem::forget` with a value that implements `Copy` does nothing - --> $DIR/forget_copy.rs:35:5 + --> $DIR/forgetting_copy_types.rs:35:5 | LL | forget(s2); | ^^^^^^^--^ @@ -24,7 +24,7 @@ LL | forget(s2); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing - --> $DIR/forget_copy.rs:36:5 + --> $DIR/forgetting_copy_types.rs:36:5 | LL | forget(s3); | ^^^^^^^--^ @@ -32,10 +32,10 @@ LL | forget(s3); | argument has type `&SomeStruct` | = note: use `let _ = ...` to ignore the expression or result - = note: `#[warn(forget_ref)]` on by default + = note: `#[warn(forgetting_references)]` on by default warning: calls to `std::mem::forget` with a value that implements `Copy` does nothing - --> $DIR/forget_copy.rs:37:5 + --> $DIR/forgetting_copy_types.rs:37:5 | LL | forget(s4); | ^^^^^^^--^ @@ -45,7 +45,7 @@ LL | forget(s4); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing - --> $DIR/forget_copy.rs:38:5 + --> $DIR/forgetting_copy_types.rs:38:5 | LL | forget(s5); | ^^^^^^^--^ @@ -55,7 +55,7 @@ LL | forget(s5); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing - --> $DIR/forget_copy.rs:50:5 + --> $DIR/forgetting_copy_types.rs:50:5 | LL | forget(a2); | ^^^^^^^--^ @@ -65,7 +65,7 @@ LL | forget(a2); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing - --> $DIR/forget_copy.rs:52:5 + --> $DIR/forgetting_copy_types.rs:52:5 | LL | forget(a3); | ^^^^^^^--^ @@ -75,7 +75,7 @@ LL | forget(a3); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing - --> $DIR/forget_copy.rs:53:5 + --> $DIR/forgetting_copy_types.rs:53:5 | LL | forget(a4); | ^^^^^^^--^ diff --git a/tests/ui/lint/forget_ref.rs b/tests/ui/lint/forgetting_references.rs index 13f6d4be3d1..bd51e980031 100644 --- a/tests/ui/lint/forget_ref.rs +++ b/tests/ui/lint/forgetting_references.rs @@ -1,6 +1,6 @@ // check-pass -#![warn(forget_ref)] +#![warn(forgetting_references)] use std::mem::forget; diff --git a/tests/ui/lint/forget_ref.stderr b/tests/ui/lint/forgetting_references.stderr index 63fc7791980..5624b690789 100644 --- a/tests/ui/lint/forget_ref.stderr +++ b/tests/ui/lint/forgetting_references.stderr @@ -1,5 +1,5 @@ warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing - --> $DIR/forget_ref.rs:10:5 + --> $DIR/forgetting_references.rs:10:5 | LL | forget(&SomeStruct); | ^^^^^^^-----------^ @@ -8,13 +8,13 @@ LL | forget(&SomeStruct); | = note: use `let _ = ...` to ignore the expression or result note: the lint level is defined here - --> $DIR/forget_ref.rs:3:9 + --> $DIR/forgetting_references.rs:3:9 | -LL | #![warn(forget_ref)] - | ^^^^^^^^^^ +LL | #![warn(forgetting_references)] + | ^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing - --> $DIR/forget_ref.rs:13:5 + --> $DIR/forgetting_references.rs:13:5 | LL | forget(&owned); | ^^^^^^^------^ @@ -24,7 +24,7 @@ LL | forget(&owned); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing - --> $DIR/forget_ref.rs:14:5 + --> $DIR/forgetting_references.rs:14:5 | LL | forget(&&owned); | ^^^^^^^-------^ @@ -34,7 +34,7 @@ LL | forget(&&owned); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing - --> $DIR/forget_ref.rs:15:5 + --> $DIR/forgetting_references.rs:15:5 | LL | forget(&mut owned); | ^^^^^^^----------^ @@ -44,7 +44,7 @@ LL | forget(&mut owned); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing - --> $DIR/forget_ref.rs:19:5 + --> $DIR/forgetting_references.rs:19:5 | LL | forget(&*reference1); | ^^^^^^^------------^ @@ -54,7 +54,7 @@ LL | forget(&*reference1); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing - --> $DIR/forget_ref.rs:22:5 + --> $DIR/forgetting_references.rs:22:5 | LL | forget(reference2); | ^^^^^^^----------^ @@ -64,7 +64,7 @@ LL | forget(reference2); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing - --> $DIR/forget_ref.rs:25:5 + --> $DIR/forgetting_references.rs:25:5 | LL | forget(reference3); | ^^^^^^^----------^ @@ -74,7 +74,7 @@ LL | forget(reference3); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing - --> $DIR/forget_ref.rs:30:5 + --> $DIR/forgetting_references.rs:30:5 | LL | forget(&val); | ^^^^^^^----^ @@ -84,7 +84,7 @@ LL | forget(&val); = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing - --> $DIR/forget_ref.rs:38:5 + --> $DIR/forgetting_references.rs:38:5 | LL | std::mem::forget(&SomeStruct); | ^^^^^^^^^^^^^^^^^-----------^ diff --git a/tests/ui/lint/unused/auxiliary/must-use-foreign.rs b/tests/ui/lint/unused/auxiliary/must-use-foreign.rs new file mode 100644 index 00000000000..f773f09c382 --- /dev/null +++ b/tests/ui/lint/unused/auxiliary/must-use-foreign.rs @@ -0,0 +1,12 @@ +// edition:2021 + +use std::future::Future; + +pub struct Manager; + +impl Manager { + #[must_use] + pub async fn new() -> (Self, impl Future<Output = ()>) { + (Manager, async {}) + } +} diff --git a/tests/ui/lint/unused/must-use-foreign.rs b/tests/ui/lint/unused/must-use-foreign.rs new file mode 100644 index 00000000000..21a11058562 --- /dev/null +++ b/tests/ui/lint/unused/must-use-foreign.rs @@ -0,0 +1,15 @@ +// edition:2021 +// aux-build:must-use-foreign.rs +// check-pass + +extern crate must_use_foreign; + +use must_use_foreign::Manager; + +async fn async_main() { + Manager::new().await.1.await; +} + +fn main() { + let _ = async_main(); +} diff --git a/tests/ui/lint/unused/unused-async.rs b/tests/ui/lint/unused/unused-async.rs index 4be93aa155a..6355f47f037 100644 --- a/tests/ui/lint/unused/unused-async.rs +++ b/tests/ui/lint/unused/unused-async.rs @@ -33,7 +33,7 @@ async fn test() { foo().await; //~ ERROR unused output of future returned by `foo` that must be used bar(); //~ ERROR unused return value of `bar` that must be used //~^ ERROR unused implementer of `Future` that must be used - bar().await; //~ ERROR unused output of future returned by `bar` that must be used + bar().await; // ok, it's not an async fn baz(); //~ ERROR unused implementer of `Future` that must be used baz().await; // ok } diff --git a/tests/ui/lint/unused/unused-async.stderr b/tests/ui/lint/unused/unused-async.stderr index 1c3702ba265..e93a40658f3 100644 --- a/tests/ui/lint/unused/unused-async.stderr +++ b/tests/ui/lint/unused/unused-async.stderr @@ -52,17 +52,6 @@ help: use `let _ = ...` to ignore the resulting value LL | let _ = bar(); | +++++++ -error: unused output of future returned by `bar` that must be used - --> $DIR/unused-async.rs:36:5 - | -LL | bar().await; - | ^^^^^^^^^^^ - | -help: use `let _ = ...` to ignore the resulting value - | -LL | let _ = bar().await; - | +++++++ - error: unused implementer of `Future` that must be used --> $DIR/unused-async.rs:37:5 | @@ -71,5 +60,5 @@ LL | baz(); | = note: futures do nothing unless you `.await` or poll them -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/liveness/liveness-unused.rs b/tests/ui/liveness/liveness-unused.rs index 8ef6ab1b6ff..ba635e6638c 100644 --- a/tests/ui/liveness/liveness-unused.rs +++ b/tests/ui/liveness/liveness-unused.rs @@ -1,7 +1,7 @@ #![warn(unused)] #![deny(unused_variables)] #![deny(unused_assignments)] -#![allow(dead_code, non_camel_case_types, trivial_numeric_casts, drop_copy)] +#![allow(dead_code, non_camel_case_types, trivial_numeric_casts, dropping_copy_types)] use std::ops::AddAssign; diff --git a/tests/ui/macros/issue-111749.rs b/tests/ui/macros/issue-111749.rs new file mode 100644 index 00000000000..6c45e4e8cd7 --- /dev/null +++ b/tests/ui/macros/issue-111749.rs @@ -0,0 +1,12 @@ +macro_rules! cbor_map { + ($key:expr) => { + $key.signum(); + }; +} + +fn main() { + cbor_map! { #[test(test)] 4}; + //~^ ERROR removing an expression is not supported in this position + //~| ERROR attribute must be of the form `#[test]` + //~| WARNING this was previously accepted by the compiler but is being phased out +} diff --git a/tests/ui/macros/issue-111749.stderr b/tests/ui/macros/issue-111749.stderr new file mode 100644 index 00000000000..7db2b8e6ad1 --- /dev/null +++ b/tests/ui/macros/issue-111749.stderr @@ -0,0 +1,18 @@ +error: removing an expression is not supported in this position + --> $DIR/issue-111749.rs:8:17 + | +LL | cbor_map! { #[test(test)] 4}; + | ^^^^^^^^^^^^^ + +error: attribute must be of the form `#[test]` + --> $DIR/issue-111749.rs:8:17 + | +LL | cbor_map! { #[test(test)] 4}; + | ^^^^^^^^^^^^^ + | + = 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 #57571 <https://github.com/rust-lang/rust/issues/57571> + = note: `#[deny(ill_formed_attribute_input)]` on by default + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/panic-temporaries-2018.rs b/tests/ui/macros/panic-temporaries-2018.rs new file mode 100644 index 00000000000..d914df38062 --- /dev/null +++ b/tests/ui/macros/panic-temporaries-2018.rs @@ -0,0 +1,55 @@ +// check-pass +// edition:2018 + +#![allow(non_fmt_panics, unreachable_code)] + +use std::fmt::{self, Display}; +use std::marker::PhantomData; + +struct NotSend { + marker: PhantomData<*const u8>, +} + +const NOT_SEND: NotSend = NotSend { marker: PhantomData }; + +impl Display for NotSend { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("this value does not implement Send") + } +} + +async fn f(_: u8) {} + +// Exercises this matcher in panic_2015: +// ($fmt:expr, $($arg:tt)+) => $crate::panicking::panic_fmt(...) +async fn panic_fmt() { + // Panic returns `!`, so the await is never reached, and in particular the + // temporaries inside the formatting machinery are not still alive at the + // await point. + let todo = "..."; + f(panic!("not yet implemented: {}", todo)).await; +} + +// Exercises ("{}", $arg:expr) => $crate::panicking::panic_display(&$arg) +async fn panic_display() { + f(panic!("{}", NOT_SEND)).await; +} + +// Exercises ($msg:expr) => $crate::panicking::panic_str($msg) +async fn panic_str() { + f(panic!((NOT_SEND, "...").1)).await; +} + +// Exercises ($msg:expr) => $crate::panicking::unreachable_display(&$msg) +async fn unreachable_display() { + f(unreachable!(NOT_SEND)).await; +} + +fn require_send(_: impl Send) {} + +fn main() { + require_send(panic_fmt()); + require_send(panic_display()); + require_send(panic_str()); + require_send(unreachable_display()); +} diff --git a/tests/ui/macros/panic-temporaries.rs b/tests/ui/macros/panic-temporaries.rs index 5b5b8b7c2d9..db65601fb73 100644 --- a/tests/ui/macros/panic-temporaries.rs +++ b/tests/ui/macros/panic-temporaries.rs @@ -3,17 +3,41 @@ #![allow(unreachable_code)] +use std::fmt::{self, Display}; +use std::marker::PhantomData; + +struct NotSend { + marker: PhantomData<*const u8>, +} + +const NOT_SEND: NotSend = NotSend { marker: PhantomData }; + +impl Display for NotSend { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("this value does not implement Send") + } +} + async fn f(_: u8) {} -async fn g() { - // Todo returns `!`, so the await is never reached, and in particular the +// Exercises this matcher in panic_2021: +// ($($t:tt)+) => $crate::panicking::panic_fmt(...) +async fn panic_fmt() { + // Panic returns `!`, so the await is never reached, and in particular the // temporaries inside the formatting machinery are not still alive at the // await point. - f(todo!("...")).await; + let todo = "..."; + f(panic!("not yet implemented: {}", todo)).await; +} + +// Exercises ("{}", $arg:expr) => $crate::panicking::panic_display(&$arg) +async fn panic_display() { + f(panic!("{}", NOT_SEND)).await; } fn require_send(_: impl Send) {} fn main() { - require_send(g()); + require_send(panic_fmt()); + require_send(panic_display()); } diff --git a/tests/ui/macros/parse-complex-macro-invoc-op.rs b/tests/ui/macros/parse-complex-macro-invoc-op.rs index c50dfdf0116..10810388d20 100644 --- a/tests/ui/macros/parse-complex-macro-invoc-op.rs +++ b/tests/ui/macros/parse-complex-macro-invoc-op.rs @@ -4,7 +4,7 @@ #![allow(unused_assignments)] #![allow(unused_variables)] #![allow(stable_features)] -#![allow(drop_copy)] +#![allow(dropping_copy_types)] // Test parsing binary operators after macro invocations. diff --git a/tests/ui/never_type/never-assign-dead-code.rs b/tests/ui/never_type/never-assign-dead-code.rs index e95a992d780..39df7de5a7f 100644 --- a/tests/ui/never_type/never-assign-dead-code.rs +++ b/tests/ui/never_type/never-assign-dead-code.rs @@ -3,7 +3,7 @@ // check-pass #![feature(never_type)] -#![allow(drop_copy)] +#![allow(dropping_copy_types)] #![warn(unused)] fn main() { diff --git a/tests/ui/nll/relate_tys/hr-fn-aba-as-aaa.rs b/tests/ui/nll/relate_tys/hr-fn-aba-as-aaa.rs index 73ceaeeb875..2e9eff59386 100644 --- a/tests/ui/nll/relate_tys/hr-fn-aba-as-aaa.rs +++ b/tests/ui/nll/relate_tys/hr-fn-aba-as-aaa.rs @@ -5,7 +5,7 @@ // check-pass // compile-flags:-Zno-leak-check -#![allow(drop_copy)] +#![allow(dropping_copy_types)] fn make_it() -> for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 { panic!() diff --git a/tests/ui/nll/ty-outlives/projection-body.rs b/tests/ui/nll/ty-outlives/projection-body.rs index bff9058a507..722d6747102 100644 --- a/tests/ui/nll/ty-outlives/projection-body.rs +++ b/tests/ui/nll/ty-outlives/projection-body.rs @@ -3,7 +3,7 @@ // // check-pass -#![allow(drop_ref)] +#![allow(dropping_references)] trait MyTrait<'a> { type Output; diff --git a/tests/ui/offset-of/offset-of-arg-count.rs b/tests/ui/offset-of/offset-of-arg-count.rs index 5e66e33f8a2..31de45bc756 100644 --- a/tests/ui/offset-of/offset-of-arg-count.rs +++ b/tests/ui/offset-of/offset-of-arg-count.rs @@ -12,6 +12,11 @@ fn main() { offset_of!(S, f.,); //~ ERROR expected identifier offset_of!(S, f..); //~ ERROR no rules expected the token offset_of!(S, f..,); //~ ERROR no rules expected the token + offset_of!(Lt<'static>, bar); // issue #111657 + offset_of!(Lt<'_>, bar); // issue #111678 } struct S { f: u8, } +struct Lt<'a> { + bar: &'a (), +} diff --git a/tests/ui/offset-of/offset-of-dst-field.rs b/tests/ui/offset-of/offset-of-dst-field.rs index a0269ca2d12..3b8dc0b84a4 100644 --- a/tests/ui/offset-of/offset-of-dst-field.rs +++ b/tests/ui/offset-of/offset-of-dst-field.rs @@ -26,8 +26,24 @@ struct Gamma { z: Extern, } +struct Delta<T: ?Sized> { + x: u8, + y: u16, + z: T, +} + fn main() { offset_of!(Alpha, z); //~ ERROR the size for values of type offset_of!(Beta, z); //~ ERROR the size for values of type offset_of!(Gamma, z); //~ ERROR the size for values of type } + +fn delta() { + offset_of!(Delta<Alpha>, z); //~ ERROR the size for values of type + offset_of!(Delta<Extern>, z); //~ ERROR the size for values of type + offset_of!(Delta<dyn Trait>, z); //~ ERROR the size for values of type +} + +fn generic_with_maybe_sized<T: ?Sized>() -> usize { + offset_of!(Delta<T>, z) //~ ERROR the size for values of type +} diff --git a/tests/ui/offset-of/offset-of-dst-field.stderr b/tests/ui/offset-of/offset-of-dst-field.stderr index e6e0f499236..128c783d5dd 100644 --- a/tests/ui/offset-of/offset-of-dst-field.stderr +++ b/tests/ui/offset-of/offset-of-dst-field.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/offset-of-dst-field.rs:30:5 + --> $DIR/offset-of-dst-field.rs:36:5 | LL | offset_of!(Alpha, z); | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -8,7 +8,7 @@ LL | offset_of!(Alpha, z); = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time - --> $DIR/offset-of-dst-field.rs:31:5 + --> $DIR/offset-of-dst-field.rs:37:5 | LL | offset_of!(Beta, z); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -17,7 +17,7 @@ LL | offset_of!(Beta, z); = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `Extern` cannot be known at compilation time - --> $DIR/offset-of-dst-field.rs:32:5 + --> $DIR/offset-of-dst-field.rs:38:5 | LL | offset_of!(Gamma, z); | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -25,6 +25,53 @@ LL | offset_of!(Gamma, z); = help: the trait `Sized` is not implemented for `Extern` = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 3 previous errors +error[E0277]: the size for values of type `Extern` cannot be known at compilation time + --> $DIR/offset-of-dst-field.rs:43:5 + | +LL | offset_of!(Delta<Extern>, z); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `Extern` + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time + --> $DIR/offset-of-dst-field.rs:44:5 + | +LL | offset_of!(Delta<dyn Trait>, z); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `dyn Trait` + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/offset-of-dst-field.rs:42:5 + | +LL | offset_of!(Delta<Alpha>, z); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `Alpha`, the trait `Sized` is not implemented for `[u8]` +note: required because it appears within the type `Alpha` + --> $DIR/offset-of-dst-field.rs:5:8 + | +LL | struct Alpha { + | ^^^^^ + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/offset-of-dst-field.rs:48:5 + | +LL | fn generic_with_maybe_sized<T: ?Sized>() -> usize { + | - this type parameter needs to be `std::marker::Sized` +LL | offset_of!(Delta<T>, z) + | ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn generic_with_maybe_sized<T: ?Sized>() -> usize { +LL + fn generic_with_maybe_sized<T>() -> usize { + | + +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/offset-of/offset-of-inference.rs b/tests/ui/offset-of/offset-of-inference.rs new file mode 100644 index 00000000000..ba87574eae0 --- /dev/null +++ b/tests/ui/offset-of/offset-of-inference.rs @@ -0,0 +1,11 @@ +// Test that inference types in `offset_of!` don't ICE. + +#![feature(offset_of)] + +struct Foo<T> { + x: T, +} + +fn main() { + let _ = core::mem::offset_of!(Foo<_>, x); //~ ERROR: type annotations needed +} diff --git a/tests/ui/offset-of/offset-of-inference.stderr b/tests/ui/offset-of/offset-of-inference.stderr new file mode 100644 index 00000000000..2a520f6f906 --- /dev/null +++ b/tests/ui/offset-of/offset-of-inference.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/offset-of-inference.rs:10:35 + | +LL | let _ = core::mem::offset_of!(Foo<_>, x); + | ^^^^^^ cannot infer type + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/offset-of/offset-of-output-type.rs b/tests/ui/offset-of/offset-of-output-type.rs new file mode 100644 index 00000000000..50c2e93841f --- /dev/null +++ b/tests/ui/offset-of/offset-of-output-type.rs @@ -0,0 +1,20 @@ +#![feature(offset_of)] + +use std::mem::offset_of; + +struct S { + v: u8, + w: u16, +} + + +fn main() { + let _: u8 = offset_of!(S, v); //~ ERROR mismatched types + let _: u16 = offset_of!(S, v); //~ ERROR mismatched types + let _: u32 = offset_of!(S, v); //~ ERROR mismatched types + let _: u64 = offset_of!(S, v); //~ ERROR mismatched types + let _: isize = offset_of!(S, v); //~ ERROR mismatched types + let _: usize = offset_of!(S, v); + + offset_of!(S, v) //~ ERROR mismatched types +} diff --git a/tests/ui/offset-of/offset-of-output-type.stderr b/tests/ui/offset-of/offset-of-output-type.stderr new file mode 100644 index 00000000000..6f8c9475029 --- /dev/null +++ b/tests/ui/offset-of/offset-of-output-type.stderr @@ -0,0 +1,64 @@ +error[E0308]: mismatched types + --> $DIR/offset-of-output-type.rs:12:17 + | +LL | let _: u8 = offset_of!(S, v); + | -- ^^^^^^^^^^^^^^^^ expected `u8`, found `usize` + | | + | expected due to this + | + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/offset-of-output-type.rs:13:18 + | +LL | let _: u16 = offset_of!(S, v); + | --- ^^^^^^^^^^^^^^^^ expected `u16`, found `usize` + | | + | expected due to this + | + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/offset-of-output-type.rs:14:18 + | +LL | let _: u32 = offset_of!(S, v); + | --- ^^^^^^^^^^^^^^^^ expected `u32`, found `usize` + | | + | expected due to this + | + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/offset-of-output-type.rs:15:18 + | +LL | let _: u64 = offset_of!(S, v); + | --- ^^^^^^^^^^^^^^^^ expected `u64`, found `usize` + | | + | expected due to this + | + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/offset-of-output-type.rs:16:20 + | +LL | let _: isize = offset_of!(S, v); + | ----- ^^^^^^^^^^^^^^^^ expected `isize`, found `usize` + | | + | expected due to this + | + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/offset-of-output-type.rs:19:5 + | +LL | fn main() { + | - expected `()` because of default return type +... +LL | offset_of!(S, v) + | ^^^^^^^^^^^^^^^^ expected `()`, found `usize` + | + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/offset-of/offset-of-private.rs b/tests/ui/offset-of/offset-of-private.rs index 0291b7825ca..6b1a16ba62b 100644 --- a/tests/ui/offset-of/offset-of-private.rs +++ b/tests/ui/offset-of/offset-of-private.rs @@ -8,9 +8,21 @@ mod m { pub public: u8, private: u8, } + #[repr(C)] + pub struct FooTuple(pub u8, u8); + #[repr(C)] + struct Bar { + pub public: u8, + private: u8, + } } fn main() { offset_of!(m::Foo, public); offset_of!(m::Foo, private); //~ ERROR field `private` of struct `Foo` is private + offset_of!(m::FooTuple, 0); + offset_of!(m::FooTuple, 1); //~ ERROR field `1` of struct `FooTuple` is private + offset_of!(m::Bar, public); //~ ERROR struct `Bar` is private + offset_of!(m::Bar, private); //~ ERROR struct `Bar` is private + //~| ERROR field `private` of struct `Bar` is private } diff --git a/tests/ui/offset-of/offset-of-private.stderr b/tests/ui/offset-of/offset-of-private.stderr index 8a186dd5a02..0674b58f860 100644 --- a/tests/ui/offset-of/offset-of-private.stderr +++ b/tests/ui/offset-of/offset-of-private.stderr @@ -1,9 +1,46 @@ +error[E0603]: struct `Bar` is private + --> $DIR/offset-of-private.rs:25:19 + | +LL | offset_of!(m::Bar, public); + | ^^^ private struct + | +note: the struct `Bar` is defined here + --> $DIR/offset-of-private.rs:14:5 + | +LL | struct Bar { + | ^^^^^^^^^^ + +error[E0603]: struct `Bar` is private + --> $DIR/offset-of-private.rs:26:19 + | +LL | offset_of!(m::Bar, private); + | ^^^ private struct + | +note: the struct `Bar` is defined here + --> $DIR/offset-of-private.rs:14:5 + | +LL | struct Bar { + | ^^^^^^^^^^ + error[E0616]: field `private` of struct `Foo` is private - --> $DIR/offset-of-private.rs:15:24 + --> $DIR/offset-of-private.rs:22:24 | LL | offset_of!(m::Foo, private); | ^^^^^^^ private field -error: aborting due to previous error +error[E0616]: field `1` of struct `FooTuple` is private + --> $DIR/offset-of-private.rs:24:29 + | +LL | offset_of!(m::FooTuple, 1); + | ^ private field + +error[E0616]: field `private` of struct `Bar` is private + --> $DIR/offset-of-private.rs:26:24 + | +LL | offset_of!(m::Bar, private); + | ^^^^^^^ private field + +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0616`. +Some errors have detailed explanations: E0603, E0616. +For more information about an error, try `rustc --explain E0603`. diff --git a/tests/ui/offset-of/offset-of-self.rs b/tests/ui/offset-of/offset-of-self.rs new file mode 100644 index 00000000000..dbeef0e74dc --- /dev/null +++ b/tests/ui/offset-of/offset-of-self.rs @@ -0,0 +1,58 @@ +#![feature(offset_of)] + +use std::mem::offset_of; + +struct C<T> { + v: T, + w: T, +} + +struct S { + v: u8, + w: u16, +} + +impl S { + fn v_offs() -> usize { + offset_of!(Self, v) + } + fn v_offs_wrong_syntax() { + offset_of!(Self, Self::v); //~ ERROR no rules expected the token `::` + offset_of!(S, Self); //~ ERROR expected identifier, found keyword `Self` + //~| no field `Self` on type `S` + } + fn offs_in_c() -> usize { + offset_of!(C<Self>, w) + } + fn offs_in_c_colon() -> usize { + offset_of!(C::<Self>, w) + } +} + +mod m { + use std::mem::offset_of; + fn off() { + offset_of!(self::S, v); //~ ERROR cannot find type `S` in module + offset_of!(super::S, v); + offset_of!(crate::S, v); + } + impl super::n::T { + fn v_offs_self() -> usize { + offset_of!(Self, v) //~ ERROR field `v` of struct `T` is private + } + } +} + +mod n { + pub struct T { v: u8, } +} + +fn main() { + offset_of!(self::S, v); + offset_of!(Self, v); //~ ERROR cannot find type `Self` in this scope + + offset_of!(S, self); //~ ERROR expected identifier, found keyword `self` + //~| no field `self` on type `S` + offset_of!(S, v.self); //~ ERROR expected identifier, found keyword `self` + //~| no field `self` on type `u8` +} diff --git a/tests/ui/offset-of/offset-of-self.stderr b/tests/ui/offset-of/offset-of-self.stderr new file mode 100644 index 00000000000..df555463f98 --- /dev/null +++ b/tests/ui/offset-of/offset-of-self.stderr @@ -0,0 +1,79 @@ +error: no rules expected the token `::` + --> $DIR/offset-of-self.rs:20:30 + | +LL | offset_of!(Self, Self::v); + | ^^ no rules expected this token in macro call + | + = note: while trying to match sequence start + +error: expected identifier, found keyword `Self` + --> $DIR/offset-of-self.rs:21:23 + | +LL | offset_of!(S, Self); + | ^^^^ expected identifier, found keyword + +error: expected identifier, found keyword `self` + --> $DIR/offset-of-self.rs:54:19 + | +LL | offset_of!(S, self); + | ^^^^ expected identifier, found keyword + +error: expected identifier, found keyword `self` + --> $DIR/offset-of-self.rs:56:21 + | +LL | offset_of!(S, v.self); + | ^^^^ expected identifier, found keyword + +error[E0412]: cannot find type `S` in module `self` + --> $DIR/offset-of-self.rs:35:26 + | +LL | offset_of!(self::S, v); + | ^ not found in `self` + | +help: consider importing this struct + | +LL + use S; + | +help: if you import `S`, refer to it directly + | +LL - offset_of!(self::S, v); +LL + offset_of!(S, v); + | + +error[E0411]: cannot find type `Self` in this scope + --> $DIR/offset-of-self.rs:52:16 + | +LL | fn main() { + | ---- `Self` not allowed in a function +LL | offset_of!(self::S, v); +LL | offset_of!(Self, v); + | ^^^^ `Self` is only available in impls, traits, and type definitions + +error[E0609]: no field `Self` on type `S` + --> $DIR/offset-of-self.rs:21:23 + | +LL | offset_of!(S, Self); + | ^^^^ + +error[E0616]: field `v` of struct `T` is private + --> $DIR/offset-of-self.rs:41:30 + | +LL | offset_of!(Self, v) + | ^ private field + +error[E0609]: no field `self` on type `S` + --> $DIR/offset-of-self.rs:54:19 + | +LL | offset_of!(S, self); + | ^^^^ + +error[E0609]: no field `self` on type `u8` + --> $DIR/offset-of-self.rs:56:21 + | +LL | offset_of!(S, v.self); + | ^^^^ + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0411, E0412, E0609, E0616. +For more information about an error, try `rustc --explain E0411`. diff --git a/tests/ui/or-patterns/or-patterns-default-binding-modes.rs b/tests/ui/or-patterns/or-patterns-default-binding-modes.rs index c138d99d303..df6aab0e6a8 100644 --- a/tests/ui/or-patterns/or-patterns-default-binding-modes.rs +++ b/tests/ui/or-patterns/or-patterns-default-binding-modes.rs @@ -3,8 +3,8 @@ // check-pass #![allow(irrefutable_let_patterns)] -#![allow(drop_copy)] -#![allow(drop_ref)] +#![allow(dropping_copy_types)] +#![allow(dropping_references)] fn main() { // A regression test for a mistake we made at one point: diff --git a/tests/ui/panics/default-backtrace-ice.stderr b/tests/ui/panics/default-backtrace-ice.stderr index ddbfc4e7f3a..815ce4dd015 100644 --- a/tests/ui/panics/default-backtrace-ice.stderr +++ b/tests/ui/panics/default-backtrace-ice.stderr @@ -8,6 +8,8 @@ LL | fn main() { missing_ident; } stack backtrace: (end_short_backtrace) (begin_short_backtrace) +(end_short_backtrace) +(begin_short_backtrace) error: the compiler unexpectedly panicked. this is a bug. diff --git a/tests/ui/panics/short-ice-remove-middle-frames-2.rs b/tests/ui/panics/short-ice-remove-middle-frames-2.rs new file mode 100644 index 00000000000..38a80f8b670 --- /dev/null +++ b/tests/ui/panics/short-ice-remove-middle-frames-2.rs @@ -0,0 +1,61 @@ +// compile-flags:-Cstrip=none +// run-fail +// check-run-results +// exec-env:RUST_BACKTRACE=1 +// ignore-android FIXME #17520 +// ignore-wasm no panic support +// ignore-openbsd no support for libbacktrace without filename +// ignore-emscripten no panic +// ignore-sgx Backtraces not symbolized +// ignore-fuchsia Backtraces not symbolized +// ignore-msvc the `__rust_{begin,end}_short_backtrace` symbols aren't reliable. + +/// This test case make sure that we can have multiple pairs of `__rust_{begin,end}_short_backtrace` + +#[inline(never)] +fn __rust_begin_short_backtrace<T, F: FnOnce() -> T>(f: F) -> T { + let result = f(); + std::hint::black_box(result) +} + +#[inline(never)] +fn __rust_end_short_backtrace<T, F: FnOnce() -> T>(f: F) -> T { + let result = f(); + std::hint::black_box(result) +} + +fn first() { + __rust_end_short_backtrace(|| second()); +} + +fn second() { + third(); // won't show up +} + +fn third() { + fourth(); // won't show up +} + +fn fourth() { + __rust_begin_short_backtrace(|| fifth()); +} + +fn fifth() { + __rust_end_short_backtrace(|| sixth()); +} + +fn sixth() { + seven(); // won't show up +} + +fn seven() { + __rust_begin_short_backtrace(|| eight()); +} + +fn eight() { + panic!("debug!!!"); +} + +fn main() { + first(); +} diff --git a/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr b/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr new file mode 100644 index 00000000000..2592b747918 --- /dev/null +++ b/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr @@ -0,0 +1,11 @@ +thread 'main' panicked at 'debug!!!', $DIR/short-ice-remove-middle-frames-2.rs:56:5 +stack backtrace: + 0: std::panicking::begin_panic + 1: short_ice_remove_middle_frames_2::eight + 2: short_ice_remove_middle_frames_2::seven::{{closure}} + 3: short_ice_remove_middle_frames_2::fifth + 4: short_ice_remove_middle_frames_2::fourth::{{closure}} + 5: short_ice_remove_middle_frames_2::first + 6: short_ice_remove_middle_frames_2::main + 7: core::ops::function::FnOnce::call_once +note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. diff --git a/tests/ui/panics/short-ice-remove-middle-frames.rs b/tests/ui/panics/short-ice-remove-middle-frames.rs new file mode 100644 index 00000000000..c872084f033 --- /dev/null +++ b/tests/ui/panics/short-ice-remove-middle-frames.rs @@ -0,0 +1,57 @@ +// compile-flags:-Cstrip=none +// run-fail +// check-run-results +// exec-env:RUST_BACKTRACE=1 +// ignore-android FIXME #17520 +// ignore-wasm no panic support +// ignore-openbsd no support for libbacktrace without filename +// ignore-emscripten no panic +// ignore-sgx Backtraces not symbolized +// ignore-fuchsia Backtraces not symbolized +// ignore-msvc the `__rust_{begin,end}_short_backtrace` symbols aren't reliable. + + +#[inline(never)] +fn __rust_begin_short_backtrace<T, F: FnOnce() -> T>(f: F) -> T { + let result = f(); + std::hint::black_box(result) +} + +#[inline(never)] +fn __rust_end_short_backtrace<T, F: FnOnce() -> T>(f: F) -> T { + let result = f(); + std::hint::black_box(result) +} + +fn first() { + __rust_end_short_backtrace(|| second()); + // do not take effect since we already has a inner call of __rust_end_short_backtrace +} + +fn second() { + __rust_end_short_backtrace(|| third()); +} + +fn third() { + fourth(); // won't show up in backtrace +} + +fn fourth() { + fifth(); // won't show up in backtrace +} + +fn fifth() { + __rust_begin_short_backtrace(|| sixth()); +} + +fn sixth() { + seven(); +} + +fn seven() { + panic!("debug!!!"); +} + +fn main() { + first(); +} diff --git a/tests/ui/panics/short-ice-remove-middle-frames.run.stderr b/tests/ui/panics/short-ice-remove-middle-frames.run.stderr new file mode 100644 index 00000000000..9c15f2e08fe --- /dev/null +++ b/tests/ui/panics/short-ice-remove-middle-frames.run.stderr @@ -0,0 +1,12 @@ +thread 'main' panicked at 'debug!!!', $DIR/short-ice-remove-middle-frames.rs:52:5 +stack backtrace: + 0: std::panicking::begin_panic + 1: short_ice_remove_middle_frames::seven + 2: short_ice_remove_middle_frames::sixth + 3: short_ice_remove_middle_frames::fifth::{{closure}} + 4: short_ice_remove_middle_frames::second + 5: short_ice_remove_middle_frames::first::{{closure}} + 6: short_ice_remove_middle_frames::first + 7: short_ice_remove_middle_frames::main + 8: core::ops::function::FnOnce::call_once +note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs index 965204bf240..43b53b7cf1f 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs @@ -2,8 +2,8 @@ // Test `@` patterns combined with `box` patterns. -#![allow(drop_ref)] -#![allow(drop_copy)] +#![allow(dropping_references)] +#![allow(dropping_copy_types)] #![feature(box_patterns)] diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs index 3eb5d2cbf54..1df51c0edd9 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs @@ -2,7 +2,7 @@ // Test `Copy` bindings in the rhs of `@` patterns. -#![allow(drop_copy)] +#![allow(dropping_copy_types)] #[derive(Copy, Clone)] struct C; diff --git a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs index 0550238549e..204cd3e6657 100644 --- a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs +++ b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs @@ -1,6 +1,6 @@ // check-pass -#![allow(drop_ref)] +#![allow(dropping_references)] fn main() {} diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs index 788975d960a..4de1f653db0 100644 --- a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs @@ -1,6 +1,6 @@ // check-pass -#![allow(drop_ref)] +#![allow(dropping_references)] fn main() { struct U; diff --git a/tests/ui/print_type_sizes/async.rs b/tests/ui/print_type_sizes/async.rs index c73268dc46a..f38a6e674da 100644 --- a/tests/ui/print_type_sizes/async.rs +++ b/tests/ui/print_type_sizes/async.rs @@ -3,7 +3,7 @@ // build-pass // ignore-pass -#![allow(drop_copy)] +#![allow(dropping_copy_types)] async fn wait() {} diff --git a/tests/ui/print_type_sizes/generator_discr_placement.rs b/tests/ui/print_type_sizes/generator_discr_placement.rs index a77a03f0a8a..6adc14f9b99 100644 --- a/tests/ui/print_type_sizes/generator_discr_placement.rs +++ b/tests/ui/print_type_sizes/generator_discr_placement.rs @@ -6,7 +6,7 @@ // Avoid emitting panic handlers, like the rest of these tests... #![feature(generators)] -#![allow(drop_copy)] +#![allow(dropping_copy_types)] pub fn foo() { let a = || { diff --git a/tests/ui/regions/type-param-outlives-reempty-issue-74429.rs b/tests/ui/regions/type-param-outlives-reempty-issue-74429.rs index af2bb09805a..0c1e9314441 100644 --- a/tests/ui/regions/type-param-outlives-reempty-issue-74429.rs +++ b/tests/ui/regions/type-param-outlives-reempty-issue-74429.rs @@ -3,7 +3,7 @@ // check-pass -#![allow(drop_copy)] +#![allow(dropping_copy_types)] use std::marker::PhantomData; diff --git a/tests/ui/resolve/issue-111312.rs b/tests/ui/resolve/issue-111312.rs new file mode 100644 index 00000000000..acea37b358b --- /dev/null +++ b/tests/ui/resolve/issue-111312.rs @@ -0,0 +1,11 @@ +// edition: 2021 + +trait Has { + fn has() {} +} + +trait HasNot {} + +fn main() { + HasNot::has(); //~ ERROR +} diff --git a/tests/ui/resolve/issue-111312.stderr b/tests/ui/resolve/issue-111312.stderr new file mode 100644 index 00000000000..4c864029c98 --- /dev/null +++ b/tests/ui/resolve/issue-111312.stderr @@ -0,0 +1,15 @@ +error[E0599]: no function or associated item named `has` found for trait `HasNot` + --> $DIR/issue-111312.rs:10:13 + | +LL | HasNot::has(); + | ^^^ function or associated item not found in `HasNot` + | +note: `Has` defines an item `has` + --> $DIR/issue-111312.rs:3:1 + | +LL | trait Has { + | ^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/resolve/issue-111727.rs b/tests/ui/resolve/issue-111727.rs new file mode 100644 index 00000000000..36f3081211d --- /dev/null +++ b/tests/ui/resolve/issue-111727.rs @@ -0,0 +1,5 @@ +// edition: 2021 + +fn main() { + std::any::Any::create(); //~ ERROR +} diff --git a/tests/ui/resolve/issue-111727.stderr b/tests/ui/resolve/issue-111727.stderr new file mode 100644 index 00000000000..bd748211ed3 --- /dev/null +++ b/tests/ui/resolve/issue-111727.stderr @@ -0,0 +1,9 @@ +error[E0599]: no function or associated item named `create` found for trait `Any` + --> $DIR/issue-111727.rs:4:20 + | +LL | std::any::Any::create(); + | ^^^^^^ function or associated item not found in `Any` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/rfc-2008-non-exhaustive/borrowck-exhaustive.rs b/tests/ui/rfc-2008-non-exhaustive/borrowck-exhaustive.rs index 8f45b989f13..b9ff24c7624 100644 --- a/tests/ui/rfc-2008-non-exhaustive/borrowck-exhaustive.rs +++ b/tests/ui/rfc-2008-non-exhaustive/borrowck-exhaustive.rs @@ -3,7 +3,7 @@ // check-pass -#![allow(drop_ref)] +#![allow(dropping_references)] // aux-build:monovariants.rs extern crate monovariants; diff --git a/tests/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs b/tests/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs index 4c1562790d5..542be3942b7 100644 --- a/tests/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs +++ b/tests/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs @@ -4,7 +4,7 @@ // Tests ensuring that `dbg!(expr)` has the expected run-time behavior. // as well as some compile time properties we expect. -#![allow(drop_copy)] +#![allow(dropping_copy_types)] #[derive(Copy, Clone, Debug)] struct Unit; diff --git a/tests/ui/rust-2018/remove-extern-crate.fixed b/tests/ui/rust-2018/remove-extern-crate.fixed index 4ed4d610025..209b91af1dd 100644 --- a/tests/ui/rust-2018/remove-extern-crate.fixed +++ b/tests/ui/rust-2018/remove-extern-crate.fixed @@ -5,7 +5,7 @@ // compile-flags:--extern remove_extern_crate #![warn(rust_2018_idioms)] -#![allow(drop_copy)] +#![allow(dropping_copy_types)] //~ WARNING unused extern crate // Shouldn't suggest changing to `use`, as `another_name` diff --git a/tests/ui/rust-2018/remove-extern-crate.rs b/tests/ui/rust-2018/remove-extern-crate.rs index 5dafdb2b7b7..ef3c2db696a 100644 --- a/tests/ui/rust-2018/remove-extern-crate.rs +++ b/tests/ui/rust-2018/remove-extern-crate.rs @@ -5,7 +5,7 @@ // compile-flags:--extern remove_extern_crate #![warn(rust_2018_idioms)] -#![allow(drop_copy)] +#![allow(dropping_copy_types)] extern crate core; //~ WARNING unused extern crate // Shouldn't suggest changing to `use`, as `another_name` diff --git a/tests/ui/self/arbitrary-self-from-method-substs.rs b/tests/ui/self/arbitrary-self-from-method-substs.rs new file mode 100644 index 00000000000..0f911a20842 --- /dev/null +++ b/tests/ui/self/arbitrary-self-from-method-substs.rs @@ -0,0 +1,16 @@ +#![feature(arbitrary_self_types)] + +use std::ops::Deref; + +struct Foo(u32); +impl Foo { + fn get<R: Deref<Target=Self>>(self: R) -> u32 { + self.0 + } +} + +fn main() { + let mut foo = Foo(1); + foo.get::<&Foo>(); + //~^ ERROR mismatched types +} diff --git a/tests/ui/self/arbitrary-self-from-method-substs.stderr b/tests/ui/self/arbitrary-self-from-method-substs.stderr new file mode 100644 index 00000000000..6c252fadf46 --- /dev/null +++ b/tests/ui/self/arbitrary-self-from-method-substs.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/arbitrary-self-from-method-substs.rs:14:5 + | +LL | foo.get::<&Foo>(); + | ^^^ expected `&Foo`, found `Foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/self/self-ctor-inner-const.rs b/tests/ui/self/self-ctor-inner-const.rs deleted file mode 100644 index b015397a5bc..00000000000 --- a/tests/ui/self/self-ctor-inner-const.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Verify that we ban usage of `Self` as constructor from inner items. - -struct S0<T>(T); - -impl<T> S0<T> { - fn foo() { - const C: S0<u8> = Self(0); - //~^ ERROR can't use generic parameters from outer function - fn bar() -> Self { - //~^ ERROR can't use generic parameters from outer function - Self(0) - //~^ ERROR can't use generic parameters from outer function - } - } -} - -fn main() {} diff --git a/tests/ui/self/self-ctor-inner-const.stderr b/tests/ui/self/self-ctor-inner-const.stderr deleted file mode 100644 index 7287c64c659..00000000000 --- a/tests/ui/self/self-ctor-inner-const.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0401]: can't use generic parameters from outer function - --> $DIR/self-ctor-inner-const.rs:7:27 - | -LL | const C: S0<u8> = Self(0); - | ^^^^ - | | - | use of generic parameter from outer function - | can't use `Self` here - -error[E0401]: can't use generic parameters from outer function - --> $DIR/self-ctor-inner-const.rs:9:21 - | -LL | impl<T> S0<T> { - | ---- `Self` type implicitly declared here, by this `impl` -... -LL | fn bar() -> Self { - | ^^^^ - | | - | use of generic parameter from outer function - | use a type here instead - -error[E0401]: can't use generic parameters from outer function - --> $DIR/self-ctor-inner-const.rs:11:13 - | -LL | Self(0) - | ^^^^ - | | - | use of generic parameter from outer function - | can't use `Self` here - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0401`. diff --git a/tests/ui/self/self-ctor-nongeneric.rs b/tests/ui/self/self-ctor-nongeneric.rs new file mode 100644 index 00000000000..0ae7f8da4b4 --- /dev/null +++ b/tests/ui/self/self-ctor-nongeneric.rs @@ -0,0 +1,15 @@ +// `Self` as a constructor is currently allowed when the outer item is not generic. +// check-pass + +struct S0(usize); + +impl S0 { + fn foo() { + const C: S0 = Self(0); + fn bar() -> S0 { + Self(0) + } + } +} + +fn main() {} diff --git a/tests/ui/statics/issue-91050-1.rs b/tests/ui/statics/issue-91050-1.rs index f59bcf0b803..c6268dba567 100644 --- a/tests/ui/statics/issue-91050-1.rs +++ b/tests/ui/statics/issue-91050-1.rs @@ -12,7 +12,7 @@ // // In regular builds, the bad cast was UB, like "Invalid LLVMRustVisibility value!" -#![allow(drop_copy)] +#![allow(dropping_copy_types)] pub mod before { #[no_mangle] diff --git a/tests/ui/suggestions/issue-109854.rs b/tests/ui/suggestions/issue-109854.rs new file mode 100644 index 00000000000..dd4542dd71f --- /dev/null +++ b/tests/ui/suggestions/issue-109854.rs @@ -0,0 +1,12 @@ +fn generate_setter() { + String::with_capacity( + //~^ ERROR this function takes 1 argument but 3 arguments were supplied + generate_setter, + r#" +pub(crate) struct Person<T: Clone> {} +"#, + r#""#, + ); +} + +fn main() {} diff --git a/tests/ui/suggestions/issue-109854.stderr b/tests/ui/suggestions/issue-109854.stderr new file mode 100644 index 00000000000..621a3897165 --- /dev/null +++ b/tests/ui/suggestions/issue-109854.stderr @@ -0,0 +1,31 @@ +error[E0061]: this function takes 1 argument but 3 arguments were supplied + --> $DIR/issue-109854.rs:2:5 + | +LL | String::with_capacity( + | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | / r#" +LL | | pub(crate) struct Person<T: Clone> {} +LL | | "#, + | |__- unexpected argument of type `&'static str` +LL | r#""#, + | ----- unexpected argument of type `&'static str` + | +note: expected `usize`, found fn item + --> $DIR/issue-109854.rs:4:5 + | +LL | generate_setter, + | ^^^^^^^^^^^^^^^ + = note: expected type `usize` + found fn item `fn() {generate_setter}` +note: associated function defined here + --> $SRC_DIR/alloc/src/string.rs:LL:COL +help: remove the extra arguments + | +LL - generate_setter, +LL + /* usize */, + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0061`. diff --git a/tests/ui/suggestions/issue-94171.rs b/tests/ui/suggestions/issue-94171.rs new file mode 100644 index 00000000000..cbb9f9cec72 --- /dev/null +++ b/tests/ui/suggestions/issue-94171.rs @@ -0,0 +1,5 @@ +fn L(]{match +(; {` +//~^^ ERROR mismatched closing delimiter +//~^^ ERROR unknown start of token +//~ ERROR this file contains an unclosed delimiter diff --git a/tests/ui/suggestions/issue-94171.stderr b/tests/ui/suggestions/issue-94171.stderr new file mode 100644 index 00000000000..b3440e46e8a --- /dev/null +++ b/tests/ui/suggestions/issue-94171.stderr @@ -0,0 +1,36 @@ +error: unknown start of token: ` + --> $DIR/issue-94171.rs:2:5 + | +LL | (; {` + | ^ + | +help: Unicode character '`' (Grave Accent) looks like ''' (Single Quote), but it is not + | +LL | (; {' + | ~ + +error: mismatched closing delimiter: `]` + --> $DIR/issue-94171.rs:1:5 + | +LL | fn L(]{match + | ^^ mismatched closing delimiter + | | + | unclosed delimiter + +error: this file contains an unclosed delimiter + --> $DIR/issue-94171.rs:5:52 + | +LL | fn L(]{match + | -- unclosed delimiter + | | + | missing open `[` for this delimiter +LL | (; {` + | - - unclosed delimiter + | | + | unclosed delimiter +... +LL | + | ^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/traits/copy-guessing.rs b/tests/ui/traits/copy-guessing.rs index 558303c2e40..af25010e3bd 100644 --- a/tests/ui/traits/copy-guessing.rs +++ b/tests/ui/traits/copy-guessing.rs @@ -1,7 +1,5 @@ -// run-pass - #![allow(dead_code)] -#![allow(drop_copy)] +#![allow(dropping_copy_types)] // "guessing" in trait selection can affect `copy_or_move`. Check that this // is correctly handled. I am not sure what is the "correct" behaviour, @@ -20,6 +18,7 @@ fn assert_impls_fn<R,T: Fn()->R>(_: &T){} fn main() { let n = None; + //~^ ERROR type annotations needed for `Option<T>` let e = S(&n); let f = || { // S being copy is critical for this to work diff --git a/tests/ui/traits/copy-guessing.stderr b/tests/ui/traits/copy-guessing.stderr new file mode 100644 index 00000000000..568b7e5a64a --- /dev/null +++ b/tests/ui/traits/copy-guessing.stderr @@ -0,0 +1,14 @@ +error[E0282]: type annotations needed for `Option<T>` + --> $DIR/copy-guessing.rs:20:9 + | +LL | let n = None; + | ^ + | +help: consider giving `n` an explicit type, where the type for type parameter `T` is specified + | +LL | let n: Option<T> = None; + | +++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/cycle-cache-err-60010.stderr b/tests/ui/traits/cycle-cache-err-60010.stderr index 2ff16b4af38..aee41c43aef 100644 --- a/tests/ui/traits/cycle-cache-err-60010.stderr +++ b/tests/ui/traits/cycle-cache-err-60010.stderr @@ -1,9 +1,25 @@ -error[E0275]: overflow evaluating the requirement `RootDatabase: RefUnwindSafe` +error[E0275]: overflow evaluating the requirement `SalsaStorage: RefUnwindSafe` --> $DIR/cycle-cache-err-60010.rs:27:13 | LL | _parse: <ParseQuery as Query<RootDatabase>>::Data, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | +note: required because it appears within the type `PhantomData<SalsaStorage>` + --> $SRC_DIR/core/src/marker.rs:LL:COL +note: required because it appears within the type `Unique<SalsaStorage>` + --> $SRC_DIR/core/src/ptr/unique.rs:LL:COL +note: required because it appears within the type `Box<SalsaStorage>` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL +note: required because it appears within the type `Runtime<RootDatabase>` + --> $DIR/cycle-cache-err-60010.rs:23:8 + | +LL | struct Runtime<DB: Database> { + | ^^^^^^^ +note: required because it appears within the type `RootDatabase` + --> $DIR/cycle-cache-err-60010.rs:20:8 + | +LL | struct RootDatabase { + | ^^^^^^^^^^^^ note: required for `RootDatabase` to implement `SourceDatabase` --> $DIR/cycle-cache-err-60010.rs:44:9 | diff --git a/tests/ui/traits/impl-evaluation-order.rs b/tests/ui/traits/impl-evaluation-order.rs index 256ce992eef..2ce0b6b0df8 100644 --- a/tests/ui/traits/impl-evaluation-order.rs +++ b/tests/ui/traits/impl-evaluation-order.rs @@ -6,7 +6,7 @@ // check-pass -#![allow(drop_copy)] +#![allow(dropping_copy_types)] trait A { type B; diff --git a/tests/ui/traits/issue-106072.rs b/tests/ui/traits/issue-106072.rs index 7064a39d21e..b174669545a 100644 --- a/tests/ui/traits/issue-106072.rs +++ b/tests/ui/traits/issue-106072.rs @@ -1,5 +1,4 @@ #[derive(Clone)] //~ trait objects must include the `dyn` keyword - //~| trait objects must include the `dyn` keyword struct Foo; trait Foo {} //~ the name `Foo` is defined multiple times fn main() {} diff --git a/tests/ui/traits/issue-106072.stderr b/tests/ui/traits/issue-106072.stderr index f9b7b814663..1037603ceb7 100644 --- a/tests/ui/traits/issue-106072.stderr +++ b/tests/ui/traits/issue-106072.stderr @@ -1,5 +1,5 @@ error[E0428]: the name `Foo` is defined multiple times - --> $DIR/issue-106072.rs:4:1 + --> $DIR/issue-106072.rs:3:1 | LL | struct Foo; | ----------- previous definition of the type `Foo` here @@ -16,15 +16,7 @@ LL | #[derive(Clone)] | = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/issue-106072.rs:1:10 - | -LL | #[derive(Clone)] - | ^^^^^ - | - = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0428, E0782. For more information about an error, try `rustc --explain E0428`. diff --git a/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.rs b/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.rs index f115e143318..e311a4af2f4 100644 --- a/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.rs +++ b/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.rs @@ -14,7 +14,7 @@ async fn foo() { #[cfg(fail)] let x = &NotSync; bar().await; - #[allow(drop_ref)] + #[allow(dropping_references)] drop(x); } diff --git a/tests/ui/traits/new-solver/normalize-rcvr-for-inherent.rs b/tests/ui/traits/new-solver/normalize-rcvr-for-inherent.rs new file mode 100644 index 00000000000..d70534feb07 --- /dev/null +++ b/tests/ui/traits/new-solver/normalize-rcvr-for-inherent.rs @@ -0,0 +1,25 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +// Verify that we can assemble inherent impl candidates on a possibly +// unnormalized self type. + +trait Foo { + type Assoc; +} +impl Foo for i32 { + type Assoc = Bar; +} + +struct Bar; +impl Bar { + fn method(&self) {} +} + +fn build<T: Foo>(_: T) -> T::Assoc { + todo!() +} + +fn main() { + build(1i32).method(); +} diff --git a/tests/ui/traits/new-solver/structural-resolve-field.rs b/tests/ui/traits/new-solver/structural-resolve-field.rs new file mode 100644 index 00000000000..01899c9ad64 --- /dev/null +++ b/tests/ui/traits/new-solver/structural-resolve-field.rs @@ -0,0 +1,13 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +#[derive(Default)] +struct Foo { + x: i32, +} + +fn main() { + let mut xs = <[Foo; 1]>::default(); + xs[0].x = 1; + (&mut xs[0]).x = 2; +} diff --git a/tests/ui/traits/solver-cycles/cycle-via-builtin-auto-trait-impl.rs b/tests/ui/traits/solver-cycles/cycle-via-builtin-auto-trait-impl.rs new file mode 100644 index 00000000000..d37943b929a --- /dev/null +++ b/tests/ui/traits/solver-cycles/cycle-via-builtin-auto-trait-impl.rs @@ -0,0 +1,34 @@ +//~ ERROR overflow +// A regression test for #111729 checking that we correctly +// track recursion depth for obligations returned by confirmation. +use std::panic::RefUnwindSafe; + +trait Database { + type Storage; +} +trait Query<DB> { + type Data; +} +struct ParseQuery; +struct RootDatabase { + _runtime: Runtime<RootDatabase>, +} + +impl<T: RefUnwindSafe> Database for T { + type Storage = SalsaStorage; +} +impl Database for RootDatabase { + type Storage = SalsaStorage; +} + +struct Runtime<DB: Database> { + _storage: Box<DB::Storage>, +} +struct SalsaStorage { + _parse: <ParseQuery as Query<RootDatabase>>::Data, +} + +impl<DB: Database> Query<DB> for ParseQuery { + type Data = RootDatabase; +} +fn main() {} diff --git a/tests/ui/traits/solver-cycles/cycle-via-builtin-auto-trait-impl.stderr b/tests/ui/traits/solver-cycles/cycle-via-builtin-auto-trait-impl.stderr new file mode 100644 index 00000000000..8f9ce3ef1e9 --- /dev/null +++ b/tests/ui/traits/solver-cycles/cycle-via-builtin-auto-trait-impl.stderr @@ -0,0 +1,24 @@ +error[E0275]: overflow evaluating the requirement `Runtime<RootDatabase>: RefUnwindSafe` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_via_builtin_auto_trait_impl`) +note: required because it appears within the type `RootDatabase` + --> $DIR/cycle-via-builtin-auto-trait-impl.rs:13:8 + | +LL | struct RootDatabase { + | ^^^^^^^^^^^^ +note: required for `RootDatabase` to implement `Database` + --> $DIR/cycle-via-builtin-auto-trait-impl.rs:17:24 + | +LL | impl<T: RefUnwindSafe> Database for T { + | ------------- ^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here +note: required because it appears within the type `Runtime<RootDatabase>` + --> $DIR/cycle-via-builtin-auto-trait-impl.rs:24:8 + | +LL | struct Runtime<DB: Database> { + | ^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/trivial-bounds/trivial-bounds-inconsistent-copy.rs b/tests/ui/trivial-bounds/trivial-bounds-inconsistent-copy.rs index 6ed7667115a..f98c3164d7e 100644 --- a/tests/ui/trivial-bounds/trivial-bounds-inconsistent-copy.rs +++ b/tests/ui/trivial-bounds/trivial-bounds-inconsistent-copy.rs @@ -2,7 +2,7 @@ // Check tautalogically false `Copy` bounds #![feature(trivial_bounds)] -#![allow(drop_ref, drop_copy)] +#![allow(dropping_references, dropping_copy_types)] fn copy_string(t: String) -> String where String: Copy { //~ WARNING trivial_bounds is_copy(&t); diff --git a/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-2.rs b/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-2.rs new file mode 100644 index 00000000000..e5bfbfdae91 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-2.rs @@ -0,0 +1,15 @@ +#![feature(type_alias_impl_trait)] + +type Tait<'a> = impl Sized + 'a; + +fn foo<'a, 'b>() { + if false { + if { return } { + let y: Tait<'b> = 1i32; + //~^ ERROR concrete type differs from previous defining opaque type use + } + } + let x: Tait<'a> = (); +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-2.stderr b/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-2.stderr new file mode 100644 index 00000000000..f2eb7bc4dc7 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-2.stderr @@ -0,0 +1,14 @@ +error: concrete type differs from previous defining opaque type use + --> $DIR/different_defining_uses_never_type-2.rs:8:31 + | +LL | let y: Tait<'b> = 1i32; + | ^^^^ expected `()`, got `i32` + | +note: previous use here + --> $DIR/different_defining_uses_never_type-2.rs:12:23 + | +LL | let x: Tait<'a> = (); + | ^^ + +error: aborting due to previous error + diff --git a/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-3.rs b/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-3.rs new file mode 100644 index 00000000000..2b30a9cd57c --- /dev/null +++ b/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-3.rs @@ -0,0 +1,15 @@ +#![feature(type_alias_impl_trait)] + +type Tait<T> = impl Sized; + +fn foo<T, U>() { + if false { + if { return } { + let y: Tait<U> = 1i32; + //~^ ERROR concrete type differs from previous defining opaque type use + } + } + let x: Tait<T> = (); +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-3.stderr b/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-3.stderr new file mode 100644 index 00000000000..8fc2e22848c --- /dev/null +++ b/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-3.stderr @@ -0,0 +1,14 @@ +error: concrete type differs from previous defining opaque type use + --> $DIR/different_defining_uses_never_type-3.rs:8:30 + | +LL | let y: Tait<U> = 1i32; + | ^^^^ expected `()`, got `i32` + | +note: previous use here + --> $DIR/different_defining_uses_never_type-3.rs:12:22 + | +LL | let x: Tait<T> = (); + | ^^ + +error: aborting due to previous error + diff --git a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs index da845e86147..9ae2c34b935 100644 --- a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs +++ b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs @@ -8,6 +8,7 @@ type X<A, B> = impl Into<&'static A>; fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) { //~^ ERROR the trait bound `&'static B: From<&A>` is not satisfied + //~| ERROR concrete type differs from previous defining opaque type use (a, a) } diff --git a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr index 66a6b0bbf74..0d24d42ba62 100644 --- a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr +++ b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr @@ -10,6 +10,15 @@ help: consider introducing a `where` clause, but there might be an alternative b LL | fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) where &'static B: From<&A> { | ++++++++++++++++++++++++++ -error: aborting due to previous error +error: concrete type differs from previous defining opaque type use + --> $DIR/multiple-def-uses-in-one-fn.rs:9:45 + | +LL | fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) { + | ^^^^^^^^^^^^^^^^^^ + | | + | expected `&B`, got `&A` + | this expression supplies two conflicting concrete types for the same opaque type + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/underscore-imports/issue-110164.rs b/tests/ui/underscore-imports/issue-110164.rs new file mode 100644 index 00000000000..6fd13414500 --- /dev/null +++ b/tests/ui/underscore-imports/issue-110164.rs @@ -0,0 +1,19 @@ +use self::*; +//~^ ERROR unresolved import `self::*` +use crate::*; +//~^ ERROR unresolved import `crate::*` +use _::a; +//~^ ERROR expected identifier, found reserved identifier `_` +//~| ERROR unresolved import `_` +use _::*; +//~^ ERROR expected identifier, found reserved identifier `_` +//~| ERROR unresolved import `_` + +fn main() { + use _::a; + //~^ ERROR expected identifier, found reserved identifier `_` + //~| ERROR unresolved import `_` + use _::*; + //~^ ERROR expected identifier, found reserved identifier `_` + //~| ERROR unresolved import `_` +} diff --git a/tests/ui/underscore-imports/issue-110164.stderr b/tests/ui/underscore-imports/issue-110164.stderr new file mode 100644 index 00000000000..5016c41e8a5 --- /dev/null +++ b/tests/ui/underscore-imports/issue-110164.stderr @@ -0,0 +1,71 @@ +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-110164.rs:5:5 + | +LL | use _::a; + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-110164.rs:8:5 + | +LL | use _::*; + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-110164.rs:13:9 + | +LL | use _::a; + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-110164.rs:16:9 + | +LL | use _::*; + | ^ expected identifier, found reserved identifier + +error[E0432]: unresolved import `self::*` + --> $DIR/issue-110164.rs:1:5 + | +LL | use self::*; + | ^^^^^^^ cannot glob-import a module into itself + +error[E0432]: unresolved import `crate::*` + --> $DIR/issue-110164.rs:3:5 + | +LL | use crate::*; + | ^^^^^^^^ cannot glob-import a module into itself + +error[E0432]: unresolved import `_` + --> $DIR/issue-110164.rs:8:5 + | +LL | use _::*; + | ^ maybe a missing crate `_`? + | + = help: consider adding `extern crate _` to use the `_` crate + +error[E0432]: unresolved import `_` + --> $DIR/issue-110164.rs:5:5 + | +LL | use _::a; + | ^ maybe a missing crate `_`? + | + = help: consider adding `extern crate _` to use the `_` crate + +error[E0432]: unresolved import `_` + --> $DIR/issue-110164.rs:13:9 + | +LL | use _::a; + | ^ maybe a missing crate `_`? + | + = help: consider adding `extern crate _` to use the `_` crate + +error[E0432]: unresolved import `_` + --> $DIR/issue-110164.rs:16:9 + | +LL | use _::*; + | ^ maybe a missing crate `_`? + | + = help: consider adding `extern crate _` to use the `_` crate + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/unsized-locals/issue-67981.rs b/tests/ui/unsized-locals/issue-67981.rs new file mode 100644 index 00000000000..3eb6498e9dc --- /dev/null +++ b/tests/ui/unsized-locals/issue-67981.rs @@ -0,0 +1,9 @@ +#![feature(unsized_fn_params)] + +fn main() { + let f: fn([u8]) = |_| {}; + //~^ERROR the size for values of type `[u8]` cannot be known at compilation time + let slice: Box<[u8]> = Box::new([1; 8]); + + f(*slice); +} diff --git a/tests/ui/unsized-locals/issue-67981.stderr b/tests/ui/unsized-locals/issue-67981.stderr new file mode 100644 index 00000000000..a4b179ae2fd --- /dev/null +++ b/tests/ui/unsized-locals/issue-67981.stderr @@ -0,0 +1,15 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/issue-67981.rs:4:24 + | +LL | let f: fn([u8]) = |_| {}; + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | let f: fn([u8]) = |&_| {}; + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/unsized/box-instead-of-dyn-fn.rs b/tests/ui/unsized/box-instead-of-dyn-fn.rs index 2fa741bc1c5..321c2ebf5a1 100644 --- a/tests/ui/unsized/box-instead-of-dyn-fn.rs +++ b/tests/ui/unsized/box-instead-of-dyn-fn.rs @@ -8,7 +8,6 @@ fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> dyn Fn() + 'a { move || println!("{a}") } else { Box::new(move || println!("{}", b)) - //~^ ERROR `if` and `else` have incompatible types } } diff --git a/tests/ui/unsized/box-instead-of-dyn-fn.stderr b/tests/ui/unsized/box-instead-of-dyn-fn.stderr index bfb7c3957f4..6087f5c5465 100644 --- a/tests/ui/unsized/box-instead-of-dyn-fn.stderr +++ b/tests/ui/unsized/box-instead-of-dyn-fn.stderr @@ -1,42 +1,21 @@ -error[E0308]: `if` and `else` have incompatible types - --> $DIR/box-instead-of-dyn-fn.rs:10:9 - | -LL | / if a % 2 == 0 { -LL | | move || println!("{a}") - | | ----------------------- - | | | - | | the expected closure - | | expected because of this -LL | | } else { -LL | | Box::new(move || println!("{}", b)) - | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found `Box<[closure@box-instead-of-dyn-fn.rs:10:18]>` -LL | | -LL | | } - | |_____- `if` and `else` have incompatible types - | - = note: expected closure `[closure@$DIR/box-instead-of-dyn-fn.rs:8:9: 8:16]` - found struct `Box<[closure@$DIR/box-instead-of-dyn-fn.rs:10:18: 10:25]>` - error[E0746]: return type cannot have an unboxed trait object --> $DIR/box-instead-of-dyn-fn.rs:5:56 | LL | fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> dyn Fn() + 'a { | ^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types> - = note: if all the returned values were of the same type you could use `impl Fn() + 'a` as the return type - = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> - = note: you can create a new `enum` with a variant for each returned type -help: return a boxed trait object instead +help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type + | +LL | fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> impl Fn() + 'a { + | ~~~~ +help: box the return type, and wrap all of the returned values in `Box::new` | -LL | fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> Box<dyn Fn() + 'a> { - | ++++ + -help: ... and box this value +LL ~ fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> Box<dyn Fn() + 'a> { +LL | +LL | if a % 2 == 0 { +LL ~ Box::new(move || println!("{a}")) | -LL | Box::new(move || println!("{a}")) - | +++++++++ + -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0308, E0746. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0746`. diff --git a/tests/ui/unsized/issue-91801.stderr b/tests/ui/unsized/issue-91801.stderr index 8795aa1687f..da5c4322403 100644 --- a/tests/ui/unsized/issue-91801.stderr +++ b/tests/ui/unsized/issue-91801.stderr @@ -4,11 +4,10 @@ error[E0746]: return type cannot have an unboxed trait object LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Validator<'a> { | ^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> -help: use `impl Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a` as the return type, as all return paths are of type `Box<[closure@$DIR/issue-91801.rs:10:21: 10:70]>`, which implements `Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a` +help: box the return type, and wrap all of the returned values in `Box::new` | -LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> impl Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Box<Validator<'a>> { + | ++++ + error: aborting due to previous error diff --git a/tests/ui/unsized/issue-91803.stderr b/tests/ui/unsized/issue-91803.stderr index 2dad9e89294..a43b8d0741f 100644 --- a/tests/ui/unsized/issue-91803.stderr +++ b/tests/ui/unsized/issue-91803.stderr @@ -4,11 +4,14 @@ error[E0746]: return type cannot have an unboxed trait object LL | fn or<'a>(first: &'static dyn Foo<'a>) -> dyn Foo<'a> { | ^^^^^^^^^^^ doesn't have a size known at compile-time | - = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> -help: use `impl Foo<'a>` as the return type, as all return paths are of type `Box<_>`, which implements `Foo<'a>` +help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type | LL | fn or<'a>(first: &'static dyn Foo<'a>) -> impl Foo<'a> { - | ~~~~~~~~~~~~ + | ~~~~ +help: box the return type, and wrap all of the returned values in `Box::new` + | +LL | fn or<'a>(first: &'static dyn Foo<'a>) -> Box<dyn Foo<'a>> { + | ++++ + error: aborting due to previous error diff --git a/tests/ui/use/use-self-type.stderr b/tests/ui/use/use-self-type.stderr index e6153941151..3da04a851f6 100644 --- a/tests/ui/use/use-self-type.stderr +++ b/tests/ui/use/use-self-type.stderr @@ -8,7 +8,7 @@ error[E0432]: unresolved import `Self` --> $DIR/use-self-type.rs:6:13 | LL | use Self::f; - | ^^^^ `Self` is only available in impls, traits, and type definitions + | ^^^^ `Self` cannot be used in imports error: aborting due to 2 previous errors diff --git a/triagebot.toml b/triagebot.toml index a5152434d89..d7cd3ea1275 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -371,31 +371,6 @@ cc = ["@GuillaumeGomez"] message = "Some changes might have occurred in exhaustiveness checking" cc = ["@Nadrieril"] -[mentions."library"] -message = """ -Hey! It looks like you've submitted a new PR for the library teams! - -If this PR contains changes to any `rust-lang/rust` public library APIs then \ -please comment with `@rustbot label +T-libs-api -T-libs` to tag it \ -appropriately. If this PR contains changes to any unstable APIs please edit \ -the PR description to add a link to the relevant [API Change \ -Proposal](https://std-dev-guide.rust-lang.org/feature-lifecycle/api-change-proposals.html) \ -or [create one](https://github.com/rust-lang/libs-team/issues/new?assignees=&labels=api-change-proposal%2C+T-libs-api&template=api-change-proposal.md&title=%28My+API+Change+Proposal%29) \ -if you haven't already. If you're unsure where your change falls no worries, \ -just leave it as is and the reviewer will take a look and make a decision to \ -forward on if necessary. - -Examples of `T-libs-api` changes: - -* Stabilizing library features -* Introducing insta-stable changes such as new implementations of existing \ - stable traits on existing stable types -* Introducing new or changing existing unstable library APIs (excluding \ - permanently unstable features / features without a tracking issue) -* Changing public documentation in ways that create new stability guarantees -* Changing observable runtime behavior of library APIs -""" - [mentions."src/librustdoc/clean/types.rs"] cc = ["@camelid"] @@ -507,7 +482,6 @@ compiler-team = [ "@petrochenkov", "@davidtwco", "@oli-obk", - "@lcnr", "@wesleywiser", ] compiler-team-contributors = [ @@ -618,6 +592,7 @@ style-team = [ "/compiler/rustc_llvm" = ["@cuviper"] "/compiler/rustc_middle/src/mir" = ["compiler", "mir"] "/compiler/rustc_middle/src/traits" = ["compiler", "types"] +"/compiler/rustc_middle/src/ty" = ["compiler", "types"] "/compiler/rustc_const_eval/src/interpret" = ["compiler", "mir"] "/compiler/rustc_const_eval/src/transform" = ["compiler", "mir-opt"] "/compiler/rustc_mir_build/src/build" = ["compiler", "mir"] |
