From eff35e59c698df379806add4c9f2c1d8d3fe55ca Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Thu, 7 Apr 2022 18:06:53 -0700 Subject: [PATCH 01/16] Introduce dyn_star feature flag The primary purpose of this commit is to introduce the dyn_star flag so we can begin experimenting with implementation. In order to have something to do in the feature gate test, we also add parser support for `dyn* Trait` objects. These are currently treated just like `dyn Trait` objects, but this will change in the future. Note that for now `dyn* Trait` is experimental syntax to enable implementing some of the machinery needed for async fn in dyn traits without fully supporting the feature. --- compiler/rustc_ast/src/ast.rs | 1 + compiler/rustc_ast_passes/src/ast_validation.rs | 15 ++++++++++++++- compiler/rustc_feature/src/active.rs | 2 ++ compiler/rustc_parse/src/parser/ty.rs | 15 +++++++++++++-- compiler/rustc_span/src/symbol.rs | 1 + src/test/ui/dyn-star/feature-gate-dyn_star.rs | 9 +++++++++ src/test/ui/dyn-star/feature-gate-dyn_star.stderr | 12 ++++++++++++ src/test/ui/dyn-star/syntax.rs | 11 +++++++++++ 8 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/dyn-star/feature-gate-dyn_star.rs create mode 100644 src/test/ui/dyn-star/feature-gate-dyn_star.stderr create mode 100644 src/test/ui/dyn-star/syntax.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3f4911c4ecfcf..722d7b71c7ac6 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2072,6 +2072,7 @@ impl TyKind { #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum TraitObjectSyntax { Dyn, + DynStar, None, } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 6a0a1b0836013..5558f0c8c7686 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -19,6 +19,7 @@ use rustc_session::lint::builtin::{ DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY, }; use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; +use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident}; @@ -753,7 +754,19 @@ impl<'a> AstValidator<'a> { self.maybe_lint_missing_abi(sig_span, ty.id); } } - TyKind::TraitObject(ref bounds, ..) => { + TyKind::TraitObject(ref bounds, syntax, ..) => { + if syntax == TraitObjectSyntax::DynStar + && !self.session.features_untracked().dyn_star + { + feature_err( + &self.session.parse_sess, + sym::dyn_star, + ty.span, + "dyn* trait objects are unstable", + ) + .emit(); + } + let mut any_lifetime_bounds = false; for bound in bounds { if let GenericBound::Outlives(ref lifetime) = *bound { diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 5377ebde1683f..72f7064b6cae6 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -380,6 +380,8 @@ declare_features! ( (active, doc_cfg_hide, "1.57.0", Some(43781), None), /// Allows `#[doc(masked)]`. (active, doc_masked, "1.21.0", Some(44027), None), + /// Allows `dyn* Trait` objects. + (active, dyn_star, "1.65.0", Some(91611), None), /// Allows `X..Y` patterns. (active, exclusive_range_pattern, "1.11.0", Some(37854), None), /// Allows exhaustive pattern matching on types that contain uninhabited types. diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 4a2cf74905bf5..ffe3618bc4951 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -567,7 +567,8 @@ impl<'a> Parser<'a> { self.check_keyword(kw::Dyn) && (!self.token.uninterpolated_span().rust_2015() || self.look_ahead(1, |t| { - t.can_begin_bound() && !can_continue_type_after_non_fn_ident(t) + (t.can_begin_bound() || t.kind == TokenKind::BinOp(token::Star)) + && !can_continue_type_after_non_fn_ident(t) })) } @@ -576,10 +577,20 @@ impl<'a> Parser<'a> { /// Note that this does *not* parse bare trait objects. fn parse_dyn_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> { self.bump(); // `dyn` + + // parse dyn* types + let dyn_star = matches!(self.token.kind, TokenKind::BinOp(token::Star)); + let syntax = if dyn_star { + self.bump(); // `*` + TraitObjectSyntax::DynStar + } else { + TraitObjectSyntax::Dyn + }; + // Always parse bounds greedily for better error recovery. let bounds = self.parse_generic_bounds(None)?; *impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus); - Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)) + Ok(TyKind::TraitObject(bounds, syntax)) } /// Parses a type starting with a path. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 871bc5c1cdb06..aeb535352f656 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -649,6 +649,7 @@ symbols! { dropck_parametricity, dylib, dyn_metadata, + dyn_star, dyn_trait, e, edition_macro_pats, diff --git a/src/test/ui/dyn-star/feature-gate-dyn_star.rs b/src/test/ui/dyn-star/feature-gate-dyn_star.rs new file mode 100644 index 0000000000000..4756661cf41b7 --- /dev/null +++ b/src/test/ui/dyn-star/feature-gate-dyn_star.rs @@ -0,0 +1,9 @@ +// Feature gate test for dyn_star + +/// dyn* is not necessarily the final surface syntax (if we have one at all), +/// but for now we will support it to aid in writing tests independently. +pub fn dyn_star_parameter(_: &dyn* Send) { + //~^ dyn* trait objects are unstable +} + +fn main() {} diff --git a/src/test/ui/dyn-star/feature-gate-dyn_star.stderr b/src/test/ui/dyn-star/feature-gate-dyn_star.stderr new file mode 100644 index 0000000000000..2767e9478e2e8 --- /dev/null +++ b/src/test/ui/dyn-star/feature-gate-dyn_star.stderr @@ -0,0 +1,12 @@ +error[E0658]: dyn* trait objects are unstable + --> $DIR/feature-gate-dyn_star.rs:5:31 + | +LL | pub fn dyn_star_parameter(_: &dyn* Send) { + | ^^^^^^^^^ + | + = note: see issue #91611 for more information + = help: add `#![feature(dyn_star)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/dyn-star/syntax.rs b/src/test/ui/dyn-star/syntax.rs new file mode 100644 index 0000000000000..dd96bf0672dde --- /dev/null +++ b/src/test/ui/dyn-star/syntax.rs @@ -0,0 +1,11 @@ +// Make sure we can parse the `dyn* Trait` syntax +// +// check-pass + + +#![feature(dyn_star)] + +pub fn dyn_star_parameter(_: &dyn* Send) { +} + +fn main() {} From 6c01273a1566bc312ea88225880d35c2259914a6 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 13 Apr 2022 16:11:28 -0700 Subject: [PATCH 02/16] Plumb dyn trait representation through ty::Dynamic --- compiler/rustc_codegen_ssa/src/meth.rs | 2 +- .../rustc_const_eval/src/interpret/cast.rs | 2 +- .../src/interpret/intrinsics.rs | 2 +- .../src/interpret/intrinsics/type_name.rs | 2 +- .../nice_region_error/static_impl_trait.rs | 2 +- compiler/rustc_lint/src/unused.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 7 ++- compiler/rustc_middle/src/ty/diagnostics.rs | 2 +- compiler/rustc_middle/src/ty/flags.rs | 2 +- compiler/rustc_middle/src/ty/layout.rs | 3 +- compiler/rustc_middle/src/ty/print/pretty.rs | 9 ++- compiler/rustc_middle/src/ty/relate.rs | 6 +- .../rustc_middle/src/ty/structural_impls.rs | 10 +-- compiler/rustc_middle/src/ty/walk.rs | 2 +- .../src/typeid/typeid_itanium_cxx_abi.rs | 2 +- compiler/rustc_symbol_mangling/src/v0.rs | 2 +- .../error_reporting/on_unimplemented.rs | 2 +- .../src/traits/error_reporting/suggestions.rs | 6 +- .../src/traits/object_safety.rs | 4 +- .../src/traits/select/confirmation.rs | 14 +++-- .../rustc_trait_selection/src/traits/wf.rs | 2 +- compiler/rustc_traits/src/chalk/lowering.rs | 2 +- compiler/rustc_ty_utils/src/ty.rs | 2 +- compiler/rustc_type_ir/src/sty.rs | 63 ++++++++++++++----- compiler/rustc_typeck/src/astconv/mod.rs | 7 ++- .../src/check/generator_interior.rs | 2 +- .../rustc_typeck/src/check/method/suggest.rs | 2 +- .../rustc_typeck/src/variance/constraints.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- 29 files changed, 110 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index f8e982b775189..f6b9ddf2eeac7 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -69,7 +69,7 @@ impl<'a, 'tcx> VirtualIndex { fn expect_dyn_trait_in_self<'tcx>(ty: Ty<'tcx>) -> ty::PolyExistentialTraitRef<'tcx> { for arg in ty.peel_refs().walk() { if let GenericArgKind::Type(ty) = arg.unpack() { - if let ty::Dynamic(data, _) = ty.kind() { + if let ty::Dynamic(data, _, _) = ty.kind() { return data.principal().expect("expected principal trait object"); } } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 07dbd80e077f9..3af48c3ed1a15 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -312,7 +312,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?; self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) } - (_, &ty::Dynamic(ref data, _)) => { + (_, &ty::Dynamic(ref data, _, _repr)) => { // Initial cast from sized to dyn trait let vtable = self.get_vtable_ptr(src_pointee_ty, data.principal())?; let ptr = self.read_scalar(src)?; diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 7dba5059307ea..8637d6a7767e4 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -95,7 +95,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>( | ty::Ref(_, _, _) | ty::FnDef(_, _) | ty::FnPtr(_) - | ty::Dynamic(_, _) + | ty::Dynamic(_, _, _) | ty::Closure(_, _) | ty::Generator(_, _, _) | ty::GeneratorWitness(_) diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs index f9847742f0883..7e4c5fcb031b0 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs @@ -48,7 +48,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { | ty::FnPtr(_) | ty::Never | ty::Tuple(_) - | ty::Dynamic(_, _) => self.pretty_print_type(ty), + | ty::Dynamic(_, _, _) => self.pretty_print_type(ty), // Placeholders (all printed as `_` to uniformize them). ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index b115ac8b3df95..ae56bea6f862d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -544,7 +544,7 @@ pub struct TraitObjectVisitor(pub FxHashSet); impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match t.kind() { - ty::Dynamic(preds, re) if re.is_static() => { + ty::Dynamic(preds, re, _) if re.is_static() => { if let Some(def_id) = preds.principal_def_id() { self.0.insert(def_id); } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 9a7d722c05a90..3d426ecbfcb05 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -222,7 +222,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } has_emitted } - ty::Dynamic(binder, _) => { + ty::Dynamic(binder, _, _) => { let mut has_emitted = false; for predicate in binder.iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index afb2d5b2ba5e5..1b6b97dc22953 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -63,7 +63,9 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; use rustc_type_ir::sty::TyKind::*; -use rustc_type_ir::{InternAs, InternIteratorElement, Interner, TypeFlags}; +use rustc_type_ir::{ + InternAs, InternIteratorElement, Interner, TraitObjectRepresentation, TypeFlags, +}; use std::any::Any; use std::borrow::Borrow; @@ -2545,8 +2547,9 @@ impl<'tcx> TyCtxt<'tcx> { self, obj: &'tcx List>>, reg: ty::Region<'tcx>, + repr: TraitObjectRepresentation, ) -> Ty<'tcx> { - self.mk_ty(Dynamic(obj, reg)) + self.mk_ty(Dynamic(obj, reg, repr)) } #[inline] diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 648f5f7161fa6..855917fb82869 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -467,7 +467,7 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { } } - Dynamic(dty, _) => { + Dynamic(dty, _, _) => { for pred in *dty { match pred.skip_binder() { ExistentialPredicate::Trait(_) | ExistentialPredicate::Projection(_) => { diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index c22c899c5cce1..98b8a7386fe6a 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -171,7 +171,7 @@ impl FlagComputation { self.add_substs(substs); } - &ty::Dynamic(obj, r) => { + &ty::Dynamic(obj, r, _) => { for predicate in obj.iter() { self.bound_computation(predicate, |computation, predicate| match predicate { ty::ExistentialPredicate::Trait(tr) => computation.add_substs(tr.substs), diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index abb7ddd88b14d..b9b46518fa23b 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2464,7 +2464,8 @@ where match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() { ty::Slice(_) | ty::Str => TyMaybeWithLayout::Ty(tcx.types.usize), - ty::Dynamic(_, _) => { + // FIXME(eholk): Do the right thing with trait object representation + ty::Dynamic(_, _, _repr) => { TyMaybeWithLayout::Ty(tcx.mk_imm_ref( tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3), diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index e9eecfe78d32c..839f3ffff245c 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -16,6 +16,7 @@ use rustc_session::cstore::{ExternCrate, ExternCrateSource}; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; +use rustc_type_ir::TraitObjectRepresentation; use std::cell::Cell; use std::char; @@ -619,12 +620,16 @@ pub trait PrettyPrinter<'tcx>: ty::Adt(def, substs) => { p!(print_def_path(def.did(), substs)); } - ty::Dynamic(data, r) => { + ty::Dynamic(data, r, repr) => { let print_r = self.should_print_region(r); if print_r { p!("("); } - p!("dyn ", print(data)); + match repr { + TraitObjectRepresentation::Unsized => p!("dyn "), + TraitObjectRepresentation::Sized => p!("dyn* "), + } + p!(print(data)); if print_r { p!(" + ", print(r), ")"); } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 81476195d2995..5b3750b8b4da0 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -441,7 +441,9 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( (&ty::Foreign(a_id), &ty::Foreign(b_id)) if a_id == b_id => Ok(tcx.mk_foreign(a_id)), - (&ty::Dynamic(a_obj, a_region), &ty::Dynamic(b_obj, b_region)) => { + (&ty::Dynamic(a_obj, a_region, a_repr), &ty::Dynamic(b_obj, b_region, b_repr)) + if a_repr == b_repr => + { let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| { relation.relate_with_variance( ty::Contravariant, @@ -450,7 +452,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( b_region, ) })?; - Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound)) + Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound, a_repr)) } (&ty::Generator(a_id, a_substs, movability), &ty::Generator(b_id, b_substs, _)) diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index e6bd2eed565a1..323aa6599b8d5 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -1014,9 +1014,11 @@ impl<'tcx> TypeSuperFoldable<'tcx> for Ty<'tcx> { ty::Array(typ, sz) => ty::Array(typ.try_fold_with(folder)?, sz.try_fold_with(folder)?), ty::Slice(typ) => ty::Slice(typ.try_fold_with(folder)?), ty::Adt(tid, substs) => ty::Adt(tid, substs.try_fold_with(folder)?), - ty::Dynamic(trait_ty, region) => { - ty::Dynamic(trait_ty.try_fold_with(folder)?, region.try_fold_with(folder)?) - } + ty::Dynamic(trait_ty, region, representation) => ty::Dynamic( + trait_ty.try_fold_with(folder)?, + region.try_fold_with(folder)?, + representation, + ), ty::Tuple(ts) => ty::Tuple(ts.try_fold_with(folder)?), ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.try_fold_with(folder)?), ty::FnPtr(f) => ty::FnPtr(f.try_fold_with(folder)?), @@ -1060,7 +1062,7 @@ impl<'tcx> TypeSuperVisitable<'tcx> for Ty<'tcx> { } ty::Slice(typ) => typ.visit_with(visitor), ty::Adt(_, substs) => substs.visit_with(visitor), - ty::Dynamic(ref trait_ty, ref reg) => { + ty::Dynamic(ref trait_ty, ref reg, _) => { trait_ty.visit_with(visitor)?; reg.visit_with(visitor) } diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 831724bc4b09b..a3e11bbf056b3 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -152,7 +152,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) ty::Projection(data) => { stack.extend(data.substs.iter().rev()); } - ty::Dynamic(obj, lt) => { + ty::Dynamic(obj, lt, _) => { stack.push(lt.into()); stack.extend(obj.iter().rev().flat_map(|predicate| { let (substs, opt_ty) = match predicate.skip_binder() { 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 bd8126f617773..7621ba571fd47 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 @@ -627,7 +627,7 @@ fn encode_ty<'tcx>( } // Trait types - ty::Dynamic(predicates, region) => { + ty::Dynamic(predicates, region, _repr) => { // u3dynIE, where is , as // vendor extended type. let mut s = String::from("u3dynI"); diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index cfb8d47e54534..cedc87f5e2bba 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -479,7 +479,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { })?; } - ty::Dynamic(predicates, r) => { + ty::Dynamic(predicates, r, _repr) => { self.push("D"); self = self.print_dyn_existential(predicates)?; self = r.print(self)?; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 6b03555bc6985..e11a42201443d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -256,7 +256,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } } - if let ty::Dynamic(traits, _) = self_ty.kind() { + if let ty::Dynamic(traits, _, _) = self_ty.kind() { for t in traits.iter() { if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() { flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id)))) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index ecbeb9d79b118..e1d548323bf4a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1067,7 +1067,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self_ty: Ty<'tcx>, object_ty: Ty<'tcx>, ) { - let ty::Dynamic(predicates, _) = object_ty.kind() else { return; }; + let ty::Dynamic(predicates, _, _) = object_ty.kind() else { return; }; let self_ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, self_ty); for predicate in predicates.iter() { @@ -1365,7 +1365,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let trait_pred = self.resolve_vars_if_possible(trait_pred); let ty = trait_pred.skip_binder().self_ty(); let is_object_safe = match ty.kind() { - ty::Dynamic(predicates, _) => { + ty::Dynamic(predicates, _, _) => { // If the `dyn Trait` is not object safe, do not suggest `Box`. predicates .principal_def_id() @@ -1425,7 +1425,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let mut spans_and_needs_box = vec![]; match liberated_sig.output().kind() { - ty::Dynamic(predicates, _) => { + ty::Dynamic(predicates, _, _) => { let cause = ObligationCause::misc(ret_ty.span, fn_hir_id); let param_env = ty::ParamEnv::empty(); diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 5542f187f93f7..f31dde044f9d1 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -21,6 +21,7 @@ use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst}; use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst}; use rustc_middle::ty::{ self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, + TraitObjectRepresentation, }; use rustc_middle::ty::{Predicate, ToPredicate}; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; @@ -600,7 +601,8 @@ fn object_ty_for_trait<'tcx>( let existential_predicates = tcx .mk_poly_existential_predicates(iter::once(trait_predicate).chain(projection_predicates)); - let object_ty = tcx.mk_dynamic(existential_predicates, lifetime); + let object_ty = + tcx.mk_dynamic(existential_predicates, lifetime, TraitObjectRepresentation::Unsized); debug!("object_ty_for_trait: object_ty=`{}`", object_ty); diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 046a587205b51..158b00e275e67 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -784,7 +784,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let upcast_trait_ref; match (source.kind(), target.kind()) { // TraitA+Kx+'a -> TraitB+Ky+'b (trait upcasting coercion). - (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => { + (&ty::Dynamic(ref data_a, r_a, repr_a), &ty::Dynamic(ref data_b, r_b, repr_b)) + if repr_a == repr_b => + { // See `assemble_candidates_for_unsizing` for more info. // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`. let principal_a = data_a.principal().unwrap(); @@ -810,7 +812,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map(ty::Binder::dummy), ); let existential_predicates = tcx.mk_poly_existential_predicates(iter); - let source_trait = tcx.mk_dynamic(existential_predicates, r_b); + let source_trait = tcx.mk_dynamic(existential_predicates, r_b, repr_b); // Require that the traits involved in this upcast are **equal**; // only the **lifetime bound** is changed. @@ -888,7 +890,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut nested = vec![]; match (source.kind(), target.kind()) { // Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping). - (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => { + (&ty::Dynamic(ref data_a, r_a, repr_a), &ty::Dynamic(ref data_b, r_b, repr_b)) + if repr_a == repr_b => + { // See `assemble_candidates_for_unsizing` for more info. // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`. let iter = data_a @@ -907,7 +911,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map(ty::Binder::dummy), ); let existential_predicates = tcx.mk_poly_existential_predicates(iter); - let source_trait = tcx.mk_dynamic(existential_predicates, r_b); + let source_trait = tcx.mk_dynamic(existential_predicates, r_b, repr_b); // Require that the traits involved in this upcast are **equal**; // only the **lifetime bound** is changed. @@ -934,7 +938,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // `T` -> `Trait` - (_, &ty::Dynamic(ref data, r)) => { + (_, &ty::Dynamic(ref data, r, _repr)) => { let mut object_dids = data.auto_traits().chain(data.principal_def_id()); if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) { return Err(TraitNotObjectSafe(did)); diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 9d3a1a4a031ae..f95e217da3073 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -639,7 +639,7 @@ impl<'tcx> WfPredicates<'tcx> { } } - ty::Dynamic(data, r) => { + ty::Dynamic(data, r, _) => { // WfObject // // Here, we defer WF checking due to higher-ranked diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index a6a098ce73f8d..86da6d7bbd1e2 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -326,7 +326,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { )), }) } - ty::Dynamic(predicates, region) => chalk_ir::TyKind::Dyn(chalk_ir::DynTy { + ty::Dynamic(predicates, region, _repr) => chalk_ir::TyKind::Dyn(chalk_ir::DynTy { bounds: predicates.lower_into(interner), lifetime: region.lower_into(interner), }), diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 9d640672cf92c..9266e4e3f6efb 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -389,7 +389,7 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { let self_ty = trait_ref.self_ty(); let self_ty_matches = match self_ty.kind() { - ty::Dynamic(ref data, re) if re.is_static() => data.principal().is_none(), + ty::Dynamic(ref data, re, _) if re.is_static() => data.principal().is_none(), _ => false, }; diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index e164aaed6b4b8..b57f32de8ce5c 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -18,6 +18,27 @@ use self::TyKind::*; use rustc_data_structures::stable_hasher::HashStable; use rustc_serialize::{Decodable, Decoder, Encodable}; +/// Specifies how a trait object is represented. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)] +pub enum TraitObjectRepresentation { + /// An unsized `dyn Trait` object + Unsized, + /// A sized `dyn* Trait` object + Sized, +} + +// Manually implemented because deriving HashStable requires rustc_query_system, which would +// create a cyclic dependency. +impl HashStable for TraitObjectRepresentation { + fn hash_stable( + &self, + hcx: &mut CTX, + hasher: &mut rustc_data_structures::stable_hasher::StableHasher, + ) { + std::mem::discriminant(self).hash_stable(hcx, hasher); + } +} + /// Defines the kinds of types used by the type system. /// /// Types written by the user start out as `hir::TyKind` and get @@ -95,7 +116,7 @@ pub enum TyKind { FnPtr(I::PolyFnSig), /// A trait object. Written as `dyn for<'b> Trait<'b, Assoc = u32> + Send + 'a`. - Dynamic(I::ListBinderExistentialPredicate, I::Region), + Dynamic(I::ListBinderExistentialPredicate, I::Region, TraitObjectRepresentation), /// The anonymous type of a closure. Used to represent the type of `|a| a`. /// @@ -218,7 +239,7 @@ const fn tykind_discriminant(value: &TyKind) -> usize { Ref(_, _, _) => 11, FnDef(_, _) => 12, FnPtr(_) => 13, - Dynamic(_, _) => 14, + Dynamic(..) => 14, Closure(_, _) => 15, Generator(_, _, _) => 16, GeneratorWitness(_) => 17, @@ -252,7 +273,7 @@ impl Clone for TyKind { Ref(r, t, m) => Ref(r.clone(), t.clone(), m.clone()), FnDef(d, s) => FnDef(d.clone(), s.clone()), FnPtr(s) => FnPtr(s.clone()), - Dynamic(p, r) => Dynamic(p.clone(), r.clone()), + Dynamic(p, r, repr) => Dynamic(p.clone(), r.clone(), repr.clone()), Closure(d, s) => Closure(d.clone(), s.clone()), Generator(d, s, m) => Generator(d.clone(), s.clone(), m.clone()), GeneratorWitness(g) => GeneratorWitness(g.clone()), @@ -297,9 +318,10 @@ impl PartialEq for TyKind { __self_0 == __arg_1_0 && __self_1 == __arg_1_1 } (&FnPtr(ref __self_0), &FnPtr(ref __arg_1_0)) => __self_0 == __arg_1_0, - (&Dynamic(ref __self_0, ref __self_1), &Dynamic(ref __arg_1_0, ref __arg_1_1)) => { - __self_0 == __arg_1_0 && __self_1 == __arg_1_1 - } + ( + &Dynamic(ref __self_0, ref __self_1, ref self_repr), + &Dynamic(ref __arg_1_0, ref __arg_1_1, ref arg_repr), + ) => __self_0 == __arg_1_0 && __self_1 == __arg_1_1 && self_repr == arg_repr, (&Closure(ref __self_0, ref __self_1), &Closure(ref __arg_1_0, ref __arg_1_1)) => { __self_0 == __arg_1_0 && __self_1 == __arg_1_1 } @@ -384,12 +406,16 @@ impl Ord for TyKind { } } (&FnPtr(ref __self_0), &FnPtr(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), - (&Dynamic(ref __self_0, ref __self_1), &Dynamic(ref __arg_1_0, ref __arg_1_1)) => { - match Ord::cmp(__self_0, __arg_1_0) { - Ordering::Equal => Ord::cmp(__self_1, __arg_1_1), + ( + &Dynamic(ref __self_0, ref __self_1, ref self_repr), + &Dynamic(ref __arg_1_0, ref __arg_1_1, ref arg_repr), + ) => match Ord::cmp(__self_0, __arg_1_0) { + Ordering::Equal => match Ord::cmp(__self_1, __arg_1_1) { + Ordering::Equal => Ord::cmp(self_repr, arg_repr), cmp => cmp, - } - } + }, + cmp => cmp, + }, (&Closure(ref __self_0, ref __self_1), &Closure(ref __arg_1_0, ref __arg_1_1)) => { match Ord::cmp(__self_0, __arg_1_0) { Ordering::Equal => Ord::cmp(__self_1, __arg_1_1), @@ -492,10 +518,11 @@ impl hash::Hash for TyKind { hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state) } - (&Dynamic(ref __self_0, ref __self_1),) => { + (&Dynamic(ref __self_0, ref __self_1, ref repr),) => { hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state); - hash::Hash::hash(__self_1, state) + hash::Hash::hash(__self_1, state); + hash::Hash::hash(repr, state) } (&Closure(ref __self_0, ref __self_1),) => { hash::Hash::hash(&tykind_discriminant(self), state); @@ -570,7 +597,7 @@ impl fmt::Debug for TyKind { Ref(f0, f1, f2) => Formatter::debug_tuple_field3_finish(f, "Ref", f0, f1, f2), FnDef(f0, f1) => Formatter::debug_tuple_field2_finish(f, "FnDef", f0, f1), FnPtr(f0) => Formatter::debug_tuple_field1_finish(f, "FnPtr", f0), - Dynamic(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Dynamic", f0, f1), + Dynamic(f0, f1, f2) => Formatter::debug_tuple_field3_finish(f, "Dynamic", f0, f1, f2), Closure(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Closure", f0, f1), Generator(f0, f1, f2) => { Formatter::debug_tuple_field3_finish(f, "Generator", f0, f1, f2) @@ -659,9 +686,10 @@ where FnPtr(polyfnsig) => e.emit_enum_variant(disc, |e| { polyfnsig.encode(e); }), - Dynamic(l, r) => e.emit_enum_variant(disc, |e| { + Dynamic(l, r, repr) => e.emit_enum_variant(disc, |e| { l.encode(e); r.encode(e); + repr.encode(e); }), Closure(def_id, substs) => e.emit_enum_variant(disc, |e| { def_id.encode(e); @@ -748,7 +776,7 @@ where 11 => Ref(Decodable::decode(d), Decodable::decode(d), Decodable::decode(d)), 12 => FnDef(Decodable::decode(d), Decodable::decode(d)), 13 => FnPtr(Decodable::decode(d)), - 14 => Dynamic(Decodable::decode(d), Decodable::decode(d)), + 14 => Dynamic(Decodable::decode(d), Decodable::decode(d), Decodable::decode(d)), 15 => Closure(Decodable::decode(d), Decodable::decode(d)), 16 => Generator(Decodable::decode(d), Decodable::decode(d), Decodable::decode(d)), 17 => GeneratorWitness(Decodable::decode(d)), @@ -845,9 +873,10 @@ where FnPtr(polyfnsig) => { polyfnsig.hash_stable(__hcx, __hasher); } - Dynamic(l, r) => { + Dynamic(l, r, repr) => { l.hash_stable(__hcx, __hasher); r.hash_stable(__hcx, __hasher); + repr.hash_stable(__hcx, __hasher); } Closure(def_id, substs) => { def_id.hash_stable(__hcx, __hasher); diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index d9789d5aaf031..586ede3d90cd0 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -31,6 +31,7 @@ use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::{ self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeVisitable, }; +use rustc_middle::ty::{TraitObjectRepresentation}; use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS}; use rustc_span::edition::Edition; use rustc_span::lev_distance::find_best_match_for_name; @@ -1572,7 +1573,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }; debug!("region_bound: {:?}", region_bound); - let ty = tcx.mk_dynamic(existential_predicates, region_bound); + let ty = tcx.mk_dynamic( + existential_predicates, + region_bound, + TraitObjectRepresentation::Unsized, // FIXME: check whether the source syntax was dyn or dyn* + ); debug!("trait_object_type: {:?}", ty); ty } diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index 7fda6f79f238d..7ab6d9e2bab12 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -527,7 +527,7 @@ fn check_must_not_suspend_ty<'tcx>( } has_emitted } - ty::Dynamic(binder, _) => { + ty::Dynamic(binder, _, _) => { let mut has_emitted = false; for predicate in binder.iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 8065b848ad6f8..2d459b2cc0e32 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -537,7 +537,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bound_spans.push((self.tcx.def_span(def.did()), msg)) } // Point at the trait object that couldn't satisfy the bound. - ty::Dynamic(preds, _) => { + ty::Dynamic(preds, _, _) => { for pred in preds.iter() { match pred.skip_binder() { ty::ExistentialPredicate::Trait(tr) => bound_spans diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs index 840f0c978484d..eaf0310d57aec 100644 --- a/compiler/rustc_typeck/src/variance/constraints.rs +++ b/compiler/rustc_typeck/src/variance/constraints.rs @@ -257,7 +257,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_invariant_substs(current, substs, variance); } - ty::Dynamic(data, r) => { + ty::Dynamic(data, r, _) => { // The type `Foo` is contravariant w/r/t `'a`: let contra = self.contravariant(variance); self.add_constraints_from_region(current, r, contra); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9f0b7018af5f0..c8875c272bb08 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1600,7 +1600,7 @@ pub(crate) fn clean_middle_ty<'tcx>( let path = external_path(cx, did, false, ThinVec::new(), InternalSubsts::empty()); Type::Path { path } } - ty::Dynamic(obj, ref reg) => { + ty::Dynamic(obj, ref reg, _) => { // HACK: pick the first `did` as the `did` of the trait object. Someone // might want to implement "native" support for marker-trait-only // trait objects. From 7fccac3ea0db7cbbb1b84ff4ab824f8d85f415fe Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 13 Apr 2022 16:38:16 -0700 Subject: [PATCH 03/16] Typecheck dyn* coercions Also changes things to treat dyn* as a sized type, unlike dyn Trait. --- compiler/rustc_middle/src/ty/sty.rs | 12 ++- .../src/traits/object_safety.rs | 4 +- .../src/traits/select/mod.rs | 2 + compiler/rustc_typeck/src/astconv/mod.rs | 19 +++-- compiler/rustc_typeck/src/check/cast.rs | 80 ++++++++++++++++++- compiler/rustc_typeck/src/check/expr.rs | 20 +++-- .../src/check/fn_ctxt/suggestions.rs | 2 +- .../ui/async-await/dyn-star-trait-error.rs | 12 +++ .../async-await/dyn-star-trait-error.stderr | 9 +++ src/test/ui/dyn-star/make-dyn-star.rs | 14 ++++ src/test/ui/dyn-star/syntax.rs | 3 +- 11 files changed, 148 insertions(+), 29 deletions(-) create mode 100644 src/test/ui/async-await/dyn-star-trait-error.rs create mode 100644 src/test/ui/async-await/dyn-star-trait-error.stderr create mode 100644 src/test/ui/dyn-star/make-dyn-star.rs diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 702c2d27187ee..6713660ab8faf 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -31,7 +31,7 @@ use ty::util::IntTypeExt; use rustc_type_ir::sty::TyKind::*; use rustc_type_ir::RegionKind as IrRegionKind; -use rustc_type_ir::TyKind as IrTyKind; +use rustc_type_ir::{TraitObjectRepresentation, TyKind as IrTyKind}; // Re-export the `TyKind` from `rustc_type_ir` here for convenience #[rustc_diagnostic_item = "TyKind"] @@ -692,6 +692,9 @@ impl<'tcx> ExistentialPredicate<'tcx> { } impl<'tcx> Binder<'tcx, ExistentialPredicate<'tcx>> { + /// Given an existential predicate like `?Self: PartialEq` (e.g., derived from `dyn PartialEq`), + /// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self` + /// has been replaced with `self_ty` (e.g., `self_ty: PartialEq`, in our example). pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> { use crate::ty::ToPredicate; match self.skip_binder() { @@ -1849,7 +1852,12 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn is_trait(self) -> bool { - matches!(self.kind(), Dynamic(..)) + matches!(self.kind(), Dynamic(_, _, TraitObjectRepresentation::Unsized)) + } + + #[inline] + pub fn is_dyn_star(self) -> bool { + matches!(self.kind(), Dynamic(_, _, TraitObjectRepresentation::Sized)) } #[inline] diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index f31dde044f9d1..43ee5b5545543 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -20,8 +20,8 @@ use rustc_hir::def_id::DefId; use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst}; use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst}; use rustc_middle::ty::{ - self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, - TraitObjectRepresentation, + self, EarlyBinder, TraitObjectRepresentation, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, + TypeVisitor, }; use rustc_middle::ty::{Predicate, ToPredicate}; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 8b15e10ba9cbf..a64179c14f51e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -38,6 +38,7 @@ use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::subst::{Subst, SubstsRef}; +use rustc_middle::ty::TraitObjectRepresentation; use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitable}; use rustc_span::symbol::sym; @@ -1865,6 +1866,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Array(..) | ty::Closure(..) | ty::Never + | ty::Dynamic(_, _, TraitObjectRepresentation::Sized) | ty::Error(_) => { // safe for everything Where(ty::Binder::dummy(Vec::new())) diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 586ede3d90cd0..0010bcc4bf620 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -28,10 +28,10 @@ use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin}; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::GenericParamDefKind; +use rustc_middle::ty::TraitObjectRepresentation; use rustc_middle::ty::{ self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeVisitable, }; -use rustc_middle::ty::{TraitObjectRepresentation}; use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS}; use rustc_span::edition::Edition; use rustc_span::lev_distance::find_best_match_for_name; @@ -1253,6 +1253,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_bounds: &[hir::PolyTraitRef<'_>], lifetime: &hir::Lifetime, borrowed: bool, + representation: TraitObjectRepresentation, ) -> Ty<'tcx> { let tcx = self.tcx(); @@ -1573,11 +1574,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }; debug!("region_bound: {:?}", region_bound); - let ty = tcx.mk_dynamic( - existential_predicates, - region_bound, - TraitObjectRepresentation::Unsized, // FIXME: check whether the source syntax was dyn or dyn* - ); + let ty = tcx.mk_dynamic(existential_predicates, region_bound, representation); debug!("trait_object_type: {:?}", ty); ty } @@ -2623,9 +2620,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { Some(ast_ty), )) } - hir::TyKind::TraitObject(bounds, ref lifetime, _) => { + hir::TyKind::TraitObject(bounds, ref lifetime, repr) => { self.maybe_lint_bare_trait(ast_ty, in_path); - self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed) + let repr = match repr { + TraitObjectSyntax::Dyn | TraitObjectSyntax::None => { + TraitObjectRepresentation::Unsized + } + TraitObjectSyntax::DynStar => TraitObjectRepresentation::Sized, + }; + self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed, repr) } hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => { debug!(?maybe_qself, ?path); diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index a3fcda5864b3f..fa6224f1915a9 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -35,12 +35,15 @@ use crate::type_error_struct; use hir::def_id::LOCAL_CRATE; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; +use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode}; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::cast::{CastKind, CastTy}; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef}; +use rustc_middle::ty::{ + self, Binder, TraitObjectRepresentation, Ty, TypeAndMut, TypeVisitable, VariantDef, +}; use rustc_session::lint; use rustc_session::Session; use rustc_span::symbol::sym; @@ -52,9 +55,12 @@ use rustc_trait_selection::traits::error_reporting::report_object_safety_error; /// a function context. #[derive(Debug)] pub struct CastCheck<'tcx> { + /// The expression whose value is being casted expr: &'tcx hir::Expr<'tcx>, + /// The source type for the cast expression expr_ty: Ty<'tcx>, expr_span: Span, + /// The target type. That is, the type we are casting to. cast_ty: Ty<'tcx>, cast_span: Span, span: Span, @@ -199,8 +205,76 @@ fn make_invalid_casting_error<'a, 'tcx>( ) } +pub enum CastCheckResult<'tcx> { + Ok, + Deferred(CastCheck<'tcx>), + Err(ErrorGuaranteed), +} + +pub fn check_cast<'tcx>( + fcx: &FnCtxt<'_, 'tcx>, + expr: &'tcx hir::Expr<'tcx>, + expr_ty: Ty<'tcx>, + cast_ty: Ty<'tcx>, + cast_span: Span, + span: Span, +) -> CastCheckResult<'tcx> { + if cast_ty.is_dyn_star() { + check_dyn_star_cast(fcx, expr, expr_ty, cast_ty) + } else { + match CastCheck::new(fcx, expr, expr_ty, cast_ty, cast_span, span) { + Ok(check) => CastCheckResult::Deferred(check), + Err(e) => CastCheckResult::Err(e), + } + } +} + +fn check_dyn_star_cast<'tcx>( + fcx: &FnCtxt<'_, 'tcx>, + expr: &'tcx hir::Expr<'tcx>, + expr_ty: Ty<'tcx>, + cast_ty: Ty<'tcx>, +) -> CastCheckResult<'tcx> { + // Find the bounds in the dyn*. For eaxmple, if we have + // + // let x = 22_usize as dyn* (Clone + Debug + 'static) + // + // this would return `existential_predicates = [?Self: Clone, ?Self: Debug]` and `region = 'static`. + let (existential_predicates, region) = match cast_ty.kind() { + ty::Dynamic(predicates, region, TraitObjectRepresentation::Sized) => (predicates, region), + _ => panic!("Invalid dyn* cast_ty"), + }; + + let cause = ObligationCause::new( + expr.span, + fcx.body_id, + // FIXME: Use a better obligation cause code + ObligationCauseCode::MiscObligation, + ); + + // For each existential predicate (e.g., `?Self: Clone`) substitute + // the type of the expression (e.g., `usize` in our example above) + // and then require that the resulting predicate (e.g., `usize: Clone`) + // holds (it does). + for existential_predicate in existential_predicates.iter() { + let predicate = existential_predicate.with_self_ty(fcx.tcx, expr_ty); + fcx.register_predicate(Obligation::new(cause.clone(), fcx.param_env, predicate)); + } + + // Enforce the region bound `'static` (e.g., `usize: 'static`, in our example). + fcx.register_predicate(Obligation::new( + cause, + fcx.param_env, + fcx.tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives( + ty::OutlivesPredicate(expr_ty, *region), + ))), + )); + + CastCheckResult::Ok +} + impl<'a, 'tcx> CastCheck<'tcx> { - pub fn new( + fn new( fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr<'tcx>, expr_ty: Ty<'tcx>, @@ -215,7 +289,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // cases now. We do a more thorough check at the end, once // inference is more completely known. match cast_ty.kind() { - ty::Dynamic(..) | ty::Slice(..) => { + ty::Dynamic(_, _, TraitObjectRepresentation::Unsized) | ty::Slice(..) => { let reported = check.report_cast_to_unsized_type(fcx); Err(reported) } diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 2139200136413..93b00850069c2 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -3,18 +3,15 @@ //! See `mod.rs` for more context on type checking in general. use crate::astconv::AstConv as _; -use crate::check::cast; +use crate::check::cast::{self, CastCheckResult}; use crate::check::coercion::CoerceMany; use crate::check::fatally_break_rust; use crate::check::method::SelfSource; -use crate::check::report_unexpected_variant_res; -use crate::check::BreakableCtxt; -use crate::check::Diverges; -use crate::check::DynamicCoerceMany; use crate::check::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation}; -use crate::check::FnCtxt; -use crate::check::Needs; -use crate::check::TupleArgumentsFlag::DontTupleArguments; +use crate::check::{ + report_unexpected_variant_res, BreakableCtxt, Diverges, DynamicCoerceMany, FnCtxt, Needs, + TupleArgumentsFlag::DontTupleArguments, +}; use crate::errors::{ FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct, YieldExprOutsideOfGenerator, @@ -1252,8 +1249,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // Defer other checks until we're done type checking. let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); - match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { - Ok(cast_check) => { + match cast::check_cast(self, e, t_expr, t_cast, t.span, expr.span) { + CastCheckResult::Ok => t_cast, + CastCheckResult::Deferred(cast_check) => { debug!( "check_expr_cast: deferring cast from {:?} to {:?}: {:?}", t_cast, t_expr, cast_check, @@ -1261,7 +1259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { deferred_cast_checks.push(cast_check); t_cast } - Err(_) => self.tcx.ty_error(), + CastCheckResult::Err(ErrorGuaranteed { .. }) => self.tcx.ty_error(), } } } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 2bfee9a536439..82b7101baa3a8 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -182,7 +182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }) } - ty::Dynamic(data, _) => { + ty::Dynamic(data, _, ty::TraitObjectRepresentation::Unsized) => { data.iter().find_map(|pred| { if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder() && Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output() diff --git a/src/test/ui/async-await/dyn-star-trait-error.rs b/src/test/ui/async-await/dyn-star-trait-error.rs new file mode 100644 index 0000000000000..20e183c74554a --- /dev/null +++ b/src/test/ui/async-await/dyn-star-trait-error.rs @@ -0,0 +1,12 @@ +#![feature(async_fn_in_traits)] + +use std::fmt::Debug; + +trait Foo {} + +fn make_dyn_star() { + let i = 42; + let dyn_i: dyn* Foo = i as dyn* Foo; //~ ERROR trait bound `{integer}: Foo` is not satisfied +} + +fn main() {} diff --git a/src/test/ui/async-await/dyn-star-trait-error.stderr b/src/test/ui/async-await/dyn-star-trait-error.stderr new file mode 100644 index 0000000000000..932bc50ffde5a --- /dev/null +++ b/src/test/ui/async-await/dyn-star-trait-error.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `{integer}: Foo` is not satisfied + --> $DIR/dyn-star-trait-error.rs:9:27 + | +LL | let dyn_i: dyn* Foo = i as dyn* Foo; + | ^ the trait `Foo` is not implemented for `{integer}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/dyn-star/make-dyn-star.rs b/src/test/ui/dyn-star/make-dyn-star.rs new file mode 100644 index 0000000000000..17356bfbd84b9 --- /dev/null +++ b/src/test/ui/dyn-star/make-dyn-star.rs @@ -0,0 +1,14 @@ +// check-pass +#![feature(dyn_star)] + +use std::fmt::Debug; + +pub fn dyn_star_parameter(_: dyn* Send) { +} + +fn make_dyn_star() { + let i = 42usize; + let dyn_i: dyn* Debug = i as dyn* Debug; +} + +fn main() {} diff --git a/src/test/ui/dyn-star/syntax.rs b/src/test/ui/dyn-star/syntax.rs index dd96bf0672dde..7848996e5e022 100644 --- a/src/test/ui/dyn-star/syntax.rs +++ b/src/test/ui/dyn-star/syntax.rs @@ -2,10 +2,9 @@ // // check-pass - #![feature(dyn_star)] -pub fn dyn_star_parameter(_: &dyn* Send) { +pub fn dyn_star_parameter(_: dyn* Send) { } fn main() {} From 549c105bb365e14cb132b29a94126715158c5cfa Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Tue, 28 Jun 2022 14:02:30 -0700 Subject: [PATCH 04/16] dyn* through more typechecking and MIR --- compiler/rustc_borrowck/src/type_check/mod.rs | 37 ++++++++++++++- compiler/rustc_codegen_ssa/src/mir/block.rs | 46 ++++++++++++++++++- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 10 ++++ .../rustc_const_eval/src/interpret/cast.rs | 4 ++ .../src/transform/check_consts/check.rs | 4 ++ .../src/transform/validate.rs | 3 ++ compiler/rustc_middle/src/mir/mod.rs | 1 + compiler/rustc_middle/src/mir/syntax.rs | 2 + compiler/rustc_middle/src/ty/cast.rs | 5 ++ compiler/rustc_middle/src/ty/layout.rs | 26 ++++++++++- compiler/rustc_middle/src/ty/mod.rs | 6 +++ .../src/build/expr/as_rvalue.rs | 5 ++ compiler/rustc_typeck/src/check/cast.rs | 6 +++ .../ui/async-await/dyn-star-trait-const.rs | 14 ++++++ src/test/ui/dyn-star/make-dyn-star.rs | 12 ++--- 15 files changed, 168 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/async-await/dyn-star-trait-const.rs diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index fc0e95f30c98f..c78f9282e307a 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -30,8 +30,9 @@ use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts}; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{ - self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueHiddenType, - OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, + self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, Dynamic, + OpaqueHiddenType, OpaqueTypeKey, RegionVid, ToPredicate, TraitObjectRepresentation, Ty, TyCtxt, + UserType, UserTypeAnnotationIndex, }; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::{Span, DUMMY_SP}; @@ -2009,6 +2010,38 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } + CastKind::DynStar => { + // get the constraints from the target type (`dyn* Clone`) + // + // apply them to prove that the source type `Foo` implements `Clone` etc + let (existential_predicates, region) = match ty.kind() { + Dynamic(predicates, region, TraitObjectRepresentation::Sized) => { + (predicates, region) + } + _ => panic!("Invalid dyn* cast_ty"), + }; + + let self_ty = op.ty(body, tcx); + + self.prove_predicates( + existential_predicates + .iter() + .map(|predicate| predicate.with_self_ty(tcx, self_ty)), + location.to_locations(), + ConstraintCategory::Cast, + ); + + let outlives_predicate = + tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives( + ty::OutlivesPredicate(self_ty, *region), + ))); + self.prove_predicate( + outlives_predicate, + location.to_locations(), + ConstraintCategory::Cast, + ); + } + CastKind::Pointer(PointerCast::MutToConstPointer) => { let ty::RawPtr(ty::TypeAndMut { ty: ty_from, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 3154f12a77964..fb75ecc17356b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -16,7 +16,7 @@ use rustc_index::vec::Idx; use rustc_middle::mir::{self, AssertKind, SwitchTargets}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; -use rustc_middle::ty::{self, Instance, Ty, TypeVisitable}; +use rustc_middle::ty::{self, Instance, Ty, TypeVisitable, TraitObjectRepresentation}; use rustc_span::source_map::Span; use rustc_span::{sym, Symbol}; use rustc_symbol_mangling::typeid::typeid_for_fnabi; @@ -367,6 +367,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.ret(llval); } + #[tracing::instrument(level = "debug", skip(self, helper, bx))] fn codegen_drop_terminator( &mut self, helper: TerminatorCodegenHelper<'tcx>, @@ -397,13 +398,29 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (drop_fn, fn_abi) = match ty.kind() { // FIXME(eddyb) perhaps move some of this logic into // `Instance::resolve_drop_in_place`? - ty::Dynamic(..) => { + ty::Dynamic(_, _, TraitObjectRepresentation::Unsized) => { + // IN THIS ARM, WE HAVE: + // ty = *mut (dyn Trait) + // which is: exists ( *mut T, Vtable ) + // args[0] args[1] + // + // args = ( Data, Vtable ) + // | + // v + // /-------\ + // | ... | + // \-------/ + // let virtual_drop = Instance { def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), substs: drop_fn.substs, }; + debug!("ty = {:?}", ty); + debug!("drop_fn = {:?}", drop_fn); + debug!("args = {:?}", args); let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty()); let vtable = args[1]; + // Truncate vtable off of args list args = &args[..1]; ( meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE) @@ -411,6 +428,31 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn_abi, ) } + ty::Dynamic(_, _, TraitObjectRepresentation::Sized) => { + // IN THIS ARM, WE HAVE: + // ty = *mut (dyn* Trait) + // which is: *mut exists (T, Vtable) + // + // args = [ * ] + // | + // v + // ( Data, Vtable ) + // | + // v + // /-------\ + // | ... | + // \-------/ + // + // + // WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING + // + // data = &(*args[0]).0 // gives a pointer to Data above (really the same pointer) + // vtable = (*args[0]).1 // loads the vtable out + // (data, vtable) // an equivalent Rust `*mut dyn Trait` + // + // SO THEN WE CAN USE THE ABOVE CODE. + todo!() + } _ => (bx.get_fn_addr(drop_fn), bx.fn_abi_of_instance(drop_fn, ty::List::empty())), }; helper.do_call( diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 574746e340b7b..d3c6b731de334 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -271,6 +271,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bug!("unexpected non-pair operand"); } } + #[allow(unreachable_code, unused)] // FIXME: remove this + mir::CastKind::DynStar => { + let data = match operand.val { + OperandValue::Ref(_, _, _) => todo!(), + OperandValue::Immediate(_) => todo!(), + OperandValue::Pair(_, _) => todo!(), + }; + let vtable = todo!(); + OperandValue::Pair(data, vtable) + } mir::CastKind::Pointer( PointerCast::MutToConstPointer | PointerCast::ArrayToPointer, ) diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 3af48c3ed1a15..9beeb2d8b2c7e 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -108,6 +108,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { _ => span_bug!(self.cur_span(), "closure fn pointer on {:?}", src.layout.ty), } } + + DynStar => { + unimplemented!() + } } Ok(()) } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 3fa40dc305952..7e15858c8c188 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -546,6 +546,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // Since no pointer can ever get exposed (rejected above), this is easy to support. } + Rvalue::Cast(CastKind::DynStar, _, _) => { + unimplemented!() + } + Rvalue::Cast(CastKind::Misc, _, _) => {} Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {} diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 8576e0f0f7c16..1c4c7e7079d64 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -569,6 +569,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } } + CastKind::DynStar => { + // FIXME: make sure nothing needs to be done here. + } // Nothing to check here CastKind::PointerFromExposedAddress | CastKind::PointerExposeAddress diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index dd768c5358d5a..47e62e82ac4aa 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1834,6 +1834,7 @@ impl<'tcx> Rvalue<'tcx> { // While the model is undecided, we should be conservative. See // Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false, + Rvalue::Cast(CastKind::DynStar, _, _) => false, Rvalue::Use(_) | Rvalue::CopyForDeref(_) diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 1f7643a76afe5..d2bb897b5b676 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1139,6 +1139,8 @@ pub enum CastKind { /// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are /// translated into `&raw mut/const *r`, i.e., they are not actually casts. Pointer(PointerCast), + /// Cast into a dyn* object. + DynStar, /// Remaining unclassified casts. Misc, } diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs index c4b743dd46701..cc5381b467d78 100644 --- a/compiler/rustc_middle/src/ty/cast.rs +++ b/compiler/rustc_middle/src/ty/cast.rs @@ -4,6 +4,7 @@ use crate::ty::{self, Ty}; use rustc_macros::HashStable; +use rustc_type_ir::TraitObjectRepresentation; /// Types that are represented as ints. #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -33,6 +34,8 @@ pub enum CastTy<'tcx> { FnPtr, /// Raw pointers. Ptr(ty::TypeAndMut<'tcx>), + /// Casting into a `dyn*` value. + DynStar, } /// Cast Kind. See [RFC 401](https://rust-lang.github.io/rfcs/0401-coercions.html) @@ -50,6 +53,7 @@ pub enum CastKind { ArrayPtrCast, FnPtrPtrCast, FnPtrAddrCast, + DynStarCast, } impl<'tcx> CastTy<'tcx> { @@ -67,6 +71,7 @@ impl<'tcx> CastTy<'tcx> { ty::Adt(d, _) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)), ty::RawPtr(mt) => Some(CastTy::Ptr(mt)), ty::FnPtr(..) => Some(CastTy::FnPtr), + ty::Dynamic(_, _, TraitObjectRepresentation::Sized) => Some(CastTy::DynStar), _ => None, } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index b9b46518fa23b..2e68b96f87bc6 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -21,6 +21,7 @@ use rustc_target::abi::call::{ }; use rustc_target::abi::*; use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target}; +use rustc_type_ir::TraitObjectRepresentation; use std::cmp::{self, Ordering}; use std::fmt; @@ -625,6 +626,14 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { tcx.intern_layout(self.scalar_pair(data_ptr, metadata)) } + ty::Dynamic(_, _, TraitObjectRepresentation::Sized) => { + let mut pointer = scalar_unit(Pointer); + pointer.valid_range_mut().start = 1; + let mut vtable = scalar_unit(Pointer); + vtable.valid_range_mut().start = 1; + tcx.intern_layout(self.scalar_pair(pointer, vtable)) + } + // Arrays and slices. ty::Array(element, mut count) => { if count.has_projections() { @@ -679,7 +688,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // Odd unit types. ty::FnDef(..) => univariant(&[], &ReprOptions::default(), StructKind::AlwaysSized)?, - ty::Dynamic(..) | ty::Foreign(..) => { + ty::Dynamic(_, _, TraitObjectRepresentation::Unsized) | ty::Foreign(..) => { let mut unit = self.univariant_uninterned( ty, &[], @@ -2435,7 +2444,9 @@ where | ty::FnDef(..) | ty::GeneratorWitness(..) | ty::Foreign(..) - | ty::Dynamic(..) => bug!("TyAndLayout::field({:?}): not applicable", this), + | ty::Dynamic(_, _, TraitObjectRepresentation::Unsized) => { + bug!("TyAndLayout::field({:?}): not applicable", this) + } // Potentially-fat pointers. ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { @@ -2534,6 +2545,17 @@ where } } + // dyn* + ty::Dynamic(_, _, TraitObjectRepresentation::Sized) => { + TyMaybeWithLayout::TyAndLayout( + tcx.layout_of( + ty::ParamEnv::reveal_all() + .and(tcx.mk_tup([tcx.types.usize, tcx.types.usize].into_iter())), + ) + .unwrap(), + ) + } + ty::Projection(_) | ty::Bound(..) | ty::Placeholder(..) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index df72260597f9f..b4418ef9aa0f6 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1113,6 +1113,12 @@ pub trait ToPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx>; } +impl<'tcx> ToPredicate<'tcx> for Predicate<'tcx> { + fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + self + } +} + impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index c1282b8ddaff4..f9394564f0eb1 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -216,6 +216,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let from_ty = CastTy::from_ty(ty); let cast_ty = CastTy::from_ty(expr.ty); + debug!( + "ExprKind::Cast from_ty={from_ty:?}, cast_ty={:?}/{cast_ty:?}", + expr.ty, + ); let cast_kind = match (from_ty, cast_ty) { (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => { CastKind::PointerExposeAddress @@ -223,6 +227,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => { CastKind::PointerFromExposedAddress } + (_, Some(CastTy::DynStar)) => CastKind::DynStar, (_, _) => CastKind::Misc, }; block.and(Rvalue::Cast(cast_kind, source, expr.ty)) diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index fa6224f1915a9..1248d5c8426ae 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -928,6 +928,12 @@ impl<'a, 'tcx> CastCheck<'tcx> { (Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast), (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast), + + // FIXME: this needs more conditions... + (_, DynStar) => Ok(CastKind::DynStarCast), + + // FIXME: do we want to allow dyn* upcasting or other casts? + (DynStar, _) => Err(CastError::IllegalCast), } } diff --git a/src/test/ui/async-await/dyn-star-trait-const.rs b/src/test/ui/async-await/dyn-star-trait-const.rs new file mode 100644 index 0000000000000..c4861de3606c7 --- /dev/null +++ b/src/test/ui/async-await/dyn-star-trait-const.rs @@ -0,0 +1,14 @@ +// run-pass +// ignore-test +#![feature(async_fn_in_traits)] + +use std::fmt::Debug; + +fn make_dyn_star() { + let i = 42usize; + let dyn_i: dyn* Debug = i as dyn* Debug; +} + +fn main() { + make_dyn_star(); +} diff --git a/src/test/ui/dyn-star/make-dyn-star.rs b/src/test/ui/dyn-star/make-dyn-star.rs index 17356bfbd84b9..593a4509f7d53 100644 --- a/src/test/ui/dyn-star/make-dyn-star.rs +++ b/src/test/ui/dyn-star/make-dyn-star.rs @@ -1,14 +1,12 @@ -// check-pass +// run-pass #![feature(dyn_star)] use std::fmt::Debug; -pub fn dyn_star_parameter(_: dyn* Send) { -} - -fn make_dyn_star() { - let i = 42usize; +fn make_dyn_star(i: usize) { let dyn_i: dyn* Debug = i as dyn* Debug; } -fn main() {} +fn main() { + make_dyn_star(42); +} From c5441acf67f0a9766fe361dd8a9e8182648e433d Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 27 Jul 2022 14:50:11 -0700 Subject: [PATCH 05/16] Call destructors when dyn* object goes out of scope --- compiler/rustc_codegen_ssa/src/meth.rs | 3 +-- compiler/rustc_codegen_ssa/src/mir/block.rs | 24 +++++++++++++++++-- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 13 +++++++--- compiler/rustc_middle/src/ty/layout.rs | 15 +++++++++--- .../src/ty/normalize_erasing_regions.rs | 2 ++ .../src/build/expr/as_rvalue.rs | 5 +--- compiler/rustc_monomorphize/src/collector.rs | 13 +++++++--- src/test/ui/dyn-star/make-dyn-star.rs | 2 +- 8 files changed, 59 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index f6b9ddf2eeac7..cae46ebd2e9a7 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -86,6 +86,7 @@ fn expect_dyn_trait_in_self<'tcx>(ty: Ty<'tcx>) -> ty::PolyExistentialTraitRef<' /// The `trait_ref` encodes the erased self type. Hence if we are /// making an object `Foo` from a value of type `Foo`, then /// `trait_ref` would map `T: Trait`. +#[instrument(level = "debug", skip(cx))] pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( cx: &Cx, ty: Ty<'tcx>, @@ -93,8 +94,6 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( ) -> Cx::Value { let tcx = cx.tcx(); - debug!("get_vtable(ty={:?}, trait_ref={:?})", ty, trait_ref); - // Check the cache. if let Some(&val) = cx.vtables().borrow().get(&(ty, trait_ref)) { return val; diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index fb75ecc17356b..438bb133fd1dc 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -16,7 +16,7 @@ use rustc_index::vec::Idx; use rustc_middle::mir::{self, AssertKind, SwitchTargets}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; -use rustc_middle::ty::{self, Instance, Ty, TypeVisitable, TraitObjectRepresentation}; +use rustc_middle::ty::{self, Instance, TraitObjectRepresentation, Ty, TypeVisitable}; use rustc_span::source_map::Span; use rustc_span::{sym, Symbol}; use rustc_symbol_mangling::typeid::typeid_for_fnabi; @@ -451,7 +451,27 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // (data, vtable) // an equivalent Rust `*mut dyn Trait` // // SO THEN WE CAN USE THE ABOVE CODE. - todo!() + let virtual_drop = Instance { + def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), + substs: drop_fn.substs, + }; + debug!("ty = {:?}", ty); + debug!("drop_fn = {:?}", drop_fn); + debug!("args = {:?}", args); + let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty()); + let data = args[0]; + let data_ty = bx.cx().backend_type(place.layout); + let vtable_ptr = + bx.gep(data_ty, data, &[bx.cx().const_i32(0), bx.cx().const_i32(1)]); + let vtable = bx.load(bx.type_i8p(), vtable_ptr, abi::Align::ONE); + // Truncate vtable off of args list + args = &args[..1]; + debug!("args' = {:?}", args); + ( + meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE) + .get_fn(&mut bx, vtable, ty, &fn_abi), + fn_abi, + ) } _ => (bx.get_fn_addr(drop_fn), bx.fn_abi_of_instance(drop_fn, ty::List::empty())), }; diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index d3c6b731de334..d68a89fe79350 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -4,6 +4,7 @@ use super::{FunctionCx, LocalRef}; use crate::base; use crate::common::{self, IntPredicate}; +use crate::meth::get_vtable; use crate::traits::*; use crate::MemFlags; @@ -11,6 +12,7 @@ use rustc_middle::mir; use rustc_middle::mir::Operand; use rustc_middle::ty::cast::{CastTy, IntTy}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; +use rustc_middle::ty::TraitObjectRepresentation; use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt}; use rustc_span::source_map::{Span, DUMMY_SP}; @@ -271,14 +273,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bug!("unexpected non-pair operand"); } } - #[allow(unreachable_code, unused)] // FIXME: remove this mir::CastKind::DynStar => { let data = match operand.val { OperandValue::Ref(_, _, _) => todo!(), - OperandValue::Immediate(_) => todo!(), + OperandValue::Immediate(v) => v, OperandValue::Pair(_, _) => todo!(), }; - let vtable = todo!(); + // FIXME: find the real vtable! + let trait_ref = if let ty::Dynamic(data, _, TraitObjectRepresentation::Sized) = cast.ty.kind() { + data.principal() + } else { + bug!("Only valid to do a DynStar cast into a DynStar type") + }; + let vtable = get_vtable(bx.cx(), source.ty(self.mir, bx.tcx()), trait_ref); OperandValue::Pair(data, vtable) } mir::CastKind::Pointer( diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 2e68b96f87bc6..240bead5494df 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2751,6 +2751,7 @@ impl<'tcx> ty::Instance<'tcx> { // for `Instance` (e.g. typeck would use `Ty::fn_sig` instead), // or should go through `FnAbi` instead, to avoid losing any // adjustments `fn_abi_of_instance` might be performing. + #[tracing::instrument(level = "debug", skip(tcx, param_env))] fn fn_sig_for_fn_abi( &self, tcx: TyCtxt<'tcx>, @@ -2897,6 +2898,7 @@ impl<'tcx> ty::Instance<'tcx> { /// with `-Cpanic=abort` will look like they can't unwind when in fact they /// might (from a foreign exception or similar). #[inline] +#[tracing::instrument(level = "debug", skip(tcx))] pub fn fn_can_unwind<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: Option, abi: SpecAbi) -> bool { if let Some(did) = fn_def_id { // Special attribute for functions which can't unwind. @@ -3113,6 +3115,7 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { /// NB: that includes virtual calls, which are represented by "direct calls" /// to an `InstanceDef::Virtual` instance (of `::fn`). #[inline] + #[tracing::instrument(level = "debug", skip(self))] fn fn_abi_of_instance( &self, instance: ty::Instance<'tcx>, @@ -3259,6 +3262,10 @@ pub fn adjust_for_rust_scalar<'tcx>( impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // FIXME(eddyb) perhaps group the signature/type-containing (or all of them?) // arguments of this method, into a separate `struct`. + #[tracing::instrument( + level = "debug", + skip(self, caller_location, fn_def_id, force_thin_self_ptr) + )] fn fn_abi_new_uncached( &self, sig: ty::PolyFnSig<'tcx>, @@ -3268,8 +3275,6 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // FIXME(eddyb) replace this with something typed, like an `enum`. force_thin_self_ptr: bool, ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> { - debug!("fn_abi_new_uncached({:?}, {:?})", sig, extra_args); - let sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, sig); let conv = conv_from_spec_abi(self.tcx(), sig.abi); @@ -3312,6 +3317,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall); let arg_of = |ty: Ty<'tcx>, arg_idx: Option| -> Result<_, FnAbiError<'tcx>> { + let span = tracing::debug_span!("arg_of"); + let _entered = span.enter(); let is_return = arg_idx.is_none(); let layout = self.layout_of(ty)?; @@ -3368,6 +3375,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { Ok(self.tcx.arena.alloc(fn_abi)) } + #[tracing::instrument(level = "debug", skip(self))] fn fn_abi_adjust_for_abi( &self, fn_abi: &mut FnAbi<'tcx, Ty<'tcx>>, @@ -3442,6 +3450,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } } +#[tracing::instrument(level = "debug", skip(cx))] fn make_thin_self_ptr<'tcx>( cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>), layout: TyAndLayout<'tcx>, @@ -3453,7 +3462,7 @@ fn make_thin_self_ptr<'tcx>( tcx.mk_mut_ptr(layout.ty) } else { match layout.abi { - Abi::ScalarPair(..) => (), + Abi::ScalarPair(..) | Abi::Scalar(..) => (), _ => bug!("receiver type has unsupported layout: {:?}", layout), } diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index cac8560ce1c32..9db5a2894843c 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -36,6 +36,7 @@ impl<'tcx> TyCtxt<'tcx> { /// /// This should only be used outside of type inference. For example, /// it assumes that normalization will succeed. + #[tracing::instrument(level = "debug", skip(self, param_env))] pub fn normalize_erasing_regions(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T where T: TypeFoldable<'tcx>, @@ -100,6 +101,7 @@ impl<'tcx> TyCtxt<'tcx> { /// N.B., currently, higher-ranked type bounds inhibit /// normalization. Therefore, each time we erase them in /// codegen, we need to normalize the contents. + #[tracing::instrument(level = "debug", skip(self, param_env))] pub fn normalize_erasing_late_bound_regions( self, param_env: ty::ParamEnv<'tcx>, diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index f9394564f0eb1..98bdaf0bc62e2 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -216,10 +216,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let from_ty = CastTy::from_ty(ty); let cast_ty = CastTy::from_ty(expr.ty); - debug!( - "ExprKind::Cast from_ty={from_ty:?}, cast_ty={:?}/{cast_ty:?}", - expr.ty, - ); + debug!("ExprKind::Cast from_ty={from_ty:?}, cast_ty={:?}/{cast_ty:?}", expr.ty,); let cast_kind = match (from_ty, cast_ty) { (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => { CastKind::PointerExposeAddress diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index be74a9d11e3c5..8b318d5e249ae 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -189,7 +189,8 @@ use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::{ - self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitable, VtblEntry, + self, GenericParamDefKind, Instance, TraitObjectRepresentation, Ty, TyCtxt, TypeFoldable, + TypeVisitable, VtblEntry, }; use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext}; use rustc_session::config::EntryFnType; @@ -689,7 +690,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { mir::CastKind::Pointer(PointerCast::Unsize), ref operand, target_ty, - ) => { + ) + | mir::Rvalue::Cast(mir::CastKind::DynStar, ref operand, target_ty) => { let target_ty = self.monomorphize(target_ty); let source_ty = operand.ty(self.body, self.tcx); let source_ty = self.monomorphize(source_ty); @@ -698,7 +700,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // This could also be a different Unsize instruction, like // from a fixed sized array to a slice. But we are only // interested in things that produce a vtable. - if target_ty.is_trait() && !source_ty.is_trait() { + if (target_ty.is_trait() || target_ty.is_dyn_star()) && !source_ty.is_trait() { create_mono_items_for_vtable_methods( self.tcx, target_ty, @@ -1112,6 +1114,11 @@ fn find_vtable_types_for_unsizing<'tcx>( ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty()) } + // T as dyn* Trait + (_, &ty::Dynamic(_, _, TraitObjectRepresentation::Sized)) => { + ptr_vtable(source_ty, target_ty) + } + (&ty::Adt(source_adt_def, source_substs), &ty::Adt(target_adt_def, target_substs)) => { assert_eq!(source_adt_def, target_adt_def); diff --git a/src/test/ui/dyn-star/make-dyn-star.rs b/src/test/ui/dyn-star/make-dyn-star.rs index 593a4509f7d53..b0b8f07abe58e 100644 --- a/src/test/ui/dyn-star/make-dyn-star.rs +++ b/src/test/ui/dyn-star/make-dyn-star.rs @@ -4,7 +4,7 @@ use std::fmt::Debug; fn make_dyn_star(i: usize) { - let dyn_i: dyn* Debug = i as dyn* Debug; + let _dyn_i: dyn* Debug = i as dyn* Debug; } fn main() { From 48e7f248042b392b7ab324f74f52abef8f6675d0 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 17 Aug 2022 16:51:16 -0700 Subject: [PATCH 06/16] Add test case for calling methods on dyn* object --- .../ui/async-await/dyn-star-trait-method.rs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/test/ui/async-await/dyn-star-trait-method.rs diff --git a/src/test/ui/async-await/dyn-star-trait-method.rs b/src/test/ui/async-await/dyn-star-trait-method.rs new file mode 100644 index 0000000000000..f7919fb29dbf7 --- /dev/null +++ b/src/test/ui/async-await/dyn-star-trait-method.rs @@ -0,0 +1,25 @@ +// run-pass +#![feature(async_fn_in_traits)] + +trait Foo { + fn get(&self) -> usize; +} + +impl Foo for usize { + fn get(&self) -> usize { + *self + } +} + +fn invoke_dyn_star(i: dyn* Foo) -> usize { + i.get() +} + +fn make_and_invoke_dyn_star(i: usize) -> usize { + let dyn_i: dyn* Foo = i as dyn* Foo; + invoke_dyn_star(dyn_i) +} + +fn main() { + println!("{}", make_and_invoke_dyn_star(42)); +} From ef7062dad6300a42b8a13e86ff5743a1d926a5d9 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 17 Aug 2022 16:58:49 -0700 Subject: [PATCH 07/16] Add test to make sure we run custom destructors --- .../ui/async-await/dyn-star-trait-drop.rs | 22 +++++++++++++++++++ .../dyn-star-trait-drop.run.stdout | 1 + 2 files changed, 23 insertions(+) create mode 100644 src/test/ui/async-await/dyn-star-trait-drop.rs create mode 100644 src/test/ui/async-await/dyn-star-trait-drop.run.stdout diff --git a/src/test/ui/async-await/dyn-star-trait-drop.rs b/src/test/ui/async-await/dyn-star-trait-drop.rs new file mode 100644 index 0000000000000..b1c987351fcf7 --- /dev/null +++ b/src/test/ui/async-await/dyn-star-trait-drop.rs @@ -0,0 +1,22 @@ +// run-pass +// check-run-results +#![feature(async_fn_in_traits)] + +use std::fmt::Debug; + +#[derive(Debug)] +struct Foo(usize); + +impl Drop for Foo { + fn drop(&mut self) { + println!("destructor called"); + } +} + +fn make_dyn_star(i: Foo) { + let _dyn_i: dyn* Debug = i as dyn* Debug; +} + +fn main() { + make_dyn_star(Foo(42)); +} diff --git a/src/test/ui/async-await/dyn-star-trait-drop.run.stdout b/src/test/ui/async-await/dyn-star-trait-drop.run.stdout new file mode 100644 index 0000000000000..dadb33ccf3ac3 --- /dev/null +++ b/src/test/ui/async-await/dyn-star-trait-drop.run.stdout @@ -0,0 +1 @@ +destructor called From 12353c11ca2848c15511d3b3d400fca412daff7b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 29 Aug 2022 02:49:04 +0000 Subject: [PATCH 08/16] Use principal of cast target as dyn-star trait ref in codegen --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index d68a89fe79350..d41817d7b65c0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -12,7 +12,6 @@ use rustc_middle::mir; use rustc_middle::mir::Operand; use rustc_middle::ty::cast::{CastTy, IntTy}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; -use rustc_middle::ty::TraitObjectRepresentation; use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt}; use rustc_span::source_map::{Span, DUMMY_SP}; @@ -279,12 +278,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValue::Immediate(v) => v, OperandValue::Pair(_, _) => todo!(), }; - // FIXME: find the real vtable! - let trait_ref = if let ty::Dynamic(data, _, TraitObjectRepresentation::Sized) = cast.ty.kind() { - data.principal() - } else { - bug!("Only valid to do a DynStar cast into a DynStar type") - }; + let trait_ref = + if let ty::Dynamic(data, _, ty::TraitObjectRepresentation::Sized) = cast.ty.kind() { + data.principal() + } else { + bug!("Only valid to do a DynStar cast into a DynStar type") + }; let vtable = get_vtable(bx.cx(), source.ty(self.mir, bx.tcx()), trait_ref); OperandValue::Pair(data, vtable) } From 12ec2f0e34e230a5d95d7ef06c6de92efcdcbedf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 29 Aug 2022 03:24:30 +0000 Subject: [PATCH 09/16] Construct dyn* during const interp --- compiler/rustc_codegen_ssa/src/mir/block.rs | 2 +- compiler/rustc_const_eval/src/interpret/cast.rs | 13 ++++++++++++- compiler/rustc_middle/src/ty/layout.rs | 10 ++-------- src/test/ui/async-await/dyn-star-trait-const.rs | 2 +- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 438bb133fd1dc..0c7cd43eb27d6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -907,7 +907,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { llargs.push(data_ptr); continue; } - _ => span_bug!(span, "can't codegen a virtual call on {:?}", op), + _ => span_bug!(span, "can't codegen a virtual call on {:#?}", op), } } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 9beeb2d8b2c7e..6831e53d01412 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -110,7 +110,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } DynStar => { - unimplemented!() + if let ty::Dynamic(data, _, ty::TraitObjectRepresentation::Sized) = cast_ty.kind() { + // Initial cast from sized to dyn trait + let vtable = self.get_vtable_ptr(src.layout.ty, data.principal())?; + let ptr = self.read_immediate(src)?.to_scalar(); + // FIXME(dyn-star): This should not use new_dyn_trait, but + // it does exactly the same thing (makes a scalar pair)... + // so maybe we should just duplicate/rename the function. + let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx); + self.write_immediate(val, dest)?; + } else { + bug!() + } } } Ok(()) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 240bead5494df..c0d21250c3030 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2545,15 +2545,9 @@ where } } - // dyn* + // dyn* (both fields are usize-sized) ty::Dynamic(_, _, TraitObjectRepresentation::Sized) => { - TyMaybeWithLayout::TyAndLayout( - tcx.layout_of( - ty::ParamEnv::reveal_all() - .and(tcx.mk_tup([tcx.types.usize, tcx.types.usize].into_iter())), - ) - .unwrap(), - ) + TyMaybeWithLayout::Ty(tcx.types.usize) } ty::Projection(_) diff --git a/src/test/ui/async-await/dyn-star-trait-const.rs b/src/test/ui/async-await/dyn-star-trait-const.rs index c4861de3606c7..315bc1a27412f 100644 --- a/src/test/ui/async-await/dyn-star-trait-const.rs +++ b/src/test/ui/async-await/dyn-star-trait-const.rs @@ -1,6 +1,6 @@ // run-pass -// ignore-test #![feature(async_fn_in_traits)] +#![allow(unused)] use std::fmt::Debug; From b2ed2dcaaedf0a96dece85a5409b3a1f30a84360 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 29 Aug 2022 03:53:33 +0000 Subject: [PATCH 10/16] Rename some variants --- compiler/rustc_borrowck/src/type_check/mod.rs | 8 +++----- compiler/rustc_codegen_ssa/src/mir/block.rs | 6 +++--- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +- compiler/rustc_const_eval/src/interpret/cast.rs | 2 +- compiler/rustc_middle/src/ty/cast.rs | 3 +-- compiler/rustc_middle/src/ty/context.rs | 6 ++---- compiler/rustc_middle/src/ty/layout.rs | 11 ++++------- compiler/rustc_middle/src/ty/mod.rs | 1 + compiler/rustc_middle/src/ty/print/pretty.rs | 5 ++--- compiler/rustc_middle/src/ty/sty.rs | 6 +++--- compiler/rustc_monomorphize/src/collector.rs | 7 ++----- .../rustc_trait_selection/src/traits/object_safety.rs | 6 ++---- .../rustc_trait_selection/src/traits/select/mod.rs | 3 +-- compiler/rustc_type_ir/src/sty.rs | 10 +++++----- compiler/rustc_typeck/src/astconv/mod.rs | 10 ++++------ compiler/rustc_typeck/src/check/cast.rs | 8 +++----- 16 files changed, 38 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index c78f9282e307a..d2a54df10b571 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -31,8 +31,8 @@ use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts}; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{ self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, Dynamic, - OpaqueHiddenType, OpaqueTypeKey, RegionVid, ToPredicate, TraitObjectRepresentation, Ty, TyCtxt, - UserType, UserTypeAnnotationIndex, + OpaqueHiddenType, OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, + UserTypeAnnotationIndex, }; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::{Span, DUMMY_SP}; @@ -2015,9 +2015,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // // apply them to prove that the source type `Foo` implements `Clone` etc let (existential_predicates, region) = match ty.kind() { - Dynamic(predicates, region, TraitObjectRepresentation::Sized) => { - (predicates, region) - } + Dynamic(predicates, region, ty::DynStar) => (predicates, region), _ => panic!("Invalid dyn* cast_ty"), }; diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 0c7cd43eb27d6..59bae7f7e91fa 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -16,7 +16,7 @@ use rustc_index::vec::Idx; use rustc_middle::mir::{self, AssertKind, SwitchTargets}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; -use rustc_middle::ty::{self, Instance, TraitObjectRepresentation, Ty, TypeVisitable}; +use rustc_middle::ty::{self, Instance, Ty, TypeVisitable}; use rustc_span::source_map::Span; use rustc_span::{sym, Symbol}; use rustc_symbol_mangling::typeid::typeid_for_fnabi; @@ -398,7 +398,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (drop_fn, fn_abi) = match ty.kind() { // FIXME(eddyb) perhaps move some of this logic into // `Instance::resolve_drop_in_place`? - ty::Dynamic(_, _, TraitObjectRepresentation::Unsized) => { + ty::Dynamic(_, _, ty::Dyn) => { // IN THIS ARM, WE HAVE: // ty = *mut (dyn Trait) // which is: exists ( *mut T, Vtable ) @@ -428,7 +428,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn_abi, ) } - ty::Dynamic(_, _, TraitObjectRepresentation::Sized) => { + ty::Dynamic(_, _, ty::DynStar) => { // IN THIS ARM, WE HAVE: // ty = *mut (dyn* Trait) // which is: *mut exists (T, Vtable) diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index d41817d7b65c0..56852b0fcc821 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -279,7 +279,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValue::Pair(_, _) => todo!(), }; let trait_ref = - if let ty::Dynamic(data, _, ty::TraitObjectRepresentation::Sized) = cast.ty.kind() { + if let ty::Dynamic(data, _, ty::DynStar) = cast.ty.kind() { data.principal() } else { bug!("Only valid to do a DynStar cast into a DynStar type") diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 6831e53d01412..5301266b82452 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -110,7 +110,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } DynStar => { - if let ty::Dynamic(data, _, ty::TraitObjectRepresentation::Sized) = cast_ty.kind() { + if let ty::Dynamic(data, _, ty::DynStar) = cast_ty.kind() { // Initial cast from sized to dyn trait let vtable = self.get_vtable_ptr(src.layout.ty, data.principal())?; let ptr = self.read_immediate(src)?.to_scalar(); diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs index cc5381b467d78..981e2d3b6d2d3 100644 --- a/compiler/rustc_middle/src/ty/cast.rs +++ b/compiler/rustc_middle/src/ty/cast.rs @@ -4,7 +4,6 @@ use crate::ty::{self, Ty}; use rustc_macros::HashStable; -use rustc_type_ir::TraitObjectRepresentation; /// Types that are represented as ints. #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -71,7 +70,7 @@ impl<'tcx> CastTy<'tcx> { ty::Adt(d, _) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)), ty::RawPtr(mt) => Some(CastTy::Ptr(mt)), ty::FnPtr(..) => Some(CastTy::FnPtr), - ty::Dynamic(_, _, TraitObjectRepresentation::Sized) => Some(CastTy::DynStar), + ty::Dynamic(_, _, ty::DynStar) => Some(CastTy::DynStar), _ => None, } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 1b6b97dc22953..9359703472150 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -63,9 +63,7 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; use rustc_type_ir::sty::TyKind::*; -use rustc_type_ir::{ - InternAs, InternIteratorElement, Interner, TraitObjectRepresentation, TypeFlags, -}; +use rustc_type_ir::{DynKind, InternAs, InternIteratorElement, Interner, TypeFlags}; use std::any::Any; use std::borrow::Borrow; @@ -2547,7 +2545,7 @@ impl<'tcx> TyCtxt<'tcx> { self, obj: &'tcx List>>, reg: ty::Region<'tcx>, - repr: TraitObjectRepresentation, + repr: DynKind, ) -> Ty<'tcx> { self.mk_ty(Dynamic(obj, reg, repr)) } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index c0d21250c3030..922891ecc3435 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -21,7 +21,6 @@ use rustc_target::abi::call::{ }; use rustc_target::abi::*; use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target}; -use rustc_type_ir::TraitObjectRepresentation; use std::cmp::{self, Ordering}; use std::fmt; @@ -626,7 +625,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { tcx.intern_layout(self.scalar_pair(data_ptr, metadata)) } - ty::Dynamic(_, _, TraitObjectRepresentation::Sized) => { + ty::Dynamic(_, _, ty::DynStar) => { let mut pointer = scalar_unit(Pointer); pointer.valid_range_mut().start = 1; let mut vtable = scalar_unit(Pointer); @@ -688,7 +687,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // Odd unit types. ty::FnDef(..) => univariant(&[], &ReprOptions::default(), StructKind::AlwaysSized)?, - ty::Dynamic(_, _, TraitObjectRepresentation::Unsized) | ty::Foreign(..) => { + ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => { let mut unit = self.univariant_uninterned( ty, &[], @@ -2444,7 +2443,7 @@ where | ty::FnDef(..) | ty::GeneratorWitness(..) | ty::Foreign(..) - | ty::Dynamic(_, _, TraitObjectRepresentation::Unsized) => { + | ty::Dynamic(_, _, ty::Dyn) => { bug!("TyAndLayout::field({:?}): not applicable", this) } @@ -2546,9 +2545,7 @@ where } // dyn* (both fields are usize-sized) - ty::Dynamic(_, _, TraitObjectRepresentation::Sized) => { - TyMaybeWithLayout::Ty(tcx.types.usize) - } + ty::Dynamic(_, _, ty::DynStar) => TyMaybeWithLayout::Ty(tcx.types.usize), ty::Projection(_) | ty::Bound(..) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index b4418ef9aa0f6..e80cc2ed5fab7 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -58,6 +58,7 @@ use std::ops::ControlFlow; use std::{fmt, str}; pub use crate::ty::diagnostics::*; +pub use rustc_type_ir::DynKind::*; pub use rustc_type_ir::InferTy::*; pub use rustc_type_ir::RegionKind::*; pub use rustc_type_ir::TyKind::*; diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 839f3ffff245c..f7d5d3116afb7 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -16,7 +16,6 @@ use rustc_session::cstore::{ExternCrate, ExternCrateSource}; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; -use rustc_type_ir::TraitObjectRepresentation; use std::cell::Cell; use std::char; @@ -626,8 +625,8 @@ pub trait PrettyPrinter<'tcx>: p!("("); } match repr { - TraitObjectRepresentation::Unsized => p!("dyn "), - TraitObjectRepresentation::Sized => p!("dyn* "), + ty::Dyn => p!("dyn "), + ty::DynStar => p!("dyn* "), } p!(print(data)); if print_r { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 6713660ab8faf..18169045c901c 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -31,7 +31,7 @@ use ty::util::IntTypeExt; use rustc_type_ir::sty::TyKind::*; use rustc_type_ir::RegionKind as IrRegionKind; -use rustc_type_ir::{TraitObjectRepresentation, TyKind as IrTyKind}; +use rustc_type_ir::TyKind as IrTyKind; // Re-export the `TyKind` from `rustc_type_ir` here for convenience #[rustc_diagnostic_item = "TyKind"] @@ -1852,12 +1852,12 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn is_trait(self) -> bool { - matches!(self.kind(), Dynamic(_, _, TraitObjectRepresentation::Unsized)) + matches!(self.kind(), Dynamic(_, _, ty::Dyn)) } #[inline] pub fn is_dyn_star(self) -> bool { - matches!(self.kind(), Dynamic(_, _, TraitObjectRepresentation::Sized)) + matches!(self.kind(), Dynamic(_, _, ty::DynStar)) } #[inline] diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 8b318d5e249ae..4e7eba2d02fef 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -189,8 +189,7 @@ use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::{ - self, GenericParamDefKind, Instance, TraitObjectRepresentation, Ty, TyCtxt, TypeFoldable, - TypeVisitable, VtblEntry, + self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitable, VtblEntry, }; use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext}; use rustc_session::config::EntryFnType; @@ -1115,9 +1114,7 @@ fn find_vtable_types_for_unsizing<'tcx>( } // T as dyn* Trait - (_, &ty::Dynamic(_, _, TraitObjectRepresentation::Sized)) => { - ptr_vtable(source_ty, target_ty) - } + (_, &ty::Dynamic(_, _, ty::DynStar)) => ptr_vtable(source_ty, target_ty), (&ty::Adt(source_adt_def, source_substs), &ty::Adt(target_adt_def, target_substs)) => { assert_eq!(source_adt_def, target_adt_def); diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 43ee5b5545543..f2779ce2db140 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -20,8 +20,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst}; use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst}; use rustc_middle::ty::{ - self, EarlyBinder, TraitObjectRepresentation, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, - TypeVisitor, + self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; use rustc_middle::ty::{Predicate, ToPredicate}; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; @@ -601,8 +600,7 @@ fn object_ty_for_trait<'tcx>( let existential_predicates = tcx .mk_poly_existential_predicates(iter::once(trait_predicate).chain(projection_predicates)); - let object_ty = - tcx.mk_dynamic(existential_predicates, lifetime, TraitObjectRepresentation::Unsized); + let object_ty = tcx.mk_dynamic(existential_predicates, lifetime, ty::Dyn); debug!("object_ty_for_trait: object_ty=`{}`", object_ty); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index a64179c14f51e..9efc95b4405ce 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -38,7 +38,6 @@ use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::subst::{Subst, SubstsRef}; -use rustc_middle::ty::TraitObjectRepresentation; use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitable}; use rustc_span::symbol::sym; @@ -1866,7 +1865,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Array(..) | ty::Closure(..) | ty::Never - | ty::Dynamic(_, _, TraitObjectRepresentation::Sized) + | ty::Dynamic(_, _, ty::DynStar) | ty::Error(_) => { // safe for everything Where(ty::Binder::dummy(Vec::new())) diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index b57f32de8ce5c..f8090cd9dd831 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -20,16 +20,16 @@ use rustc_serialize::{Decodable, Decoder, Encodable}; /// Specifies how a trait object is represented. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)] -pub enum TraitObjectRepresentation { +pub enum DynKind { /// An unsized `dyn Trait` object - Unsized, + Dyn, /// A sized `dyn* Trait` object - Sized, + DynStar, } // Manually implemented because deriving HashStable requires rustc_query_system, which would // create a cyclic dependency. -impl HashStable for TraitObjectRepresentation { +impl HashStable for DynKind { fn hash_stable( &self, hcx: &mut CTX, @@ -116,7 +116,7 @@ pub enum TyKind { FnPtr(I::PolyFnSig), /// A trait object. Written as `dyn for<'b> Trait<'b, Assoc = u32> + Send + 'a`. - Dynamic(I::ListBinderExistentialPredicate, I::Region, TraitObjectRepresentation), + Dynamic(I::ListBinderExistentialPredicate, I::Region, DynKind), /// The anonymous type of a closure. Used to represent the type of `|a| a`. /// diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 0010bcc4bf620..38128081e8542 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -27,8 +27,8 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin}; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef}; +use rustc_middle::ty::DynKind; use rustc_middle::ty::GenericParamDefKind; -use rustc_middle::ty::TraitObjectRepresentation; use rustc_middle::ty::{ self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeVisitable, }; @@ -1253,7 +1253,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_bounds: &[hir::PolyTraitRef<'_>], lifetime: &hir::Lifetime, borrowed: bool, - representation: TraitObjectRepresentation, + representation: DynKind, ) -> Ty<'tcx> { let tcx = self.tcx(); @@ -2623,10 +2623,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { hir::TyKind::TraitObject(bounds, ref lifetime, repr) => { self.maybe_lint_bare_trait(ast_ty, in_path); let repr = match repr { - TraitObjectSyntax::Dyn | TraitObjectSyntax::None => { - TraitObjectRepresentation::Unsized - } - TraitObjectSyntax::DynStar => TraitObjectRepresentation::Sized, + TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn, + TraitObjectSyntax::DynStar => ty::DynStar, }; self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed, repr) } diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 1248d5c8426ae..640aa8c65ed83 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -41,9 +41,7 @@ use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::cast::{CastKind, CastTy}; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{ - self, Binder, TraitObjectRepresentation, Ty, TypeAndMut, TypeVisitable, VariantDef, -}; +use rustc_middle::ty::{self, Binder, Ty, TypeAndMut, TypeVisitable, VariantDef}; use rustc_session::lint; use rustc_session::Session; use rustc_span::symbol::sym; @@ -241,7 +239,7 @@ fn check_dyn_star_cast<'tcx>( // // this would return `existential_predicates = [?Self: Clone, ?Self: Debug]` and `region = 'static`. let (existential_predicates, region) = match cast_ty.kind() { - ty::Dynamic(predicates, region, TraitObjectRepresentation::Sized) => (predicates, region), + ty::Dynamic(predicates, region, ty::DynStar) => (predicates, region), _ => panic!("Invalid dyn* cast_ty"), }; @@ -289,7 +287,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // cases now. We do a more thorough check at the end, once // inference is more completely known. match cast_ty.kind() { - ty::Dynamic(_, _, TraitObjectRepresentation::Unsized) | ty::Slice(..) => { + ty::Dynamic(_, _, ty::Dyn) | ty::Slice(..) => { let reported = check.report_cast_to_unsized_type(fcx); Err(reported) } From 03148ff735c561629c7e880383d3e0d44eebf738 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 29 Aug 2022 06:00:58 +0000 Subject: [PATCH 11/16] Make dyn-trait-method work --- compiler/rustc_codegen_ssa/src/mir/block.rs | 25 ++++++++++++++++++++- compiler/rustc_middle/src/ty/layout.rs | 19 +++++++++++++--- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 59bae7f7e91fa..7cee9ea3e1dc8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -907,7 +907,30 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { llargs.push(data_ptr); continue; } - _ => span_bug!(span, "can't codegen a virtual call on {:#?}", op), + Immediate(_) => { + let ty::Ref(_, ty, _) = op.layout.ty.kind() else { + span_bug!(span, "can't codegen a virtual call on {:#?}", op); + }; + if !ty.is_dyn_star() { + span_bug!(span, "can't codegen a virtual call on {:#?}", op); + } + // FIXME(dyn-star): Make sure this is done on a &dyn* receiver + let place = op.deref(bx.cx()); + let data_ptr = place.project_field(&mut bx, 0); + let meta_ptr = place.project_field(&mut bx, 1); + let meta = bx.load_operand(meta_ptr); + llfn = Some(meth::VirtualIndex::from_index(idx).get_fn( + &mut bx, + meta.immediate(), + op.layout.ty, + &fn_abi, + )); + llargs.push(data_ptr.llval); + continue; + } + _ => { + span_bug!(span, "can't codegen a virtual call on {:#?}", op); + } } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 922891ecc3435..b8c4534307cc6 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -626,7 +626,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } ty::Dynamic(_, _, ty::DynStar) => { - let mut pointer = scalar_unit(Pointer); + let mut pointer = scalar_unit(Int(dl.ptr_sized_integer(), false)); pointer.valid_range_mut().start = 1; let mut vtable = scalar_unit(Pointer); vtable.valid_range_mut().start = 1; @@ -2544,8 +2544,21 @@ where } } - // dyn* (both fields are usize-sized) - ty::Dynamic(_, _, ty::DynStar) => TyMaybeWithLayout::Ty(tcx.types.usize), + ty::Dynamic(_, _, ty::DynStar) => { + if i == 0 { + TyMaybeWithLayout::Ty(tcx.types.usize) + } else if i == 1 { + // FIXME(dyn-star) same FIXME as above applies here too + TyMaybeWithLayout::Ty( + tcx.mk_imm_ref( + tcx.lifetimes.re_static, + tcx.mk_array(tcx.types.usize, 3), + ), + ) + } else { + bug!("no field {i} on dyn*") + } + } ty::Projection(_) | ty::Bound(..) From ddfcca48c679b1cd9c8415c4d5e7de8259e3b1fb Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Mon, 29 Aug 2022 12:02:03 -0700 Subject: [PATCH 12/16] Update feature flags on dyn-star tests --- src/test/ui/async-await/dyn-star-trait-const.rs | 2 +- src/test/ui/async-await/dyn-star-trait-drop.rs | 2 +- src/test/ui/async-await/dyn-star-trait-error.rs | 2 +- src/test/ui/async-await/dyn-star-trait-method.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/ui/async-await/dyn-star-trait-const.rs b/src/test/ui/async-await/dyn-star-trait-const.rs index 315bc1a27412f..29a1a0d025305 100644 --- a/src/test/ui/async-await/dyn-star-trait-const.rs +++ b/src/test/ui/async-await/dyn-star-trait-const.rs @@ -1,5 +1,5 @@ // run-pass -#![feature(async_fn_in_traits)] +#![feature(dyn_star)] #![allow(unused)] use std::fmt::Debug; diff --git a/src/test/ui/async-await/dyn-star-trait-drop.rs b/src/test/ui/async-await/dyn-star-trait-drop.rs index b1c987351fcf7..2ce77593777aa 100644 --- a/src/test/ui/async-await/dyn-star-trait-drop.rs +++ b/src/test/ui/async-await/dyn-star-trait-drop.rs @@ -1,6 +1,6 @@ // run-pass // check-run-results -#![feature(async_fn_in_traits)] +#![feature(dyn_star)] use std::fmt::Debug; diff --git a/src/test/ui/async-await/dyn-star-trait-error.rs b/src/test/ui/async-await/dyn-star-trait-error.rs index 20e183c74554a..81f7f39ae1359 100644 --- a/src/test/ui/async-await/dyn-star-trait-error.rs +++ b/src/test/ui/async-await/dyn-star-trait-error.rs @@ -1,4 +1,4 @@ -#![feature(async_fn_in_traits)] +#![feature(dyn_star)] use std::fmt::Debug; diff --git a/src/test/ui/async-await/dyn-star-trait-method.rs b/src/test/ui/async-await/dyn-star-trait-method.rs index f7919fb29dbf7..4d32db034a4da 100644 --- a/src/test/ui/async-await/dyn-star-trait-method.rs +++ b/src/test/ui/async-await/dyn-star-trait-method.rs @@ -1,5 +1,5 @@ // run-pass -#![feature(async_fn_in_traits)] +#![feature(dyn_star)] trait Foo { fn get(&self) -> usize; From 3c2d20ef0b9cbb6f7c2cbc8112bb2e9f0d8ef755 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Tue, 30 Aug 2022 12:39:28 -0700 Subject: [PATCH 13/16] Make x.py check work --- compiler/rustc_codegen_cranelift/src/base.rs | 4 + .../src/value_and_place.rs | 2 +- .../src/traits/select/candidate_assembly.rs | 2 +- .../src/check/fn_ctxt/suggestions.rs | 2 +- .../clippy_lints/src/transmute/utils.rs | 29 ++- .../clippy_utils/src/qualify_min_const_fn.rs | 141 +++++++++------ src/tools/clippy/clippy_utils/src/ty.rs | 165 +++++++++++------- 7 files changed, 211 insertions(+), 134 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 2aa11ac2eeaa6..399474d79e3b6 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -701,6 +701,10 @@ fn codegen_stmt<'tcx>( let operand = codegen_operand(fx, operand); operand.unsize_value(fx, lval); } + Rvalue::Cast(CastKind::DynStar, _, _) => { + // FIXME(dyn-star) + unimplemented!() + } Rvalue::Discriminant(place) => { let place = codegen_place(fx, place); let value = place.to_cvalue(fx); diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 2ee98546c992a..d58b52851ac04 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -815,7 +815,7 @@ pub(crate) fn assert_assignable<'tcx>( ); // fn(&T) -> for<'l> fn(&'l T) is allowed } - (&ty::Dynamic(from_traits, _), &ty::Dynamic(to_traits, _)) => { + (&ty::Dynamic(from_traits, _, _from_kind), &ty::Dynamic(to_traits, _, _to_kind)) => { for (from, to) in from_traits.iter().zip(to_traits) { let from = fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from); diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 83bde1c50e23d..a80527f63a004 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -1039,7 +1039,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Ref(_, _, _) | ty::FnDef(_, _) | ty::FnPtr(_) - | ty::Dynamic(_, _) + | ty::Dynamic(_, _, _) | ty::Closure(_, _) | ty::Generator(_, _, _) | ty::GeneratorWitness(_) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 82b7101baa3a8..ee0ad7b5d0ab4 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -182,7 +182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }) } - ty::Dynamic(data, _, ty::TraitObjectRepresentation::Unsized) => { + ty::Dynamic(data, _, ty::Dyn) => { data.iter().find_map(|pred| { if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder() && Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output() diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs index 74927570b40eb..78cc589cc291b 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs @@ -2,11 +2,18 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{cast::CastKind, Ty}; use rustc_span::DUMMY_SP; -use rustc_typeck::check::{cast::CastCheck, FnCtxt, Inherited}; +use rustc_typeck::check::{ + cast::{self, CastCheckResult}, + FnCtxt, Inherited, +}; // check if the component types of the transmuted collection and the result have different ABI, // size or alignment -pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx>, to: Ty<'tcx>) -> bool { +pub(super) fn is_layout_incompatible<'tcx>( + cx: &LateContext<'tcx>, + from: Ty<'tcx>, + to: Ty<'tcx>, +) -> bool { if let Ok(from) = cx.tcx.try_normalize_erasing_regions(cx.param_env, from) && let Ok(to) = cx.tcx.try_normalize_erasing_regions(cx.param_env, to) && let Ok(from_layout) = cx.tcx.layout_of(cx.param_env.and(from)) @@ -29,7 +36,9 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>( from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, ) -> bool { - use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast}; + use CastKind::{ + AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast, + }; matches!( check_cast(cx, e, from_ty, to_ty), Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) @@ -40,7 +49,12 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>( /// the cast. In certain cases, including some invalid casts from array references /// to pointers, this may cause additional errors to be emitted and/or ICE error /// messages. This function will panic if that occurs. -fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option { +fn check_cast<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + from_ty: Ty<'tcx>, + to_ty: Ty<'tcx>, +) -> Option { let hir_id = e.hir_id; let local_def_id = hir_id.owner; @@ -48,12 +62,9 @@ fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx> let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, hir_id); // If we already have errors, we can't be sure we can pointer cast. - assert!( - !fn_ctxt.errors_reported_since_creation(), - "Newly created FnCtxt contained errors" - ); + assert!(!fn_ctxt.errors_reported_since_creation(), "Newly created FnCtxt contained errors"); - if let Ok(check) = CastCheck::new( + if let CastCheckResult::Deferred(check) = cast::check_cast( &fn_ctxt, e, from_ty, to_ty, // We won't show any error to the user, so we don't care what the span is here. DUMMY_SP, DUMMY_SP, diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index d5f64e5118f56..781744870cb91 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -18,7 +18,11 @@ use std::borrow::Cow; type McfResult = Result<(), (Span, Cow<'static, str>)>; -pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option) -> McfResult { +pub fn is_min_const_fn<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + msrv: Option, +) -> McfResult { let def_id = body.source.def_id(); let mut current = def_id; loop { @@ -33,10 +37,18 @@ pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Trait(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue, - ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate), - ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate), - ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate), - ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {:#?}", predicate), + ty::PredicateKind::ObjectSafe(_) => { + panic!("object safe predicate on function: {:#?}", predicate) + } + ty::PredicateKind::ClosureKind(..) => { + panic!("closure kind predicate on function: {:#?}", predicate) + } + ty::PredicateKind::Subtype(_) => { + panic!("subtype predicate on function: {:#?}", predicate) + } + ty::PredicateKind::Coerce(_) => { + panic!("coerce predicate on function: {:#?}", predicate) + } } } match predicates.parent { @@ -77,22 +89,23 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { match ty.kind() { ty::Ref(_, _, hir::Mutability::Mut) => { return Err((span, "mutable references in const fn are unstable".into())); - }, + } ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())), ty::FnPtr(..) => { return Err((span, "function pointers in const fn are unstable".into())); - }, - ty::Dynamic(preds, _) => { + } + ty::Dynamic(preds, _, _) => { for pred in preds.iter() { match pred.skip_binder() { - ty::ExistentialPredicate::AutoTrait(_) | ty::ExistentialPredicate::Projection(_) => { + ty::ExistentialPredicate::AutoTrait(_) + | ty::ExistentialPredicate::Projection(_) => { return Err(( span, "trait bounds other than `Sized` \ on const fn parameters are unstable" .into(), )); - }, + } ty::ExistentialPredicate::Trait(trait_ref) => { if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() { return Err(( @@ -102,11 +115,11 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { .into(), )); } - }, + } } } - }, - _ => {}, + } + _ => {} } } Ok(()) @@ -120,10 +133,13 @@ fn check_rvalue<'tcx>( span: Span, ) -> McfResult { match rvalue { - Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())), - Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { - check_place(tcx, *place, span, body) - }, + Rvalue::ThreadLocalRef(_) => { + Err((span, "cannot access thread local storage in const fn".into())) + } + Rvalue::Len(place) + | Rvalue::Discriminant(place) + | Rvalue::Ref(_, _, place) + | Rvalue::AddressOf(_, place) => check_place(tcx, *place, span, body), Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body), Rvalue::Repeat(operand, _) | Rvalue::Use(operand) @@ -136,7 +152,9 @@ fn check_rvalue<'tcx>( ) => check_operand(tcx, operand, span, body), Rvalue::Cast( CastKind::Pointer( - PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) | PointerCast::ReifyFnPointer, + PointerCast::UnsafeFnPointer + | PointerCast::ClosureFnPointer(_) + | PointerCast::ReifyFnPointer, ), _, _, @@ -146,7 +164,10 @@ fn check_rvalue<'tcx>( deref_ty.ty } else { // We cannot allow this for now. - return Err((span, "unsizing casts are only allowed for references right now".into())); + return Err(( + span, + "unsizing casts are only allowed for references right now".into(), + )); }; let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id)); if let ty::Slice(_) | ty::Str = unsized_ty.kind() { @@ -157,10 +178,14 @@ fn check_rvalue<'tcx>( // We just can't allow trait objects until we have figured out trait method calls. Err((span, "unsizing casts are not allowed in const fn".into())) } - }, + } Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => { Err((span, "casting pointers to ints is unstable in const fn".into())) - }, + } + Rvalue::Cast(CastKind::DynStar, _, _) => { + // FIXME(dyn-star) + unimplemented!() + } // binops are fine on integers Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => { check_operand(tcx, lhs, span, body)?; @@ -169,13 +194,12 @@ fn check_rvalue<'tcx>( if ty.is_integral() || ty.is_bool() || ty.is_char() { Ok(()) } else { - Err(( - span, - "only int, `bool` and `char` operations are stable in const fn".into(), - )) + Err((span, "only int, `bool` and `char` operations are stable in const fn".into())) } - }, - Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::ShallowInitBox(_, _) => Ok(()), + } + Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::ShallowInitBox(_, _) => { + Ok(()) + } Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, tcx); if ty.is_integral() || ty.is_bool() { @@ -183,13 +207,13 @@ fn check_rvalue<'tcx>( } else { Err((span, "only int and `bool` operations are stable in const fn".into())) } - }, + } Rvalue::Aggregate(_, operands) => { for operand in operands { check_operand(tcx, operand, span, body)?; } Ok(()) - }, + } } } @@ -204,7 +228,7 @@ fn check_statement<'tcx>( StatementKind::Assign(box (place, rval)) => { check_place(tcx, *place, span, body)?; check_rvalue(tcx, body, def_id, rval, span) - }, + } StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body), // just an assignment @@ -214,14 +238,15 @@ fn check_statement<'tcx>( StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(tcx, op, span, body), - StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping( - rustc_middle::mir::CopyNonOverlapping { dst, src, count }, - )) => { + StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { + dst, + src, + count, + }) => { check_operand(tcx, dst, span, body)?; check_operand(tcx, src, span, body)?; check_operand(tcx, count, span, body) - }, - + } // These are all NOPs StatementKind::StorageLive(_) | StatementKind::StorageDead(_) @@ -232,7 +257,12 @@ fn check_statement<'tcx>( } } -fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { +fn check_operand<'tcx>( + tcx: TyCtxt<'tcx>, + operand: &Operand<'tcx>, + span: Span, + body: &Body<'tcx>, +) -> McfResult { match operand { Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, body), Operand::Constant(c) => match c.check_static_ptr(tcx) { @@ -242,7 +272,12 @@ fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, b } } -fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { +fn check_place<'tcx>( + tcx: TyCtxt<'tcx>, + place: Place<'tcx>, + span: Span, + body: &Body<'tcx>, +) -> McfResult { let mut cursor = place.projection.as_ref(); while let [ref proj_base @ .., elem] = *cursor { cursor = proj_base; @@ -255,12 +290,12 @@ fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &B return Err((span, "accessing union fields is unstable".into())); } } - }, + } ProjectionElem::ConstantIndex { .. } | ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } | ProjectionElem::Deref - | ProjectionElem::Index(_) => {}, + | ProjectionElem::Index(_) => {} } } @@ -286,18 +321,16 @@ fn check_terminator<'a, 'tcx>( TerminatorKind::DropAndReplace { place, value, .. } => { check_place(tcx, *place, span, body)?; check_operand(tcx, value, span, body) - }, + } - TerminatorKind::SwitchInt { - discr, - switch_ty: _, - targets: _, - } => check_operand(tcx, discr, span, body), + TerminatorKind::SwitchInt { discr, switch_ty: _, targets: _ } => { + check_operand(tcx, discr, span, body) + } TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())), TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { Err((span, "const fn generators are unstable".into())) - }, + } TerminatorKind::Call { func, @@ -342,17 +375,15 @@ fn check_terminator<'a, 'tcx>( } else { Err((span, "can only call other const fns within const fn".into())) } - }, + } - TerminatorKind::Assert { - cond, - expected: _, - msg: _, - target: _, - cleanup: _, - } => check_operand(tcx, cond, span, body), + TerminatorKind::Assert { cond, expected: _, msg: _, target: _, cleanup: _ } => { + check_operand(tcx, cond, span, body) + } - TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())), + TerminatorKind::InlineAsm { .. } => { + Err((span, "cannot use inline assembly in const fn".into())) + } } } diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 5a7f9568441c9..99803ae93a712 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -14,8 +14,9 @@ use rustc_lint::LateContext; use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; use rustc_middle::ty::{ - self, AdtDef, Binder, BoundRegion, DefIdTree, FnSig, IntTy, ParamEnv, Predicate, PredicateKind, ProjectionTy, - Region, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy, VariantDef, VariantDiscr, + self, AdtDef, Binder, BoundRegion, DefIdTree, FnSig, IntTy, ParamEnv, Predicate, PredicateKind, + ProjectionTy, Region, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, + UintTy, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; @@ -166,9 +167,7 @@ pub fn implements_trait_with_env<'tcx>( } let ty_params = tcx.mk_substs(ty_params.iter()); tcx.infer_ctxt().enter(|infcx| { - infcx - .type_implements_trait(trait_id, ty, ty_params, param_env) - .must_apply_modulo_regions() + infcx.type_implements_trait(trait_id, ty, ty_params, param_env).must_apply_modulo_regions() }) } @@ -185,11 +184,14 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind() { ty::Adt(adt, _) => cx.tcx.has_attr(adt.did(), sym::must_use), ty::Foreign(did) => cx.tcx.has_attr(*did, sym::must_use), - ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => { + ty::Slice(ty) + | ty::Array(ty, _) + | ty::RawPtr(ty::TypeAndMut { ty, .. }) + | ty::Ref(_, ty, _) => { // for the Array case we don't need to care for the len == 0 case // because we don't want to lint functions returning empty arrays is_must_use_ty(cx, *ty) - }, + } ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)), ty::Opaque(def_id, _) => { for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { @@ -200,8 +202,8 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { } } false - }, - ty::Dynamic(binder, _) => { + } + ty::Dynamic(binder, _, _) => { for predicate in binder.iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { if cx.tcx.has_attr(trait_ref.def_id, sym::must_use) { @@ -210,7 +212,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { } } false - }, + } _ => false, } } @@ -220,7 +222,11 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { // not succeed /// Checks if `Ty` is normalizable. This function is useful /// to avoid crashes on `layout_of`. -pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { +pub fn is_normalizable<'tcx>( + cx: &LateContext<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, +) -> bool { is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default()) } @@ -240,15 +246,14 @@ fn is_normalizable_helper<'tcx>( if infcx.at(&cause, param_env).normalize(ty).is_ok() { match ty.kind() { ty::Adt(def, substs) => def.variants().iter().all(|variant| { - variant - .fields - .iter() - .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache)) + variant.fields.iter().all(|field| { + is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache) + }) }), _ => ty.walk().all(|generic_arg| match generic_arg.unpack() { GenericArgKind::Type(inner_ty) if inner_ty != ty => { is_normalizable_helper(cx, param_env, inner_ty, cache) - }, + } _ => true, // if inner_ty == ty, we've already checked it }), } @@ -273,7 +278,9 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool { match *ty.kind() { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true, ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true, - ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type), + ty::Array(inner_type, _) | ty::Slice(inner_type) => { + is_recursively_primitive_type(inner_type) + } ty::Tuple(inner_types) => inner_types.iter().all(is_recursively_primitive_type), _ => false, } @@ -313,11 +320,9 @@ pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symb /// Returns `false` if the `LangItem` is not defined. pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool { match ty.kind() { - ty::Adt(adt, _) => cx - .tcx - .lang_items() - .require(lang_item) - .map_or(false, |li| li == adt.did()), + ty::Adt(adt, _) => { + cx.tcx.lang_items().require(lang_item).map_or(false, |li| li == adt.did()) + } _ => false, } } @@ -342,7 +347,11 @@ pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool { /// deallocate memory. For these types, and composites containing them, changing the drop order /// won't result in any observable side effects. pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - fn needs_ordered_drop_inner<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, seen: &mut FxHashSet>) -> bool { + fn needs_ordered_drop_inner<'tcx>( + cx: &LateContext<'tcx>, + ty: Ty<'tcx>, + seen: &mut FxHashSet>, + ) -> bool { if !seen.insert(ty) { return false; } @@ -393,11 +402,7 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { /// removed. pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) { fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) { - if let ty::Ref(_, ty, _) = ty.kind() { - peel(*ty, count + 1) - } else { - (ty, count) - } + if let ty::Ref(_, ty, _) = ty.kind() { peel(*ty, count + 1) } else { (ty, count) } } peel(ty, 0) } @@ -452,17 +457,18 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { return false; } - substs_a - .iter() - .zip(substs_b.iter()) - .all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) { - (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b, + substs_a.iter().zip(substs_b.iter()).all(|(arg_a, arg_b)| { + match (arg_a.unpack(), arg_b.unpack()) { + (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => { + inner_a == inner_b + } (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => { same_type_and_consts(type_a, type_b) - }, + } _ => true, - }) - }, + } + }) + } _ => a == b, } } @@ -478,7 +484,10 @@ pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { } /// Gets an iterator over all predicates which apply to the given item. -pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator, Span)> { +pub fn all_predicates_of( + tcx: TyCtxt<'_>, + id: DefId, +) -> impl Iterator, Span)> { let mut next_id = Some(id); iter::from_fn(move || { next_id.take().map(|id| { @@ -508,7 +517,7 @@ impl<'tcx> ExprFnSig<'tcx> { } else { Some(sig.input(i)) } - }, + } Self::Closure(_, sig) => Some(sig.input(0).map_bound(|ty| ty.tuple_fields()[i])), Self::Trait(inputs, _, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])), } @@ -517,7 +526,10 @@ impl<'tcx> ExprFnSig<'tcx> { /// Gets the argument type at the given offset. For closures this will also get the type as /// written. This will return `None` when the index is out of bounds only for variadic /// functions, otherwise this will panic. - pub fn input_with_hir(self, i: usize) -> Option<(Option<&'tcx hir::Ty<'tcx>>, Binder<'tcx, Ty<'tcx>>)> { + pub fn input_with_hir( + self, + i: usize, + ) -> Option<(Option<&'tcx hir::Ty<'tcx>>, Binder<'tcx, Ty<'tcx>>)> { match self { Self::Sig(sig, _) => { if sig.c_variadic() { @@ -528,7 +540,7 @@ impl<'tcx> ExprFnSig<'tcx> { } else { Some((None, sig.input(i))) } - }, + } Self::Closure(decl, sig) => Some(( decl.and_then(|decl| decl.inputs.get(i)), sig.input(0).map_bound(|ty| ty.tuple_fields()[i]), @@ -547,17 +559,15 @@ impl<'tcx> ExprFnSig<'tcx> { } pub fn predicates_id(&self) -> Option { - if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self { - id - } else { - None - } + if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self { id } else { None } } } /// If the expression is function like, get the signature for it. pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option> { - if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = path_res(cx, expr) { + if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = + path_res(cx, expr) + { Some(ExprFnSig::Sig(cx.tcx.fn_sig(id), Some(id))) } else { ty_sig(cx, cx.typeck_results().expr_ty_adjusted(expr).peel_refs()) @@ -571,15 +581,17 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option { - let decl = id - .as_local() - .and_then(|id| cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id))); + let decl = id.as_local().and_then(|id| { + cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id)) + }); Some(ExprFnSig::Closure(decl, subs.as_closure().sig())) - }, - ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))), + } + ty::FnDef(id, subs) => { + Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))) + } ty::Opaque(id, _) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(id), cx.tcx.opt_parent(id)), ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)), - ty::Dynamic(bounds, _) => { + ty::Dynamic(bounds, _, _) => { let lang_items = cx.tcx.lang_items(); match bounds.principal() { Some(bound) @@ -589,16 +601,19 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option None, } - }, + } ty::Projection(proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) { Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty), - _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)), + _ => sig_for_projection(cx, proj) + .or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)), }, ty::Param(_) => sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None), _ => None, @@ -629,7 +644,7 @@ fn sig_from_bounds<'tcx>( return None; } inputs = Some(i); - }, + } PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() && p.projection_ty.self_ty() == ty => @@ -639,7 +654,7 @@ fn sig_from_bounds<'tcx>( return None; } output = Some(pred.kind().rebind(p.term.ty().unwrap())); - }, + } _ => (), } } @@ -647,7 +662,10 @@ fn sig_from_bounds<'tcx>( inputs.map(|ty| ExprFnSig::Trait(ty, output, predicates_id)) } -fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> Option> { +fn sig_for_projection<'tcx>( + cx: &LateContext<'tcx>, + ty: ProjectionTy<'tcx>, +) -> Option> { let mut inputs = None; let mut output = None; let lang_items = cx.tcx.lang_items(); @@ -673,8 +691,10 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O return None; } inputs = Some(i); - }, - PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => { + } + PredicateKind::Projection(p) + if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => + { if output.is_some() { // Multiple different fn trait impls. Is this even allowed? return None; @@ -683,7 +703,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O pred.map_bound(|pred| pred.kind().rebind(p.term.ty().unwrap())) .subst(cx.tcx, ty.substs), ); - }, + } _ => (), } } @@ -777,7 +797,10 @@ pub fn for_each_top_level_late_bound_region( ControlFlow::Continue(()) } } - fn visit_binder>(&mut self, t: &Binder<'tcx, T>) -> ControlFlow { + fn visit_binder>( + &mut self, + t: &Binder<'tcx, T>, + ) -> ControlFlow { self.index += 1; let res = t.super_visit_with(self); self.index -= 1; @@ -791,19 +814,27 @@ pub fn for_each_top_level_late_bound_region( pub fn variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<&'tcx VariantDef> { match res { Res::Def(DefKind::Struct, id) => Some(cx.tcx.adt_def(id).non_enum_variant()), - Res::Def(DefKind::Variant, id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).variant_with_id(id)), - Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).non_enum_variant()), + Res::Def(DefKind::Variant, id) => { + Some(cx.tcx.adt_def(cx.tcx.parent(id)).variant_with_id(id)) + } + Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => { + Some(cx.tcx.adt_def(cx.tcx.parent(id)).non_enum_variant()) + } Res::Def(DefKind::Ctor(CtorOf::Variant, _), id) => { let var_id = cx.tcx.parent(id); Some(cx.tcx.adt_def(cx.tcx.parent(var_id)).variant_with_id(var_id)) - }, + } Res::SelfCtor(id) => Some(cx.tcx.type_of(id).ty_adt_def().unwrap().non_enum_variant()), _ => None, } } /// Checks if the type is a type parameter implementing `FnOnce`, but not `FnMut`. -pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tcx [Predicate<'_>]) -> bool { +pub fn ty_is_fn_once_param<'tcx>( + tcx: TyCtxt<'_>, + ty: Ty<'tcx>, + predicates: &'tcx [Predicate<'_>], +) -> bool { let ty::Param(ty) = *ty.kind() else { return false; }; From de42ac39709f2307f20530c587bc2bdd110524fc Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Tue, 30 Aug 2022 12:42:54 -0700 Subject: [PATCH 14/16] Move dyn* tests to their own directory --- .../{async-await/dyn-star-trait-const.rs => dyn-star/const.rs} | 0 .../ui/{async-await/dyn-star-trait-drop.rs => dyn-star/drop.rs} | 0 .../dyn-star-trait-drop.run.stdout => dyn-star/drop.run.stdout} | 0 .../{async-await/dyn-star-trait-error.rs => dyn-star/error.rs} | 0 .../dyn-star-trait-error.stderr => dyn-star/error.stderr} | 2 +- .../dyn-star-trait-method.rs => dyn-star/method.rs} | 0 6 files changed, 1 insertion(+), 1 deletion(-) rename src/test/ui/{async-await/dyn-star-trait-const.rs => dyn-star/const.rs} (100%) rename src/test/ui/{async-await/dyn-star-trait-drop.rs => dyn-star/drop.rs} (100%) rename src/test/ui/{async-await/dyn-star-trait-drop.run.stdout => dyn-star/drop.run.stdout} (100%) rename src/test/ui/{async-await/dyn-star-trait-error.rs => dyn-star/error.rs} (100%) rename src/test/ui/{async-await/dyn-star-trait-error.stderr => dyn-star/error.stderr} (88%) rename src/test/ui/{async-await/dyn-star-trait-method.rs => dyn-star/method.rs} (100%) diff --git a/src/test/ui/async-await/dyn-star-trait-const.rs b/src/test/ui/dyn-star/const.rs similarity index 100% rename from src/test/ui/async-await/dyn-star-trait-const.rs rename to src/test/ui/dyn-star/const.rs diff --git a/src/test/ui/async-await/dyn-star-trait-drop.rs b/src/test/ui/dyn-star/drop.rs similarity index 100% rename from src/test/ui/async-await/dyn-star-trait-drop.rs rename to src/test/ui/dyn-star/drop.rs diff --git a/src/test/ui/async-await/dyn-star-trait-drop.run.stdout b/src/test/ui/dyn-star/drop.run.stdout similarity index 100% rename from src/test/ui/async-await/dyn-star-trait-drop.run.stdout rename to src/test/ui/dyn-star/drop.run.stdout diff --git a/src/test/ui/async-await/dyn-star-trait-error.rs b/src/test/ui/dyn-star/error.rs similarity index 100% rename from src/test/ui/async-await/dyn-star-trait-error.rs rename to src/test/ui/dyn-star/error.rs diff --git a/src/test/ui/async-await/dyn-star-trait-error.stderr b/src/test/ui/dyn-star/error.stderr similarity index 88% rename from src/test/ui/async-await/dyn-star-trait-error.stderr rename to src/test/ui/dyn-star/error.stderr index 932bc50ffde5a..92ae2780d293b 100644 --- a/src/test/ui/async-await/dyn-star-trait-error.stderr +++ b/src/test/ui/dyn-star/error.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `{integer}: Foo` is not satisfied - --> $DIR/dyn-star-trait-error.rs:9:27 + --> $DIR/error.rs:9:27 | LL | let dyn_i: dyn* Foo = i as dyn* Foo; | ^ the trait `Foo` is not implemented for `{integer}` diff --git a/src/test/ui/async-await/dyn-star-trait-method.rs b/src/test/ui/dyn-star/method.rs similarity index 100% rename from src/test/ui/async-await/dyn-star-trait-method.rs rename to src/test/ui/dyn-star/method.rs From cf04547b0b793b55f1255142dc07d3c8437f6815 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Tue, 30 Aug 2022 12:44:00 -0700 Subject: [PATCH 15/16] Address code review comments --- .../rustc_ast_passes/src/ast_validation.rs | 15 +- compiler/rustc_ast_passes/src/feature_gate.rs | 3 + .../src/value_and_place.rs | 1 + compiler/rustc_codegen_ssa/src/mir/block.rs | 2 +- .../rustc_const_eval/src/interpret/cast.rs | 11 +- .../src/transform/validate.rs | 2 +- compiler/rustc_feature/src/active.rs | 2 +- compiler/rustc_middle/src/ty/layout.rs | 11 +- compiler/rustc_monomorphize/src/collector.rs | 4 +- compiler/rustc_parse/src/parser/ty.rs | 4 +- .../src/typeid/typeid_itanium_cxx_abi.rs | 7 +- compiler/rustc_symbol_mangling/src/v0.rs | 8 +- .../src/traits/error_reporting/suggestions.rs | 4 +- .../src/traits/select/confirmation.rs | 8 +- compiler/rustc_traits/src/chalk/lowering.rs | 3 +- compiler/rustc_type_ir/src/sty.rs | 33 ++-- compiler/rustc_typeck/src/check/cast.rs | 9 +- src/test/ui/dyn-star/const.rs | 2 +- src/test/ui/dyn-star/drop.rs | 1 + src/test/ui/dyn-star/error.rs | 1 + src/test/ui/dyn-star/error.stderr | 2 +- src/test/ui/dyn-star/make-dyn-star.rs | 1 + src/test/ui/dyn-star/method.rs | 1 + src/test/ui/dyn-star/syntax.rs | 1 + .../clippy_lints/src/transmute/utils.rs | 27 +-- .../clippy_utils/src/qualify_min_const_fn.rs | 136 ++++++--------- src/tools/clippy/clippy_utils/src/ty.rs | 161 +++++++----------- 27 files changed, 199 insertions(+), 261 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 5558f0c8c7686..6a0a1b0836013 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -19,7 +19,6 @@ use rustc_session::lint::builtin::{ DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY, }; use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; -use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident}; @@ -754,19 +753,7 @@ impl<'a> AstValidator<'a> { self.maybe_lint_missing_abi(sig_span, ty.id); } } - TyKind::TraitObject(ref bounds, syntax, ..) => { - if syntax == TraitObjectSyntax::DynStar - && !self.session.features_untracked().dyn_star - { - feature_err( - &self.session.parse_sess, - sym::dyn_star, - ty.span, - "dyn* trait objects are unstable", - ) - .emit(); - } - + TyKind::TraitObject(ref bounds, ..) => { let mut any_lifetime_bounds = false; for bound in bounds { if let GenericBound::Outlives(ref lifetime) = *bound { diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index ca5b7a6415515..8a2b265c400da 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -573,6 +573,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::TyKind::Never => { gate_feature_post!(&self, never_type, ty.span, "the `!` type is experimental"); } + ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::DynStar, ..) => { + gate_feature_post!(&self, dyn_star, ty.span, "dyn* trait objects are unstable"); + } _ => {} } visit::walk_ty(self, ty) diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index d58b52851ac04..cfaadca949107 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -816,6 +816,7 @@ pub(crate) fn assert_assignable<'tcx>( // fn(&T) -> for<'l> fn(&'l T) is allowed } (&ty::Dynamic(from_traits, _, _from_kind), &ty::Dynamic(to_traits, _, _to_kind)) => { + // FIXME(dyn-star): Do the right thing with DynKinds for (from, to) in from_traits.iter().zip(to_traits) { let from = fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 7cee9ea3e1dc8..a6b226ef72096 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -367,7 +367,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.ret(llval); } - #[tracing::instrument(level = "debug", skip(self, helper, bx))] + #[tracing::instrument(level = "trace", skip(self, helper, bx))] fn codegen_drop_terminator( &mut self, helper: TerminatorCodegenHelper<'tcx>, diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 5301266b82452..cbe98548025bc 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -113,11 +113,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if let ty::Dynamic(data, _, ty::DynStar) = cast_ty.kind() { // Initial cast from sized to dyn trait let vtable = self.get_vtable_ptr(src.layout.ty, data.principal())?; - let ptr = self.read_immediate(src)?.to_scalar(); - // FIXME(dyn-star): This should not use new_dyn_trait, but - // it does exactly the same thing (makes a scalar pair)... - // so maybe we should just duplicate/rename the function. - let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx); + let vtable = Scalar::from_maybe_pointer(vtable, self); + let data = self.read_immediate(src)?.to_scalar(); + let _assert_pointer_sized = data.to_pointer(self)?; + let val = Immediate::ScalarPair(data, vtable); self.write_immediate(val, dest)?; } else { bug!() @@ -327,7 +326,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?; self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) } - (_, &ty::Dynamic(ref data, _, _repr)) => { + (_, &ty::Dynamic(ref data, _, ty::Dyn)) => { // Initial cast from sized to dyn trait let vtable = self.get_vtable_ptr(src_pointee_ty, data.principal())?; let ptr = self.read_scalar(src)?; diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 1c4c7e7079d64..4aa98cb13d82b 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -570,7 +570,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } CastKind::DynStar => { - // FIXME: make sure nothing needs to be done here. + // FIXME(dyn-star): make sure nothing needs to be done here. } // Nothing to check here CastKind::PointerFromExposedAddress diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 72f7064b6cae6..d5ec5feffa732 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -381,7 +381,7 @@ declare_features! ( /// Allows `#[doc(masked)]`. (active, doc_masked, "1.21.0", Some(44027), None), /// Allows `dyn* Trait` objects. - (active, dyn_star, "1.65.0", Some(91611), None), + (incomplete, dyn_star, "CURRENT_RUSTC_VERSION", Some(91611), None), /// Allows `X..Y` patterns. (active, exclusive_range_pattern, "1.11.0", Some(37854), None), /// Allows exhaustive pattern matching on types that contain uninhabited types. diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index b8c4534307cc6..042eeec3f4622 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -626,11 +626,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } ty::Dynamic(_, _, ty::DynStar) => { - let mut pointer = scalar_unit(Int(dl.ptr_sized_integer(), false)); - pointer.valid_range_mut().start = 1; + let mut data = scalar_unit(Int(dl.ptr_sized_integer(), false)); + data.valid_range_mut().start = 0; let mut vtable = scalar_unit(Pointer); vtable.valid_range_mut().start = 1; - tcx.intern_layout(self.scalar_pair(pointer, vtable)) + tcx.intern_layout(self.scalar_pair(data, vtable)) } // Arrays and slices. @@ -2474,8 +2474,7 @@ where match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() { ty::Slice(_) | ty::Str => TyMaybeWithLayout::Ty(tcx.types.usize), - // FIXME(eholk): Do the right thing with trait object representation - ty::Dynamic(_, _, _repr) => { + ty::Dynamic(_, _, ty::Dyn) => { TyMaybeWithLayout::Ty(tcx.mk_imm_ref( tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3), @@ -3379,7 +3378,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { Ok(self.tcx.arena.alloc(fn_abi)) } - #[tracing::instrument(level = "debug", skip(self))] + #[tracing::instrument(level = "trace", skip(self))] fn fn_abi_adjust_for_abi( &self, fn_abi: &mut FnAbi<'tcx, Ty<'tcx>>, diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 4e7eba2d02fef..2a843ab0b8b4b 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -699,7 +699,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // This could also be a different Unsize instruction, like // from a fixed sized array to a slice. But we are only // interested in things that produce a vtable. - if (target_ty.is_trait() || target_ty.is_dyn_star()) && !source_ty.is_trait() { + if (target_ty.is_trait() && !source_ty.is_trait()) + || (target_ty.is_dyn_star() && !source_ty.is_dyn_star()) + { create_mono_items_for_vtable_methods( self.tcx, target_ty, diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index ffe3618bc4951..b47f0c0978381 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -579,9 +579,7 @@ impl<'a> Parser<'a> { self.bump(); // `dyn` // parse dyn* types - let dyn_star = matches!(self.token.kind, TokenKind::BinOp(token::Star)); - let syntax = if dyn_star { - self.bump(); // `*` + let syntax = if self.eat(&TokenKind::BinOp(token::Star)) { TraitObjectSyntax::DynStar } else { TraitObjectSyntax::Dyn 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 7621ba571fd47..aa65a72ab646a 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 @@ -627,10 +627,13 @@ fn encode_ty<'tcx>( } // Trait types - ty::Dynamic(predicates, region, _repr) => { + ty::Dynamic(predicates, region, kind) => { // u3dynIE, where is , as // vendor extended type. - let mut s = String::from("u3dynI"); + let mut s = String::from(match kind { + ty::Dyn => "u3dynI", + ty::DynStar => "u7dynstarI", + }); s.push_str(&encode_predicates(tcx, predicates, dict, options)); s.push_str(&encode_region(tcx, *region, dict, options)); s.push('E'); diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index cedc87f5e2bba..79d0ef69ba733 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -479,8 +479,12 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { })?; } - ty::Dynamic(predicates, r, _repr) => { - self.push("D"); + ty::Dynamic(predicates, r, kind) => { + self.push(match kind { + ty::Dyn => "D", + // FIXME(dyn-star): need to update v0 mangling docs + ty::DynStar => "D*", + }); self = self.print_dyn_existential(predicates)?; self = r.print(self)?; } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index e1d548323bf4a..bd73ec4716060 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1067,7 +1067,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self_ty: Ty<'tcx>, object_ty: Ty<'tcx>, ) { - let ty::Dynamic(predicates, _, _) = object_ty.kind() else { return; }; + let ty::Dynamic(predicates, _, ty::Dyn) = object_ty.kind() else { return; }; let self_ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, self_ty); for predicate in predicates.iter() { @@ -1365,7 +1365,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let trait_pred = self.resolve_vars_if_possible(trait_pred); let ty = trait_pred.skip_binder().self_ty(); let is_object_safe = match ty.kind() { - ty::Dynamic(predicates, _, _) => { + ty::Dynamic(predicates, _, ty::Dyn) => { // If the `dyn Trait` is not object safe, do not suggest `Box`. predicates .principal_def_id() diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 158b00e275e67..43c4ddd3f6faf 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -890,9 +890,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut nested = vec![]; match (source.kind(), target.kind()) { // Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping). - (&ty::Dynamic(ref data_a, r_a, repr_a), &ty::Dynamic(ref data_b, r_b, repr_b)) - if repr_a == repr_b => - { + (&ty::Dynamic(ref data_a, r_a, ty::Dyn), &ty::Dynamic(ref data_b, r_b, ty::Dyn)) => { // See `assemble_candidates_for_unsizing` for more info. // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`. let iter = data_a @@ -911,7 +909,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map(ty::Binder::dummy), ); let existential_predicates = tcx.mk_poly_existential_predicates(iter); - let source_trait = tcx.mk_dynamic(existential_predicates, r_b, repr_b); + let source_trait = tcx.mk_dynamic(existential_predicates, r_b, ty::Dyn); // Require that the traits involved in this upcast are **equal**; // only the **lifetime bound** is changed. @@ -938,7 +936,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // `T` -> `Trait` - (_, &ty::Dynamic(ref data, r, _repr)) => { + (_, &ty::Dynamic(ref data, r, ty::Dyn)) => { let mut object_dids = data.auto_traits().chain(data.principal_def_id()); if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) { return Err(TraitNotObjectSafe(did)); diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 86da6d7bbd1e2..45d5ea93d547f 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -326,7 +326,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { )), }) } - ty::Dynamic(predicates, region, _repr) => chalk_ir::TyKind::Dyn(chalk_ir::DynTy { + // FIXME(dyn-star): handle the dynamic kind (dyn or dyn*) + ty::Dynamic(predicates, region, _kind) => chalk_ir::TyKind::Dyn(chalk_ir::DynTy { bounds: predicates.lower_into(interner), lifetime: region.lower_into(interner), }), diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index f8090cd9dd831..6d54924e515fc 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -19,26 +19,33 @@ use rustc_data_structures::stable_hasher::HashStable; use rustc_serialize::{Decodable, Decoder, Encodable}; /// Specifies how a trait object is represented. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)] +#[derive( + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Debug, + Encodable, + Decodable, + HashStable_Generic +)] pub enum DynKind { /// An unsized `dyn Trait` object Dyn, /// A sized `dyn* Trait` object + /// + /// These objects are represented as a `(data, vtable)` pair where `data` is a ptr-sized value + /// (often a pointer to the real object, but not necessarily) and `vtable` is a pointer to + /// the vtable for `dyn* Trait`. The representation is essentially the same as `&dyn Trait` + /// or similar, but the drop function included in the vtable is responsible for freeing the + /// underlying storage if needed. This allows a `dyn*` object to be treated agnostically with + /// respect to whether it points to a `Box`, `Rc`, etc. DynStar, } -// Manually implemented because deriving HashStable requires rustc_query_system, which would -// create a cyclic dependency. -impl HashStable for DynKind { - fn hash_stable( - &self, - hcx: &mut CTX, - hasher: &mut rustc_data_structures::stable_hasher::StableHasher, - ) { - std::mem::discriminant(self).hash_stable(hcx, hasher); - } -} - /// Defines the kinds of types used by the type system. /// /// Types written by the user start out as `hir::TyKind` and get diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 640aa8c65ed83..81a979865acc3 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -105,7 +105,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(match *t.kind() { ty::Slice(_) | ty::Str => Some(PointerKind::Length), - ty::Dynamic(ref tty, ..) => Some(PointerKind::VTable(tty.principal_def_id())), + ty::Dynamic(ref tty, _, ty::Dyn) => Some(PointerKind::VTable(tty.principal_def_id())), ty::Adt(def, substs) if def.is_struct() => match def.non_enum_variant().fields.last() { None => Some(PointerKind::Thin), Some(f) => { @@ -142,6 +142,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::Generator(..) | ty::Adt(..) | ty::Never + | ty::Dynamic(_, _, ty::DynStar) | ty::Error(_) => { let reported = self .tcx @@ -246,7 +247,7 @@ fn check_dyn_star_cast<'tcx>( let cause = ObligationCause::new( expr.span, fcx.body_id, - // FIXME: Use a better obligation cause code + // FIXME(dyn-star): Use a better obligation cause code ObligationCauseCode::MiscObligation, ); @@ -927,10 +928,10 @@ impl<'a, 'tcx> CastCheck<'tcx> { (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast), - // FIXME: this needs more conditions... + // FIXME(dyn-star): this needs more conditions... (_, DynStar) => Ok(CastKind::DynStarCast), - // FIXME: do we want to allow dyn* upcasting or other casts? + // FIXME(dyn-star): do we want to allow dyn* upcasting or other casts? (DynStar, _) => Err(CastError::IllegalCast), } } diff --git a/src/test/ui/dyn-star/const.rs b/src/test/ui/dyn-star/const.rs index 29a1a0d025305..e49caf649f892 100644 --- a/src/test/ui/dyn-star/const.rs +++ b/src/test/ui/dyn-star/const.rs @@ -1,6 +1,6 @@ // run-pass #![feature(dyn_star)] -#![allow(unused)] +#![allow(unused, incomplete_features)] use std::fmt::Debug; diff --git a/src/test/ui/dyn-star/drop.rs b/src/test/ui/dyn-star/drop.rs index 2ce77593777aa..46b232f3dd399 100644 --- a/src/test/ui/dyn-star/drop.rs +++ b/src/test/ui/dyn-star/drop.rs @@ -1,6 +1,7 @@ // run-pass // check-run-results #![feature(dyn_star)] +#![allow(incomplete_features)] use std::fmt::Debug; diff --git a/src/test/ui/dyn-star/error.rs b/src/test/ui/dyn-star/error.rs index 81f7f39ae1359..33eff80a5fe70 100644 --- a/src/test/ui/dyn-star/error.rs +++ b/src/test/ui/dyn-star/error.rs @@ -1,4 +1,5 @@ #![feature(dyn_star)] +#![allow(incomplete_features)] use std::fmt::Debug; diff --git a/src/test/ui/dyn-star/error.stderr b/src/test/ui/dyn-star/error.stderr index 92ae2780d293b..d612ccc630ea8 100644 --- a/src/test/ui/dyn-star/error.stderr +++ b/src/test/ui/dyn-star/error.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `{integer}: Foo` is not satisfied - --> $DIR/error.rs:9:27 + --> $DIR/error.rs:10:27 | LL | let dyn_i: dyn* Foo = i as dyn* Foo; | ^ the trait `Foo` is not implemented for `{integer}` diff --git a/src/test/ui/dyn-star/make-dyn-star.rs b/src/test/ui/dyn-star/make-dyn-star.rs index b0b8f07abe58e..708ffa25d6fee 100644 --- a/src/test/ui/dyn-star/make-dyn-star.rs +++ b/src/test/ui/dyn-star/make-dyn-star.rs @@ -1,5 +1,6 @@ // run-pass #![feature(dyn_star)] +#![allow(incomplete_features)] use std::fmt::Debug; diff --git a/src/test/ui/dyn-star/method.rs b/src/test/ui/dyn-star/method.rs index 4d32db034a4da..d04958ca2aac9 100644 --- a/src/test/ui/dyn-star/method.rs +++ b/src/test/ui/dyn-star/method.rs @@ -1,5 +1,6 @@ // run-pass #![feature(dyn_star)] +#![allow(incomplete_features)] trait Foo { fn get(&self) -> usize; diff --git a/src/test/ui/dyn-star/syntax.rs b/src/test/ui/dyn-star/syntax.rs index 7848996e5e022..618c72562b2a7 100644 --- a/src/test/ui/dyn-star/syntax.rs +++ b/src/test/ui/dyn-star/syntax.rs @@ -3,6 +3,7 @@ // check-pass #![feature(dyn_star)] +#![allow(incomplete_features)] pub fn dyn_star_parameter(_: dyn* Send) { } diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs index 78cc589cc291b..8bdadf2440231 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs @@ -2,18 +2,11 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{cast::CastKind, Ty}; use rustc_span::DUMMY_SP; -use rustc_typeck::check::{ - cast::{self, CastCheckResult}, - FnCtxt, Inherited, -}; +use rustc_typeck::check::{cast::{self, CastCheckResult}, FnCtxt, Inherited}; // check if the component types of the transmuted collection and the result have different ABI, // size or alignment -pub(super) fn is_layout_incompatible<'tcx>( - cx: &LateContext<'tcx>, - from: Ty<'tcx>, - to: Ty<'tcx>, -) -> bool { +pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx>, to: Ty<'tcx>) -> bool { if let Ok(from) = cx.tcx.try_normalize_erasing_regions(cx.param_env, from) && let Ok(to) = cx.tcx.try_normalize_erasing_regions(cx.param_env, to) && let Ok(from_layout) = cx.tcx.layout_of(cx.param_env.and(from)) @@ -36,9 +29,7 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>( from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, ) -> bool { - use CastKind::{ - AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast, - }; + use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast}; matches!( check_cast(cx, e, from_ty, to_ty), Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) @@ -49,12 +40,7 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>( /// the cast. In certain cases, including some invalid casts from array references /// to pointers, this may cause additional errors to be emitted and/or ICE error /// messages. This function will panic if that occurs. -fn check_cast<'tcx>( - cx: &LateContext<'tcx>, - e: &'tcx Expr<'_>, - from_ty: Ty<'tcx>, - to_ty: Ty<'tcx>, -) -> Option { +fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option { let hir_id = e.hir_id; let local_def_id = hir_id.owner; @@ -62,7 +48,10 @@ fn check_cast<'tcx>( let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, hir_id); // If we already have errors, we can't be sure we can pointer cast. - assert!(!fn_ctxt.errors_reported_since_creation(), "Newly created FnCtxt contained errors"); + assert!( + !fn_ctxt.errors_reported_since_creation(), + "Newly created FnCtxt contained errors" + ); if let CastCheckResult::Deferred(check) = cast::check_cast( &fn_ctxt, e, from_ty, to_ty, diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 781744870cb91..8835b93290958 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -18,11 +18,7 @@ use std::borrow::Cow; type McfResult = Result<(), (Span, Cow<'static, str>)>; -pub fn is_min_const_fn<'a, 'tcx>( - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - msrv: Option, -) -> McfResult { +pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option) -> McfResult { let def_id = body.source.def_id(); let mut current = def_id; loop { @@ -37,18 +33,10 @@ pub fn is_min_const_fn<'a, 'tcx>( | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Trait(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue, - ty::PredicateKind::ObjectSafe(_) => { - panic!("object safe predicate on function: {:#?}", predicate) - } - ty::PredicateKind::ClosureKind(..) => { - panic!("closure kind predicate on function: {:#?}", predicate) - } - ty::PredicateKind::Subtype(_) => { - panic!("subtype predicate on function: {:#?}", predicate) - } - ty::PredicateKind::Coerce(_) => { - panic!("coerce predicate on function: {:#?}", predicate) - } + ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate), + ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate), + ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate), + ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {:#?}", predicate), } } match predicates.parent { @@ -89,23 +77,22 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { match ty.kind() { ty::Ref(_, _, hir::Mutability::Mut) => { return Err((span, "mutable references in const fn are unstable".into())); - } + }, ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())), ty::FnPtr(..) => { return Err((span, "function pointers in const fn are unstable".into())); - } + }, ty::Dynamic(preds, _, _) => { for pred in preds.iter() { match pred.skip_binder() { - ty::ExistentialPredicate::AutoTrait(_) - | ty::ExistentialPredicate::Projection(_) => { + ty::ExistentialPredicate::AutoTrait(_) | ty::ExistentialPredicate::Projection(_) => { return Err(( span, "trait bounds other than `Sized` \ on const fn parameters are unstable" .into(), )); - } + }, ty::ExistentialPredicate::Trait(trait_ref) => { if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() { return Err(( @@ -115,11 +102,11 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { .into(), )); } - } + }, } } - } - _ => {} + }, + _ => {}, } } Ok(()) @@ -133,13 +120,10 @@ fn check_rvalue<'tcx>( span: Span, ) -> McfResult { match rvalue { - Rvalue::ThreadLocalRef(_) => { - Err((span, "cannot access thread local storage in const fn".into())) - } - Rvalue::Len(place) - | Rvalue::Discriminant(place) - | Rvalue::Ref(_, _, place) - | Rvalue::AddressOf(_, place) => check_place(tcx, *place, span, body), + Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())), + Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { + check_place(tcx, *place, span, body) + }, Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body), Rvalue::Repeat(operand, _) | Rvalue::Use(operand) @@ -152,9 +136,7 @@ fn check_rvalue<'tcx>( ) => check_operand(tcx, operand, span, body), Rvalue::Cast( CastKind::Pointer( - PointerCast::UnsafeFnPointer - | PointerCast::ClosureFnPointer(_) - | PointerCast::ReifyFnPointer, + PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) | PointerCast::ReifyFnPointer, ), _, _, @@ -164,10 +146,7 @@ fn check_rvalue<'tcx>( deref_ty.ty } else { // We cannot allow this for now. - return Err(( - span, - "unsizing casts are only allowed for references right now".into(), - )); + return Err((span, "unsizing casts are only allowed for references right now".into())); }; let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id)); if let ty::Slice(_) | ty::Str = unsized_ty.kind() { @@ -178,14 +157,14 @@ fn check_rvalue<'tcx>( // We just can't allow trait objects until we have figured out trait method calls. Err((span, "unsizing casts are not allowed in const fn".into())) } - } + }, Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => { Err((span, "casting pointers to ints is unstable in const fn".into())) - } + }, Rvalue::Cast(CastKind::DynStar, _, _) => { // FIXME(dyn-star) unimplemented!() - } + }, // binops are fine on integers Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => { check_operand(tcx, lhs, span, body)?; @@ -194,12 +173,13 @@ fn check_rvalue<'tcx>( if ty.is_integral() || ty.is_bool() || ty.is_char() { Ok(()) } else { - Err((span, "only int, `bool` and `char` operations are stable in const fn".into())) + Err(( + span, + "only int, `bool` and `char` operations are stable in const fn".into(), + )) } - } - Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::ShallowInitBox(_, _) => { - Ok(()) - } + }, + Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::ShallowInitBox(_, _) => Ok(()), Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, tcx); if ty.is_integral() || ty.is_bool() { @@ -207,13 +187,13 @@ fn check_rvalue<'tcx>( } else { Err((span, "only int and `bool` operations are stable in const fn".into())) } - } + }, Rvalue::Aggregate(_, operands) => { for operand in operands { check_operand(tcx, operand, span, body)?; } Ok(()) - } + }, } } @@ -228,7 +208,7 @@ fn check_statement<'tcx>( StatementKind::Assign(box (place, rval)) => { check_place(tcx, *place, span, body)?; check_rvalue(tcx, body, def_id, rval, span) - } + }, StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body), // just an assignment @@ -238,15 +218,13 @@ fn check_statement<'tcx>( StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(tcx, op, span, body), - StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { - dst, - src, - count, - }) => { + StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping( + rustc_middle::mir::CopyNonOverlapping { dst, src, count }, + )) => { check_operand(tcx, dst, span, body)?; check_operand(tcx, src, span, body)?; check_operand(tcx, count, span, body) - } + }, // These are all NOPs StatementKind::StorageLive(_) | StatementKind::StorageDead(_) @@ -257,12 +235,7 @@ fn check_statement<'tcx>( } } -fn check_operand<'tcx>( - tcx: TyCtxt<'tcx>, - operand: &Operand<'tcx>, - span: Span, - body: &Body<'tcx>, -) -> McfResult { +fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { match operand { Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, body), Operand::Constant(c) => match c.check_static_ptr(tcx) { @@ -272,12 +245,7 @@ fn check_operand<'tcx>( } } -fn check_place<'tcx>( - tcx: TyCtxt<'tcx>, - place: Place<'tcx>, - span: Span, - body: &Body<'tcx>, -) -> McfResult { +fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { let mut cursor = place.projection.as_ref(); while let [ref proj_base @ .., elem] = *cursor { cursor = proj_base; @@ -290,12 +258,12 @@ fn check_place<'tcx>( return Err((span, "accessing union fields is unstable".into())); } } - } + }, ProjectionElem::ConstantIndex { .. } | ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } | ProjectionElem::Deref - | ProjectionElem::Index(_) => {} + | ProjectionElem::Index(_) => {}, } } @@ -321,16 +289,18 @@ fn check_terminator<'a, 'tcx>( TerminatorKind::DropAndReplace { place, value, .. } => { check_place(tcx, *place, span, body)?; check_operand(tcx, value, span, body) - } + }, - TerminatorKind::SwitchInt { discr, switch_ty: _, targets: _ } => { - check_operand(tcx, discr, span, body) - } + TerminatorKind::SwitchInt { + discr, + switch_ty: _, + targets: _, + } => check_operand(tcx, discr, span, body), TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())), TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { Err((span, "const fn generators are unstable".into())) - } + }, TerminatorKind::Call { func, @@ -375,15 +345,17 @@ fn check_terminator<'a, 'tcx>( } else { Err((span, "can only call other const fns within const fn".into())) } - } + }, - TerminatorKind::Assert { cond, expected: _, msg: _, target: _, cleanup: _ } => { - check_operand(tcx, cond, span, body) - } + TerminatorKind::Assert { + cond, + expected: _, + msg: _, + target: _, + cleanup: _, + } => check_operand(tcx, cond, span, body), - TerminatorKind::InlineAsm { .. } => { - Err((span, "cannot use inline assembly in const fn".into())) - } + TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())), } } diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 99803ae93a712..a8ad6cf4f6a3c 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -14,9 +14,8 @@ use rustc_lint::LateContext; use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; use rustc_middle::ty::{ - self, AdtDef, Binder, BoundRegion, DefIdTree, FnSig, IntTy, ParamEnv, Predicate, PredicateKind, - ProjectionTy, Region, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, - UintTy, VariantDef, VariantDiscr, + self, AdtDef, Binder, BoundRegion, DefIdTree, FnSig, IntTy, ParamEnv, Predicate, PredicateKind, ProjectionTy, + Region, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; @@ -167,7 +166,9 @@ pub fn implements_trait_with_env<'tcx>( } let ty_params = tcx.mk_substs(ty_params.iter()); tcx.infer_ctxt().enter(|infcx| { - infcx.type_implements_trait(trait_id, ty, ty_params, param_env).must_apply_modulo_regions() + infcx + .type_implements_trait(trait_id, ty, ty_params, param_env) + .must_apply_modulo_regions() }) } @@ -184,14 +185,11 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind() { ty::Adt(adt, _) => cx.tcx.has_attr(adt.did(), sym::must_use), ty::Foreign(did) => cx.tcx.has_attr(*did, sym::must_use), - ty::Slice(ty) - | ty::Array(ty, _) - | ty::RawPtr(ty::TypeAndMut { ty, .. }) - | ty::Ref(_, ty, _) => { + ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => { // for the Array case we don't need to care for the len == 0 case // because we don't want to lint functions returning empty arrays is_must_use_ty(cx, *ty) - } + }, ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)), ty::Opaque(def_id, _) => { for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { @@ -202,7 +200,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { } } false - } + }, ty::Dynamic(binder, _, _) => { for predicate in binder.iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { @@ -212,7 +210,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { } } false - } + }, _ => false, } } @@ -222,11 +220,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { // not succeed /// Checks if `Ty` is normalizable. This function is useful /// to avoid crashes on `layout_of`. -pub fn is_normalizable<'tcx>( - cx: &LateContext<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, -) -> bool { +pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default()) } @@ -246,14 +240,15 @@ fn is_normalizable_helper<'tcx>( if infcx.at(&cause, param_env).normalize(ty).is_ok() { match ty.kind() { ty::Adt(def, substs) => def.variants().iter().all(|variant| { - variant.fields.iter().all(|field| { - is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache) - }) + variant + .fields + .iter() + .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache)) }), _ => ty.walk().all(|generic_arg| match generic_arg.unpack() { GenericArgKind::Type(inner_ty) if inner_ty != ty => { is_normalizable_helper(cx, param_env, inner_ty, cache) - } + }, _ => true, // if inner_ty == ty, we've already checked it }), } @@ -278,9 +273,7 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool { match *ty.kind() { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true, ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true, - ty::Array(inner_type, _) | ty::Slice(inner_type) => { - is_recursively_primitive_type(inner_type) - } + ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type), ty::Tuple(inner_types) => inner_types.iter().all(is_recursively_primitive_type), _ => false, } @@ -320,9 +313,11 @@ pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symb /// Returns `false` if the `LangItem` is not defined. pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool { match ty.kind() { - ty::Adt(adt, _) => { - cx.tcx.lang_items().require(lang_item).map_or(false, |li| li == adt.did()) - } + ty::Adt(adt, _) => cx + .tcx + .lang_items() + .require(lang_item) + .map_or(false, |li| li == adt.did()), _ => false, } } @@ -347,11 +342,7 @@ pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool { /// deallocate memory. For these types, and composites containing them, changing the drop order /// won't result in any observable side effects. pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - fn needs_ordered_drop_inner<'tcx>( - cx: &LateContext<'tcx>, - ty: Ty<'tcx>, - seen: &mut FxHashSet>, - ) -> bool { + fn needs_ordered_drop_inner<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, seen: &mut FxHashSet>) -> bool { if !seen.insert(ty) { return false; } @@ -402,7 +393,11 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { /// removed. pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) { fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) { - if let ty::Ref(_, ty, _) = ty.kind() { peel(*ty, count + 1) } else { (ty, count) } + if let ty::Ref(_, ty, _) = ty.kind() { + peel(*ty, count + 1) + } else { + (ty, count) + } } peel(ty, 0) } @@ -457,18 +452,17 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { return false; } - substs_a.iter().zip(substs_b.iter()).all(|(arg_a, arg_b)| { - match (arg_a.unpack(), arg_b.unpack()) { - (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => { - inner_a == inner_b - } + substs_a + .iter() + .zip(substs_b.iter()) + .all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) { + (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b, (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => { same_type_and_consts(type_a, type_b) - } + }, _ => true, - } - }) - } + }) + }, _ => a == b, } } @@ -484,10 +478,7 @@ pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { } /// Gets an iterator over all predicates which apply to the given item. -pub fn all_predicates_of( - tcx: TyCtxt<'_>, - id: DefId, -) -> impl Iterator, Span)> { +pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator, Span)> { let mut next_id = Some(id); iter::from_fn(move || { next_id.take().map(|id| { @@ -517,7 +508,7 @@ impl<'tcx> ExprFnSig<'tcx> { } else { Some(sig.input(i)) } - } + }, Self::Closure(_, sig) => Some(sig.input(0).map_bound(|ty| ty.tuple_fields()[i])), Self::Trait(inputs, _, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])), } @@ -526,10 +517,7 @@ impl<'tcx> ExprFnSig<'tcx> { /// Gets the argument type at the given offset. For closures this will also get the type as /// written. This will return `None` when the index is out of bounds only for variadic /// functions, otherwise this will panic. - pub fn input_with_hir( - self, - i: usize, - ) -> Option<(Option<&'tcx hir::Ty<'tcx>>, Binder<'tcx, Ty<'tcx>>)> { + pub fn input_with_hir(self, i: usize) -> Option<(Option<&'tcx hir::Ty<'tcx>>, Binder<'tcx, Ty<'tcx>>)> { match self { Self::Sig(sig, _) => { if sig.c_variadic() { @@ -540,7 +528,7 @@ impl<'tcx> ExprFnSig<'tcx> { } else { Some((None, sig.input(i))) } - } + }, Self::Closure(decl, sig) => Some(( decl.and_then(|decl| decl.inputs.get(i)), sig.input(0).map_bound(|ty| ty.tuple_fields()[i]), @@ -559,15 +547,17 @@ impl<'tcx> ExprFnSig<'tcx> { } pub fn predicates_id(&self) -> Option { - if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self { id } else { None } + if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self { + id + } else { + None + } } } /// If the expression is function like, get the signature for it. pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option> { - if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = - path_res(cx, expr) - { + if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = path_res(cx, expr) { Some(ExprFnSig::Sig(cx.tcx.fn_sig(id), Some(id))) } else { ty_sig(cx, cx.typeck_results().expr_ty_adjusted(expr).peel_refs()) @@ -581,14 +571,12 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option { - let decl = id.as_local().and_then(|id| { - cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id)) - }); + let decl = id + .as_local() + .and_then(|id| cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id))); Some(ExprFnSig::Closure(decl, subs.as_closure().sig())) - } - ty::FnDef(id, subs) => { - Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))) - } + }, + ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))), ty::Opaque(id, _) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(id), cx.tcx.opt_parent(id)), ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)), ty::Dynamic(bounds, _, _) => { @@ -601,19 +589,16 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option None, } - } + }, ty::Projection(proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) { Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty), - _ => sig_for_projection(cx, proj) - .or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)), + _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)), }, ty::Param(_) => sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None), _ => None, @@ -644,7 +629,7 @@ fn sig_from_bounds<'tcx>( return None; } inputs = Some(i); - } + }, PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() && p.projection_ty.self_ty() == ty => @@ -654,7 +639,7 @@ fn sig_from_bounds<'tcx>( return None; } output = Some(pred.kind().rebind(p.term.ty().unwrap())); - } + }, _ => (), } } @@ -662,10 +647,7 @@ fn sig_from_bounds<'tcx>( inputs.map(|ty| ExprFnSig::Trait(ty, output, predicates_id)) } -fn sig_for_projection<'tcx>( - cx: &LateContext<'tcx>, - ty: ProjectionTy<'tcx>, -) -> Option> { +fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> Option> { let mut inputs = None; let mut output = None; let lang_items = cx.tcx.lang_items(); @@ -691,10 +673,8 @@ fn sig_for_projection<'tcx>( return None; } inputs = Some(i); - } - PredicateKind::Projection(p) - if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => - { + }, + PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => { if output.is_some() { // Multiple different fn trait impls. Is this even allowed? return None; @@ -703,7 +683,7 @@ fn sig_for_projection<'tcx>( pred.map_bound(|pred| pred.kind().rebind(p.term.ty().unwrap())) .subst(cx.tcx, ty.substs), ); - } + }, _ => (), } } @@ -797,10 +777,7 @@ pub fn for_each_top_level_late_bound_region( ControlFlow::Continue(()) } } - fn visit_binder>( - &mut self, - t: &Binder<'tcx, T>, - ) -> ControlFlow { + fn visit_binder>(&mut self, t: &Binder<'tcx, T>) -> ControlFlow { self.index += 1; let res = t.super_visit_with(self); self.index -= 1; @@ -814,27 +791,19 @@ pub fn for_each_top_level_late_bound_region( pub fn variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<&'tcx VariantDef> { match res { Res::Def(DefKind::Struct, id) => Some(cx.tcx.adt_def(id).non_enum_variant()), - Res::Def(DefKind::Variant, id) => { - Some(cx.tcx.adt_def(cx.tcx.parent(id)).variant_with_id(id)) - } - Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => { - Some(cx.tcx.adt_def(cx.tcx.parent(id)).non_enum_variant()) - } + Res::Def(DefKind::Variant, id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).variant_with_id(id)), + Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).non_enum_variant()), Res::Def(DefKind::Ctor(CtorOf::Variant, _), id) => { let var_id = cx.tcx.parent(id); Some(cx.tcx.adt_def(cx.tcx.parent(var_id)).variant_with_id(var_id)) - } + }, Res::SelfCtor(id) => Some(cx.tcx.type_of(id).ty_adt_def().unwrap().non_enum_variant()), _ => None, } } /// Checks if the type is a type parameter implementing `FnOnce`, but not `FnMut`. -pub fn ty_is_fn_once_param<'tcx>( - tcx: TyCtxt<'_>, - ty: Ty<'tcx>, - predicates: &'tcx [Predicate<'_>], -) -> bool { +pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tcx [Predicate<'_>]) -> bool { let ty::Param(ty) = *ty.kind() else { return false; }; From 0faafbf1d91f7b9ea4c775cd33cf12008575a35b Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Tue, 13 Sep 2022 15:32:38 -0700 Subject: [PATCH 16/16] Update parsing test --- src/test/ui/parser/trait-object-delimiters.rs | 2 +- src/test/ui/parser/trait-object-delimiters.stderr | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/ui/parser/trait-object-delimiters.rs b/src/test/ui/parser/trait-object-delimiters.rs index b5258eebb90ad..cc04ac052040e 100644 --- a/src/test/ui/parser/trait-object-delimiters.rs +++ b/src/test/ui/parser/trait-object-delimiters.rs @@ -6,7 +6,7 @@ fn foo1(_: &dyn Drop + AsRef) {} //~ ERROR ambiguous `+` in a type fn foo2(_: &dyn (Drop + AsRef)) {} //~ ERROR incorrect braces around trait bounds fn foo3(_: &dyn {Drop + AsRef}) {} //~ ERROR expected parameter name, found `{` -//~^ ERROR expected one of `!`, `(`, `)`, `,`, `?`, `for`, `~`, lifetime, or path, found `{` +//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{` //~| ERROR at least one trait is required for an object type fn foo4(_: &dyn >) {} //~ ERROR expected identifier, found `<` diff --git a/src/test/ui/parser/trait-object-delimiters.stderr b/src/test/ui/parser/trait-object-delimiters.stderr index 6eb9c7238cb82..99c4515459d2e 100644 --- a/src/test/ui/parser/trait-object-delimiters.stderr +++ b/src/test/ui/parser/trait-object-delimiters.stderr @@ -22,11 +22,11 @@ error: expected parameter name, found `{` LL | fn foo3(_: &dyn {Drop + AsRef}) {} | ^ expected parameter name -error: expected one of `!`, `(`, `)`, `,`, `?`, `for`, `~`, lifetime, or path, found `{` +error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{` --> $DIR/trait-object-delimiters.rs:8:17 | LL | fn foo3(_: &dyn {Drop + AsRef}) {} - | -^ expected one of 9 possible tokens + | -^ expected one of 10 possible tokens | | | help: missing `,`