about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs1
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl2
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs19
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs4
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_trait_selection/src/solve/canonicalize.rs12
-rw-r--r--tests/ui/impl-trait/erased-regions-in-hidden-ty.current.stderr14
-rw-r--r--tests/ui/impl-trait/erased-regions-in-hidden-ty.next.stderr14
-rw-r--r--tests/ui/impl-trait/erased-regions-in-hidden-ty.rs23
12 files changed, 100 insertions, 9 deletions
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 65e697c8f3b..e808e4815fe 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 ee475e3de7e..6bf6650986a 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 640138a3e5e..9636c614446 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 47a412c2110..d7bd2a7b17f 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 0544c5ca866..e8d5264c2b8 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 1120585f1aa..189564d4e33 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -468,6 +468,14 @@ pub(crate) struct VariancesOf {
 }
 
 #[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> {
     #[primary_span]
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 88f3db03a4e..0622aa2ee80 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 5b58cf8b6d6..38ae8f570e9 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 19f0c9fe826..377ae1b4e85 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<TyCtxt<'tcx>> 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 00000000000..84b61dc5044
--- /dev/null
+++ b/tests/ui/impl-trait/erased-regions-in-hidden-ty.current.stderr
@@ -0,0 +1,14 @@
+error: {foo<ReEarlyBound(DefId(..), 0, 'a)>::{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<i32>) -> 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 00000000000..84b61dc5044
--- /dev/null
+++ b/tests/ui/impl-trait/erased-regions-in-hidden-ty.next.stderr
@@ -0,0 +1,14 @@
+error: {foo<ReEarlyBound(DefId(..), 0, 'a)>::{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<i32>) -> 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 00000000000..698123a932d
--- /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<i32>) -> 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() {}