From 1f3e1cf9530c358676a2bb5c6a4c7734d96f2eca Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 19 Mar 2024 16:09:16 +0000 Subject: [PATCH 01/12] Strip placeholders from hidden types before remapping generic parameter in the hidden type to the generic parameters of the definition of the opaque --- .../src/region_infer/opaque_types.rs | 5 ++ .../type-alias-impl-trait/hkl_forbidden4.rs | 26 ++++++++++ .../hkl_forbidden4.stderr | 51 +++++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 tests/ui/type-alias-impl-trait/hkl_forbidden4.rs create mode 100644 tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 8a17223303718..4bc80ccc84215 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -136,6 +136,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { .find(|ur_vid| self.eval_equal(vid, **ur_vid)) .and_then(|ur_vid| self.definitions[*ur_vid].external_name) .unwrap_or(infcx.tcx.lifetimes.re_erased), + ty::RePlaceholder(_) => ty::Region::new_error_with_message( + infcx.tcx, + concrete_type.span, + "hidden type contains placeholders, we don't support higher kinded opaques yet", + ), _ => region, }); debug!(?universal_concrete_type); diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs b/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs new file mode 100644 index 0000000000000..2ebf497dc5f61 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs @@ -0,0 +1,26 @@ +//! This test used to ICE because, while an error was emitted, +//! we still tried to remap generic params used in the hidden type +//! to the ones of the opaque type definition. + +//@ edition: 2021 + +#![feature(type_alias_impl_trait)] +use std::future::Future; + +type FutNothing<'a> = impl 'a + Future; +//~^ ERROR: unconstrained opaque type + +async fn operation(_: &mut ()) -> () { + //~^ ERROR: concrete type differs from previous + call(operation).await + //~^ ERROR: concrete type differs from previous +} + +async fn call(_f: F) +where + for<'any> F: FnMut(&'any mut ()) -> FutNothing<'any>, +{ + //~^ ERROR: expected generic lifetime parameter, found `'any` +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr b/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr new file mode 100644 index 0000000000000..db3c3245a5158 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr @@ -0,0 +1,51 @@ +error: unconstrained opaque type + --> $DIR/hkl_forbidden4.rs:10:23 + | +LL | type FutNothing<'a> = impl 'a + Future; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `FutNothing` must be used in combination with a concrete type within the same module + +error: concrete type differs from previous defining opaque type use + --> $DIR/hkl_forbidden4.rs:13:1 + | +LL | async fn operation(_: &mut ()) -> () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `FutNothing<'_>`, got `{async fn body@$DIR/hkl_forbidden4.rs:13:38: 17:2}` + | +note: previous use here + --> $DIR/hkl_forbidden4.rs:15:5 + | +LL | call(operation).await + | ^^^^^^^^^^^^^^^ + +error: concrete type differs from previous defining opaque type use + --> $DIR/hkl_forbidden4.rs:15:5 + | +LL | call(operation).await + | ^^^^^^^^^^^^^^^ expected `{async fn body@$DIR/hkl_forbidden4.rs:13:38: 17:2}`, got `FutNothing<'_>` + | +note: previous use here + --> $DIR/hkl_forbidden4.rs:13:38 + | +LL | async fn operation(_: &mut ()) -> () { + | ______________________________________^ +LL | | +LL | | call(operation).await +LL | | +LL | | } + | |_^ + +error[E0792]: expected generic lifetime parameter, found `'any` + --> $DIR/hkl_forbidden4.rs:22:1 + | +LL | type FutNothing<'a> = impl 'a + Future; + | -- this generic parameter must be used with a generic lifetime parameter +... +LL | / { +LL | | +LL | | } + | |_^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0792`. From e0980cca9c12af603276f71dfdc8616d77315dd8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Mar 2024 12:06:07 +0100 Subject: [PATCH 02/12] add some comments to hir::ModuleItems --- compiler/rustc_middle/src/hir/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index f9fa8ac2f7aa5..8ebdd92ad0c72 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -30,6 +30,10 @@ pub struct ModuleItems { } impl ModuleItems { + /// Returns all non-associated locally defined items in all modules. + /// + /// Note that this does *not* include associated items of `impl` blocks! It also does not + /// include foreign items. If you want to e.g. get all functions, use `definitions()` below. pub fn items(&self) -> impl Iterator + '_ { self.items.iter().copied() } @@ -38,6 +42,8 @@ impl ModuleItems { self.trait_items.iter().copied() } + /// Returns all items that are associated with some `impl` block (both inherent and trait impl + /// blocks). pub fn impl_items(&self) -> impl Iterator + '_ { self.impl_items.iter().copied() } From 3e8ff90935df46ed24a073a1ac2d79c600da2b45 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 20 Mar 2024 14:31:05 +0200 Subject: [PATCH 03/12] make "expected paren or brace" error translatable --- compiler/rustc_expand/messages.ftl | 3 +++ compiler/rustc_expand/src/errors.rs | 8 ++++++++ compiler/rustc_expand/src/mbe/quoted.rs | 8 +++++--- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 1f0488130b27d..fdd1a87cae809 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -33,6 +33,9 @@ expand_duplicate_matcher_binding = duplicate matcher binding expand_expected_comma_in_list = expected token: `,` +expand_expected_paren_or_brace = + expected `(` or `{"{"}`, found `{$token}` + expand_explain_doc_comment_inner = inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index fe901603c731c..21ce5e1d81e6e 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -448,3 +448,11 @@ pub struct InvalidFragmentSpecifier { pub fragment: Ident, pub help: String, } + +#[derive(Diagnostic)] +#[diag(expand_expected_paren_or_brace)] +pub struct ExpectedParenOrBrace<'a> { + #[primary_span] + pub span: Span, + pub token: Cow<'a, str>, +} diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 5fd3716743b22..06c1612ddbaea 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -194,9 +194,11 @@ fn parse_tree<'a>( } Delimiter::Parenthesis => {} _ => { - let tok = pprust::token_kind_to_string(&token::OpenDelim(delim)); - let msg = format!("expected `(` or `{{`, found `{tok}`"); - sess.dcx().span_err(delim_span.entire(), msg); + let token = pprust::token_kind_to_string(&token::OpenDelim(delim)); + sess.dcx().emit_err(errors::ExpectedParenOrBrace { + span: delim_span.entire(), + token, + }); } } } From 2fca27cd3b68bf8e883f1aeb0ae56fbf77ad2ef0 Mon Sep 17 00:00:00 2001 From: Roy Buitenhuis Date: Mon, 18 Mar 2024 17:15:12 +0100 Subject: [PATCH 04/12] Add bare metal riscv32 target. --- compiler/rustc_target/src/spec/mod.rs | 1 + .../targets/riscv32ima_unknown_none_elf.rs | 29 +++++++++++++++++++ src/doc/rustc/src/platform-support.md | 1 + .../riscv32-unknown-none-elf.md | 6 +++- src/tools/build-manifest/src/main.rs | 1 + tests/assembly/targets/targets-elf.rs | 3 ++ 6 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 941d767b850dc..896f208f560b4 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1621,6 +1621,7 @@ supported_targets! { ("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf), ("riscv32im-risc0-zkvm-elf", riscv32im_risc0_zkvm_elf), ("riscv32im-unknown-none-elf", riscv32im_unknown_none_elf), + ("riscv32ima-unknown-none-elf", riscv32ima_unknown_none_elf), ("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf), ("riscv32imc-esp-espidf", riscv32imc_esp_espidf), ("riscv32imac-esp-espidf", riscv32imac_esp_espidf), diff --git a/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs new file mode 100644 index 0000000000000..9acf6a3b5a0ee --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs @@ -0,0 +1,29 @@ +use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), + llvm_target: "riscv32".into(), + metadata: crate::spec::TargetMetadata { + description: None, + tier: None, + host_tools: None, + std: None, + }, + pointer_width: 32, + arch: "riscv32".into(), + + options: TargetOptions { + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + cpu: "generic-rv32".into(), + max_atomic_width: Some(32), + features: "+m,+a".into(), + panic_strategy: PanicStrategy::Abort, + relocation_model: RelocModel::Static, + emit_debug_gdb_scripts: false, + eh_frame_header: false, + ..Default::default() + }, + } +} diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 274745b908294..75d38dd20bdeb 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -339,6 +339,7 @@ target | std | host | notes `riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33) `riscv32gc-unknown-linux-musl` | | | RISC-V Linux (kernel 5.4, musl 1.2.3 + RISCV32 support patches) [`riscv32im-risc0-zkvm-elf`](platform-support/riscv32im-risc0-zkvm-elf.md) | ? | | RISC Zero's zero-knowledge Virtual Machine (RV32IM ISA) +[`riscv32ima-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | | Bare RISC-V (RV32IMA ISA) [`riscv32imac-unknown-xous-elf`](platform-support/riscv32imac-unknown-xous-elf.md) | ? | | RISC-V Xous (RV32IMAC ISA) [`riscv32imc-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF [`riscv32imac-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF diff --git a/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md index 739b12bad8b47..9a27a568b5703 100644 --- a/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md +++ b/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md @@ -1,9 +1,13 @@ -# `riscv32{i,im,imc,imac,imafc}-unknown-none-elf` +# `riscv32{i,im,ima,imc,imac,imafc}-unknown-none-elf` **Tier: 2** Bare-metal target for RISC-V CPUs with the RV32I, RV32IM, RV32IMC, RV32IMAFC and RV32IMAC ISAs. +**Tier: 3** + +Bare-metal target for RISC-V CPUs with the RV32IMA ISA. + ## Target maintainers * Rust Embedded Working Group, [RISC-V team](https://github.com/rust-embedded/wg#the-risc-v-team) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index eab9138b8fed6..392a5a1196761 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -126,6 +126,7 @@ static TARGETS: &[&str] = &[ "riscv32i-unknown-none-elf", "riscv32im-risc0-zkvm-elf", "riscv32im-unknown-none-elf", + "riscv32ima-unknown-none-elf", "riscv32imc-unknown-none-elf", "riscv32imac-unknown-none-elf", "riscv32imafc-unknown-none-elf", diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index bda77b5f09b8e..3563aec6d8078 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -369,6 +369,9 @@ //@ revisions: riscv32im_unknown_none_elf //@ [riscv32im_unknown_none_elf] compile-flags: --target riscv32im-unknown-none-elf //@ [riscv32im_unknown_none_elf] needs-llvm-components: riscv +//@ revisions: riscv32ima_unknown_none_elf +//@ [riscv32ima_unknown_none_elf] compile-flags: --target riscv32ima-unknown-none-elf +//@ [riscv32ima_unknown_none_elf] needs-llvm-components: riscv //@ revisions: riscv32imac_esp_espidf //@ [riscv32imac_esp_espidf] compile-flags: --target riscv32imac-esp-espidf //@ [riscv32imac_esp_espidf] needs-llvm-components: riscv From 120d3570aa467c287814fe3edb9003920d8232aa Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 8 Mar 2024 19:17:23 +0100 Subject: [PATCH 05/12] Add barest-bones deref patterns Co-authored-by: Deadbeef --- compiler/rustc_ast_passes/src/feature_gate.rs | 10 ++++-- compiler/rustc_feature/src/unstable.rs | 2 ++ compiler/rustc_hir_typeck/src/pat.rs | 28 +++++++++++++++-- compiler/rustc_middle/src/thir.rs | 9 ++++++ compiler/rustc_middle/src/thir/visit.rs | 1 + .../rustc_mir_build/src/build/matches/mod.rs | 4 +++ .../rustc_mir_build/src/build/matches/util.rs | 6 ++++ .../rustc_mir_build/src/check_unsafety.rs | 3 +- .../rustc_mir_build/src/thir/pattern/mod.rs | 3 ++ compiler/rustc_mir_build/src/thir/print.rs | 6 ++++ compiler/rustc_pattern_analysis/src/rustc.rs | 6 ++++ compiler/rustc_span/src/symbol.rs | 1 + tests/ui/cfg/cfg-false-feature.stderr | 24 +++++++------- .../feature-gate-deref_patterns.rs | 9 ++++++ .../feature-gate-deref_patterns.stderr | 13 ++++++++ tests/ui/pattern/deref-patterns/typeck.rs | 31 +++++++++++++++++++ 16 files changed, 139 insertions(+), 17 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-deref_patterns.rs create mode 100644 tests/ui/feature-gates/feature-gate-deref_patterns.stderr create mode 100644 tests/ui/pattern/deref-patterns/typeck.rs diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 2c396a6478922..277e82b4e5399 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -413,7 +413,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } PatKind::Box(..) => { - gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental"); + if !self.features.deref_patterns { + // Allow box patterns under `deref_patterns`. + gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental"); + } } PatKind::Range(_, Some(_), Spanned { node: RangeEnd::Excluded, .. }) => { gate!( @@ -607,13 +610,16 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { }; } + if !visitor.features.deref_patterns { + // Allow box patterns under `deref_patterns`. + gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental"); + } gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental"); // Despite being a new feature, `where T: Trait`, which is RTN syntax now, // used to be gated under associated_type_bounds, which are right above, so RTN needs to // be too. gate_all_legacy_dont_use!(return_type_notation, "return type notation is experimental"); gate_all_legacy_dont_use!(decl_macro, "`macro` is experimental"); - gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental"); gate_all_legacy_dont_use!( exclusive_range_pattern, "exclusive range pattern syntax is experimental" diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index a3b13c4d907cd..1820e172ea580 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -436,6 +436,8 @@ declare_features! ( (unstable, deprecated_safe, "1.61.0", Some(94978)), /// Allows having using `suggestion` in the `#[deprecated]` attribute. (unstable, deprecated_suggestion, "1.61.0", Some(94785)), + /// Allows deref patterns. + (incomplete, deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121)), /// Controls errors in trait implementations. (unstable, do_not_recommend, "1.67.0", Some(51992)), /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 491da7eb2c2a9..633f851c7d541 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -18,8 +18,7 @@ use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::Span; -use rustc_span::{BytePos, DUMMY_SP}; +use rustc_span::{BytePos, Span, DUMMY_SP}; use rustc_target::abi::FieldIdx; use rustc_trait_selection::traits::{ObligationCause, Pattern}; use ty::VariantDef; @@ -211,6 +210,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PatKind::Tuple(elements, ddpos) => { self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info) } + PatKind::Box(inner) if self.tcx.features().deref_patterns => { + self.check_pat_deref(pat.span, inner, expected, pat_info) + } PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info), PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info), PatKind::Slice(before, slice, after) => { @@ -1975,6 +1977,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { box_ty } + fn check_pat_deref( + &self, + span: Span, + inner: &'tcx Pat<'tcx>, + expected: Ty<'tcx>, + pat_info: PatInfo<'tcx, '_>, + ) -> Ty<'tcx> { + let tcx = self.tcx; + // FIXME(deref_patterns): use `DerefPure` for soundness + // FIXME(deref_patterns): use `DerefMut` when required + // ::Target + let ty = Ty::new_projection( + tcx, + tcx.require_lang_item(hir::LangItem::DerefTarget, Some(span)), + [expected], + ); + let ty = self.normalize(span, ty); + let ty = self.try_structurally_resolve_type(span, ty); + self.check_pat(inner, ty, pat_info); + expected + } + // Precondition: Pat is Ref(inner) fn check_pat_ref( &self, diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 96a61883cc14f..fc9950a51fb2a 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -647,6 +647,7 @@ impl<'tcx> Pat<'tcx> { AscribeUserType { subpattern, .. } | Binding { subpattern: Some(subpattern), .. } | Deref { subpattern } + | DerefPattern { subpattern } | InlineConstant { subpattern, .. } => subpattern.walk_(it), Leaf { subpatterns } | Variant { subpatterns, .. } => { subpatterns.iter().for_each(|field| field.pattern.walk_(it)) @@ -762,6 +763,11 @@ pub enum PatKind<'tcx> { subpattern: Box>, }, + /// Deref pattern, written `box P` for now. + DerefPattern { + subpattern: Box>, + }, + /// One of the following: /// * `&str` (represented as a valtree), which will be handled as a string pattern and thus /// exhaustiveness checking will detect if you use the same string twice in different @@ -1172,6 +1178,9 @@ impl<'tcx> fmt::Display for Pat<'tcx> { } write!(f, "{subpattern}") } + PatKind::DerefPattern { ref subpattern } => { + write!(f, "k#deref {subpattern}") + } PatKind::Constant { value } => write!(f, "{value}"), PatKind::InlineConstant { def: _, ref subpattern } => { write!(f, "{} (from inline const)", subpattern) diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 5952c296fb642..99ab006bcc066 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -229,6 +229,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( match &pat.kind { AscribeUserType { subpattern, ascription: _ } | Deref { subpattern } + | DerefPattern { subpattern } | Binding { subpattern: Some(subpattern), mutability: _, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index d2cbbf9be32c3..f4f452d474f12 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -879,6 +879,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f); } + PatKind::DerefPattern { ref subpattern } => { + self.visit_primary_bindings(subpattern, UserTypeProjections::none(), f); + } + PatKind::AscribeUserType { ref subpattern, ascription: thir::Ascription { ref annotation, variance: _ }, diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index d0d49c13f133d..1148cd19a01c7 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -256,6 +256,12 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { subpairs.push(MatchPair::new(place_builder, subpattern, cx)); default_irrefutable() } + + PatKind::DerefPattern { .. } => { + // FIXME(deref_patterns) + // Treat it like a wildcard for now. + default_irrefutable() + } }; MatchPair { place, test_case, subpairs, pattern } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 1ce8da162bfa5..e04fe31a76f2b 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -250,6 +250,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { | PatKind::Variant { .. } | PatKind::Leaf { .. } | PatKind::Deref { .. } + | PatKind::DerefPattern { .. } | PatKind::Range { .. } | PatKind::Slice { .. } | PatKind::Array { .. } => { @@ -310,7 +311,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { } visit::walk_pat(self, pat); } - PatKind::Deref { .. } => { + PatKind::Deref { .. } | PatKind::DerefPattern { .. } => { let old_inside_adt = std::mem::replace(&mut self.inside_adt, false); visit::walk_pat(self, pat); self.inside_adt = old_inside_adt; diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 03eda9a932223..f4aed91cd724b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -257,6 +257,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { return self.lower_path(qpath, pat.hir_id, pat.span); } + hir::PatKind::Box(subpattern) if self.tcx.features().deref_patterns => { + PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern) } + } hir::PatKind::Ref(subpattern, _) | hir::PatKind::Box(subpattern) => { PatKind::Deref { subpattern: self.lower_pattern(subpattern) } } diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index d53704f89e79e..16c4248a15969 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -688,6 +688,12 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_pat(subpattern, depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } + PatKind::DerefPattern { subpattern } => { + print_indented!(self, "DerefPattern { ", depth_lvl + 1); + print_indented!(self, "subpattern:", depth_lvl + 2); + self.print_pat(subpattern, depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } PatKind::Constant { value } => { print_indented!(self, "Constant {", depth_lvl + 1); print_indented!(self, format!("value: {:?}", value), depth_lvl + 2); diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index eedc00a561304..4cb306b19505a 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -462,6 +462,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { _ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, ty), }; } + PatKind::DerefPattern { .. } => { + // FIXME(deref_patterns): At least detect that `box _` is irrefutable. + fields = vec![]; + arity = 0; + ctor = Opaque(OpaqueId::new()); + } PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => { match ty.kind() { ty::Tuple(fs) => { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8b911a41a112f..8b35087a0056b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -674,6 +674,7 @@ symbols! { deref_method, deref_mut, deref_mut_method, + deref_patterns, deref_target, derive, derive_const, diff --git a/tests/ui/cfg/cfg-false-feature.stderr b/tests/ui/cfg/cfg-false-feature.stderr index 9309b59ca591f..542aeaf5caf81 100644 --- a/tests/ui/cfg/cfg-false-feature.stderr +++ b/tests/ui/cfg/cfg-false-feature.stderr @@ -1,15 +1,3 @@ -warning: trait aliases are experimental - --> $DIR/cfg-false-feature.rs:12:1 - | -LL | trait A = Clone; - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #41517 for more information - = help: add `#![feature(trait_alias)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = warning: unstable syntax can change at any point in the future, causing a hard error! - = note: for more information, see issue #65860 - warning: box pattern syntax is experimental --> $DIR/cfg-false-feature.rs:16:9 | @@ -22,5 +10,17 @@ LL | let box _ = Box::new(0); = warning: unstable syntax can change at any point in the future, causing a hard error! = note: for more information, see issue #65860 +warning: trait aliases are experimental + --> $DIR/cfg-false-feature.rs:12:1 + | +LL | trait A = Clone; + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #41517 for more information + = help: add `#![feature(trait_alias)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + warning: 2 warnings emitted diff --git a/tests/ui/feature-gates/feature-gate-deref_patterns.rs b/tests/ui/feature-gates/feature-gate-deref_patterns.rs new file mode 100644 index 0000000000000..b43001f2d53fa --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-deref_patterns.rs @@ -0,0 +1,9 @@ +fn main() { + // We reuse the `box` syntax so this doesn't actually test the feature gate but eh. + let box x = Box::new('c'); //~ ERROR box pattern syntax is experimental + println!("x: {}", x); + + // `box` syntax is allowed to be cfg-ed out for historical reasons (#65742). + #[cfg(FALSE)] + let box _x = Box::new('c'); +} diff --git a/tests/ui/feature-gates/feature-gate-deref_patterns.stderr b/tests/ui/feature-gates/feature-gate-deref_patterns.stderr new file mode 100644 index 0000000000000..48426b50d8948 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-deref_patterns.stderr @@ -0,0 +1,13 @@ +error[E0658]: box pattern syntax is experimental + --> $DIR/feature-gate-deref_patterns.rs:3:9 + | +LL | let box x = Box::new('c'); + | ^^^^^ + | + = note: see issue #29641 for more information + = help: add `#![feature(box_patterns)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/pattern/deref-patterns/typeck.rs b/tests/ui/pattern/deref-patterns/typeck.rs new file mode 100644 index 0000000000000..20577abe48575 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/typeck.rs @@ -0,0 +1,31 @@ +//@ check-pass +#![feature(deref_patterns)] +#![allow(incomplete_features)] + +use std::rc::Rc; + +fn main() { + let vec: Vec = Vec::new(); + match vec { + box [..] => {} + _ => {} + } + match Box::new(true) { + box true => {} + _ => {} + } + match &Box::new(true) { + box true => {} + _ => {} + } + match &Rc::new(0) { + box (1..) => {} + _ => {} + } + // FIXME(deref_patterns): fails to typecheck because `"foo"` has type &str but deref creates a + // place of type `str`. + // match "foo".to_string() { + // box "foo" => {} + // _ => {} + // } +} From ff504a09fee5817acc043939bda1b0b1c8787eda Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Wed, 20 Mar 2024 15:55:35 -0700 Subject: [PATCH 06/12] Improve emit stable mir body --- .../rustc_smir/src/rustc_internal/internal.rs | 46 +- .../rustc_smir/src/rustc_internal/pretty.rs | 2 +- compiler/rustc_smir/src/rustc_smir/context.rs | 15 +- compiler/stable_mir/src/compiler_interface.rs | 10 +- compiler/stable_mir/src/lib.rs | 6 +- compiler/stable_mir/src/mir/body.rs | 29 +- compiler/stable_mir/src/mir/pretty.rs | 521 +++++++----------- tests/ui/stable-mir-print/basic_function.rs | 13 +- .../ui/stable-mir-print/basic_function.stdout | 266 ++------- 9 files changed, 348 insertions(+), 560 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 2cc9bc31873a4..bf7346be31fe8 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -10,7 +10,7 @@ use rustc_span::Symbol; use stable_mir::abi::Layout; use stable_mir::mir::alloc::AllocId; use stable_mir::mir::mono::{Instance, MonoItem, StaticDef}; -use stable_mir::mir::{Mutability, Safety}; +use stable_mir::mir::{Mutability, Place, ProjectionElem, Safety}; use stable_mir::ty::{ Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, DynKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig, @@ -492,6 +492,50 @@ impl RustcInternal for Layout { } } +impl RustcInternal for Place { + type T<'tcx> = rustc_middle::mir::Place<'tcx>; + + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + rustc_middle::mir::Place { + local: rustc_middle::mir::Local::from_usize(self.local), + projection: tcx.mk_place_elems(&self.projection.internal(tables, tcx)), + } + } +} + +impl RustcInternal for ProjectionElem { + type T<'tcx> = rustc_middle::mir::PlaceElem<'tcx>; + + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + match self { + ProjectionElem::Deref => rustc_middle::mir::PlaceElem::Deref, + ProjectionElem::Field(idx, ty) => { + rustc_middle::mir::PlaceElem::Field((*idx).into(), ty.internal(tables, tcx)) + } + ProjectionElem::Index(idx) => rustc_middle::mir::PlaceElem::Index((*idx).into()), + ProjectionElem::ConstantIndex { offset, min_length, from_end } => { + rustc_middle::mir::PlaceElem::ConstantIndex { + offset: *offset, + min_length: *min_length, + from_end: *from_end, + } + } + ProjectionElem::Subslice { from, to, from_end } => { + rustc_middle::mir::PlaceElem::Subslice { from: *from, to: *to, from_end: *from_end } + } + ProjectionElem::Downcast(idx) => { + rustc_middle::mir::PlaceElem::Downcast(None, idx.internal(tables, tcx)) + } + ProjectionElem::OpaqueCast(ty) => { + rustc_middle::mir::PlaceElem::OpaqueCast(ty.internal(tables, tcx)) + } + ProjectionElem::Subtype(ty) => { + rustc_middle::mir::PlaceElem::Subtype(ty.internal(tables, tcx)) + } + } + } +} + impl RustcInternal for &T where T: RustcInternal, diff --git a/compiler/rustc_smir/src/rustc_internal/pretty.rs b/compiler/rustc_smir/src/rustc_internal/pretty.rs index 3ef2d28ea4734..c0dce08b0d33a 100644 --- a/compiler/rustc_smir/src/rustc_internal/pretty.rs +++ b/compiler/rustc_smir/src/rustc_internal/pretty.rs @@ -14,7 +14,7 @@ pub fn write_smir_pretty<'tcx, W: io::Write>(tcx: TyCtxt<'tcx>, w: &mut W) -> io )?; let _ = run(tcx, || { let items = stable_mir::all_local_items(); - let _ = items.iter().map(|item| -> io::Result<()> { item.dump(w) }).collect::>(); + let _ = items.iter().map(|item| -> io::Result<()> { item.emit_mir(w) }).collect::>(); }); Ok(()) } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index d427e5fb88d61..66917c73aa520 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -19,7 +19,7 @@ use stable_mir::abi::{FnAbi, Layout, LayoutShape}; use stable_mir::compiler_interface::Context; use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::mono::{InstanceDef, StaticDef}; -use stable_mir::mir::Body; +use stable_mir::mir::{Body, Place}; use stable_mir::target::{MachineInfo, MachineSize}; use stable_mir::ty::{ AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef, @@ -423,7 +423,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { def_ty.instantiate(tables.tcx, args).stable(&mut *tables) } - fn const_literal(&self, cnst: &stable_mir::ty::Const) -> String { + fn const_pretty(&self, cnst: &stable_mir::ty::Const) -> String { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; cnst.internal(&mut *tables, tcx).to_string() @@ -434,6 +434,11 @@ impl<'tcx> Context for TablesWrapper<'tcx> { tables.tcx.def_span(tables[def_id]).stable(&mut *tables) } + fn ty_pretty(&self, ty: stable_mir::ty::Ty) -> String { + let tables = self.0.borrow_mut(); + tables.types[ty].to_string() + } + fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind { let mut tables = self.0.borrow_mut(); tables.types[ty].kind().stable(&mut *tables) @@ -654,6 +659,12 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let tcx = tables.tcx; id.internal(&mut *tables, tcx).0.stable(&mut *tables) } + + fn place_debug(&self, place: &Place) -> String { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + format!("{:?}", place.internal(&mut *tables, tcx)) + } } pub struct TablesWrapper<'tcx>(pub RefCell>); diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index f53dbcfbd966e..68f078892ef04 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -8,7 +8,7 @@ use std::cell::Cell; use crate::abi::{FnAbi, Layout, LayoutShape}; use crate::mir::alloc::{AllocId, GlobalAlloc}; use crate::mir::mono::{Instance, InstanceDef, StaticDef}; -use crate::mir::Body; +use crate::mir::{Body, Place}; use crate::target::MachineInfo; use crate::ty::{ AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef, @@ -126,11 +126,14 @@ pub trait Context { fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty; /// Returns literal value of a const as a string. - fn const_literal(&self, cnst: &Const) -> String; + fn const_pretty(&self, cnst: &Const) -> String; /// `Span` of an item fn span_of_an_item(&self, def_id: DefId) -> Span; + /// Obtain the representation of a type. + fn ty_pretty(&self, ty: Ty) -> String; + /// Obtain the representation of a type. fn ty_kind(&self, ty: Ty) -> TyKind; @@ -205,6 +208,9 @@ pub trait Context { /// Get the layout shape. fn layout_shape(&self, id: Layout) -> LayoutShape; + + /// Get a debug string representation of a place. + fn place_debug(&self, place: &Place) -> String; } // A thread local variable that stores a pointer to the tables mapping between TyCtxt diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index d849c834ae00e..d1a2948ea77ca 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -27,7 +27,6 @@ use crate::compiler_interface::with; pub use crate::crate_def::CrateDef; pub use crate::crate_def::DefId; pub use crate::error::*; -use crate::mir::pretty::function_name; use crate::mir::Body; use crate::mir::Mutability; use crate::ty::{ForeignModuleDef, ImplDef, IndexedVal, Span, TraitDef, Ty}; @@ -148,9 +147,8 @@ impl CrateItem { with(|cx| cx.is_foreign_item(self.0)) } - pub fn dump(&self, w: &mut W) -> io::Result<()> { - writeln!(w, "{}", function_name(*self))?; - self.body().dump(w) + pub fn emit_mir(&self, w: &mut W) -> io::Result<()> { + self.body().dump(w, &self.name()) } } diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index ae8e71bb950a1..4f67a76e24c2c 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -1,10 +1,11 @@ -use crate::mir::pretty::{function_body, pretty_statement, pretty_terminator}; +use crate::mir::pretty::function_body; use crate::ty::{ AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind, VariantIdx, }; use crate::{Error, Opaque, Span, Symbol}; use std::io; + /// The SMIR representation of a single function. #[derive(Clone, Debug)] pub struct Body { @@ -90,28 +91,8 @@ impl Body { self.locals.iter().enumerate() } - pub fn dump(&self, w: &mut W) -> io::Result<()> { - writeln!(w, "{}", function_body(self))?; - self.blocks - .iter() - .enumerate() - .map(|(index, block)| -> io::Result<()> { - writeln!(w, " bb{}: {{", index)?; - let _ = block - .statements - .iter() - .map(|statement| -> io::Result<()> { - writeln!(w, "{}", pretty_statement(&statement.kind))?; - Ok(()) - }) - .collect::>(); - pretty_terminator(&block.terminator.kind, w)?; - writeln!(w, "").unwrap(); - writeln!(w, " }}").unwrap(); - Ok(()) - }) - .collect::, _>>()?; - Ok(()) + pub(crate) fn dump(&self, w: &mut W, fn_name: &str) -> io::Result<()> { + function_body(w, self, fn_name) } pub fn spread_arg(&self) -> Option { @@ -674,7 +655,7 @@ pub enum Operand { Constant(Constant), } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Eq, PartialEq)] pub struct Place { pub local: Local, /// projection out of a place (access a field, deref a pointer, etc) diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs index 8b7b488d312cf..8c3ebb56fb07a 100644 --- a/compiler/stable_mir/src/mir/pretty.rs +++ b/compiler/stable_mir/src/mir/pretty.rs @@ -1,185 +1,193 @@ -use crate::crate_def::CrateDef; -use crate::mir::{Operand, Rvalue, StatementKind, UnwindAction}; -use crate::ty::{DynKind, FloatTy, IntTy, RigidTy, TyKind, UintTy}; -use crate::{with, Body, CrateItem, Mutability}; +use crate::mir::{Operand, Place, Rvalue, StatementKind, UnwindAction, VarDebugInfoContents}; +use crate::ty::{Const, IndexedVal, Ty}; +use crate::{with, Body, Mutability}; +use fmt::{Display, Formatter}; +use std::fmt::Debug; use std::io::Write; -use std::{io, iter}; +use std::{fmt, io, iter}; use super::{AssertMessage, BinOp, TerminatorKind}; -pub fn function_name(item: CrateItem) -> String { - let mut pretty_name = String::new(); - let body = item.body(); - pretty_name.push_str("fn "); - pretty_name.push_str(item.name().as_str()); - if body.arg_locals().is_empty() { - pretty_name.push_str("()"); - } else { - pretty_name.push_str("("); - } - body.arg_locals().iter().enumerate().for_each(|(index, local)| { - pretty_name.push_str(format!("_{}: ", index).as_str()); - pretty_name.push_str(&pretty_ty(local.ty.kind())); - }); - if !body.arg_locals().is_empty() { - pretty_name.push_str(")"); +use super::BorrowKind; + +impl Display for Ty { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + with(|ctx| write!(f, "{}", ctx.ty_pretty(*self))) } - let return_local = body.ret_local(); - pretty_name.push_str(" -> "); - pretty_name.push_str(&pretty_ty(return_local.ty.kind())); - pretty_name.push_str(" {"); - pretty_name } -pub fn function_body(body: &Body) -> String { - let mut pretty_body = String::new(); - body.inner_locals().iter().enumerate().for_each(|(index, local)| { - pretty_body.push_str(" "); - pretty_body.push_str(format!("let {}", ret_mutability(&local.mutability)).as_str()); - pretty_body.push_str(format!("_{}: ", index).as_str()); - pretty_body.push_str(format!("{}", pretty_ty(local.ty.kind())).as_str()); - pretty_body.push_str(";\n"); - }); - pretty_body.push_str("}"); - pretty_body +impl Debug for Place { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + with(|ctx| write!(f, "{}", ctx.place_debug(self))) + } } -pub fn ret_mutability(mutability: &Mutability) -> String { - match mutability { - Mutability::Not => "".to_string(), - Mutability::Mut => "mut ".to_string(), - } +pub(crate) fn function_body(writer: &mut W, body: &Body, name: &str) -> io::Result<()> { + write!(writer, "fn {}(", name)?; + body.arg_locals() + .iter() + .enumerate() + .try_for_each(|(index, local)| write!(writer, "_{}: {}", index + 1, local.ty))?; + write!(writer, ")")?; + + let return_local = body.ret_local(); + writeln!(writer, " -> {} {{", return_local.ty)?; + + body.locals().iter().enumerate().try_for_each(|(index, local)| -> io::Result<()> { + if index == 0 || index > body.arg_count { + writeln!(writer, " let {}_{}: {};", pretty_mut(local.mutability), index, local.ty) + } else { + Ok(()) + } + })?; + + body.var_debug_info.iter().try_for_each(|info| { + let content = match &info.value { + VarDebugInfoContents::Place(place) => { + format!("{place:?}") + } + VarDebugInfoContents::Const(constant) => pretty_const(&constant.const_), + }; + writeln!(writer, " debug {} => {};", info.name, content) + })?; + + body.blocks + .iter() + .enumerate() + .map(|(index, block)| -> io::Result<()> { + writeln!(writer, " bb{}: {{", index)?; + let _ = block + .statements + .iter() + .map(|statement| -> io::Result<()> { + pretty_statement(writer, &statement.kind)?; + Ok(()) + }) + .collect::>(); + pretty_terminator(writer, &block.terminator.kind)?; + writeln!(writer, " }}").unwrap(); + Ok(()) + }) + .collect::, _>>()?; + writeln!(writer, "}}")?; + Ok(()) } -pub fn pretty_statement(statement: &StatementKind) -> String { - let mut pretty = String::new(); +fn pretty_statement(writer: &mut W, statement: &StatementKind) -> io::Result<()> { match statement { StatementKind::Assign(place, rval) => { - pretty.push_str(format!(" _{} = ", place.local).as_str()); - pretty.push_str(format!("{}", &pretty_rvalue(rval)).as_str()); + write!(writer, " {:?} = ", place)?; + pretty_rvalue(writer, rval)?; + writeln!(writer, ";") } // FIXME: Add rest of the statements - StatementKind::FakeRead(_, _) => { - return String::from("StatementKind::FakeRead:Unimplemented"); + StatementKind::FakeRead(cause, place) => { + writeln!(writer, "FakeRead({cause:?}, {place:?});") } - StatementKind::SetDiscriminant { .. } => { - return String::from("StatementKind::SetDiscriminant:Unimplemented"); + StatementKind::SetDiscriminant { place, variant_index } => { + writeln!(writer, "discriminant({place:?} = {};", variant_index.to_index()) } - StatementKind::Deinit(_) => return String::from("StatementKind::Deinit:Unimplemented"), - StatementKind::StorageLive(_) => { - return String::from("StatementKind::StorageLive:Unimplemented"); + StatementKind::Deinit(place) => writeln!(writer, "Deinit({place:?};"), + StatementKind::StorageLive(local) => { + writeln!(writer, "StorageLive(_{local});") } - StatementKind::StorageDead(_) => { - return String::from("StatementKind::StorageDead:Unimplemented"); + StatementKind::StorageDead(local) => { + writeln!(writer, "StorageDead(_{local});") } - StatementKind::Retag(_, _) => return String::from("StatementKind::Retag:Unimplemented"), - StatementKind::PlaceMention(_) => { - return String::from("StatementKind::PlaceMention:Unimplemented"); - } - StatementKind::AscribeUserType { .. } => { - return String::from("StatementKind::AscribeUserType:Unimplemented"); - } - StatementKind::Coverage(_) => return String::from("StatementKind::Coverage:Unimplemented"), - StatementKind::Intrinsic(_) => { - return String::from("StatementKind::Intrinsic:Unimplemented"); + StatementKind::Retag(kind, place) => writeln!(writer, "Retag({kind:?}, {place:?});"), + StatementKind::PlaceMention(place) => { + writeln!(writer, "PlaceMention({place:?};") } StatementKind::ConstEvalCounter => { - return String::from("StatementKind::ConstEvalCounter:Unimplemented"); + writeln!(writer, "ConstEvalCounter;") + } + StatementKind::Nop => writeln!(writer, "nop;"), + StatementKind::AscribeUserType { .. } + | StatementKind::Coverage(_) + | StatementKind::Intrinsic(_) => { + // FIX-ME: Make them pretty. + writeln!(writer, "{statement:?};") } - StatementKind::Nop => return String::from("StatementKind::Nop:Unimplemented"), } - pretty } -pub fn pretty_terminator(terminator: &TerminatorKind, w: &mut W) -> io::Result<()> { - write!(w, "{}", pretty_terminator_head(terminator))?; +fn pretty_terminator(writer: &mut W, terminator: &TerminatorKind) -> io::Result<()> { + pretty_terminator_head(writer, terminator)?; let successors = terminator.successors(); let successor_count = successors.len(); let labels = pretty_successor_labels(terminator); let show_unwind = !matches!(terminator.unwind(), None | Some(UnwindAction::Cleanup(_))); - let fmt_unwind = |fmt: &mut dyn Write| -> io::Result<()> { - write!(fmt, "unwind ")?; + let fmt_unwind = |w: &mut W| -> io::Result<()> { + write!(w, "unwind ")?; match terminator.unwind() { None | Some(UnwindAction::Cleanup(_)) => unreachable!(), - Some(UnwindAction::Continue) => write!(fmt, "continue"), - Some(UnwindAction::Unreachable) => write!(fmt, "unreachable"), - Some(UnwindAction::Terminate) => write!(fmt, "terminate"), + Some(UnwindAction::Continue) => write!(w, "continue"), + Some(UnwindAction::Unreachable) => write!(w, "unreachable"), + Some(UnwindAction::Terminate) => write!(w, "terminate"), } }; match (successor_count, show_unwind) { - (0, false) => Ok(()), + (0, false) => {} (0, true) => { - write!(w, " -> ")?; - fmt_unwind(w)?; - Ok(()) - } - (1, false) => { - write!(w, " -> {:?}", successors[0])?; - Ok(()) + write!(writer, " -> ")?; + fmt_unwind(writer)?; } + (1, false) => write!(writer, " -> bb{:?}", successors[0])?, _ => { - write!(w, " -> [")?; + write!(writer, " -> [")?; for (i, target) in successors.iter().enumerate() { if i > 0 { - write!(w, ", ")?; + write!(writer, ", ")?; } - write!(w, "{}: bb{:?}", labels[i], target)?; + write!(writer, "{}: bb{:?}", labels[i], target)?; } if show_unwind { - write!(w, ", ")?; - fmt_unwind(w)?; + write!(writer, ", ")?; + fmt_unwind(writer)?; } - write!(w, "]") + write!(writer, "]")?; } - }?; + }; - Ok(()) + writeln!(writer, ";") } -pub fn pretty_terminator_head(terminator: &TerminatorKind) -> String { +fn pretty_terminator_head(writer: &mut W, terminator: &TerminatorKind) -> io::Result<()> { use self::TerminatorKind::*; - let mut pretty = String::new(); + const INDENT: &'static str = " "; match terminator { - Goto { .. } => format!(" goto"), + Goto { .. } => write!(writer, "{INDENT}goto"), SwitchInt { discr, .. } => { - format!(" switchInt(_{})", pretty_operand(discr)) + write!(writer, "{INDENT}switchInt({})", pretty_operand(discr)) } - Resume => format!(" resume"), - Abort => format!(" abort"), - Return => format!(" return"), - Unreachable => format!(" unreachable"), - Drop { place, .. } => format!(" drop(_{:?})", place.local), + Resume => write!(writer, "{INDENT}resume"), + Abort => write!(writer, "{INDENT}abort"), + Return => write!(writer, "{INDENT}return"), + Unreachable => write!(writer, "{INDENT}unreachable"), + Drop { place, .. } => write!(writer, "{INDENT}drop({:?})", place), Call { func, args, destination, .. } => { - pretty.push_str(" "); - pretty.push_str(format!("_{} = ", destination.local).as_str()); - pretty.push_str(&pretty_operand(func)); - pretty.push_str("("); - args.iter().enumerate().for_each(|(i, arg)| { - if i > 0 { - pretty.push_str(", "); - } - pretty.push_str(&pretty_operand(arg)); - }); - pretty.push_str(")"); - pretty + write!(writer, "{INDENT}{:?} = {}(", destination, pretty_operand(func))?; + let mut args_iter = args.iter(); + args_iter.next().map_or(Ok(()), |arg| write!(writer, "{}", pretty_operand(arg)))?; + args_iter.try_for_each(|arg| write!(writer, ", {}", pretty_operand(arg)))?; + write!(writer, ")") } Assert { cond, expected, msg, target: _, unwind: _ } => { - pretty.push_str(" assert("); + write!(writer, "{INDENT}assert(")?; if !expected { - pretty.push_str("!"); + write!(writer, "!")?; } - pretty.push_str(format!("{} bool),", &pretty_operand(cond)).as_str()); - pretty.push_str(&pretty_assert_message(msg)); - pretty.push_str(")"); - pretty + write!(writer, "{}, ", &pretty_operand(cond))?; + pretty_assert_message(writer, msg)?; + write!(writer, ")") } - InlineAsm { .. } => todo!(), + InlineAsm { .. } => write!(writer, "{INDENT}InlineAsm"), } } -pub fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec { +fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec { use self::TerminatorKind::*; match terminator { Resume | Abort | Return | Unreachable => vec![], @@ -201,283 +209,174 @@ pub fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec { vec!["success".into(), "unwind".into()] } Assert { unwind: _, .. } => vec!["success".into()], - InlineAsm { .. } => todo!(), + InlineAsm { destination: Some(_), .. } => vec!["goto".into(), "unwind".into()], + InlineAsm { destination: None, .. } => vec!["unwind".into()], } } -pub fn pretty_assert_message(msg: &AssertMessage) -> String { - let mut pretty = String::new(); +fn pretty_assert_message(writer: &mut W, msg: &AssertMessage) -> io::Result<()> { match msg { AssertMessage::BoundsCheck { len, index } => { let pretty_len = pretty_operand(len); let pretty_index = pretty_operand(index); - pretty.push_str(format!("\"index out of bounds: the length is {{}} but the index is {{}}\", {pretty_len}, {pretty_index}").as_str()); - pretty + write!( + writer, + "\"index out of bounds: the length is {{}} but the index is {{}}\", {pretty_len}, {pretty_index}" + ) } AssertMessage::Overflow(BinOp::Add, l, r) => { let pretty_l = pretty_operand(l); let pretty_r = pretty_operand(r); - pretty.push_str(format!("\"attempt to compute `{{}} + {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str()); - pretty + write!( + writer, + "\"attempt to compute `{{}} + {{}}`, which would overflow\", {pretty_l}, {pretty_r}" + ) } AssertMessage::Overflow(BinOp::Sub, l, r) => { let pretty_l = pretty_operand(l); let pretty_r = pretty_operand(r); - pretty.push_str(format!("\"attempt to compute `{{}} - {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str()); - pretty + write!( + writer, + "\"attempt to compute `{{}} - {{}}`, which would overflow\", {pretty_l}, {pretty_r}" + ) } AssertMessage::Overflow(BinOp::Mul, l, r) => { let pretty_l = pretty_operand(l); let pretty_r = pretty_operand(r); - pretty.push_str(format!("\"attempt to compute `{{}} * {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str()); - pretty + write!( + writer, + "\"attempt to compute `{{}} * {{}}`, which would overflow\", {pretty_l}, {pretty_r}" + ) } AssertMessage::Overflow(BinOp::Div, l, r) => { let pretty_l = pretty_operand(l); let pretty_r = pretty_operand(r); - pretty.push_str(format!("\"attempt to compute `{{}} / {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str()); - pretty + write!( + writer, + "\"attempt to compute `{{}} / {{}}`, which would overflow\", {pretty_l}, {pretty_r}" + ) } AssertMessage::Overflow(BinOp::Rem, l, r) => { let pretty_l = pretty_operand(l); let pretty_r = pretty_operand(r); - pretty.push_str(format!("\"attempt to compute `{{}} % {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str()); - pretty + write!( + writer, + "\"attempt to compute `{{}} % {{}}`, which would overflow\", {pretty_l}, {pretty_r}" + ) } AssertMessage::Overflow(BinOp::Shr, _, r) => { let pretty_r = pretty_operand(r); - pretty.push_str( - format!("\"attempt to shift right by `{{}}`, which would overflow\", {pretty_r}") - .as_str(), - ); - pretty + write!(writer, "\"attempt to shift right by `{{}}`, which would overflow\", {pretty_r}") } AssertMessage::Overflow(BinOp::Shl, _, r) => { let pretty_r = pretty_operand(r); - pretty.push_str( - format!("\"attempt to shift left by `{{}}`, which would overflow\", {pretty_r}") - .as_str(), - ); - pretty + write!(writer, "\"attempt to shift left by `{{}}`, which would overflow\", {pretty_r}") } AssertMessage::Overflow(op, _, _) => unreachable!("`{:?}` cannot overflow", op), AssertMessage::OverflowNeg(op) => { let pretty_op = pretty_operand(op); - pretty.push_str( - format!("\"attempt to negate `{{}}`, which would overflow\", {pretty_op}").as_str(), - ); - pretty + write!(writer, "\"attempt to negate `{{}}`, which would overflow\", {pretty_op}") } AssertMessage::DivisionByZero(op) => { let pretty_op = pretty_operand(op); - pretty.push_str(format!("\"attempt to divide `{{}}` by zero\", {pretty_op}").as_str()); - pretty + write!(writer, "\"attempt to divide `{{}}` by zero\", {pretty_op}") } AssertMessage::RemainderByZero(op) => { let pretty_op = pretty_operand(op); - pretty.push_str( - format!("\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {pretty_op}").as_str(), - ); - pretty + write!( + writer, + "\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {pretty_op}" + ) } AssertMessage::MisalignedPointerDereference { required, found } => { let pretty_required = pretty_operand(required); let pretty_found = pretty_operand(found); - pretty.push_str(format!("\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\",{pretty_required}, {pretty_found}").as_str()); - pretty + write!( + writer, + "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\",{pretty_required}, {pretty_found}" + ) } AssertMessage::ResumedAfterReturn(_) | AssertMessage::ResumedAfterPanic(_) => { - msg.description().unwrap().to_string() + write!(writer, "{}", msg.description().unwrap()) } } } -pub fn pretty_operand(operand: &Operand) -> String { - let mut pretty = String::new(); +fn pretty_operand(operand: &Operand) -> String { match operand { Operand::Copy(copy) => { - pretty.push_str(""); - pretty.push_str(format!("{}", copy.local).as_str()); + format!("{:?}", copy) } Operand::Move(mv) => { - pretty.push_str("move "); - pretty.push_str(format!("_{}", mv.local).as_str()); - } - Operand::Constant(cnst) => { - pretty.push_str("const "); - pretty.push_str(with(|cx| cx.const_literal(&cnst.literal)).as_str()); + format!("move {:?}", mv) } + Operand::Constant(cnst) => pretty_const(&cnst.literal), } - pretty } -pub fn pretty_rvalue(rval: &Rvalue) -> String { - let mut pretty = String::new(); +fn pretty_const(literal: &Const) -> String { + with(|cx| cx.const_pretty(&literal)) +} + +fn pretty_rvalue(writer: &mut W, rval: &Rvalue) -> io::Result<()> { match rval { - Rvalue::AddressOf(muta, addr) => { - pretty.push_str("&raw "); - pretty.push_str(&ret_mutability(muta)); - pretty.push_str(format!("(*_{})", addr.local).as_str()); - } - Rvalue::Aggregate(aggregatekind, operands) => { - pretty.push_str(format!("{:#?}", aggregatekind).as_str()); - pretty.push_str("("); - operands.iter().enumerate().for_each(|(i, op)| { - pretty.push_str(&pretty_operand(op)); - if i != operands.len() - 1 { - pretty.push_str(", "); - } - }); - pretty.push_str(")"); + Rvalue::AddressOf(mutability, place) => { + write!(writer, "&raw {}(*{:?})", &pretty_mut(*mutability), place) } - Rvalue::BinaryOp(bin, op, op2) => { - pretty.push_str(&pretty_operand(op)); - pretty.push_str(" "); - pretty.push_str(format!("{:#?}", bin).as_str()); - pretty.push_str(" "); - pretty.push_str(&pretty_operand(op2)); + Rvalue::Aggregate(aggregate_kind, operands) => { + // FIXME: Add pretty_aggregate function that returns a pretty string + write!(writer, "{aggregate_kind:?} (")?; + let mut op_iter = operands.iter(); + op_iter.next().map_or(Ok(()), |op| write!(writer, "{}", pretty_operand(op)))?; + op_iter.try_for_each(|op| write!(writer, ", {}", pretty_operand(op)))?; + write!(writer, ")") + } + Rvalue::BinaryOp(bin, op1, op2) => { + write!(writer, "{:?}({}, {})", bin, &pretty_operand(op1), pretty_operand(op2)) } Rvalue::Cast(_, op, ty) => { - pretty.push_str(&pretty_operand(op)); - pretty.push_str(" as "); - pretty.push_str(&pretty_ty(ty.kind())); + write!(writer, "{} as {}", pretty_operand(op), ty) } Rvalue::CheckedBinaryOp(bin, op1, op2) => { - pretty.push_str(&pretty_operand(op1)); - pretty.push_str(" "); - pretty.push_str(format!("{:#?}", bin).as_str()); - pretty.push_str(" "); - pretty.push_str(&pretty_operand(op2)); + write!(writer, "Checked{:?}({}, {})", bin, &pretty_operand(op1), pretty_operand(op2)) } Rvalue::CopyForDeref(deref) => { - pretty.push_str("CopyForDeref"); - pretty.push_str(format!("{}", deref.local).as_str()); + write!(writer, "CopyForDeref({:?})", deref) } Rvalue::Discriminant(place) => { - pretty.push_str("discriminant"); - pretty.push_str(format!("{}", place.local).as_str()); + write!(writer, "discriminant({:?})", place) } Rvalue::Len(len) => { - pretty.push_str("len"); - pretty.push_str(format!("{}", len.local).as_str()); + write!(writer, "len({:?})", len) } Rvalue::Ref(_, borrowkind, place) => { - pretty.push_str("ref"); - pretty.push_str(format!("{:#?}", borrowkind).as_str()); - pretty.push_str(format!("{}", place.local).as_str()); + let kind = match borrowkind { + BorrowKind::Shared => "&", + BorrowKind::Fake => "&fake ", + BorrowKind::Mut { .. } => "&mut ", + }; + write!(writer, "{kind}{:?}", place) } Rvalue::Repeat(op, cnst) => { - pretty.push_str(&pretty_operand(op)); - pretty.push_str(" "); - pretty.push_str(&pretty_ty(cnst.ty().kind())); + write!(writer, "{} \" \" {}", &pretty_operand(op), cnst.ty()) } - Rvalue::ShallowInitBox(_, _) => (), + Rvalue::ShallowInitBox(_, _) => Ok(()), Rvalue::ThreadLocalRef(item) => { - pretty.push_str("thread_local_ref"); - pretty.push_str(format!("{:#?}", item).as_str()); + write!(writer, "thread_local_ref{:?}", item) } Rvalue::NullaryOp(nul, ty) => { - pretty.push_str(format!("{:#?}", nul).as_str()); - pretty.push_str(&pretty_ty(ty.kind())); - pretty.push_str(" "); + write!(writer, "{:?} {} \" \"", nul, ty) } Rvalue::UnaryOp(un, op) => { - pretty.push_str(&pretty_operand(op)); - pretty.push_str(" "); - pretty.push_str(format!("{:#?}", un).as_str()); + write!(writer, "{} \" \" {:?}", pretty_operand(op), un) } - Rvalue::Use(op) => pretty.push_str(&pretty_operand(op)), + Rvalue::Use(op) => write!(writer, "{}", pretty_operand(op)), } - pretty } -pub fn pretty_ty(ty: TyKind) -> String { - let mut pretty = String::new(); - match ty { - TyKind::RigidTy(rigid_ty) => match rigid_ty { - RigidTy::Bool => "bool".to_string(), - RigidTy::Char => "char".to_string(), - RigidTy::Int(i) => match i { - IntTy::Isize => "isize".to_string(), - IntTy::I8 => "i8".to_string(), - IntTy::I16 => "i16".to_string(), - IntTy::I32 => "i32".to_string(), - IntTy::I64 => "i64".to_string(), - IntTy::I128 => "i128".to_string(), - }, - RigidTy::Uint(u) => match u { - UintTy::Usize => "usize".to_string(), - UintTy::U8 => "u8".to_string(), - UintTy::U16 => "u16".to_string(), - UintTy::U32 => "u32".to_string(), - UintTy::U64 => "u64".to_string(), - UintTy::U128 => "u128".to_string(), - }, - RigidTy::Float(f) => match f { - FloatTy::F32 => "f32".to_string(), - FloatTy::F64 => "f64".to_string(), - }, - RigidTy::Adt(def, _) => { - format!("{:#?}", with(|cx| cx.def_ty(def.0))) - } - RigidTy::Str => "str".to_string(), - RigidTy::Array(ty, len) => { - format!("[{}; {}]", pretty_ty(ty.kind()), with(|cx| cx.const_literal(&len))) - } - RigidTy::Slice(ty) => { - format!("[{}]", pretty_ty(ty.kind())) - } - RigidTy::RawPtr(ty, mutability) => { - pretty.push_str("*"); - match mutability { - Mutability::Not => pretty.push_str("const "), - Mutability::Mut => pretty.push_str("mut "), - } - pretty.push_str(&pretty_ty(ty.kind())); - pretty - } - RigidTy::Ref(_, ty, mutability) => match mutability { - Mutability::Not => format!("&{}", pretty_ty(ty.kind())), - Mutability::Mut => format!("&mut {}", pretty_ty(ty.kind())), - }, - RigidTy::FnDef(_, _) => format!("{:#?}", rigid_ty), - RigidTy::FnPtr(_) => format!("{:#?}", rigid_ty), - RigidTy::Closure(_, _) => format!("{:#?}", rigid_ty), - RigidTy::Coroutine(_, _, _) => format!("{:#?}", rigid_ty), - RigidTy::Dynamic(data, region, repr) => { - // FIXME: Fix binder printing, it looks ugly now - pretty.push_str("("); - match repr { - DynKind::Dyn => pretty.push_str("dyn "), - DynKind::DynStar => pretty.push_str("dyn* "), - } - pretty.push_str(format!("{:#?}", data).as_str()); - pretty.push_str(format!(" + {:#?} )", region).as_str()); - pretty - } - RigidTy::Never => "!".to_string(), - RigidTy::Tuple(tuple) => { - if tuple.is_empty() { - "()".to_string() - } else { - let mut tuple_str = String::new(); - tuple_str.push_str("("); - tuple.iter().enumerate().for_each(|(i, ty)| { - tuple_str.push_str(&pretty_ty(ty.kind())); - if i != tuple.len() - 1 { - tuple_str.push_str(", "); - } - }); - tuple_str.push_str(")"); - tuple_str - } - } - _ => format!("{:#?}", rigid_ty), - }, - TyKind::Alias(_, _) => format!("{:#?}", ty), - TyKind::Param(param_ty) => { - format!("{:#?}", param_ty.name) - } - TyKind::Bound(_, _) => format!("{:#?}", ty), +fn pretty_mut(mutability: Mutability) -> &'static str { + match mutability { + Mutability::Not => " ", + Mutability::Mut => "mut ", } } diff --git a/tests/ui/stable-mir-print/basic_function.rs b/tests/ui/stable-mir-print/basic_function.rs index 9b27a56dab100..deefef63bdb6e 100644 --- a/tests/ui/stable-mir-print/basic_function.rs +++ b/tests/ui/stable-mir-print/basic_function.rs @@ -2,7 +2,7 @@ //@ check-pass //@ only-x86_64 -fn foo(i:i32) -> i32 { +fn foo(i: i32) -> i32 { i + 1 } @@ -12,4 +12,13 @@ fn bar(vec: &mut Vec) -> Vec { new_vec } -fn main(){} +pub fn demux(input: u8) -> u8 { + match input { + 0 => 10, + 1 => 6, + 2 => 8, + _ => 0, + } +} + +fn main() {} diff --git a/tests/ui/stable-mir-print/basic_function.stdout b/tests/ui/stable-mir-print/basic_function.stdout index d9b33a4257c2c..3926c1048f54a 100644 --- a/tests/ui/stable-mir-print/basic_function.stdout +++ b/tests/ui/stable-mir-print/basic_function.stdout @@ -1,234 +1,74 @@ // WARNING: This is highly experimental output it's intended for stable-mir developers only. // If you find a bug or want to improve the output open a issue at https://github.com/rust-lang/project-stable-mir. -fn foo(_0: i32) -> i32 { - let mut _0: (i32, bool); +fn foo(_1: i32) -> i32 { + let mut _0: i32; + let mut _2: (i32, bool); + debug i => _1; + bb0: { + _2 = CheckedAdd(_1, 1_i32); + assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", _1, 1_i32) -> [success: bb1, unwind continue]; + } + bb1: { + _0 = move (_2.0: i32); + return; + } } +fn bar(_1: &mut Vec) -> Vec { + let mut _0: Vec; + let mut _2: Vec; + let mut _3: &Vec; + let _4: (); + let mut _5: &mut Vec; + debug vec => _1; + debug new_vec => _2; bb0: { - _2 = 1 Add const 1_i32 - assert(!move _2 bool),"attempt to compute `{} + {}`, which would overflow", 1, const 1_i32) -> [success: bb1, unwind continue] + _3 = &(*_1); + _2 = as Clone>::clone(move _3) -> [return: bb1, unwind continue]; } bb1: { - _0 = move _2 - return + _5 = &mut _2; + _4 = Vec::::push(move _5, 1_i32) -> [return: bb2, unwind: bb3]; + } + bb2: { + _0 = move _2; + return; + } + bb3: { + drop(_2) -> [return: bb4, unwind terminate]; + } + bb4: { + resume; } -fn bar(_0: &mut Ty { - id: 10, - kind: RigidTy( - Adt( - AdtDef( - DefId { - id: 3, - name: "std::vec::Vec", - }, - ), - GenericArgs( - [ - Type( - Ty { - id: 11, - kind: Param( - ParamTy { - index: 0, - name: "T", - }, - ), - }, - ), - Type( - Ty { - id: 12, - kind: Param( - ParamTy { - index: 1, - name: "A", - }, - ), - }, - ), - ], - ), - ), - ), -}) -> Ty { - id: 10, - kind: RigidTy( - Adt( - AdtDef( - DefId { - id: 3, - name: "std::vec::Vec", - }, - ), - GenericArgs( - [ - Type( - Ty { - id: 11, - kind: Param( - ParamTy { - index: 0, - name: "T", - }, - ), - }, - ), - Type( - Ty { - id: 12, - kind: Param( - ParamTy { - index: 1, - name: "A", - }, - ), - }, - ), - ], - ), - ), - ), -} { - let mut _0: Ty { - id: 10, - kind: RigidTy( - Adt( - AdtDef( - DefId { - id: 3, - name: "std::vec::Vec", - }, - ), - GenericArgs( - [ - Type( - Ty { - id: 11, - kind: Param( - ParamTy { - index: 0, - name: "T", - }, - ), - }, - ), - Type( - Ty { - id: 12, - kind: Param( - ParamTy { - index: 1, - name: "A", - }, - ), - }, - ), - ], - ), - ), - ), -}; - let mut _1: &Ty { - id: 10, - kind: RigidTy( - Adt( - AdtDef( - DefId { - id: 3, - name: "std::vec::Vec", - }, - ), - GenericArgs( - [ - Type( - Ty { - id: 11, - kind: Param( - ParamTy { - index: 0, - name: "T", - }, - ), - }, - ), - Type( - Ty { - id: 12, - kind: Param( - ParamTy { - index: 1, - name: "A", - }, - ), - }, - ), - ], - ), - ), - ), -}; - let _2: (); - let mut _3: &mut Ty { - id: 10, - kind: RigidTy( - Adt( - AdtDef( - DefId { - id: 3, - name: "std::vec::Vec", - }, - ), - GenericArgs( - [ - Type( - Ty { - id: 11, - kind: Param( - ParamTy { - index: 0, - name: "T", - }, - ), - }, - ), - Type( - Ty { - id: 12, - kind: Param( - ParamTy { - index: 1, - name: "A", - }, - ), - }, - ), - ], - ), - ), - ), -}; } +fn demux(_1: u8) -> u8 { + let mut _0: u8; + debug input => _1; bb0: { - _3 = refShared1 - _2 = const as Clone>::clone(move _3) -> [return: bb1, unwind continue] + switchInt(_1) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb1]; } bb1: { - _5 = refMut { - kind: TwoPhaseBorrow, -}2 - _4 = const Vec::::push(move _5, const 1_i32) -> [return: bb2, unwind: bb3] + _0 = 0_u8; + goto -> bb5; } bb2: { - _0 = move _2 - return + _0 = 10_u8; + goto -> bb5; } bb3: { - drop(_2) -> [return: bb4, unwind terminate] + _0 = 6_u8; + goto -> bb5; } bb4: { - resume + _0 = 8_u8; + goto -> bb5; + } + bb5: { + return; } -fn main() -> () { } +fn main() -> () { + let mut _0: (); bb0: { - return + return; } +} From 5f6257429dffd5bf4b733f043d45179352278d61 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Wed, 20 Mar 2024 16:00:00 -0700 Subject: [PATCH 07/12] Enable users to dump the body of an instance --- compiler/stable_mir/src/mir/body.rs | 3 ++- compiler/stable_mir/src/mir/mono.rs | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 4f67a76e24c2c..e4a012d8c4774 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -91,7 +91,8 @@ impl Body { self.locals.iter().enumerate() } - pub(crate) fn dump(&self, w: &mut W, fn_name: &str) -> io::Result<()> { + /// Emit the body using the provided name for the signature. + pub fn dump(&self, w: &mut W, fn_name: &str) -> io::Result<()> { function_body(w, self, fn_name) } diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs index 38e5776c48cea..aafa89c03e000 100644 --- a/compiler/stable_mir/src/mir/mono.rs +++ b/compiler/stable_mir/src/mir/mono.rs @@ -4,6 +4,7 @@ use crate::mir::Body; use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty}; use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque, Symbol}; use std::fmt::{Debug, Formatter}; +use std::io; #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum MonoItem { @@ -157,6 +158,11 @@ impl Instance { pub fn try_const_eval(&self, const_ty: Ty) -> Result { with(|cx| cx.eval_instance(self.def, const_ty)) } + + /// Emit the body of this instance if it has one. + pub fn emit_mir(&self, w: &mut W) -> io::Result<()> { + if let Some(body) = self.body() { body.dump(w, &self.name()) } else { Ok(()) } + } } impl Debug for Instance { From 5fae66592494d37aa9b7c3add8c0e6077e0833f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 20 Mar 2024 22:50:32 +0000 Subject: [PATCH 08/12] Replace closures with `_` when suggesting fully qualified path for method call ``` error[E0283]: type annotations needed --> $DIR/into-inference-needs-type.rs:12:10 | LL | .into()?; | ^^^^ | = note: cannot satisfy `_: From<...>` = note: required for `FilterMap<...>` to implement `Into<_>` help: try using a fully qualified path to specify the expected types | LL ~ let list = , _>, _> as Into>::into(vec LL | .iter() LL | .map(|s| s.strip_prefix("t")) LL ~ .filter_map(Option::Some))?; | ``` Fix #122569. --- .../rustc_hir_analysis/src/astconv/bounds.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 6 +- .../rustc_hir_analysis/src/collect/type_of.rs | 6 +- .../src/fn_ctxt/suggestions.rs | 2 +- compiler/rustc_hir_typeck/src/op.rs | 4 +- .../infer/error_reporting/need_type_info.rs | 77 +++++++++++-------- compiler/rustc_middle/src/ty/diagnostics.rs | 28 +++++-- .../clippy/clippy_lints/src/box_default.rs | 4 +- .../types/into-inference-needs-type.rs | 15 ++++ .../types/into-inference-needs-type.stderr | 19 +++++ .../traits/suggest-fully-qualified-closure.rs | 2 - .../suggest-fully-qualified-closure.stderr | 8 +- 12 files changed, 119 insertions(+), 54 deletions(-) create mode 100644 tests/ui/suggestions/types/into-inference-needs-type.rs create mode 100644 tests/ui/suggestions/types/into-inference-needs-type.stderr diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index 3067e2d0b71de..7a5cb6e9d6f90 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -565,7 +565,7 @@ fn check_assoc_const_binding_type<'tcx>( let mut guar = ty.visit_with(&mut collector).break_value(); let ty_note = ty - .make_suggestable(tcx, false) + .make_suggestable(tcx, false, None) .map(|ty| crate::errors::TyOfAssocConstBindingNote { assoc_const, ty }); let enclosing_item_owner_id = tcx diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 5cd6862786b46..d8bcc3a687e34 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1364,7 +1364,7 @@ fn infer_return_ty_for_fn_sig<'tcx>( // recursive function definition to leak out into the fn sig. let mut should_recover = false; - if let Some(ret_ty) = ret_ty.make_suggestable(tcx, false) { + if let Some(ret_ty) = ret_ty.make_suggestable(tcx, false, None) { diag.span_suggestion( ty.span, "replace with the correct return type", @@ -1442,7 +1442,7 @@ fn suggest_impl_trait<'tcx>( let ty::Tuple(types) = *args_tuple.kind() else { return None; }; - let types = types.make_suggestable(tcx, false)?; + let types = types.make_suggestable(tcx, false, None)?; let maybe_ret = if item_ty.is_unit() { String::new() } else { format!(" -> {item_ty}") }; Some(format!( @@ -1500,7 +1500,7 @@ fn suggest_impl_trait<'tcx>( // FIXME(compiler-errors): We may benefit from resolving regions here. if ocx.select_where_possible().is_empty() && let item_ty = infcx.resolve_vars_if_possible(item_ty) - && let Some(item_ty) = item_ty.make_suggestable(tcx, false) + && let Some(item_ty) = item_ty.make_suggestable(tcx, false, None) && let Some(sugg) = formatter( tcx, infcx.resolve_vars_if_possible(args), diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index fd86f2dd1b16c..cec01abae4b55 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -47,7 +47,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { let ty = tcx.fold_regions(ty, |r, _| { if r.is_erased() { ty::Region::new_error_misc(tcx) } else { r } }); - let (ty, opt_sugg) = if let Some(ty) = ty.make_suggestable(tcx, false) { + let (ty, opt_sugg) = if let Some(ty) = ty.make_suggestable(tcx, false, None) { (ty, Some((span, Applicability::MachineApplicable))) } else { (ty, None) @@ -587,7 +587,7 @@ fn infer_placeholder_type<'a>( suggestions.clear(); } - if let Some(ty) = ty.make_suggestable(tcx, false) { + if let Some(ty) = ty.make_suggestable(tcx, false, None) { err.span_suggestion( span, format!("provide a type for the {kind}"), @@ -606,7 +606,7 @@ fn infer_placeholder_type<'a>( let mut diag = bad_placeholder(tcx, vec![span], kind); if !ty.references_error() { - if let Some(ty) = ty.make_suggestable(tcx, false) { + if let Some(ty) = ty.make_suggestable(tcx, false, None) { diag.span_suggestion( span, "replace with the correct type", diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 3f6f4cccba796..f4090feee1721 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -809,7 +809,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return true; } &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => { - if let Some(found) = found.make_suggestable(self.tcx, false) { + if let Some(found) = found.make_suggestable(self.tcx, false, None) { err.subdiagnostic( self.dcx(), errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() }, diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 79f574aa7fdc4..8969030d68340 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -601,8 +601,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(output_def_id) = output_def_id && let Some(trait_def_id) = trait_def_id && self.tcx.parent(output_def_id) == trait_def_id - && let Some(output_ty) = - output_ty.make_suggestable(self.tcx, false) + && let Some(output_ty) = output_ty + .make_suggestable(self.tcx, false, None) { Some(("Output", output_ty)) } else { diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 0686994b0378d..ce9001ccb1cc6 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -546,40 +546,55 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } InferSourceKind::FullyQualifiedMethodCall { receiver, successor, args, def_id } => { - let mut printer = fmt_printer(self, Namespace::ValueNS); - printer.print_def_path(def_id, args).unwrap(); - let def_path = printer.into_buffer(); - - // We only care about whether we have to add `&` or `&mut ` for now. - // This is the case if the last adjustment is a borrow and the - // first adjustment was not a builtin deref. - let adjustment = match typeck_results.expr_adjustments(receiver) { - [ - Adjustment { kind: Adjust::Deref(None), target: _ }, - .., - Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), target: _ }, - ] => "", - [ - .., - Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)), target: _ }, - ] => hir::Mutability::from(*mut_).ref_prefix_str(), - _ => "", - }; + let placeholder = Some(self.next_ty_var(TypeVariableOrigin { + span: rustc_span::DUMMY_SP, + kind: TypeVariableOriginKind::MiscVariable, + })); + if let Some(args) = args.make_suggestable(self.infcx.tcx, true, placeholder) { + let mut printer = fmt_printer(self, Namespace::ValueNS); + printer.print_def_path(def_id, args).unwrap(); + let def_path = printer.into_buffer(); + + // We only care about whether we have to add `&` or `&mut ` for now. + // This is the case if the last adjustment is a borrow and the + // first adjustment was not a builtin deref. + let adjustment = match typeck_results.expr_adjustments(receiver) { + [ + Adjustment { kind: Adjust::Deref(None), target: _ }, + .., + Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), target: _ }, + ] => "", + [ + .., + Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)), + target: _, + }, + ] => hir::Mutability::from(*mut_).ref_prefix_str(), + _ => "", + }; - multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified( - receiver.span, - def_path, - adjustment, - successor, - )); + multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified( + receiver.span, + def_path, + adjustment, + successor, + )); + } } InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => { - let ty_info = ty_to_string(self, ty, None); - multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return( - ty_info, - data, - should_wrap_expr, - )); + let placeholder = Some(self.next_ty_var(TypeVariableOrigin { + span: rustc_span::DUMMY_SP, + kind: TypeVariableOriginKind::MiscVariable, + })); + if let Some(ty) = ty.make_suggestable(self.infcx.tcx, true, placeholder) { + let ty_info = ty_to_string(self, ty, None); + multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return( + ty_info, + data, + should_wrap_expr, + )); + } } } match error_code { diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 05463b8554f19..ee18647cdd8fd 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -91,7 +91,12 @@ pub trait IsSuggestable<'tcx>: Sized { /// inference variables to be suggestable. fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool; - fn make_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> Option; + fn make_suggestable( + self, + tcx: TyCtxt<'tcx>, + infer_suggestable: bool, + placeholder: Option>, + ) -> Option; } impl<'tcx, T> IsSuggestable<'tcx> for T @@ -103,8 +108,13 @@ where self.visit_with(&mut IsSuggestableVisitor { tcx, infer_suggestable }).is_continue() } - fn make_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> Option { - self.try_fold_with(&mut MakeSuggestableFolder { tcx, infer_suggestable }).ok() + fn make_suggestable( + self, + tcx: TyCtxt<'tcx>, + infer_suggestable: bool, + placeholder: Option>, + ) -> Option { + self.try_fold_with(&mut MakeSuggestableFolder { tcx, infer_suggestable, placeholder }).ok() } } @@ -559,6 +569,7 @@ impl<'tcx> TypeVisitor> for IsSuggestableVisitor<'tcx> { pub struct MakeSuggestableFolder<'tcx> { tcx: TyCtxt<'tcx>, infer_suggestable: bool, + placeholder: Option>, } impl<'tcx> FallibleTypeFolder> for MakeSuggestableFolder<'tcx> { @@ -572,19 +583,24 @@ impl<'tcx> FallibleTypeFolder> for MakeSuggestableFolder<'tcx> { let t = match *t.kind() { Infer(InferTy::TyVar(_)) if self.infer_suggestable => t, - FnDef(def_id, args) => { + FnDef(def_id, args) if self.placeholder.is_none() => { Ty::new_fn_ptr(self.tcx, self.tcx.fn_sig(def_id).instantiate(self.tcx, args)) } - // FIXME(compiler-errors): We could replace these with infer, I guess. Closure(..) + | FnDef(..) | Infer(..) | Coroutine(..) | CoroutineWitness(..) | Bound(_, _) | Placeholder(_) | Error(_) => { - return Err(()); + if let Some(placeholder) = self.placeholder { + // We replace these with infer (which is passed in from an infcx). + placeholder + } else { + return Err(()); + } } Alias(Opaque, AliasTy { def_id, .. }) => { diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs index 779ae03c4640b..66206d1a059b9 100644 --- a/src/tools/clippy/clippy_lints/src/box_default.rs +++ b/src/tools/clippy/clippy_lints/src/box_default.rs @@ -70,7 +70,9 @@ impl LateLintPass<'_> for BoxDefault { "try", if is_plain_default(cx, arg_path) || given_type(cx, expr) { "Box::default()".into() - } else if let Some(arg_ty) = cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true) { + } else if let Some(arg_ty) = + cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true, None) + { // Check if we can copy from the source expression in the replacement. // We need the call to have no argument (see `explicit_default_type`). if inner_call_args.is_empty() diff --git a/tests/ui/suggestions/types/into-inference-needs-type.rs b/tests/ui/suggestions/types/into-inference-needs-type.rs new file mode 100644 index 0000000000000..4c8b6ec2113c2 --- /dev/null +++ b/tests/ui/suggestions/types/into-inference-needs-type.rs @@ -0,0 +1,15 @@ +#[derive(Debug)] +enum MyError { + MainError +} + +fn main() -> Result<(), MyError> { + let vec = vec!["one", "two", "three"]; + let list = vec + .iter() + .map(|s| s.strip_prefix("t")) + .filter_map(Option::Some) + .into()?; //~ ERROR type annotations needed + + return Ok(()); +} diff --git a/tests/ui/suggestions/types/into-inference-needs-type.stderr b/tests/ui/suggestions/types/into-inference-needs-type.stderr new file mode 100644 index 0000000000000..dd688f9028982 --- /dev/null +++ b/tests/ui/suggestions/types/into-inference-needs-type.stderr @@ -0,0 +1,19 @@ +error[E0283]: type annotations needed + --> $DIR/into-inference-needs-type.rs:12:10 + | +LL | .into()?; + | ^^^^ + | + = note: cannot satisfy `_: From, {closure@$DIR/into-inference-needs-type.rs:10:14: 10:17}>, fn(Option<&str>) -> Option> {Option::>::Some}>>` + = note: required for `FilterMap, {closure@$DIR/into-inference-needs-type.rs:10:14: 10:17}>, fn(Option<&str>) -> Option> {Option::>::Some}>` to implement `Into<_>` +help: try using a fully qualified path to specify the expected types + | +LL ~ let list = , _>, _> as Into>::into(vec +LL | .iter() +LL | .map(|s| s.strip_prefix("t")) +LL ~ .filter_map(Option::Some))?; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/traits/suggest-fully-qualified-closure.rs b/tests/ui/traits/suggest-fully-qualified-closure.rs index f401a3012da1d..3d28a4e6bf59c 100644 --- a/tests/ui/traits/suggest-fully-qualified-closure.rs +++ b/tests/ui/traits/suggest-fully-qualified-closure.rs @@ -1,7 +1,5 @@ //@ check-fail //@ known-bug: #103705 -//@ normalize-stderr-test "\{closure@.*\}" -> "{closure@}" -//@ normalize-stderr-test "\+* ~" -> "+++ ~" // The output of this currently suggests writing a closure in the qualified path. diff --git a/tests/ui/traits/suggest-fully-qualified-closure.stderr b/tests/ui/traits/suggest-fully-qualified-closure.stderr index e077bd7ac2a6e..a2c1115e673a3 100644 --- a/tests/ui/traits/suggest-fully-qualified-closure.stderr +++ b/tests/ui/traits/suggest-fully-qualified-closure.stderr @@ -1,11 +1,11 @@ error[E0283]: type annotations needed - --> $DIR/suggest-fully-qualified-closure.rs:23:7 + --> $DIR/suggest-fully-qualified-closure.rs:21:7 | LL | q.lol(||()); | ^^^ | note: multiple `impl`s satisfying `Qqq: MyTrait<_>` found - --> $DIR/suggest-fully-qualified-closure.rs:14:1 + --> $DIR/suggest-fully-qualified-closure.rs:12:1 | LL | impl MyTrait for Qqq{ | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -14,8 +14,8 @@ LL | impl MyTrait for Qqq{ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using a fully qualified path to specify the expected types | -LL | >::lol::<{closure@}>(&q, ||()); - | +++ ~ +LL | >::lol::<_>(&q, ||()); + | +++++++++++++++++++++++++++++++ ~ error: aborting due to 1 previous error From e062887d4f7a8521a687dfea87386070be0b8f33 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Sat, 17 Feb 2024 14:47:44 +0000 Subject: [PATCH 09/12] CFI: Skip non-passed arguments Rust will occasionally rely on fn((), X) -> Y being compatible with fn(X) -> Y, since () is a non-passed argument. Relax CFI by choosing not to encode non-passed arguments. --- .../src/typeid/typeid_itanium_cxx_abi.rs | 22 +++++--- ...-type-metadata-id-itanium-cxx-abi-paths.rs | 50 ++++++++++--------- ...data-id-itanium-cxx-abi-primitive-types.rs | 6 +-- ...-itanium-cxx-abi-repr-transparent-types.rs | 2 +- .../sanitizer/cfi/normalize-integers.rs | 6 +-- tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs | 16 ++++++ 6 files changed, 63 insertions(+), 39 deletions(-) create mode 100644 tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs 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 51e2c96120caa..76a5d942c66b1 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 @@ -18,7 +18,7 @@ use rustc_middle::ty::{ use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgsRef}; use rustc_span::def_id::DefId; use rustc_span::sym; -use rustc_target::abi::call::{Conv, FnAbi}; +use rustc_target::abi::call::{Conv, FnAbi, PassMode}; use rustc_target::abi::Integer; use rustc_target::spec::abi::Abi; use std::fmt::Write as _; @@ -1040,19 +1040,27 @@ pub fn typeid_for_fnabi<'tcx>( typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); // Encode the parameter types + + // We erase ZSTs as we go if the argument is skipped. This is an implementation detail of how + // MIR is currently treated by rustc, and subject to change in the future. Specifically, MIR + // interpretation today will allow skipped arguments to simply not be passed at a call-site. if !fn_abi.c_variadic { - if !fn_abi.args.is_empty() { - for arg in fn_abi.args.iter() { - let ty = transform_ty(tcx, arg.layout.ty, transform_ty_options); - typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); - } - } else { + let mut pushed_arg = false; + for arg in fn_abi.args.iter().filter(|arg| arg.mode != PassMode::Ignore) { + pushed_arg = true; + let ty = transform_ty(tcx, arg.layout.ty, transform_ty_options); + typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); + } + if !pushed_arg { // Empty parameter lists, whether declared as () or conventionally as (void), are // encoded with a void parameter specifier "v". typeid.push('v'); } } else { for n in 0..fn_abi.fixed_count as usize { + if fn_abi.args[n].mode == PassMode::Ignore { + continue; + } let ty = transform_ty(tcx, fn_abi.args[n].layout.ty, transform_ty_options); typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); } diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs index c5d8e0f22a2a0..ca781a99296be 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs @@ -47,40 +47,42 @@ pub fn foo() where let _: Type4 = ::bar; } -pub fn foo1(_: Type1) { } +// Force arguments to be passed by using a reference. Otherwise, they may end up PassMode::Ignore + +pub fn foo1(_: &Type1) { } // CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo2(_: Type1, _: Type1) { } +pub fn foo2(_: &Type1, _: &Type1) { } // CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo3(_: Type1, _: Type1, _: Type1) { } +pub fn foo3(_: &Type1, _: &Type1, _: &Type1) { } // CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo4(_: Type2) { } +pub fn foo4(_: &Type2) { } // CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo5(_: Type2, _: Type2) { } +pub fn foo5(_: &Type2, _: &Type2) { } // CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo6(_: Type2, _: Type2, _: Type2) { } +pub fn foo6(_: &Type2, _: &Type2, _: &Type2) { } // CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo7(_: Type3) { } +pub fn foo7(_: &Type3) { } // CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo8(_: Type3, _: Type3) { } +pub fn foo8(_: &Type3, _: &Type3) { } // CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo9(_: Type3, _: Type3, _: Type3) { } +pub fn foo9(_: &Type3, _: &Type3, _: &Type3) { } // CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo10(_: Type4) { } +pub fn foo10(_: &Type4) { } // CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo11(_: Type4, _: Type4) { } +pub fn foo11(_: &Type4, _: &Type4) { } // CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo12(_: Type4, _: Type4, _: Type4) { } +pub fn foo12(_: &Type4, _: &Type4, _: &Type4) { } // CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barE"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barS_E"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barS_S_E"} -// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooE"} -// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooS_E"} -// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooS_S_E"} -// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooE"} -// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooS_E"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooS_S_E"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barE"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barS_E"} -// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barS_S_E"} +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barEE"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barES0_E"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barES0_S0_E"} +// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooEE"} +// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_E"} +// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_S0_E"} +// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooEE"} +// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_E"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_S0_E"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barEE"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_E"} +// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_S0_E"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs index 3a1a09150eae9..38f507856bdee 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs @@ -12,9 +12,9 @@ use core::ffi::*; pub fn foo1(_: ()) { } // CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo2(_: (), _: c_void) { } -// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo3(_: (), _: c_void, _: c_void) { } -// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo4(_: *mut ()) { } // CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo5(_: *mut (), _: *mut c_void) { } @@ -131,8 +131,6 @@ pub fn foo60(_: &str, _: &str, _: &str) { } // CHECK: define{{.*}}5foo60{{.*}}!type ![[TYPE60:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} // CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvvE"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvvvE"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvvvvE"} // CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvPvE"} // CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvPvS_E"} // CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvPvS_S_E"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs index 0deda029c4b09..6f47f5e335577 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs @@ -28,7 +28,7 @@ pub struct Type2<'a> { member3: &'a Type2<'a>, } -pub struct Bar; +pub struct Bar(i32); // repr(transparent) user-defined generic type #[repr(transparent)] diff --git a/tests/codegen/sanitizer/cfi/normalize-integers.rs b/tests/codegen/sanitizer/cfi/normalize-integers.rs index 210814eb9ae1f..801ed312be5b1 100644 --- a/tests/codegen/sanitizer/cfi/normalize-integers.rs +++ b/tests/codegen/sanitizer/cfi/normalize-integers.rs @@ -41,6 +41,6 @@ pub fn foo11(_: (), _: usize, _: usize, _: usize) { } // CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}E.normalized"} // CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}S_E.normalized"} // CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}S_S_E.normalized"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvv{{u3u16|u3u32|u3u64|u4u128}}E.normalized"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvv{{u3u16|u3u32|u3u64|u4u128}}S_E.normalized"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvv{{u3u16|u3u32|u3u64|u4u128}}S_S_E.normalized"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}E.normalized"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}S_E.normalized"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}S_S_E.normalized"} diff --git a/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs b/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs new file mode 100644 index 0000000000000..966a87b7f71fd --- /dev/null +++ b/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs @@ -0,0 +1,16 @@ +// Tests that converting a closure to a function pointer works +// The notable thing being tested here is that when the closure does not capture anything, +// the call method from its Fn trait takes a ZST representing its environment. The compiler then +// uses the assumption that the ZST is non-passed to reify this into a function pointer. +// +// This checks that the reified function pointer will have the expected alias set at its call-site. + +//@ needs-sanitizer-cfi +//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi +//@ compile-flags:-C codegen-units=1 -C opt-level=0 +//@ run-pass + +pub fn main() { + let f: &fn() = &((|| ()) as _); + f(); +} From ebacf7acd30d5fe9e7b889ac47a238c495737346 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Wed, 20 Mar 2024 18:02:11 -0700 Subject: [PATCH 10/12] s/place_debug/place_pretty in SMIR --- compiler/rustc_smir/src/rustc_smir/context.rs | 2 +- compiler/stable_mir/src/compiler_interface.rs | 2 +- compiler/stable_mir/src/mir/pretty.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 66917c73aa520..d39a3788d4cf7 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -660,7 +660,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { id.internal(&mut *tables, tcx).0.stable(&mut *tables) } - fn place_debug(&self, place: &Place) -> String { + fn place_pretty(&self, place: &Place) -> String { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; format!("{:?}", place.internal(&mut *tables, tcx)) diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 68f078892ef04..8ed34fab54d09 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -210,7 +210,7 @@ pub trait Context { fn layout_shape(&self, id: Layout) -> LayoutShape; /// Get a debug string representation of a place. - fn place_debug(&self, place: &Place) -> String; + fn place_pretty(&self, place: &Place) -> String; } // A thread local variable that stores a pointer to the tables mapping between TyCtxt diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs index 8c3ebb56fb07a..4ac4833add715 100644 --- a/compiler/stable_mir/src/mir/pretty.rs +++ b/compiler/stable_mir/src/mir/pretty.rs @@ -18,7 +18,7 @@ impl Display for Ty { impl Debug for Place { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - with(|ctx| write!(f, "{}", ctx.place_debug(self))) + with(|ctx| write!(f, "{}", ctx.place_pretty(self))) } } From a015b90953854a388d990d1e8bef9307c4e5a9ee Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 20 Mar 2024 22:13:15 -0400 Subject: [PATCH 11/12] Make type_ascribe! not a built-in --- compiler/rustc_builtin_macros/src/lib.rs | 2 -- .../rustc_builtin_macros/src/type_ascribe.rs | 35 ------------------- compiler/rustc_parse/src/parser/expr.rs | 20 ++++++++--- library/core/src/macros/mod.rs | 4 +-- tests/ui/raw-ref-op/raw-ref-temp.stderr | 8 +++++ tests/ui/reachable/expr_type.stderr | 1 + tests/ui/typeck/issue-91267.stderr | 2 ++ 7 files changed, 28 insertions(+), 44 deletions(-) delete mode 100644 compiler/rustc_builtin_macros/src/type_ascribe.rs diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index f344dbcd10c06..554dac0852f2c 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -49,7 +49,6 @@ mod log_syntax; mod source_util; mod test; mod trace_macros; -mod type_ascribe; mod util; pub mod asm; @@ -99,7 +98,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { std_panic: edition_panic::expand_panic, stringify: source_util::expand_stringify, trace_macros: trace_macros::expand_trace_macros, - type_ascribe: type_ascribe::expand_type_ascribe, unreachable: edition_panic::expand_unreachable, // tidy-alphabetical-end } diff --git a/compiler/rustc_builtin_macros/src/type_ascribe.rs b/compiler/rustc_builtin_macros/src/type_ascribe.rs deleted file mode 100644 index f3e66ffc759db..0000000000000 --- a/compiler/rustc_builtin_macros/src/type_ascribe.rs +++ /dev/null @@ -1,35 +0,0 @@ -use rustc_ast::ptr::P; -use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{token, Expr, ExprKind, Ty}; -use rustc_errors::PResult; -use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; -use rustc_span::Span; - -pub fn expand_type_ascribe( - cx: &mut ExtCtxt<'_>, - span: Span, - tts: TokenStream, -) -> MacroExpanderResult<'static> { - let (expr, ty) = match parse_ascribe(cx, tts) { - Ok(parsed) => parsed, - Err(err) => { - let guar = err.emit(); - return ExpandResult::Ready(DummyResult::any(span, guar)); - } - }; - - let asc_expr = cx.expr(span, ExprKind::Type(expr, ty)); - - ExpandResult::Ready(MacEager::expr(asc_expr)) -} - -fn parse_ascribe<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P, P)> { - let mut parser = cx.new_parser_from_tts(stream); - - let expr = parser.parse_expr()?; - parser.expect(&token::Comma)?; - - let ty = parser.parse_ty()?; - - Ok((expr, ty)) -} diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 136145dd1826d..6256db9925197 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1939,11 +1939,11 @@ impl<'a> Parser<'a> { /// Parse `builtin # ident(args,*)`. fn parse_expr_builtin(&mut self) -> PResult<'a, P> { self.parse_builtin(|this, lo, ident| { - if ident.name == sym::offset_of { - return Ok(Some(this.parse_expr_offset_of(lo)?)); - } - - Ok(None) + Ok(match ident.name { + sym::offset_of => Some(this.parse_expr_offset_of(lo)?), + sym::type_ascribe => Some(this.parse_expr_type_ascribe(lo)?), + _ => None, + }) }) } @@ -1978,6 +1978,7 @@ impl<'a> Parser<'a> { ret } + /// Built-in macro for `offset_of!` expressions. pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, P> { let container = self.parse_ty()?; self.expect(&TokenKind::Comma)?; @@ -2007,6 +2008,15 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields))) } + /// Built-in macro for type ascription expressions. + pub(crate) fn parse_expr_type_ascribe(&mut self, lo: Span) -> PResult<'a, P> { + let expr = self.parse_expr()?; + self.expect(&token::Comma)?; + let ty = self.parse_ty()?; + let span = lo.to(self.token.span); + Ok(self.mk_expr(span, ExprKind::Type(expr, ty))) + } + /// Returns a string literal if the next token is a string literal. /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind, /// and returns `None` if the next token is not literal at all. diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 0ee7e190e3d45..ebcaa626bd333 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1704,14 +1704,14 @@ pub(crate) mod builtin { } /// Unstable placeholder for type ascription. - #[rustc_builtin_macro] + #[allow_internal_unstable(builtin_syntax)] #[unstable( feature = "type_ascription", issue = "23416", reason = "placeholder syntax for type ascription" )] pub macro type_ascribe($expr:expr, $ty:ty) { - /* compiler built-in */ + builtin # type_ascribe($expr, $ty) } /// Unstable implementation detail of the `rustc` compiler, do not use. diff --git a/tests/ui/raw-ref-op/raw-ref-temp.stderr b/tests/ui/raw-ref-op/raw-ref-temp.stderr index b96661625170f..1f6d85e4a7eb7 100644 --- a/tests/ui/raw-ref-op/raw-ref-temp.stderr +++ b/tests/ui/raw-ref-op/raw-ref-temp.stderr @@ -75,24 +75,32 @@ error[E0745]: cannot take address of a temporary | LL | let ref_ascribe = &raw const type_ascribe!(2, i32); | ^^^^^^^^^^^^^^^^^^^^^ temporary value + | + = note: this error originates in the macro `type_ascribe` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0745]: cannot take address of a temporary --> $DIR/raw-ref-temp.rs:27:36 | LL | let mut_ref_ascribe = &raw mut type_ascribe!(3, i32); | ^^^^^^^^^^^^^^^^^^^^^ temporary value + | + = note: this error originates in the macro `type_ascribe` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0745]: cannot take address of a temporary --> $DIR/raw-ref-temp.rs:29:40 | LL | let ascribe_field_ref = &raw const type_ascribe!(PAIR.0, i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value + | + = note: this error originates in the macro `type_ascribe` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0745]: cannot take address of a temporary --> $DIR/raw-ref-temp.rs:30:38 | LL | let ascribe_index_ref = &raw mut type_ascribe!(ARRAY[0], i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value + | + = note: this error originates in the macro `type_ascribe` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 16 previous errors diff --git a/tests/ui/reachable/expr_type.stderr b/tests/ui/reachable/expr_type.stderr index 70536326fd842..008b867e23071 100644 --- a/tests/ui/reachable/expr_type.stderr +++ b/tests/ui/reachable/expr_type.stderr @@ -12,6 +12,7 @@ note: the lint level is defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `type_ascribe` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/typeck/issue-91267.stderr b/tests/ui/typeck/issue-91267.stderr index 7e48b251980e8..399309d0ec44d 100644 --- a/tests/ui/typeck/issue-91267.stderr +++ b/tests/ui/typeck/issue-91267.stderr @@ -17,6 +17,8 @@ LL | fn main() { | - expected `()` because of default return type LL | type_ascribe!(0, u8=e>) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `u8` + | + = note: this error originates in the macro `type_ascribe` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors From 19339694d5c7529049ba17de68739b3704d48ef4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Mar 2024 23:52:26 +0100 Subject: [PATCH 12/12] rename items -> free_items --- .../rustc_incremental/src/persist/dirty_clean.rs | 2 +- compiler/rustc_middle/src/hir/map/mod.rs | 12 ++++++------ compiler/rustc_middle/src/hir/mod.rs | 12 +++++++----- compiler/rustc_monomorphize/src/collector.rs | 2 +- compiler/rustc_passes/src/dead.rs | 4 ++-- compiler/rustc_passes/src/reachable.rs | 2 +- compiler/rustc_privacy/src/lib.rs | 2 +- compiler/rustc_symbol_mangling/src/test.rs | 2 +- tests/run-make-fulldeps/obtain-borrowck/driver.rs | 2 +- 9 files changed, 21 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index 24512dea93999..5156a8d3479e0 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -148,7 +148,7 @@ pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) { let crate_items = tcx.hir_crate_items(()); - for id in crate_items.items() { + for id in crate_items.free_items() { dirty_clean_visitor.check_item(id.owner_id.def_id); } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index e8e80a8de50ee..6b833ed8ee154 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -170,12 +170,12 @@ impl<'hir> Map<'hir> { #[inline] pub fn items(self) -> impl Iterator + 'hir { - self.tcx.hir_crate_items(()).items.iter().copied() + self.tcx.hir_crate_items(()).free_items.iter().copied() } #[inline] pub fn module_items(self, module: LocalModDefId) -> impl Iterator + 'hir { - self.tcx.hir_module_items(module).items() + self.tcx.hir_module_items(module).free_items() } pub fn def_key(self, def_id: LocalDefId) -> DefKey { @@ -422,7 +422,7 @@ impl<'hir> Map<'hir> { V: Visitor<'hir>, { let krate = self.tcx.hir_crate_items(()); - walk_list!(visitor, visit_item, krate.items().map(|id| self.item(id))); + walk_list!(visitor, visit_item, krate.free_items().map(|id| self.item(id))); walk_list!(visitor, visit_trait_item, krate.trait_items().map(|id| self.trait_item(id))); walk_list!(visitor, visit_impl_item, krate.impl_items().map(|id| self.impl_item(id))); walk_list!( @@ -440,7 +440,7 @@ impl<'hir> Map<'hir> { V: Visitor<'hir>, { let module = self.tcx.hir_module_items(module); - walk_list!(visitor, visit_item, module.items().map(|id| self.item(id))); + walk_list!(visitor, visit_item, module.free_items().map(|id| self.item(id))); walk_list!(visitor, visit_trait_item, module.trait_items().map(|id| self.trait_item(id))); walk_list!(visitor, visit_impl_item, module.impl_items().map(|id| self.impl_item(id))); walk_list!( @@ -1201,7 +1201,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod } = collector; return ModuleItems { submodules: submodules.into_boxed_slice(), - items: items.into_boxed_slice(), + free_items: items.into_boxed_slice(), trait_items: trait_items.into_boxed_slice(), impl_items: impl_items.into_boxed_slice(), foreign_items: foreign_items.into_boxed_slice(), @@ -1230,7 +1230,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { return ModuleItems { submodules: submodules.into_boxed_slice(), - items: items.into_boxed_slice(), + free_items: items.into_boxed_slice(), trait_items: trait_items.into_boxed_slice(), impl_items: impl_items.into_boxed_slice(), foreign_items: foreign_items.into_boxed_slice(), diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 8ebdd92ad0c72..28f7574f66fc7 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -22,7 +22,7 @@ use rustc_span::{ErrorGuaranteed, ExpnId}; #[derive(Debug, HashStable, Encodable, Decodable)] pub struct ModuleItems { submodules: Box<[OwnerId]>, - items: Box<[ItemId]>, + free_items: Box<[ItemId]>, trait_items: Box<[TraitItemId]>, impl_items: Box<[ImplItemId]>, foreign_items: Box<[ForeignItemId]>, @@ -34,8 +34,10 @@ impl ModuleItems { /// /// Note that this does *not* include associated items of `impl` blocks! It also does not /// include foreign items. If you want to e.g. get all functions, use `definitions()` below. - pub fn items(&self) -> impl Iterator + '_ { - self.items.iter().copied() + /// + /// However, this does include the `impl` blocks themselves. + pub fn free_items(&self) -> impl Iterator + '_ { + self.free_items.iter().copied() } pub fn trait_items(&self) -> impl Iterator + '_ { @@ -53,7 +55,7 @@ impl ModuleItems { } pub fn owners(&self) -> impl Iterator + '_ { - self.items + self.free_items .iter() .map(|id| id.owner_id) .chain(self.trait_items.iter().map(|id| id.owner_id)) @@ -69,7 +71,7 @@ impl ModuleItems { &self, f: impl Fn(ItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync, ) -> Result<(), ErrorGuaranteed> { - try_par_for_each_in(&self.items[..], |&id| f(id)) + try_par_for_each_in(&self.free_items[..], |&id| f(id)) } pub fn par_trait_items( diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index abe691ba0d83d..ceb151d9f6dd4 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -307,7 +307,7 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec>(); let crate_items = tcx.hir_crate_items(()); - for id in crate_items.items() { + for id in crate_items.free_items() { check_item(tcx, &mut worklist, &mut struct_constructors, &mut unsolved_impl_item, id); } @@ -1084,7 +1084,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { let module_items = tcx.hir_module_items(module); - for item in module_items.items() { + for item in module_items.free_items() { let def_kind = tcx.def_kind(item.owner_id); let mut dead_codes = Vec::new(); diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index b7135de08ba84..c2e604b02b3d9 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -437,7 +437,7 @@ fn reachable_set(tcx: TyCtxt<'_>, (): ()) -> LocalDefIdSet { // trait is a lang item. let crate_items = tcx.hir_crate_items(()); - for id in crate_items.items() { + for id in crate_items.free_items() { check_item(tcx, id, &mut reachable_context.worklist, effective_visibilities); } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 073982ca5c37d..c73fdd59609d0 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1696,7 +1696,7 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { } } - for id in module.items() { + for id in module.free_items() { if let ItemKind::Impl(i) = tcx.hir().item(id).kind { if let Some(item) = i.of_trait { let trait_ref = tcx.impl_trait_ref(id.owner_id.def_id).unwrap(); diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs index 6766080a54f51..f0fb87fe83c86 100644 --- a/compiler/rustc_symbol_mangling/src/test.rs +++ b/compiler/rustc_symbol_mangling/src/test.rs @@ -25,7 +25,7 @@ pub fn report_symbol_names(tcx: TyCtxt<'_>) { let mut symbol_names = SymbolNamesTest { tcx }; let crate_items = tcx.hir_crate_items(()); - for id in crate_items.items() { + for id in crate_items.free_items() { symbol_names.process_attrs(id.owner_id.def_id); } diff --git a/tests/run-make-fulldeps/obtain-borrowck/driver.rs b/tests/run-make-fulldeps/obtain-borrowck/driver.rs index 2e3bf70e14414..e67ec8690f817 100644 --- a/tests/run-make-fulldeps/obtain-borrowck/driver.rs +++ b/tests/run-make-fulldeps/obtain-borrowck/driver.rs @@ -68,7 +68,7 @@ impl rustc_driver::Callbacks for CompilerCalls { let mut bodies = Vec::new(); let crate_items = tcx.hir_crate_items(()); - for id in crate_items.items() { + for id in crate_items.free_items() { if matches!(tcx.def_kind(id.owner_id), DefKind::Fn) { bodies.push(id.owner_id); }