diff --git a/RELEASES.md b/RELEASES.md index 5bc302305c71c..9eb8755dad99a 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -89,7 +89,6 @@ Rustdoc ------- - [Add warning block support in rustdoc](https://github.com/rust-lang/rust/pull/106561/) -- [Accept additional user-defined syntax classes in fenced code blocks](https://github.com/rust-lang/rust/pull/110800/) - [rustdoc-search: add support for type parameters](https://github.com/rust-lang/rust/pull/112725/) - [rustdoc: show inner enum and struct in type definition for concrete type](https://github.com/rust-lang/rust/pull/114855/) diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 202ca1b156aa7..632072003539f 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -9,10 +9,12 @@ use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy}; use rustc_span::Symbol; use stable_mir::mir::alloc::AllocId; use stable_mir::mir::mono::{Instance, MonoItem, StaticDef}; +use stable_mir::mir::{Mutability, Safety}; use stable_mir::ty::{ - AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, - ExistentialTraitRef, FloatTy, GenericArgKind, GenericArgs, IntTy, Region, RigidTy, Span, - TraitRef, Ty, UintTy, + Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, + DynKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig, + GenericArgKind, GenericArgs, IndexedVal, IntTy, Movability, Region, RigidTy, Span, TermKind, + TraitRef, Ty, UintTy, VariantDef, VariantIdx, }; use stable_mir::{CrateItem, DefId}; @@ -84,17 +86,38 @@ impl<'tcx> RustcInternal<'tcx> for RigidTy { } RigidTy::Str => rustc_ty::TyKind::Str, RigidTy::Slice(ty) => rustc_ty::TyKind::Slice(ty.internal(tables)), - RigidTy::RawPtr(..) - | RigidTy::Ref(..) - | RigidTy::Foreign(_) - | RigidTy::FnDef(_, _) - | RigidTy::FnPtr(_) - | RigidTy::Closure(..) - | RigidTy::Coroutine(..) - | RigidTy::CoroutineWitness(..) - | RigidTy::Dynamic(..) - | RigidTy::Tuple(..) => { - todo!() + RigidTy::RawPtr(ty, mutability) => rustc_ty::TyKind::RawPtr(rustc_ty::TypeAndMut { + ty: ty.internal(tables), + mutbl: mutability.internal(tables), + }), + RigidTy::Ref(region, ty, mutability) => rustc_ty::TyKind::Ref( + region.internal(tables), + ty.internal(tables), + mutability.internal(tables), + ), + RigidTy::Foreign(def) => rustc_ty::TyKind::Foreign(def.0.internal(tables)), + RigidTy::FnDef(def, args) => { + rustc_ty::TyKind::FnDef(def.0.internal(tables), args.internal(tables)) + } + RigidTy::FnPtr(sig) => rustc_ty::TyKind::FnPtr(sig.internal(tables)), + RigidTy::Closure(def, args) => { + rustc_ty::TyKind::Closure(def.0.internal(tables), args.internal(tables)) + } + RigidTy::Coroutine(def, args, mov) => rustc_ty::TyKind::Coroutine( + def.0.internal(tables), + args.internal(tables), + mov.internal(tables), + ), + RigidTy::CoroutineWitness(def, args) => { + rustc_ty::TyKind::CoroutineWitness(def.0.internal(tables), args.internal(tables)) + } + RigidTy::Dynamic(predicate, region, dyn_kind) => rustc_ty::TyKind::Dynamic( + tables.tcx.mk_poly_existential_predicates(&predicate.internal(tables)), + region.internal(tables), + dyn_kind.internal(tables), + ), + RigidTy::Tuple(tys) => { + rustc_ty::TyKind::Tuple(tables.tcx.mk_type_list(&tys.internal(tables))) } } } @@ -141,6 +164,57 @@ impl<'tcx> RustcInternal<'tcx> for FloatTy { } } +impl<'tcx> RustcInternal<'tcx> for Mutability { + type T = rustc_ty::Mutability; + + fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + match self { + Mutability::Not => rustc_ty::Mutability::Not, + Mutability::Mut => rustc_ty::Mutability::Mut, + } + } +} + +impl<'tcx> RustcInternal<'tcx> for Movability { + type T = rustc_ty::Movability; + + fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + match self { + Movability::Static => rustc_ty::Movability::Static, + Movability::Movable => rustc_ty::Movability::Movable, + } + } +} + +impl<'tcx> RustcInternal<'tcx> for FnSig { + type T = rustc_ty::FnSig<'tcx>; + + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + rustc_ty::FnSig { + inputs_and_output: tables.tcx.mk_type_list(&self.inputs_and_output.internal(tables)), + c_variadic: self.c_variadic, + unsafety: self.unsafety.internal(tables), + abi: self.abi.internal(tables), + } + } +} + +impl<'tcx> RustcInternal<'tcx> for VariantIdx { + type T = rustc_target::abi::VariantIdx; + + fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + rustc_target::abi::VariantIdx::from(self.to_index()) + } +} + +impl<'tcx> RustcInternal<'tcx> for VariantDef { + type T = &'tcx rustc_ty::VariantDef; + + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + self.adt_def.internal(tables).variant(self.idx.internal(tables)) + } +} + fn ty_const<'tcx>(constant: &Const, tables: &mut Tables<'tcx>) -> rustc_ty::Const<'tcx> { match constant.internal(tables) { rustc_middle::mir::Const::Ty(c) => c, @@ -230,6 +304,58 @@ impl<'tcx> RustcInternal<'tcx> for BoundVariableKind { } } +impl<'tcx> RustcInternal<'tcx> for DynKind { + type T = rustc_ty::DynKind; + + fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + match self { + DynKind::Dyn => rustc_ty::DynKind::Dyn, + DynKind::DynStar => rustc_ty::DynKind::DynStar, + } + } +} + +impl<'tcx> RustcInternal<'tcx> for ExistentialPredicate { + type T = rustc_ty::ExistentialPredicate<'tcx>; + + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + match self { + ExistentialPredicate::Trait(trait_ref) => { + rustc_ty::ExistentialPredicate::Trait(trait_ref.internal(tables)) + } + ExistentialPredicate::Projection(proj) => { + rustc_ty::ExistentialPredicate::Projection(proj.internal(tables)) + } + ExistentialPredicate::AutoTrait(trait_def) => { + rustc_ty::ExistentialPredicate::AutoTrait(trait_def.0.internal(tables)) + } + } + } +} + +impl<'tcx> RustcInternal<'tcx> for ExistentialProjection { + type T = rustc_ty::ExistentialProjection<'tcx>; + + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + rustc_ty::ExistentialProjection { + def_id: self.def_id.0.internal(tables), + args: self.generic_args.internal(tables), + term: self.term.internal(tables), + } + } +} + +impl<'tcx> RustcInternal<'tcx> for TermKind { + type T = rustc_ty::Term<'tcx>; + + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + match self { + TermKind::Type(ty) => ty.internal(tables).into(), + TermKind::Const(const_) => ty_const(const_, tables).into(), + } + } +} + impl<'tcx> RustcInternal<'tcx> for ExistentialTraitRef { type T = rustc_ty::ExistentialTraitRef<'tcx>; @@ -279,6 +405,53 @@ impl<'tcx> RustcInternal<'tcx> for AdtDef { } } +impl<'tcx> RustcInternal<'tcx> for Abi { + type T = rustc_target::spec::abi::Abi; + + fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + match *self { + Abi::Rust => rustc_target::spec::abi::Abi::Rust, + Abi::C { unwind } => rustc_target::spec::abi::Abi::C { unwind }, + Abi::Cdecl { unwind } => rustc_target::spec::abi::Abi::Cdecl { unwind }, + Abi::Stdcall { unwind } => rustc_target::spec::abi::Abi::Stdcall { unwind }, + Abi::Fastcall { unwind } => rustc_target::spec::abi::Abi::Fastcall { unwind }, + Abi::Vectorcall { unwind } => rustc_target::spec::abi::Abi::Vectorcall { unwind }, + Abi::Thiscall { unwind } => rustc_target::spec::abi::Abi::Thiscall { unwind }, + Abi::Aapcs { unwind } => rustc_target::spec::abi::Abi::Aapcs { unwind }, + Abi::Win64 { unwind } => rustc_target::spec::abi::Abi::Win64 { unwind }, + Abi::SysV64 { unwind } => rustc_target::spec::abi::Abi::SysV64 { unwind }, + Abi::PtxKernel => rustc_target::spec::abi::Abi::PtxKernel, + Abi::Msp430Interrupt => rustc_target::spec::abi::Abi::Msp430Interrupt, + Abi::X86Interrupt => rustc_target::spec::abi::Abi::X86Interrupt, + Abi::AmdGpuKernel => rustc_target::spec::abi::Abi::AmdGpuKernel, + Abi::EfiApi => rustc_target::spec::abi::Abi::EfiApi, + Abi::AvrInterrupt => rustc_target::spec::abi::Abi::AvrInterrupt, + Abi::AvrNonBlockingInterrupt => rustc_target::spec::abi::Abi::AvrNonBlockingInterrupt, + Abi::CCmseNonSecureCall => rustc_target::spec::abi::Abi::CCmseNonSecureCall, + Abi::Wasm => rustc_target::spec::abi::Abi::Wasm, + Abi::System { unwind } => rustc_target::spec::abi::Abi::System { unwind }, + Abi::RustIntrinsic => rustc_target::spec::abi::Abi::RustIntrinsic, + Abi::RustCall => rustc_target::spec::abi::Abi::RustCall, + Abi::PlatformIntrinsic => rustc_target::spec::abi::Abi::PlatformIntrinsic, + Abi::Unadjusted => rustc_target::spec::abi::Abi::Unadjusted, + Abi::RustCold => rustc_target::spec::abi::Abi::RustCold, + Abi::RiscvInterruptM => rustc_target::spec::abi::Abi::RiscvInterruptM, + Abi::RiscvInterruptS => rustc_target::spec::abi::Abi::RiscvInterruptS, + } + } +} + +impl<'tcx> RustcInternal<'tcx> for Safety { + type T = rustc_hir::Unsafety; + + fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + match self { + Safety::Unsafe => rustc_hir::Unsafety::Unsafe, + Safety::Normal => rustc_hir::Unsafety::Normal, + } + } +} + impl<'tcx> RustcInternal<'tcx> for Span { type T = rustc_span::Span; @@ -297,6 +470,7 @@ where (*self).internal(tables) } } + impl<'tcx, T> RustcInternal<'tcx> for Option where T: RustcInternal<'tcx>, @@ -307,3 +481,14 @@ where self.as_ref().map(|inner| inner.internal(tables)) } } + +impl<'tcx, T> RustcInternal<'tcx> for Vec +where + T: RustcInternal<'tcx>, +{ + type T = Vec; + + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + self.iter().map(|e| e.internal(tables)).collect() + } +} diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 0bd640ee1e3b0..93d49038fc1c7 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -12,8 +12,8 @@ use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::mono::{InstanceDef, StaticDef}; use stable_mir::mir::Body; use stable_mir::ty::{ - AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FnDef, GenericArgs, LineInfo, - PolyFnSig, RigidTy, Span, TyKind, + AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs, + LineInfo, PolyFnSig, RigidTy, Span, TyKind, VariantDef, }; use stable_mir::{self, Crate, CrateItem, DefId, Error, Filename, ItemKind, Symbol}; use std::cell::RefCell; @@ -209,6 +209,21 @@ impl<'tcx> Context for TablesWrapper<'tcx> { sig.stable(&mut *tables) } + fn adt_variants_len(&self, def: AdtDef) -> usize { + let mut tables = self.0.borrow_mut(); + def.internal(&mut *tables).variants().len() + } + + fn variant_name(&self, def: VariantDef) -> Symbol { + let mut tables = self.0.borrow_mut(); + def.internal(&mut *tables).name.to_string() + } + + fn variant_fields(&self, def: VariantDef) -> Vec { + let mut tables = self.0.borrow_mut(); + def.internal(&mut *tables).fields.iter().map(|f| f.stable(&mut *tables)).collect() + } + fn eval_target_usize(&self, cnst: &Const) -> Result { let mut tables = self.0.borrow_mut(); let mir_const = cnst.internal(&mut *tables); @@ -240,6 +255,13 @@ impl<'tcx> Context for TablesWrapper<'tcx> { tables.tcx.type_of(item.internal(&mut *tables)).instantiate_identity().stable(&mut *tables) } + fn def_ty_with_args(&self, item: stable_mir::DefId, args: &GenericArgs) -> stable_mir::ty::Ty { + let mut tables = self.0.borrow_mut(); + let args = args.internal(&mut *tables); + let def_ty = tables.tcx.type_of(item.internal(&mut *tables)); + def_ty.instantiate(tables.tcx, args).stable(&mut *tables) + } + fn const_literal(&self, cnst: &stable_mir::ty::Const) -> String { internal(cnst).to_string() } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 165b8c50e70f9..0cea3fcc7f7ac 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -517,7 +517,7 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> { mir::AggregateKind::Adt(def_id, var_idx, generic_arg, user_ty_index, field_idx) => { stable_mir::mir::AggregateKind::Adt( tables.adt_def(*def_id), - var_idx.index(), + var_idx.stable(tables), generic_arg.stable(tables), user_ty_index.map(|idx| idx.index()), field_idx.map(|idx| idx.index()), diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs index edb32df305c8e..9c0b2b29bca71 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs @@ -1,7 +1,7 @@ //! Conversion of internal Rust compiler items to stable ones. use rustc_target::abi::FieldIdx; -use stable_mir::mir::VariantIdx; +use stable_mir::ty::{IndexedVal, VariantIdx}; use crate::rustc_smir::{Stable, Tables}; @@ -25,17 +25,10 @@ impl<'tcx> Stable<'tcx> for FieldIdx { } } -impl<'tcx> Stable<'tcx> for (rustc_target::abi::VariantIdx, FieldIdx) { - type T = (usize, usize); - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { - (self.0.as_usize(), self.1.as_usize()) - } -} - impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx { type T = VariantIdx; fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { - self.as_usize() + VariantIdx::to_val(self.as_usize()) } } @@ -67,6 +60,14 @@ impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind { } } +impl<'tcx> Stable<'tcx> for rustc_span::Symbol { + type T = stable_mir::Symbol; + + fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + self.to_string() + } +} + impl<'tcx> Stable<'tcx> for rustc_span::Span { type T = stable_mir::ty::Span; diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index f837f28e11ed2..4fe847c291c87 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -137,6 +137,17 @@ impl<'tcx> Stable<'tcx> for ty::AdtKind { } } +impl<'tcx> Stable<'tcx> for ty::FieldDef { + type T = stable_mir::ty::FieldDef; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + stable_mir::ty::FieldDef { + def: tables.create_def_id(self.did), + name: self.name.stable(tables), + } + } +} + impl<'tcx> Stable<'tcx> for ty::GenericArgs<'tcx> { type T = stable_mir::ty::GenericArgs; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index eee587f3b2ab1..4cb48a12c96b5 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -141,3 +141,24 @@ where } } } + +impl<'tcx, T> Stable<'tcx> for &[T] +where + T: Stable<'tcx>, +{ + type T = Vec; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + self.iter().map(|e| e.stable(tables)).collect() + } +} + +impl<'tcx, T, U> Stable<'tcx> for (T, U) +where + T: Stable<'tcx>, + U: Stable<'tcx>, +{ + type T = (T::T, U::T); + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + (self.0.stable(tables), self.1.stable(tables)) + } +} diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d7e822382ef92..07fe3a2314768 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -973,6 +973,7 @@ symbols! { managed_boxes, manually_drop, map, + map_err, marker, marker_trait_attr, masked, @@ -1137,6 +1138,7 @@ symbols! { offset, offset_of, offset_of_enum, + ok_or_else, omit_gdb_pretty_printer_section, on, on_unimplemented, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index dbce2f30f9397..63002aa4aa404 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1637,6 +1637,7 @@ supported_targets! { ("riscv32imc-esp-espidf", riscv32imc_esp_espidf), ("riscv32imac-esp-espidf", riscv32imac_esp_espidf), ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf), + ("riscv32imafc-unknown-none-elf", riscv32imafc_unknown_none_elf), ("riscv32imac-unknown-xous-elf", riscv32imac_unknown_xous_elf), ("riscv32gc-unknown-linux-gnu", riscv32gc_unknown_linux_gnu), ("riscv32gc-unknown-linux-musl", riscv32gc_unknown_linux_musl), diff --git a/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs new file mode 100644 index 0000000000000..9fb68874ac8ea --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs @@ -0,0 +1,24 @@ +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(), + 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), + llvm_abiname: "ilp32f".into(), + features: "+m,+a,+c,+f".into(), + panic_strategy: PanicStrategy::Abort, + relocation_model: RelocModel::Static, + emit_debug_gdb_scripts: false, + eh_frame_header: false, + ..Default::default() + }, + } +} diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 857740130628f..090706070ebcf 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -3,6 +3,7 @@ use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch}; use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use crate::infer::InferCtxtExt as _; use crate::infer::{self, InferCtxt}; use crate::traits::error_reporting::infer_ctxt_ext::InferCtxtExt; use crate::traits::error_reporting::{ambiguity, ambiguity::Ambiguity::*}; @@ -40,7 +41,7 @@ use rustc_session::config::{DumpSolverProofTree, TraitSolver}; use rustc_session::Limit; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::symbol::sym; -use rustc_span::{ExpnKind, Span, DUMMY_SP}; +use rustc_span::{BytePos, ExpnKind, Span, Symbol, DUMMY_SP}; use std::borrow::Cow; use std::fmt; use std::iter; @@ -106,6 +107,13 @@ pub trait TypeErrCtxtExt<'tcx> { fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool; + fn try_conversion_context( + &self, + obligation: &PredicateObligation<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + err: &mut Diagnostic, + ) -> bool; + fn report_const_param_not_wf( &self, ty: Ty<'tcx>, @@ -509,6 +517,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut err = struct_span_err!(self.tcx.sess, span, E0277, "{}", err_msg); + let mut suggested = false; + if is_try_conversion { + suggested = self.try_conversion_context(&obligation, trait_ref.skip_binder(), &mut err); + } + if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) { err.span_label( ret_span, @@ -609,8 +622,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref); self.suggest_dereferencing_index(&obligation, &mut err, trait_predicate); - let mut suggested = - self.suggest_dereferences(&obligation, &mut err, trait_predicate); + suggested |= self.suggest_dereferences(&obligation, &mut err, trait_predicate); suggested |= self.suggest_fn_call(&obligation, &mut err, trait_predicate); let impl_candidates = self.find_similar_impl_candidates(trait_predicate); suggested = if let &[cand] = &impl_candidates[..] { @@ -982,6 +994,223 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { false } + /// When the `E` of the resulting `Result` in an expression `foo().bar().baz()?`, + /// identify thoe method chain sub-expressions that could or could not have been annotated + /// with `?`. + fn try_conversion_context( + &self, + obligation: &PredicateObligation<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + err: &mut Diagnostic, + ) -> bool { + let span = obligation.cause.span; + struct V<'v> { + search_span: Span, + found: Option<&'v hir::Expr<'v>>, + } + impl<'v> Visitor<'v> for V<'v> { + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + if let hir::ExprKind::Match(expr, _arms, hir::MatchSource::TryDesugar(_)) = ex.kind + { + if ex.span.with_lo(ex.span.hi() - BytePos(1)).source_equal(self.search_span) { + if let hir::ExprKind::Call(_, [expr, ..]) = expr.kind { + self.found = Some(expr); + return; + } + } + } + hir::intravisit::walk_expr(self, ex); + } + } + let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id); + let body_id = match self.tcx.hir().find(hir_id) { + Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) => { + body_id + } + _ => return false, + }; + let mut v = V { search_span: span, found: None }; + v.visit_body(self.tcx.hir().body(*body_id)); + let Some(expr) = v.found else { + return false; + }; + let Some(typeck) = &self.typeck_results else { + return false; + }; + let Some((ObligationCauseCode::QuestionMark, Some(y))) = obligation.cause.code().parent() + else { + return false; + }; + if !self.tcx.is_diagnostic_item(sym::FromResidual, y.def_id()) { + return false; + } + let self_ty = trait_ref.self_ty(); + let found_ty = trait_ref.args.get(1).and_then(|a| a.as_type()); + + let mut prev_ty = self.resolve_vars_if_possible( + typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), + ); + + // We always look at the `E` type, because that's the only one affected by `?`. If the + // incorrect `Result` is because of the `T`, we'll get an E0308 on the whole + // expression, after the `?` has "unwrapped" the `T`. + let get_e_type = |prev_ty: Ty<'tcx>| -> Option> { + let ty::Adt(def, args) = prev_ty.kind() else { + return None; + }; + let Some(arg) = args.get(1) else { + return None; + }; + if !self.tcx.is_diagnostic_item(sym::Result, def.did()) { + return None; + } + Some(arg.as_type()?) + }; + + let mut suggested = false; + let mut chain = vec![]; + + // The following logic is simlar to `point_at_chain`, but that's focused on associated types + let mut expr = expr; + while let hir::ExprKind::MethodCall(path_segment, rcvr_expr, args, span) = expr.kind { + // Point at every method call in the chain with the `Result` type. + // let foo = bar.iter().map(mapper)?; + // ------ ----------- + expr = rcvr_expr; + chain.push((span, prev_ty)); + + let next_ty = self.resolve_vars_if_possible( + typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), + ); + + let is_diagnostic_item = |symbol: Symbol, ty: Ty<'tcx>| { + let ty::Adt(def, _) = ty.kind() else { + return false; + }; + self.tcx.is_diagnostic_item(symbol, def.did()) + }; + // For each method in the chain, see if this is `Result::map_err` or + // `Option::ok_or_else` and if it is, see if the closure passed to it has an incorrect + // trailing `;`. + if let Some(ty) = get_e_type(prev_ty) + && let Some(found_ty) = found_ty + // Ideally we would instead use `FnCtxt::lookup_method_for_diagnostic` for 100% + // accurate check, but we are in the wrong stage to do that and looking for + // `Result::map_err` by checking the Self type and the path segment is enough. + // sym::ok_or_else + && ( + ( // Result::map_err + path_segment.ident.name == sym::map_err + && is_diagnostic_item(sym::Result, next_ty) + ) || ( // Option::ok_or_else + path_segment.ident.name == sym::ok_or_else + && is_diagnostic_item(sym::Option, next_ty) + ) + ) + // Found `Result<_, ()>?` + && let ty::Tuple(tys) = found_ty.kind() + && tys.is_empty() + // The current method call returns `Result<_, ()>` + && self.can_eq(obligation.param_env, ty, found_ty) + // There's a single argument in the method call and it is a closure + && args.len() == 1 + && let Some(arg) = args.get(0) + && let hir::ExprKind::Closure(closure) = arg.kind + // The closure has a block for its body with no tail expression + && let body = self.tcx.hir().body(closure.body) + && let hir::ExprKind::Block(block, _) = body.value.kind + && let None = block.expr + // The last statement is of a type that can be converted to the return error type + && let [.., stmt] = block.stmts + && let hir::StmtKind::Semi(expr) = stmt.kind + && let expr_ty = self.resolve_vars_if_possible( + typeck.expr_ty_adjusted_opt(expr) + .unwrap_or(Ty::new_misc_error(self.tcx)), + ) + && self + .infcx + .type_implements_trait( + self.tcx.get_diagnostic_item(sym::From).unwrap(), + [self_ty, expr_ty], + obligation.param_env, + ) + .must_apply_modulo_regions() + { + suggested = true; + err.span_suggestion_short( + stmt.span.with_lo(expr.span.hi()), + "remove this semicolon", + String::new(), + Applicability::MachineApplicable, + ); + } + + prev_ty = next_ty; + + if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind + && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path + && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id) + && let Some(parent) = self.tcx.hir().find_parent(binding.hir_id) + { + // We've reached the root of the method call chain... + if let hir::Node::Local(local) = parent + && let Some(binding_expr) = local.init + { + // ...and it is a binding. Get the binding creation and continue the chain. + expr = binding_expr; + } + if let hir::Node::Param(_param) = parent { + // ...and it is a an fn argument. + break; + } + } + } + // `expr` is now the "root" expression of the method call chain, which can be any + // expression kind, like a method call or a path. If this expression is `Result` as + // well, then we also point at it. + prev_ty = self.resolve_vars_if_possible( + typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), + ); + chain.push((expr.span, prev_ty)); + + let mut prev = None; + for (span, err_ty) in chain.into_iter().rev() { + let err_ty = get_e_type(err_ty); + let err_ty = match (err_ty, prev) { + (Some(err_ty), Some(prev)) if !self.can_eq(obligation.param_env, err_ty, prev) => { + err_ty + } + (Some(err_ty), None) => err_ty, + _ => { + prev = err_ty; + continue; + } + }; + if self + .infcx + .type_implements_trait( + self.tcx.get_diagnostic_item(sym::From).unwrap(), + [self_ty, err_ty], + obligation.param_env, + ) + .must_apply_modulo_regions() + { + if !suggested { + err.span_label(span, format!("this has type `Result<_, {err_ty}>`")); + } + } else { + err.span_label( + span, + format!( + "this can't be annotated with `?` because it has type `Result<_, {err_ty}>`", + ), + ); + } + prev = Some(err_ty); + } + suggested + } + fn report_const_param_not_wf( &self, ty: Ty<'tcx>, diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index daf4465963edd..d8a3d4eda4be3 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -9,9 +9,9 @@ use crate::mir::alloc::{AllocId, GlobalAlloc}; use crate::mir::mono::{Instance, InstanceDef, StaticDef}; use crate::mir::Body; use crate::ty::{ - AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FnDef, GenericArgs, + AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs, GenericPredicates, Generics, ImplDef, ImplTrait, LineInfo, PolyFnSig, RigidTy, Span, TraitDecl, - TraitDef, Ty, TyKind, + TraitDef, Ty, TyKind, VariantDef, }; use crate::{ mir, Crate, CrateItem, CrateItems, DefId, Error, Filename, ImplTraitDecls, ItemKind, Symbol, @@ -71,6 +71,13 @@ pub trait Context { /// Retrieve the function signature for the given generic arguments. fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig; + /// The number of variants in this ADT. + fn adt_variants_len(&self, def: AdtDef) -> usize; + + /// The name of a variant. + fn variant_name(&self, def: VariantDef) -> Symbol; + fn variant_fields(&self, def: VariantDef) -> Vec; + /// Evaluate constant as a target usize. fn eval_target_usize(&self, cnst: &Const) -> Result; @@ -83,6 +90,9 @@ pub trait Context { /// Returns the type of given crate item. fn def_ty(&self, item: DefId) -> Ty; + /// Returns the type of given definition instantiated with the given arguments. + 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; diff --git a/compiler/stable_mir/src/error.rs b/compiler/stable_mir/src/error.rs index 1ff65717e87db..bb5e1a34180ba 100644 --- a/compiler/stable_mir/src/error.rs +++ b/compiler/stable_mir/src/error.rs @@ -28,7 +28,7 @@ pub enum CompilerError { } /// A generic error to represent an API request that cannot be fulfilled. -#[derive(Debug)] +#[derive(Clone, Debug, Eq, PartialEq)] pub struct Error(pub(crate) String); impl Error { diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 3a4f42835622b..6f131cc4f0334 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -1,6 +1,7 @@ use crate::mir::pretty::{function_body, pretty_statement, pretty_terminator}; use crate::ty::{ AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind, + VariantIdx, }; use crate::{Error, Opaque, Span, Symbol}; use std::io; @@ -9,17 +10,17 @@ use std::io; pub struct Body { pub blocks: Vec, - // Declarations of locals within the function. - // - // The first local is the return value pointer, followed by `arg_count` - // locals for the function arguments, followed by any user-declared - // variables and temporaries. + /// Declarations of locals within the function. + /// + /// The first local is the return value pointer, followed by `arg_count` + /// locals for the function arguments, followed by any user-declared + /// variables and temporaries. pub(super) locals: LocalDecls, - // The number of arguments this function takes. + /// The number of arguments this function takes. pub(super) arg_count: usize, - // Debug information pertaining to user variables, including captures. + /// Debug information pertaining to user variables, including captures. pub(super) var_debug_info: Vec, } @@ -69,6 +70,11 @@ impl Body { &self.locals } + /// Get the local declaration for this local. + pub fn local_decl(&self, local: Local) -> Option<&LocalDecl> { + self.locals.get(local) + } + pub fn dump(&self, w: &mut W) -> io::Result<()> { writeln!(w, "{}", function_body(self))?; self.blocks @@ -492,12 +498,32 @@ pub struct Place { pub projection: Vec, } +impl From for Place { + fn from(local: Local) -> Self { + Place { local, projection: vec![] } + } +} + +/// Debug information pertaining to a user variable. #[derive(Clone, Debug, Eq, PartialEq)] pub struct VarDebugInfo { + /// The variable name. pub name: Symbol, + + /// Source info of the user variable, including the scope + /// within which the variable is visible (to debuginfo). pub source_info: SourceInfo, + + /// The user variable's data is split across several fragments, + /// each described by a `VarDebugInfoFragment`. pub composite: Option, + + /// Where the data for this user variable is to be found. pub value: VarDebugInfoContents, + + /// When present, indicates what argument number this variable is in the function that it + /// originated from (starting from 1). Note, if MIR inlining is enabled, then this is the + /// argument number in the original function before it was inlined. pub argument_index: Option, } @@ -632,22 +658,7 @@ pub const RETURN_LOCAL: Local = 0; /// `b`'s `FieldIdx` is `1`, /// `c`'s `FieldIdx` is `0`, and /// `g`'s `FieldIdx` is `2`. -type FieldIdx = usize; - -/// The source-order index of a variant in a type. -/// -/// For example, in the following types, -/// ```ignore(illustrative) -/// enum Demo1 { -/// Variant0 { a: bool, b: i32 }, -/// Variant1 { c: u8, d: u64 }, -/// } -/// struct Demo2 { e: u8, f: u16, g: u8 } -/// ``` -/// `a` is in the variant with the `VariantIdx` of `0`, -/// `c` is in the variant with the `VariantIdx` of `1`, and -/// `g` is in the variant with the `VariantIdx` of `0`. -pub type VariantIdx = usize; +pub type FieldIdx = usize; type UserTypeAnnotationIndex = usize; diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index 0c44781c46394..d46caad9a016b 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -452,7 +452,7 @@ impl Location { } /// Information about a place's usage. -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct PlaceContext { /// Whether the access is mutable or not. Keep this private so we can increment the type in a /// backward compatible manner. diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 6c4fb4a775352..f64b1f5f5a355 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -30,6 +30,16 @@ impl Ty { pub fn try_new_array(elem_ty: Ty, size: u64) -> Result { Ok(Ty::from_rigid_kind(RigidTy::Array(elem_ty, Const::try_from_target_usize(size)?))) } + + /// Create a new pointer type. + pub fn new_ptr(pointee_ty: Ty, mutability: Mutability) -> Ty { + Ty::from_rigid_kind(RigidTy::RawPtr(pointee_ty, mutability)) + } + + /// Create a type representing `usize`. + pub fn usize_ty() -> Ty { + Ty::from_rigid_kind(RigidTy::Uint(UintTy::Usize)) + } } impl Ty { @@ -366,9 +376,97 @@ impl AdtDef { with(|cx| cx.adt_kind(*self)) } + /// Retrieve the type of this Adt. + pub fn ty(&self) -> Ty { + with(|cx| cx.def_ty(self.0)) + } + + /// Retrieve the type of this Adt instantiating the type with the given arguments. + /// + /// This will assume the type can be instantiated with these arguments. + pub fn ty_with_args(&self, args: &GenericArgs) -> Ty { + with(|cx| cx.def_ty_with_args(self.0, args)) + } + pub fn is_box(&self) -> bool { with(|cx| cx.adt_is_box(*self)) } + + /// The number of variants in this ADT. + pub fn num_variants(&self) -> usize { + with(|cx| cx.adt_variants_len(*self)) + } + + /// Retrieve the variants in this ADT. + pub fn variants(&self) -> Vec { + self.variants_iter().collect() + } + + /// Iterate over the variants in this ADT. + pub fn variants_iter(&self) -> impl Iterator + '_ { + (0..self.num_variants()) + .map(|idx| VariantDef { idx: VariantIdx::to_val(idx), adt_def: *self }) + } + + pub fn variant(&self, idx: VariantIdx) -> Option { + (idx.to_index() < self.num_variants()).then_some(VariantDef { idx, adt_def: *self }) + } +} + +/// Definition of a variant, which can be either a struct / union field or an enum variant. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct VariantDef { + /// The variant index. + /// + /// ## Warning + /// Do not access this field directly! + pub idx: VariantIdx, + /// The data type where this variant comes from. + /// For now, we use this to retrieve information about the variant itself so we don't need to + /// cache more information. + /// + /// ## Warning + /// Do not access this field directly! + pub adt_def: AdtDef, +} + +impl VariantDef { + pub fn name(&self) -> Symbol { + with(|cx| cx.variant_name(*self)) + } + + /// Retrieve all the fields in this variant. + // We expect user to cache this and use it directly since today it is expensive to generate all + // fields name. + pub fn fields(&self) -> Vec { + with(|cx| cx.variant_fields(*self)) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct FieldDef { + /// The field definition. + /// + /// ## Warning + /// Do not access this field directly! This is public for the compiler to have access to it. + pub def: DefId, + + /// The field name. + pub name: Symbol, +} + +impl FieldDef { + /// Retrieve the type of this field instantiating the type with the given arguments. + /// + /// This will assume the type can be instantiated with these arguments. + pub fn ty_with_args(&self, args: &GenericArgs) -> Ty { + with(|cx| cx.def_ty_with_args(self.def, args)) + } + + /// Retrieve the type of this field. + pub fn ty(&self) -> Ty { + with(|cx| cx.def_ty(self.def)) + } } impl Display for AdtKind { @@ -906,3 +1004,21 @@ macro_rules! index_impl { index_impl!(ConstId); index_impl!(Ty); index_impl!(Span); + +/// The source-order index of a variant in a type. +/// +/// For example, in the following types, +/// ```ignore(illustrative) +/// enum Demo1 { +/// Variant0 { a: bool, b: i32 }, +/// Variant1 { c: u8, d: u64 }, +/// } +/// struct Demo2 { e: u8, f: u16, g: u8 } +/// ``` +/// `a` is in the variant with the `VariantIdx` of `0`, +/// `c` is in the variant with the `VariantIdx` of `1`, and +/// `g` is in the variant with the `VariantIdx` of `0`. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct VariantIdx(usize); + +index_impl!(VariantIdx); diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 25c63b425ce59..fdf5e134f4d4c 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1038,10 +1038,18 @@ impl Box { /// use std::ptr; /// /// let x = Box::new(String::from("Hello")); - /// let p = Box::into_raw(x); + /// let ptr = Box::into_raw(x); + /// unsafe { + /// ptr::drop_in_place(ptr); + /// dealloc(ptr as *mut u8, Layout::new::()); + /// } + /// ``` + /// Note: This is equivalent to the following: + /// ``` + /// let x = Box::new(String::from("Hello")); + /// let ptr = Box::into_raw(x); /// unsafe { - /// ptr::drop_in_place(p); - /// dealloc(p as *mut u8, Layout::new::()); + /// drop(Box::from_raw(ptr)); /// } /// ``` /// diff --git a/library/std/src/sys/windows/api.rs b/library/std/src/sys/windows/api.rs index 72ecb9503410e..a7ea59e85f786 100644 --- a/library/std/src/sys/windows/api.rs +++ b/library/std/src/sys/windows/api.rs @@ -48,7 +48,7 @@ use super::c; /// converted to a `u32`. Clippy would warn about this but, alas, it's not run /// on the standard library. const fn win32_size_of() -> u32 { - // Const assert that the size is less than u32::MAX. + // Const assert that the size does not exceed u32::MAX. // Uses a trait to workaround restriction on using generic types in inner items. trait Win32SizeOf: Sized { const WIN32_SIZE_OF: u32 = { diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 4691fb3ad6f9f..2328dd822afd2 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -946,6 +946,8 @@ def build_bootstrap_cmd(self, env): target_linker = self.get_toml("linker", build_section) if target_linker is not None: env["RUSTFLAGS"] += " -C linker=" + target_linker + # When changing this list, also update the corresponding list in `Builder::cargo` + # in `src/bootstrap/src/core/builder.rs`. env["RUSTFLAGS"] += " -Wrust_2018_idioms -Wunused_lifetimes" if self.warnings == "default": deny_warnings = self.get_toml("deny-warnings", "rust") != "false" diff --git a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile index 341e2de223aa5..adf3c67479b08 100644 --- a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile @@ -95,6 +95,7 @@ ENV TARGETS=$TARGETS,thumbv8m.main-none-eabihf ENV TARGETS=$TARGETS,riscv32i-unknown-none-elf ENV TARGETS=$TARGETS,riscv32imc-unknown-none-elf ENV TARGETS=$TARGETS,riscv32imac-unknown-none-elf +ENV TARGETS=$TARGETS,riscv32imafc-unknown-none-elf ENV TARGETS=$TARGETS,riscv64imac-unknown-none-elf ENV TARGETS=$TARGETS,riscv64gc-unknown-none-elf ENV TARGETS=$TARGETS,armebv7r-none-eabi diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 3bd90f7062dc2..ad33538951441 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -45,6 +45,7 @@ - [nvptx64-nvidia-cuda](platform-support/nvptx64-nvidia-cuda.md) - [powerpc64-ibm-aix](platform-support/aix.md) - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md) + - [riscv32*-unknown-none-elf](platform-support/riscv32imac-unknown-none-elf.md) - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md) - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md) - [\*-nto-qnx-\*](platform-support/nto-qnx.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 3671fdd3fd2be..457e8d90a433d 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -159,9 +159,9 @@ target | std | notes [`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * | | LoongArch64 Bare-metal (LP64D ABI) [`loongarch64-unknown-none-softfloat`](platform-support/loongarch-none.md) | * | | LoongArch64 Bare-metal (LP64S ABI) [`nvptx64-nvidia-cuda`](platform-support/nvptx64-nvidia-cuda.md) | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs] -`riscv32i-unknown-none-elf` | * | Bare RISC-V (RV32I ISA) -`riscv32imac-unknown-none-elf` | * | Bare RISC-V (RV32IMAC ISA) -`riscv32imc-unknown-none-elf` | * | Bare RISC-V (RV32IMC ISA) +[`riscv32imac-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | Bare RISC-V (RV32IMAC ISA) +[`riscv32i-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | Bare RISC-V (RV32I ISA) +[`riscv32imc-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | Bare RISC-V (RV32IMC ISA) `riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA) `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA) `sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23) @@ -314,7 +314,8 @@ target | std | host | notes [`powerpc64-ibm-aix`](platform-support/aix.md) | ? | | 64-bit AIX (7.2 and newer) `riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33) `riscv32gc-unknown-linux-musl` | | | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches) -`riscv32im-unknown-none-elf` | * | | Bare RISC-V (RV32IM ISA) +[`riscv32imafc-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | Bare RISC-V (RV32IMAFC ISA) +[`riscv32im-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | | Bare RISC-V (RV32IM 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/riscv32i-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32i-unknown-none-elf.md new file mode 100644 index 0000000000000..edfe07fc0537b --- /dev/null +++ b/src/doc/rustc/src/platform-support/riscv32i-unknown-none-elf.md @@ -0,0 +1 @@ +riscv32imac-unknown-none-elf.md diff --git a/src/doc/rustc/src/platform-support/riscv32im-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32im-unknown-none-elf.md new file mode 100644 index 0000000000000..edfe07fc0537b --- /dev/null +++ b/src/doc/rustc/src/platform-support/riscv32im-unknown-none-elf.md @@ -0,0 +1 @@ +riscv32imac-unknown-none-elf.md diff --git a/src/doc/rustc/src/platform-support/riscv32imac-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32imac-unknown-none-elf.md new file mode 100644 index 0000000000000..a069f3d3aa9c3 --- /dev/null +++ b/src/doc/rustc/src/platform-support/riscv32imac-unknown-none-elf.md @@ -0,0 +1,34 @@ +# `riscv32{i,im,imc,imac,imafc}-unknown-none-elf` + +**Tier: 2/3** + +Bare-metal target for RISC-V CPUs with the RV32I, RV32IM, RV32IMC, RV32IMAFC and RV32IMAC ISAs. + +## Target maintainers + +* Rust Embedded Working Group, [RISC-V team](https://github.com/rust-embedded/wg#the-risc-v-team) + +## Requirements + +The target is cross-compiled, and uses static linking. No external toolchain +is required and the default `rust-lld` linker works, but you must specify +a linker script. The [`riscv-rt`] crate provides a suitable one. The +[`riscv-rust-quickstart`] repository gives an example of an RV32 project. + +[`riscv-rt`]: https://crates.io/crates/riscv-rt +[`riscv-rust-quickstart`]: https://github.com/riscv-rust/riscv-rust-quickstart + +## Building the target + +This target is included in Rust and can be installed via `rustup`. + +## Testing + +This is a cross-compiled no-std target, which must be run either in a simulator +or by programming them onto suitable hardware. It is not possible to run the +Rust testsuite on this target. + +## Cross-compilation toolchains and C code + +This target supports C code. If interlinking with C or C++, you may need to use +riscv64-unknown-elf-gcc as a linker instead of rust-lld. diff --git a/src/doc/rustc/src/platform-support/riscv32imafc-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32imafc-unknown-none-elf.md new file mode 100644 index 0000000000000..edfe07fc0537b --- /dev/null +++ b/src/doc/rustc/src/platform-support/riscv32imafc-unknown-none-elf.md @@ -0,0 +1 @@ +riscv32imac-unknown-none-elf.md diff --git a/src/doc/rustc/src/platform-support/riscv32imc-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32imc-unknown-none-elf.md new file mode 100644 index 0000000000000..edfe07fc0537b --- /dev/null +++ b/src/doc/rustc/src/platform-support/riscv32imc-unknown-none-elf.md @@ -0,0 +1 @@ +riscv32imac-unknown-none-elf.md diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 83c7ccc9edeb7..9ac97236f19c8 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -124,6 +124,7 @@ static TARGETS: &[&str] = &[ "riscv32im-unknown-none-elf", "riscv32imc-unknown-none-elf", "riscv32imac-unknown-none-elf", + "riscv32imafc-unknown-none-elf", "riscv32gc-unknown-linux-gnu", "riscv64imac-unknown-none-elf", "riscv64gc-unknown-hermit", diff --git a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs new file mode 100644 index 0000000000000..b90d47d4540ba --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs @@ -0,0 +1,115 @@ +// run-pass +//! Test that users are able to use stable mir APIs to retrieve monomorphized types, and that +//! we have an error handling for trying to instantiate types with incorrect arguments. + +// ignore-stage1 +// ignore-cross-compile +// ignore-remote +// ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 +// edition: 2021 + +#![feature(rustc_private)] +#![feature(assert_matches)] +#![feature(control_flow_enum)] + +extern crate rustc_middle; +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate stable_mir; + +use rustc_middle::ty::TyCtxt; +use rustc_smir::rustc_internal; +use stable_mir::ty::{RigidTy, TyKind, Ty, }; +use stable_mir::mir::{Body, MirVisitor, FieldIdx, Place, ProjectionElem, visit::{Location, + PlaceContext}}; +use std::io::Write; +use std::ops::ControlFlow; + +const CRATE_NAME: &str = "input"; + +/// This function uses the Stable MIR APIs to get information about the test crate. +fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { + let main_fn = stable_mir::entry_fn(); + let body = main_fn.unwrap().body(); + let mut visitor = PlaceVisitor{ body: &body, tested: false}; + visitor.visit_body(&body); + assert!(visitor.tested); + ControlFlow::Continue(()) +} + +struct PlaceVisitor<'a> { + body: &'a Body, + /// Used to ensure that the test was reachable. Otherwise this test would vacuously succeed. + tested: bool, +} + +/// Check that `wrapper.inner` place projection can be correctly interpreted. +/// Ensure that instantiation is correct. +fn check_tys(local_ty: Ty, idx: FieldIdx, expected_ty: Ty) { + let TyKind::RigidTy(RigidTy::Adt(def, args)) = local_ty.kind() else { unreachable!() }; + assert_eq!(def.ty_with_args(&args), local_ty); + + let field_def = &def.variants_iter().next().unwrap().fields()[idx]; + let field_ty = field_def.ty_with_args(&args); + assert_eq!(field_ty, expected_ty); + + // Check that the generic version is different than the instantiated one. + let field_ty_gen = field_def.ty(); + assert_ne!(field_ty_gen, field_ty); +} + +impl<'a> MirVisitor for PlaceVisitor<'a> { + fn visit_place(&mut self, place: &Place, _ptx: PlaceContext, _loc: Location) { + let start_ty = self.body.locals()[place.local].ty; + match place.projection.as_slice() { + [ProjectionElem::Field(idx, ty)] => { + check_tys(start_ty, *idx, *ty); + self.tested = true; + } + _ => {} + } + } +} + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "ty_fold_input.rs"; + generate_input(&path).unwrap(); + let args = vec![ + "rustc".to_string(), + "-Cpanic=abort".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + run!(args, tcx, test_stable_mir(tcx)).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + struct Wrapper {{ + pub inner: T + }} + + impl Wrapper {{ + pub fn new() -> Wrapper {{ + Wrapper {{ inner: T::default() }} + }} + }} + + fn main() {{ + let wrapper = Wrapper::::new(); + let _inner = wrapper.inner; + }} + "# + )?; + Ok(()) +} diff --git a/tests/ui/traits/question-mark-result-err-mismatch.rs b/tests/ui/traits/question-mark-result-err-mismatch.rs new file mode 100644 index 0000000000000..0ca18b5b0ddce --- /dev/null +++ b/tests/ui/traits/question-mark-result-err-mismatch.rs @@ -0,0 +1,59 @@ +fn foo() -> Result { //~ NOTE expected `String` because of this + let test = String::from("one,two"); + let x = test + .split_whitespace() + .next() + .ok_or_else(|| { + "Couldn't split the test string" + }); + let one = x + .map(|s| ()) + .map_err(|e| { //~ NOTE this can't be annotated with `?` because it has type `Result<_, ()>` + e; //~ HELP remove this semicolon + }) + .map(|()| "")?; //~ ERROR `?` couldn't convert the error to `String` + //~^ NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE the trait `From<()>` is not implemented for `String` + //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + //~| NOTE required for `Result` to implement `FromResidual>` + Ok(one.to_string()) +} + +fn bar() -> Result<(), String> { //~ NOTE expected `String` because of this + let x = foo(); //~ NOTE this has type `Result<_, String>` + let one = x + .map(|s| ()) + .map_err(|_| ())?; //~ ERROR `?` couldn't convert the error to `String` + //~^ NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE this can't be annotated with `?` because it has type `Result<_, ()>` + //~| NOTE the trait `From<()>` is not implemented for `String` + //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + //~| NOTE required for `Result<(), String>` to implement `FromResidual>` + //~| HELP the following other types implement trait `From`: + Ok(one) +} + +fn baz() -> Result { //~ NOTE expected `String` because of this + let test = String::from("one,two"); + let one = test + .split_whitespace() + .next() + .ok_or_else(|| { //~ NOTE this can't be annotated with `?` because it has type `Result<_, ()>` + "Couldn't split the test string"; //~ HELP remove this semicolon + })?; + //~^ ERROR `?` couldn't convert the error to `String` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE the trait `From<()>` is not implemented for `String` + //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + //~| NOTE required for `Result` to implement `FromResidual>` + Ok(one.to_string()) +} + +fn main() {} diff --git a/tests/ui/traits/question-mark-result-err-mismatch.stderr b/tests/ui/traits/question-mark-result-err-mismatch.stderr new file mode 100644 index 0000000000000..3059e0beca3e4 --- /dev/null +++ b/tests/ui/traits/question-mark-result-err-mismatch.stderr @@ -0,0 +1,62 @@ +error[E0277]: `?` couldn't convert the error to `String` + --> $DIR/question-mark-result-err-mismatch.rs:14:22 + | +LL | fn foo() -> Result { + | ---------------------- expected `String` because of this +... +LL | .map_err(|e| { + | __________- +LL | | e; + | | - help: remove this semicolon +LL | | }) + | |__________- this can't be annotated with `?` because it has type `Result<_, ()>` +LL | .map(|()| "")?; + | ^ the trait `From<()>` is not implemented for `String` + | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + = note: required for `Result` to implement `FromResidual>` + +error[E0277]: `?` couldn't convert the error to `String` + --> $DIR/question-mark-result-err-mismatch.rs:28:25 + | +LL | fn bar() -> Result<(), String> { + | ------------------ expected `String` because of this +LL | let x = foo(); + | ----- this has type `Result<_, String>` +... +LL | .map_err(|_| ())?; + | ---------------^ the trait `From<()>` is not implemented for `String` + | | + | this can't be annotated with `?` because it has type `Result<_, ()>` + | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + = help: the following other types implement trait `From`: + > + >> + >> + > + > + > + = note: required for `Result<(), String>` to implement `FromResidual>` + +error[E0277]: `?` couldn't convert the error to `String` + --> $DIR/question-mark-result-err-mismatch.rs:48:11 + | +LL | fn baz() -> Result { + | ---------------------- expected `String` because of this +... +LL | .ok_or_else(|| { + | __________- +LL | | "Couldn't split the test string"; + | | - help: remove this semicolon +LL | | })?; + | | -^ the trait `From<()>` is not implemented for `String` + | |__________| + | this can't be annotated with `?` because it has type `Result<_, ()>` + | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + = note: required for `Result` to implement `FromResidual>` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/try-block/try-block-bad-type.stderr b/tests/ui/try-block/try-block-bad-type.stderr index b41bf86d3d911..d58a011ff5501 100644 --- a/tests/ui/try-block/try-block-bad-type.stderr +++ b/tests/ui/try-block/try-block-bad-type.stderr @@ -2,7 +2,9 @@ error[E0277]: `?` couldn't convert the error to `TryFromSliceError` --> $DIR/try-block-bad-type.rs:7:16 | LL | Err("")?; - | ^ the trait `From<&str>` is not implemented for `TryFromSliceError` + | -------^ the trait `From<&str>` is not implemented for `TryFromSliceError` + | | + | this can't be annotated with `?` because it has type `Result<_, &str>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the trait `From` is implemented for `TryFromSliceError` diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index d8b9431becc6b..97fbbdbf8f8a8 100644 --- a/tests/ui/try-trait/bad-interconversion.stderr +++ b/tests/ui/try-trait/bad-interconversion.stderr @@ -4,7 +4,9 @@ error[E0277]: `?` couldn't convert the error to `u8` LL | fn result_to_result() -> Result { | --------------- expected `u8` because of this LL | Ok(Err(123_i32)?) - | ^ the trait `From` is not implemented for `u8` + | ------------^ the trait `From` is not implemented for `u8` + | | + | this can't be annotated with `?` because it has type `Result<_, i32>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From`: diff --git a/tests/ui/try-trait/issue-32709.stderr b/tests/ui/try-trait/issue-32709.stderr index 46798f5dcfda8..b155b3ff66313 100644 --- a/tests/ui/try-trait/issue-32709.stderr +++ b/tests/ui/try-trait/issue-32709.stderr @@ -4,7 +4,9 @@ error[E0277]: `?` couldn't convert the error to `()` LL | fn a() -> Result { | --------------- expected `()` because of this LL | Err(5)?; - | ^ the trait `From<{integer}>` is not implemented for `()` + | ------^ the trait `From<{integer}>` is not implemented for `()` + | | + | this can't be annotated with `?` because it has type `Result<_, {integer}>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From`: