From 733e444965f32dcbd07ad8a4d7f1cb2d5fa8a0d6 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 14 Mar 2023 22:16:47 +0000 Subject: [PATCH] Prevent defining opaque types in nested items --- compiler/rustc_hir_analysis/messages.ftl | 3 + .../rustc_hir_analysis/src/collect/type_of.rs | 72 ++++++++++++++++--- compiler/rustc_hir_analysis/src/errors.rs | 8 +++ ...i-emit-type-metadata-id-itanium-cxx-abi.rs | 4 +- .../defining-use-item-child.rs | 30 ++++++++ .../defining-use-item-child.stderr | 26 +++++++ 6 files changed, 129 insertions(+), 14 deletions(-) create mode 100644 tests/ui/type-alias-impl-trait/defining-use-item-child.rs create mode 100644 tests/ui/type-alias-impl-trait/defining-use-item-child.stderr diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 4774d86f80517..cb8a17d6865bb 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -72,6 +72,9 @@ hir_analysis_trait_object_declared_with_no_traits = hir_analysis_opaque_type_constrained_but_not_in_sig = opaque type constrained without being represented in the signature .item_label = this item must mention the opaque type in its signature or where bounds +hir_analysis_opaque_type_constrained_but_not_in_sibling = opaque type constrained in nested item + .item_label = this item is not a sibling of the opaque type + hir_analysis_missing_type_params = the type {$parameterCount -> [one] parameter diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index fd0d32ad2e672..1a2af8a8d9409 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -22,7 +22,9 @@ use rustc_span::{sym, Span, DUMMY_SP}; use super::ItemCtxt; use super::{bad_placeholder, is_suggestable_infer_ty}; -use crate::errors::{OpaqueTypeConstrainedButNotInSig, UnconstrainedOpaqueType}; +use crate::errors::{ + OpaqueTypeConstrainedButNotInSig, OpaqueTypeConstrainedInNonSibling, UnconstrainedOpaqueType, +}; /// Computes the relevant generic parameter for a potential generic const argument. /// @@ -640,13 +642,20 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T let concrete_opaque_types = &self.tcx.mir_borrowck(item_def_id).concrete_opaque_types; debug!(?concrete_opaque_types); if let Some(&concrete_type) = concrete_opaque_types.get(&self.def_id) { - if let Err(item_def_id) = + if let Err((item_def_id, sibling)) = may_define_opaque_type(self.tcx, item_def_id, self.def_id, concrete_type.span) { - self.tcx.sess.emit_err(OpaqueTypeConstrainedButNotInSig { - span: concrete_type.span, - item_span: self.tcx.def_span(item_def_id), - }); + if sibling { + self.tcx.sess.emit_err(OpaqueTypeConstrainedButNotInSig { + span: concrete_type.span, + item_span: self.tcx.def_span(item_def_id), + }); + } else { + self.tcx.sess.emit_err(OpaqueTypeConstrainedInNonSibling { + span: concrete_type.span, + item_span: self.tcx.def_span(item_def_id), + }); + } } debug!(?concrete_type, "found constraint"); if let Some(prev) = &mut self.found { @@ -766,8 +775,27 @@ fn may_define_opaque_type<'tcx>( def_id: LocalDefId, opaque_def_id: LocalDefId, span: Span, -) -> Result<(), LocalDefId> { - if tcx.is_descendant_of(opaque_def_id.to_def_id(), def_id.to_def_id()) { +) -> Result<(), (LocalDefId, bool)> { + let mut parent = tcx.local_parent(opaque_def_id); + loop { + trace!(?parent); + match tcx.def_kind(parent) { + DefKind::AssocTy | DefKind::TyAlias => { + parent = tcx.local_parent(parent); + break; + } + // Skip nested opaque types + DefKind::OpaqueTy => { + parent = tcx.local_parent(parent); + } + def_kind => { + trace!(?def_kind); + return Err((def_id, false)); + } + } + } + trace!(?parent); + if parent == def_id { // If the opaque type is defined in the body of a function, that function // may constrain the opaque type since it can't mention it in bounds. return Ok(()); @@ -777,9 +805,31 @@ fn may_define_opaque_type<'tcx>( return may_define_opaque_type(tcx, tcx.local_parent(def_id), opaque_def_id, span); } + let mut item_parent = tcx.local_parent(def_id); + while item_parent != parent { + trace!(?item_parent); + match tcx.def_kind(item_parent) { + // Skip impls, to allow methods to constrain opaque types from the surrounding module. + DefKind::Impl { .. } | DefKind::Trait => { + item_parent = tcx.local_parent(item_parent); + } + // Skip modules, to allow constraining opaque types in child modules + DefKind::Mod => { + item_parent = tcx.local_parent(item_parent); + } + def_kind => { + trace!(?def_kind); + break; + } + } + } + + if item_parent != parent { + return Err((def_id, false)); + } + let param_env = tcx.param_env(def_id); - trace!(parent = ?tcx.parent(opaque_def_id.to_def_id())); fn has_tait<'tcx>( val: impl TypeVisitable>, opaque_def_id: LocalDefId, @@ -874,7 +924,7 @@ fn may_define_opaque_type<'tcx>( let tait_in_where_bounds = has_tait(tcx.predicates_of(def_id.to_def_id()).predicates, opaque_def_id, tcx, param_env); if tcx.features().type_alias_impl_trait_in_where_bounds { - if tait_in_where_bounds { Ok(()) } else { Err(def_id) } + if tait_in_where_bounds { Ok(()) } else { Err((def_id, true)) } } else { if tait_in_where_bounds { feature_err( @@ -885,7 +935,7 @@ fn may_define_opaque_type<'tcx>( ) .emit(); } - Err(def_id) + Err((def_id, true)) } } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 4913f09fda078..8aa15858bbf10 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -184,6 +184,14 @@ pub struct OpaqueTypeConstrainedButNotInSig { #[label(hir_analysis_item_label)] pub item_span: Span, } +#[derive(Diagnostic)] +#[diag(hir_analysis_opaque_type_constrained_but_not_in_sibling)] +pub struct OpaqueTypeConstrainedInNonSibling { + #[primary_span] + pub span: Span, + #[label(hir_analysis_item_label)] + pub item_span: Span, +} pub struct MissingTypeParams { pub span: Span, diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs b/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs index 332673d886ed3..be3a323c6f6ae 100644 --- a/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs +++ b/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs @@ -104,9 +104,7 @@ where // Type in const path const { pub struct Foo; - fn foo() -> Type5 { - Foo - } + let _: Type5 = Foo; }; // Type in impl path diff --git a/tests/ui/type-alias-impl-trait/defining-use-item-child.rs b/tests/ui/type-alias-impl-trait/defining-use-item-child.rs new file mode 100644 index 0000000000000..c2f384a9c2b7a --- /dev/null +++ b/tests/ui/type-alias-impl-trait/defining-use-item-child.rs @@ -0,0 +1,30 @@ +#![feature(type_alias_impl_trait)] + +fn main() {} + +type Foo = impl std::fmt::Display; + +fn bar() { + pub fn foo() -> Foo { + "foo" + //~^ ERROR: opaque type constrained in nested item + } +} + +fn baz() -> Foo { + pub fn foo() -> Foo { + "foo" + //~^ ERROR: opaque type constrained in nested item + } + "baz" +} + +struct Bak { + x: [u8; { + fn blob() -> Foo { + "blob" + //~^ ERROR: opaque type constrained in nested item + } + 5 + }], +} diff --git a/tests/ui/type-alias-impl-trait/defining-use-item-child.stderr b/tests/ui/type-alias-impl-trait/defining-use-item-child.stderr new file mode 100644 index 0000000000000..74595f2935465 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/defining-use-item-child.stderr @@ -0,0 +1,26 @@ +error: opaque type constrained in nested item + --> $DIR/defining-use-item-child.rs:9:9 + | +LL | pub fn foo() -> Foo { + | ------------------- this item is not a sibling of the opaque type +LL | "foo" + | ^^^^^ + +error: opaque type constrained in nested item + --> $DIR/defining-use-item-child.rs:16:9 + | +LL | pub fn foo() -> Foo { + | ------------------- this item is not a sibling of the opaque type +LL | "foo" + | ^^^^^ + +error: opaque type constrained in nested item + --> $DIR/defining-use-item-child.rs:25:13 + | +LL | fn blob() -> Foo { + | ---------------- this item is not a sibling of the opaque type +LL | "blob" + | ^^^^^^ + +error: aborting due to 3 previous errors +