diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 65e697c8f3b80..e808e4815fe0b 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -825,6 +825,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_variance_of_opaques, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_hidden_type_of_opaques, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing), rustc_attr!(TEST, rustc_abi, Normal, template!(List: "field1, field2, ..."), WarnFollowing), rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing), diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index ee475e3de7e99..6bf6650986a67 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -339,6 +339,8 @@ hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$de .label = needs at most one field with non-trivial size or alignment, but has {$field_count} .labels = this field has non-zero size or requires alignment +hir_analysis_type_of = {$type_of} + hir_analysis_typeof_reserved_keyword_used = `typeof` is a reserved keyword but unimplemented .suggestion = consider replacing `typeof(...)` with an actual type diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 640138a3e5eff..9636c6144461b 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -14,14 +14,11 @@ //! At present, however, we do run collection across all items in the //! crate as a kind of pass. This should eventually be factored away. -use crate::astconv::AstConv; -use crate::check::intrinsic::intrinsic_operation_unsafety; -use crate::errors; -use hir::def::DefKind; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey}; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{GenericParamKind, Node}; @@ -40,6 +37,11 @@ use rustc_trait_selection::traits::ObligationCtxt; use std::iter; use std::ops::Bound; +use crate::astconv::AstConv; +use crate::check::intrinsic::intrinsic_operation_unsafety; +use crate::errors; +pub use type_of::test_opaque_hidden_types; + mod generics_of; mod item_bounds; mod predicates_of; diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 47a412c211097..d7bd2a7b17fc3 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -11,6 +11,7 @@ use rustc_span::{Span, DUMMY_SP}; use super::ItemCtxt; use super::{bad_placeholder, is_suggestable_infer_ty}; +pub use opaque::test_opaque_hidden_types; mod opaque; diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 0544c5ca86619..e8d5264c2b8fe 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -1,12 +1,25 @@ use rustc_errors::StashKey; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir, def, Expr, ImplItem, Item, Node, TraitItem}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::DUMMY_SP; +use rustc_span::{sym, DUMMY_SP}; -use crate::errors::{TaitForwardCompat, UnconstrainedOpaqueType}; +use crate::errors::{TaitForwardCompat, TypeOf, UnconstrainedOpaqueType}; + +pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) { + if tcx.has_attr(CRATE_DEF_ID, sym::rustc_hidden_type_of_opaques) { + for id in tcx.hir().items() { + if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) { + let type_of = tcx.type_of(id.owner_id).instantiate_identity(); + + tcx.sess.emit_err(TypeOf { span: tcx.def_span(id.owner_id), type_of }); + } + } + } +} /// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions /// laid for "higher-order pattern unification". diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 1120585f1aa25..189564d4e3392 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -467,6 +467,14 @@ pub(crate) struct VariancesOf { pub variances_of: String, } +#[derive(Diagnostic)] +#[diag(hir_analysis_type_of)] +pub(crate) struct TypeOf<'tcx> { + #[primary_span] + pub span: Span, + pub type_of: Ty<'tcx>, +} + #[derive(Diagnostic)] #[diag(hir_analysis_pass_to_variadic_function, code = "E0617")] pub(crate) struct PassToVariadicFunction<'tcx, 'a> { diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 88f3db03a4ee0..0622aa2ee80fb 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -214,6 +214,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module)) }); + if tcx.features().rustc_attrs { + tcx.sess.track_errors(|| collect::test_opaque_hidden_types(tcx))?; + } + // Freeze definitions as we don't add new ones at this point. This improves performance by // allowing lock-free access to them. tcx.untracked().definitions.freeze(); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 5b58cf8b6d629..38ae8f570e917 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1369,6 +1369,7 @@ symbols! { rustc_evaluate_where_clauses, rustc_expected_cgu_reuse, rustc_has_incoherent_inherent_impls, + rustc_hidden_type_of_opaques, rustc_host, rustc_if_this_changed, rustc_inherit_overflow_checks, diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs index 19f0c9fe826d5..377ae1b4e85fd 100644 --- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs +++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs @@ -224,12 +224,20 @@ impl<'tcx> TypeFolder> for Canonicalizer<'_, 'tcx> { let kind = match *r { ty::ReLateBound(..) => return r, - ty::ReStatic => match self.canonicalize_mode { + // We may encounter `ReStatic` in item signatures or the hidden type + // of an opaque. `ReErased` should only be encountered in the hidden + // type of an opaque for regions that are ignored for the purposes of + // captures. + // + // FIXME: We should investigate the perf implications of not uniquifying + // `ReErased`. We may be able to short-circuit registering region + // obligations if we encounter a `ReErased` on one side, for example. + ty::ReStatic | ty::ReErased => match self.canonicalize_mode { CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), CanonicalizeMode::Response { .. } => return r, }, - ty::ReErased | ty::ReFree(_) | ty::ReEarlyBound(_) => match self.canonicalize_mode { + ty::ReFree(_) | ty::ReEarlyBound(_) => match self.canonicalize_mode { CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), CanonicalizeMode::Response { .. } => bug!("unexpected region in response: {r:?}"), }, diff --git a/tests/ui/impl-trait/erased-regions-in-hidden-ty.current.stderr b/tests/ui/impl-trait/erased-regions-in-hidden-ty.current.stderr new file mode 100644 index 0000000000000..84b61dc504480 --- /dev/null +++ b/tests/ui/impl-trait/erased-regions-in-hidden-ty.current.stderr @@ -0,0 +1,14 @@ +error: {foo::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()} + --> $DIR/erased-regions-in-hidden-ty.rs:11:36 + | +LL | fn foo<'a: 'a>(x: &'a Vec) -> impl Fn() + 'static { + | ^^^^^^^^^^^^^^^^^^^ + +error: Opaque(DefId(..), [ReErased]) + --> $DIR/erased-regions-in-hidden-ty.rs:17:13 + | +LL | fn bar() -> impl Fn() + 'static { + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/impl-trait/erased-regions-in-hidden-ty.next.stderr b/tests/ui/impl-trait/erased-regions-in-hidden-ty.next.stderr new file mode 100644 index 0000000000000..84b61dc504480 --- /dev/null +++ b/tests/ui/impl-trait/erased-regions-in-hidden-ty.next.stderr @@ -0,0 +1,14 @@ +error: {foo::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()} + --> $DIR/erased-regions-in-hidden-ty.rs:11:36 + | +LL | fn foo<'a: 'a>(x: &'a Vec) -> impl Fn() + 'static { + | ^^^^^^^^^^^^^^^^^^^ + +error: Opaque(DefId(..), [ReErased]) + --> $DIR/erased-regions-in-hidden-ty.rs:17:13 + | +LL | fn bar() -> impl Fn() + 'static { + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs b/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs new file mode 100644 index 0000000000000..698123a932d04 --- /dev/null +++ b/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs @@ -0,0 +1,23 @@ +// revisions: current next +// compile-flags: -Zverbose +//[next] compile-flags: -Ztrait-solver=next +// normalize-stderr-test "DefId\([^\)]+\)" -> "DefId(..)" + +#![feature(rustc_attrs)] +#![rustc_hidden_type_of_opaques] + +// Make sure that the compiler can handle `ReErased` in the hidden type of an opaque. + +fn foo<'a: 'a>(x: &'a Vec) -> impl Fn() + 'static { +//~^ ERROR 0, 'a)>::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()} +// Can't write whole type because of lack of path sanitization + || () +} + +fn bar() -> impl Fn() + 'static { +//~^ ERROR , [ReErased]) +// Can't write whole type because of lack of path sanitization + foo(&vec![]) +} + +fn main() {}