diff --git a/Cargo.lock b/Cargo.lock
index fb4cf235c6f49..c43811bd8501b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4513,6 +4513,7 @@ version = "0.0.0"
dependencies = [
"itertools",
"rustc_abi",
+ "rustc_attr_parsing",
"rustc_data_structures",
"rustc_errors",
"rustc_fluent_macro",
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 29c1d34a125a4..2fc7b85d081e3 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -3381,6 +3381,7 @@ pub struct Fn {
pub generics: Generics,
pub sig: FnSig,
pub contract: Option
>,
+ pub define_opaques: Option>,
pub body: Option>,
}
@@ -3678,7 +3679,7 @@ mod size_asserts {
static_assert_size!(Block, 32);
static_assert_size!(Expr, 72);
static_assert_size!(ExprKind, 40);
- static_assert_size!(Fn, 168);
+ static_assert_size!(Fn, 176);
static_assert_size!(ForeignItem, 88);
static_assert_size!(ForeignItemKind, 16);
static_assert_size!(GenericArg, 24);
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 40b29fdba2506..04dc43cfec8ac 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -978,7 +978,14 @@ fn walk_fn(vis: &mut T, kind: FnKind<'_>) {
_ctxt,
_ident,
_vis,
- Fn { defaultness, generics, contract, body, sig: FnSig { header, decl, span } },
+ Fn {
+ defaultness,
+ generics,
+ contract,
+ body,
+ sig: FnSig { header, decl, span },
+ define_opaques,
+ },
) => {
// Identifier and visibility are visited as a part of the item.
visit_defaultness(vis, defaultness);
@@ -992,6 +999,11 @@ fn walk_fn(vis: &mut T, kind: FnKind<'_>) {
vis.visit_block(body);
}
vis.visit_span(span);
+
+ for (id, path) in define_opaques.iter_mut().flatten() {
+ vis.visit_id(id);
+ vis.visit_path(path)
+ }
}
FnKind::Closure(binder, coroutine_kind, decl, body) => {
vis.visit_closure_binder(binder);
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 1cb32b56875c3..67734f60e0e28 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -802,6 +802,7 @@ pub fn walk_generics<'a, V: Visitor<'a>>(visitor: &mut V, generics: &'a Generics
let WhereClause { has_where_token: _, predicates, span: _ } = where_clause;
walk_list!(visitor, visit_generic_param, params);
walk_list!(visitor, visit_where_predicate, predicates);
+
V::Result::output()
}
@@ -891,7 +892,14 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu
_ctxt,
_ident,
_vis,
- Fn { defaultness: _, sig: FnSig { header, decl, span: _ }, generics, contract, body },
+ Fn {
+ defaultness: _,
+ sig: FnSig { header, decl, span: _ },
+ generics,
+ contract,
+ body,
+ define_opaques,
+ },
) => {
// Identifier and visibility are visited as a part of the item.
try_visit!(visitor.visit_fn_header(header));
@@ -899,6 +907,9 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu
try_visit!(visitor.visit_fn_decl(decl));
visit_opt!(visitor, visit_contract, contract);
visit_opt!(visitor, visit_block, body);
+ for (id, path) in define_opaques.iter().flatten() {
+ try_visit!(visitor.visit_path(path, *id))
+ }
}
FnKind::Closure(binder, coroutine_kind, decl, body) => {
try_visit!(visitor.visit_closure_binder(binder));
@@ -1202,7 +1213,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
FnKind::Closure(binder, coroutine_kind, fn_decl, body),
*span,
*id
- ))
+ ));
}
ExprKind::Block(block, opt_label) => {
visit_opt!(visitor, visit_label, opt_label);
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index a4fc4b3e3a121..7512e00f62ba6 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -2,6 +2,7 @@ use rustc_abi::ExternAbi;
use rustc_ast::ptr::P;
use rustc_ast::visit::AssocCtxt;
use rustc_ast::*;
+use rustc_attr_parsing::AttributeKind;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::PredicateOrigin;
@@ -158,7 +159,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
let mut ident = i.ident;
let vis_span = self.lower_span(i.vis.span);
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
- let attrs = self.lower_attrs(hir_id, &i.attrs, i.span);
+ let define_opaques = match &i.kind {
+ ItemKind::Fn(f) => self.lower_define_opaques(&f.define_opaques),
+ _ => None,
+ };
+ let attrs = self.lower_attrs_with_extra(hir_id, &i.attrs, i.span, define_opaques);
let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind);
let item = hir::Item {
owner_id: hir_id.expect_owner(),
@@ -760,7 +765,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
- let attrs = self.lower_attrs(hir_id, &i.attrs, i.span);
+ let define_opaques = match &i.kind {
+ AssocItemKind::Fn(f) => self.lower_define_opaques(&f.define_opaques),
+ _ => None,
+ };
+ let attrs = self.lower_attrs_with_extra(hir_id, &i.attrs, i.span, define_opaques);
+
let trait_item_def_id = hir_id.expect_owner();
let (generics, kind, has_default) = match &i.kind {
@@ -896,7 +906,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
let has_value = true;
let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
- let attrs = self.lower_attrs(hir_id, &i.attrs, i.span);
+ let define_opaques = match &i.kind {
+ AssocItemKind::Fn(f) => self.lower_define_opaques(&f.define_opaques),
+ _ => None,
+ };
+ let attrs = self.lower_attrs_with_extra(hir_id, &i.attrs, i.span, define_opaques);
let (generics, kind) = match &i.kind {
AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics(
@@ -1657,6 +1671,32 @@ impl<'hir> LoweringContext<'_, 'hir> {
(lowered_generics, res)
}
+ pub(super) fn lower_define_opaques(
+ &mut self,
+ define_opaques: &Option>,
+ ) -> Option {
+ let define_opaques = define_opaques.as_ref()?;
+ let define_opaques = define_opaques
+ .iter()
+ .filter_map(|(id, path)| {
+ let res = self.resolver.get_partial_res(*id).unwrap();
+ let Some(did) = res.expect_full_res().opt_def_id() else {
+ self.dcx().span_delayed_bug(path.span, "should have errored in resolve");
+ return None;
+ };
+ let Some(did) = did.as_local() else {
+ self.dcx().span_err(
+ path.span,
+ "only opaque types defined in the local crate can be defined",
+ );
+ return None;
+ };
+ Some((self.lower_span(path.span), did))
+ })
+ .collect();
+ Some(hir::Attribute::Parsed(AttributeKind::DefineOpaques(define_opaques)))
+ }
+
pub(super) fn lower_generic_bound_predicate(
&mut self,
ident: Ident,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 1c69937eed07a..51b4c1793a60b 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -35,6 +35,7 @@
#![doc(rust_logo)]
#![feature(assert_matches)]
#![feature(box_patterns)]
+#![feature(exact_size_is_empty)]
#![feature(if_let_guard)]
#![feature(let_chains)]
#![feature(rustdoc_internals)]
@@ -867,13 +868,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
attrs: &[Attribute],
target_span: Span,
) -> &'hir [hir::Attribute] {
- if attrs.is_empty() {
+ self.lower_attrs_with_extra(id, attrs, target_span, std::iter::empty())
+ }
+
+ fn lower_attrs_with_extra(
+ &mut self,
+ id: HirId,
+ attrs: &[Attribute],
+ target_span: Span,
+ extra: impl IntoIterator- ,
+ ) -> &'hir [hir::Attribute] {
+ let extra = extra.into_iter();
+ if attrs.is_empty() && extra.is_empty() {
&[]
} else {
let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span));
debug_assert_eq!(id.owner, self.current_hir_id_owner);
- let ret = self.arena.alloc_from_iter(lowered_attrs);
+ let ret = self.arena.alloc_from_iter(lowered_attrs.into_iter().chain(extra));
// this is possible if an item contained syntactical attribute,
// but none of them parse succesfully or all of them were ignored
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index f9f4035cb22f0..1f7c91d10cbe4 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -917,7 +917,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
walk_list!(self, visit_attribute, &item.attrs);
return; // Avoid visiting again.
}
- ItemKind::Fn(func @ box Fn { defaultness, generics: _, sig, contract: _, body }) => {
+ ItemKind::Fn(
+ func @ box Fn {
+ defaultness,
+ generics: _,
+ sig,
+ contract: _,
+ body,
+ define_opaques: _,
+ },
+ ) => {
self.check_defaultness(item.span, *defaultness);
let is_intrinsic =
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 44e956dc37f3e..af7a6cab30d56 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -26,7 +26,6 @@ use rustc_span::edition::Edition;
use rustc_span::source_map::{SourceMap, Spanned};
use rustc_span::symbol::IdentPrinter;
use rustc_span::{BytePos, CharPos, DUMMY_SP, FileName, Ident, Pos, Span, Symbol, kw, sym};
-use thin_vec::ThinVec;
use crate::pp::Breaks::{Consistent, Inconsistent};
use crate::pp::{self, Breaks};
@@ -1970,15 +1969,7 @@ impl<'a> State<'a> {
) {
self.ibox(INDENT_UNIT);
self.print_formal_generic_params(generic_params);
- let generics = ast::Generics {
- params: ThinVec::new(),
- where_clause: ast::WhereClause {
- has_where_token: false,
- predicates: ThinVec::new(),
- span: DUMMY_SP,
- },
- span: DUMMY_SP,
- };
+ let generics = ast::Generics::default();
let header = ast::FnHeader { safety, ext, ..ast::FnHeader::default() };
self.print_fn(decl, header, name, &generics);
self.end();
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index c10b5ad34e102..4b6c8f3dfc3de 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -650,7 +650,16 @@ impl<'a> State<'a> {
attrs: &[ast::Attribute],
func: &ast::Fn,
) {
- let ast::Fn { defaultness, generics, sig, contract, body } = func;
+ let ast::Fn { defaultness, generics, sig, contract, body, define_opaques } = func;
+
+ if let Some(define_opaques) = define_opaques {
+ for (_, path) in define_opaques {
+ self.word("define opaques from ");
+ self.print_path(path, false, 0);
+ self.word(",");
+ }
+ }
+
if body.is_some() {
self.head("");
}
@@ -698,7 +707,7 @@ impl<'a> State<'a> {
}
self.print_generic_params(&generics.params);
self.print_fn_params_and_ret(decl, false);
- self.print_where_clause(&generics.where_clause)
+ self.print_where_clause(&generics.where_clause);
}
pub(crate) fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) {
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index 9ac8de0227d79..8562f6396e243 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -2,6 +2,7 @@ use rustc_abi::Align;
use rustc_ast::token::CommentKind;
use rustc_ast::{self as ast, AttrStyle};
use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute};
+use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::Transparency;
use rustc_span::{Span, Symbol};
use thin_vec::ThinVec;
@@ -175,6 +176,8 @@ pub enum AttributeKind {
span: Span,
},
ConstStabilityIndirect,
+ /// List of type aliases that contain the opaque types that can be defined by the current item.
+ DefineOpaques(ThinVec<(Span, LocalDefId)>),
Deprecation {
deprecation: Deprecation,
span: Span,
@@ -195,3 +198,23 @@ pub enum AttributeKind {
},
// tidy-alphabetical-end
}
+
+impl AttributeKind {
+ pub fn encode_cross_crate(&self) -> bool {
+ match self {
+ AttributeKind::DefineOpaques(..) => false,
+ AttributeKind::AllowConstFnUnstable(..)
+ | AttributeKind::AllowInternalUnstable(..)
+ | AttributeKind::BodyStability { .. }
+ | AttributeKind::Confusables { .. }
+ | AttributeKind::ConstStability { .. }
+ | AttributeKind::ConstStabilityIndirect
+ | AttributeKind::Deprecation { .. }
+ | AttributeKind::Diagnostic(..)
+ | AttributeKind::DocComment { .. }
+ | AttributeKind::MacroTransparency(..)
+ | AttributeKind::Repr(..)
+ | AttributeKind::Stability { .. } => true,
+ }
+ }
+}
diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs
index e4bb459e6df5a..b48fab3656980 100644
--- a/compiler/rustc_attr_data_structures/src/lib.rs
+++ b/compiler/rustc_attr_data_structures/src/lib.rs
@@ -17,6 +17,7 @@ use rustc_abi::Align;
use rustc_ast::token::CommentKind;
use rustc_ast::{AttrStyle, IntTy, UintTy};
use rustc_ast_pretty::pp::Printer;
+use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::Transparency;
use rustc_span::{Span, Symbol};
pub use stability::*;
@@ -148,4 +149,4 @@ macro_rules! print_tup {
print_tup!(A B C D E F G H);
print_skip!(Span, ());
print_disp!(Symbol, u16, bool, NonZero);
-print_debug!(UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency);
+print_debug!(UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency, LocalDefId);
diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
index 78bf2195975d5..96b873ff86d96 100644
--- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
+++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
@@ -88,6 +88,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span
generics: Generics::default(),
contract: None,
body,
+ define_opaques: None,
}));
let attrs = thin_vec![cx.attr_word(sym::rustc_std_internal_symbol, span)];
diff --git a/compiler/rustc_builtin_macros/src/define_opaques.rs b/compiler/rustc_builtin_macros/src/define_opaques.rs
new file mode 100644
index 0000000000000..811c22da1ecfa
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/define_opaques.rs
@@ -0,0 +1,54 @@
+use rustc_ast::{DUMMY_NODE_ID, ast};
+use rustc_expand::base::{Annotatable, ExtCtxt};
+use rustc_span::Span;
+
+pub(crate) fn expand(
+ ecx: &mut ExtCtxt<'_>,
+ _expand_span: Span,
+ meta_item: &ast::MetaItem,
+ mut item: Annotatable,
+) -> Vec {
+ let define_opaques = match &mut item {
+ Annotatable::Item(p) => match &mut p.kind {
+ ast::ItemKind::Fn(f) => Some(&mut f.define_opaques),
+ _ => None,
+ },
+ Annotatable::AssocItem(i, _assoc_ctxt) => match &mut i.kind {
+ ast::AssocItemKind::Fn(func) => Some(&mut func.define_opaques),
+ _ => None,
+ },
+ Annotatable::Stmt(s) => match &mut s.kind {
+ ast::StmtKind::Item(p) => match &mut p.kind {
+ ast::ItemKind::Fn(f) => Some(&mut f.define_opaques),
+ _ => None,
+ },
+ _ => None,
+ },
+ _ => None,
+ };
+
+ let Some(list) = meta_item.meta_item_list() else {
+ ecx.dcx().span_err(meta_item.span, "expected list of type aliases");
+ return vec![item];
+ };
+
+ if let Some(define_opaques) = define_opaques {
+ *define_opaques = Some(
+ list.iter()
+ .filter_map(|entry| match entry {
+ ast::MetaItemInner::MetaItem(meta_item) if meta_item.is_word() => {
+ Some((DUMMY_NODE_ID, meta_item.path.clone()))
+ }
+ _ => {
+ ecx.dcx().span_err(entry.span(), "expected path to type alias");
+ None
+ }
+ })
+ .collect(),
+ );
+ } else {
+ ecx.dcx().span_err(meta_item.span, "only functions and methods can define opaque types");
+ }
+
+ vec![item]
+}
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 6b59ac2582755..c3b5f6220dad3 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -1033,6 +1033,7 @@ impl<'a> MethodDef<'a> {
generics: fn_generics,
contract: None,
body: Some(body_block),
+ define_opaques: None,
})),
tokens: None,
})
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index 8fdbbf8e704a9..dfc3c95f83e26 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -83,6 +83,7 @@ impl AllocFnFactory<'_, '_> {
generics: Generics::default(),
contract: None,
body,
+ define_opaques: None,
}));
let item = self.cx.item(
self.span,
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index ca16583a45de7..fe7dad6fedad1 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -39,6 +39,7 @@ mod compile_error;
mod concat;
mod concat_bytes;
mod concat_idents;
+mod define_opaques;
mod derive;
mod deriving;
mod edition_panic;
@@ -114,6 +115,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
bench: test::expand_bench,
cfg_accessible: cfg_accessible::Expander,
cfg_eval: cfg_eval::expand,
+ define_opaques: define_opaques::expand,
derive: derive::Expander { is_const: false },
derive_const: derive::Expander { is_const: true },
global_allocator: global_allocator::expand,
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 472e16e62d5b0..30a821da125a3 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -346,6 +346,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P {
generics: ast::Generics::default(),
contract: None,
body: Some(main_body),
+ define_opaques: None,
}));
// Honor the reexport_test_harness_main attribute
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index 78d69a66edc8b..f6eabaee9982a 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -315,6 +315,7 @@ mod helper {
use super::*;
pub type ObligationTreeIdGenerator = impl Iterator
- ;
impl ObligationForest {
+ #[cfg_attr(not(bootstrap), define_opaques(ObligationTreeIdGenerator))]
pub fn new() -> ObligationForest {
ObligationForest {
nodes: vec![],
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index ba1c3e185c2d9..d52dfe529f9b1 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -209,6 +209,7 @@ pub type LazyFallbackBundle = Arc Fluent
/// Return the default `FluentBundle` with standard "en-US" diagnostic messages.
#[instrument(level = "trace", skip(resources))]
+#[cfg_attr(not(bootstrap), define_opaques(LazyFallbackBundle))]
pub fn fallback_fluent_bundle(
resources: Vec<&'static str>,
with_directionality_markers: bool,
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index e3f31ebeca3f3..7acfd3d0e85c6 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -770,8 +770,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
}
Err(err) => {
- let guar = err.emit();
- fragment_kind.dummy(span, guar)
+ let _guar = err.emit();
+ fragment_kind.expect_from_annotatables(iter::once(item))
}
}
}
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 3f75cce009225..a4bde8b138456 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -514,9 +514,6 @@ hir_analysis_supertrait_item_shadowee = item from `{$supertrait}` is shadowed by
hir_analysis_supertrait_item_shadowing = trait item `{$item}` from `{$subtrait}` shadows identically named item from supertrait
-hir_analysis_tait_forward_compat = item constrains opaque type that is not in its signature
- .note = this item must mention the opaque type in its signature in order to be able to register hidden types
-
hir_analysis_tait_forward_compat2 = item does not constrain `{$opaque_type}`, but has it in its signature
.note = consider moving the opaque type's declaration and defining uses into a separate module
.opaque = this opaque type is in the signature
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index f2331f3fd8e13..2235ecb2df8c6 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -423,6 +423,12 @@ fn best_definition_site_of_opaque<'tcx>(
return ControlFlow::Continue(());
}
+ let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);
+ // Don't try to check items that cannot possibly constrain the type.
+ if !opaque_types_defined_by.contains(&self.opaque_def_id) {
+ return ControlFlow::Continue(());
+ }
+
if let Some(hidden_ty) =
self.tcx.mir_borrowck(item_def_id).concrete_opaque_types.get(&self.opaque_def_id)
{
@@ -482,19 +488,7 @@ fn best_definition_site_of_opaque<'tcx>(
None
}
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => {
- let scope = tcx.hir_get_defining_scope(tcx.local_def_id_to_hir_id(opaque_def_id));
- let found = if scope == hir::CRATE_HIR_ID {
- tcx.hir_walk_toplevel_module(&mut locator)
- } else {
- match tcx.hir_node(scope) {
- Node::Item(it) => locator.visit_item(it),
- Node::ImplItem(it) => locator.visit_impl_item(it),
- Node::TraitItem(it) => locator.visit_trait_item(it),
- Node::ForeignItem(it) => locator.visit_foreign_item(it),
- other => bug!("{:?} is not a valid scope for an opaque type item", other),
- }
- };
- found.break_value()
+ tcx.hir_walk_toplevel_module(&mut locator).break_value()
}
}
}
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 399c4fbe55a9c..142078900f0e8 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -1,14 +1,13 @@
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem, def};
+use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem, def, intravisit};
use rustc_middle::bug;
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::DUMMY_SP;
use tracing::{debug, instrument, trace};
-use crate::errors::{TaitForwardCompat, TaitForwardCompat2, UnconstrainedOpaqueType};
+use crate::errors::{TaitForwardCompat2, UnconstrainedOpaqueType};
/// Checks "defining uses" of opaque `impl Trait` in associated types.
/// These can only be defined by associated items of the same trait.
@@ -82,38 +81,9 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
/// ```
#[instrument(skip(tcx), level = "debug")]
pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
- let hir_id = tcx.local_def_id_to_hir_id(def_id);
- let scope = tcx.hir_get_defining_scope(hir_id);
let mut locator = TaitConstraintLocator { def_id, tcx, found: None, typeck_types: vec![] };
- debug!(?scope);
-
- if scope == hir::CRATE_HIR_ID {
- tcx.hir_walk_toplevel_module(&mut locator);
- } else {
- trace!("scope={:#?}", tcx.hir_node(scope));
- match tcx.hir_node(scope) {
- // We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods
- // This allows our visitor to process the defining item itself, causing
- // it to pick up any 'sibling' defining uses.
- //
- // For example, this code:
- // ```
- // fn foo() {
- // type Blah = impl Debug;
- // let my_closure = || -> Blah { true };
- // }
- // ```
- //
- // requires us to explicitly process `foo()` in order
- // to notice the defining usage of `Blah`.
- Node::Item(it) => locator.visit_item(it),
- Node::ImplItem(it) => locator.visit_impl_item(it),
- Node::TraitItem(it) => locator.visit_trait_item(it),
- Node::ForeignItem(it) => locator.visit_foreign_item(it),
- other => bug!("{:?} is not a valid scope for an opaque type item", other),
- }
- }
+ tcx.hir_walk_toplevel_module(&mut locator);
if let Some(hidden) = locator.found {
// Only check against typeck if we didn't already error
@@ -137,12 +107,7 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local
let reported = tcx.dcx().emit_err(UnconstrainedOpaqueType {
span: tcx.def_span(def_id),
name: tcx.item_ident(parent_def_id.to_def_id()),
- what: match tcx.hir_node(scope) {
- _ if scope == hir::CRATE_HIR_ID => "module",
- Node::Item(hir::Item { kind: hir::ItemKind::Mod(_), .. }) => "module",
- Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => "impl",
- _ => "item",
- },
+ what: "crate",
});
Ty::new_error(tcx, reported)
}
@@ -176,6 +141,13 @@ impl TaitConstraintLocator<'_> {
return;
}
+ let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);
+ // Don't try to check items that cannot possibly constrain the type.
+ if !opaque_types_defined_by.contains(&self.def_id) {
+ debug!("no constraint: no opaque types defined");
+ return;
+ }
+
// Function items with `_` in their return type already emit an error, skip any
// "non-defining use" errors for them.
// Note that we use `Node::fn_sig` instead of `Node::fn_decl` here, because the former
@@ -215,8 +187,6 @@ impl TaitConstraintLocator<'_> {
return;
}
- let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);
-
let mut constrained = false;
for (&opaque_type_key, &hidden_type) in &tables.concrete_opaque_types {
if opaque_type_key.def_id != self.def_id {
@@ -224,20 +194,6 @@ impl TaitConstraintLocator<'_> {
}
constrained = true;
- if !opaque_types_defined_by.contains(&self.def_id) {
- let guar = self.tcx.dcx().emit_err(TaitForwardCompat {
- span: hidden_type.span,
- item_span: self
- .tcx
- .def_ident_span(item_def_id)
- .unwrap_or_else(|| self.tcx.def_span(item_def_id)),
- });
- // Avoid "opaque type not constrained" errors on the opaque itself.
- self.found = Some(ty::OpaqueHiddenType {
- span: DUMMY_SP,
- ty: Ty::new_error(self.tcx, guar),
- });
- }
let concrete_type =
self.tcx.erase_regions(hidden_type.remap_generic_params_to_declaration_params(
opaque_type_key,
@@ -309,19 +265,13 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
}
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
trace!(?it.owner_id);
- // The opaque type itself or its children are not within its reveal scope.
- if it.owner_id.def_id != self.def_id {
- self.check(it.owner_id.def_id);
- intravisit::walk_item(self, it);
- }
+ self.check(it.owner_id.def_id);
+ intravisit::walk_item(self, it);
}
fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
trace!(?it.owner_id);
- // The opaque type itself or its children are not within its reveal scope.
- if it.owner_id.def_id != self.def_id {
- self.check(it.owner_id.def_id);
- intravisit::walk_impl_item(self, it);
- }
+ self.check(it.owner_id.def_id);
+ intravisit::walk_impl_item(self, it);
}
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
trace!(?it.owner_id);
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 852533ff5c954..49a0fc6fdb864 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -424,16 +424,6 @@ pub(crate) struct UnconstrainedOpaqueType {
pub what: &'static str,
}
-#[derive(Diagnostic)]
-#[diag(hir_analysis_tait_forward_compat)]
-#[note]
-pub(crate) struct TaitForwardCompat {
- #[primary_span]
- pub span: Span,
- #[note]
- pub item_span: Span,
-}
-
#[derive(Diagnostic)]
#[diag(hir_analysis_tait_forward_compat2)]
#[note]
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 88a88847e6b8b..683ef1daf1dc8 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -5,7 +5,6 @@ use std::io::{Read, Seek, Write};
use std::path::{Path, PathBuf};
use std::sync::Arc;
-use rustc_ast::attr::AttributeExt;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::memmap::{Mmap, MmapMut};
use rustc_data_structures::sync::{join, par_for_each_in};
@@ -820,9 +819,11 @@ struct AnalyzeAttrState<'a> {
/// visibility: this is a piece of data that can be computed once per defid, and not once per
/// attribute. Some attributes would only be usable downstream if they are public.
#[inline]
-fn analyze_attr(attr: &impl AttributeExt, state: &mut AnalyzeAttrState<'_>) -> bool {
+fn analyze_attr(attr: &hir::Attribute, state: &mut AnalyzeAttrState<'_>) -> bool {
let mut should_encode = false;
- if !rustc_feature::encode_cross_crate(attr.name_or_empty()) {
+ if let hir::Attribute::Parsed(p) = attr {
+ should_encode = p.encode_cross_crate();
+ } else if !rustc_feature::encode_cross_crate(attr.name_or_empty()) {
// Attributes not marked encode-cross-crate don't need to be encoded for downstream crates.
} else if attr.doc_str().is_some() {
// We keep all doc comments reachable to rustdoc because they might be "imported" into
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index b887370fd699a..58217bb9ca4a1 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -454,6 +454,7 @@ mod helper {
/// Like [`SwitchTargets::target_for_value`], but returning the same type as
/// [`Terminator::successors`].
#[inline]
+ #[cfg_attr(not(bootstrap), define_opaques(Successors))]
pub fn successors_for_value(&self, value: u128) -> Successors<'_> {
let target = self.target_for_value(value);
(&[]).into_iter().copied().chain(Some(target))
@@ -462,6 +463,7 @@ mod helper {
impl<'tcx> TerminatorKind<'tcx> {
#[inline]
+ #[cfg_attr(not(bootstrap), define_opaques(Successors))]
pub fn successors(&self) -> Successors<'_> {
use self::TerminatorKind::*;
match *self {
@@ -500,6 +502,7 @@ mod helper {
}
#[inline]
+ #[cfg_attr(not(bootstrap), define_opaques(SuccessorsMut))]
pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
use self::TerminatorKind::*;
match *self {
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index cbd60920bc572..985eeaf3c3c56 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -24,6 +24,7 @@ pub trait EraseType: Copy {
pub type Erase = Erased;
#[inline(always)]
+#[cfg_attr(not(bootstrap), define_opaques(Erase))]
pub fn erase(src: T) -> Erase {
// Ensure the sizes match
const {
@@ -47,6 +48,7 @@ pub fn erase(src: T) -> Erase {
/// Restores an erased value.
#[inline(always)]
+#[cfg_attr(not(bootstrap), define_opaques(Erase))]
pub fn restore(value: Erase) -> T {
let value: Erased<::Result> = value;
// See comment in `erase` for why we use `transmute_unchecked`.
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index c923717ecaf27..98f70a87a0906 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -217,7 +217,14 @@ impl<'a> Parser<'a> {
self.parse_fn(attrs, fn_parse_mode, lo, vis, case)?;
(
ident,
- ItemKind::Fn(Box::new(Fn { defaultness: def_(), sig, generics, contract, body })),
+ ItemKind::Fn(Box::new(Fn {
+ defaultness: def_(),
+ sig,
+ generics,
+ contract,
+ body,
+ define_opaques: None,
+ })),
)
} else if self.eat_keyword(exp!(Extern)) {
if self.eat_keyword(exp!(Crate)) {
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index ad9c3465f0cc6..fa26b2edffa98 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -394,32 +394,37 @@ pub(crate) enum AliasPossibility {
#[derive(Copy, Clone, Debug)]
pub(crate) enum PathSource<'a> {
- // Type paths `Path`.
+ /// Type paths `Path`.
Type,
- // Trait paths in bounds or impls.
+ /// Trait paths in bounds or impls.
Trait(AliasPossibility),
- // Expression paths `path`, with optional parent context.
+ /// Expression paths `path`, with optional parent context.
Expr(Option<&'a Expr>),
- // Paths in path patterns `Path`.
+ /// Paths in path patterns `Path`.
Pat,
- // Paths in struct expressions and patterns `Path { .. }`.
+ /// Paths in struct expressions and patterns `Path { .. }`.
Struct,
- // Paths in tuple struct patterns `Path(..)`.
+ /// Paths in tuple struct patterns `Path(..)`.
TupleStruct(Span, &'a [Span]),
- // `m::A::B` in `::B::C`.
+ /// `m::A::B` in `::B::C`.
TraitItem(Namespace),
- // Paths in delegation item
+ /// Paths in delegation item
Delegation,
/// An arg in a `use<'a, N>` precise-capturing bound.
PreciseCapturingArg(Namespace),
- // Paths that end with `(..)`, for return type notation.
+ /// Paths that end with `(..)`, for return type notation.
ReturnTypeNotation,
+ /// Paths from `#[define_opaques]` attributes
+ DefineOpaques,
}
impl<'a> PathSource<'a> {
fn namespace(self) -> Namespace {
match self {
- PathSource::Type | PathSource::Trait(_) | PathSource::Struct => TypeNS,
+ PathSource::Type
+ | PathSource::Trait(_)
+ | PathSource::Struct
+ | PathSource::DefineOpaques => TypeNS,
PathSource::Expr(..)
| PathSource::Pat
| PathSource::TupleStruct(..)
@@ -440,6 +445,7 @@ impl<'a> PathSource<'a> {
| PathSource::ReturnTypeNotation => true,
PathSource::Trait(_)
| PathSource::TraitItem(..)
+ | PathSource::DefineOpaques
| PathSource::Delegation
| PathSource::PreciseCapturingArg(..) => false,
}
@@ -447,6 +453,7 @@ impl<'a> PathSource<'a> {
fn descr_expected(self) -> &'static str {
match &self {
+ PathSource::DefineOpaques => "type alias or associated type with opaqaue types",
PathSource::Type => "type",
PathSource::Trait(_) => "trait",
PathSource::Pat => "unit struct, unit variant or constant",
@@ -490,6 +497,19 @@ impl<'a> PathSource<'a> {
pub(crate) fn is_expected(self, res: Res) -> bool {
match self {
+ PathSource::DefineOpaques => {
+ matches!(
+ res,
+ Res::Def(
+ DefKind::Struct
+ | DefKind::Union
+ | DefKind::Enum
+ | DefKind::TyAlias
+ | DefKind::AssocTy,
+ _
+ ) | Res::SelfTyAlias { .. }
+ )
+ }
PathSource::Type => matches!(
res,
Res::Def(
@@ -569,16 +589,16 @@ impl<'a> PathSource<'a> {
match (self, has_unexpected_resolution) {
(PathSource::Trait(_), true) => E0404,
(PathSource::Trait(_), false) => E0405,
- (PathSource::Type, true) => E0573,
- (PathSource::Type, false) => E0412,
+ (PathSource::Type | PathSource::DefineOpaques, true) => E0573,
+ (PathSource::Type | PathSource::DefineOpaques, false) => E0412,
(PathSource::Struct, true) => E0574,
(PathSource::Struct, false) => E0422,
(PathSource::Expr(..), true) | (PathSource::Delegation, true) => E0423,
(PathSource::Expr(..), false) | (PathSource::Delegation, false) => E0425,
(PathSource::Pat | PathSource::TupleStruct(..), true) => E0532,
(PathSource::Pat | PathSource::TupleStruct(..), false) => E0531,
- (PathSource::TraitItem(..), true) | (PathSource::ReturnTypeNotation, true) => E0575,
- (PathSource::TraitItem(..), false) | (PathSource::ReturnTypeNotation, false) => E0576,
+ (PathSource::TraitItem(..) | PathSource::ReturnTypeNotation, true) => E0575,
+ (PathSource::TraitItem(..) | PathSource::ReturnTypeNotation, false) => E0576,
(PathSource::PreciseCapturingArg(..), true) => E0799,
(PathSource::PreciseCapturingArg(..), false) => E0800,
}
@@ -1984,6 +2004,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
| PathSource::Pat
| PathSource::Struct
| PathSource::TupleStruct(..)
+ | PathSource::DefineOpaques
| PathSource::Delegation => true,
};
if inferred {
@@ -2597,7 +2618,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
);
}
- ItemKind::Fn(box Fn { ref generics, .. }) => {
+ ItemKind::Fn(box Fn { ref generics, ref define_opaques, .. }) => {
self.with_generic_param_rib(
&generics.params,
RibKind::Item(HasGenericParams::Yes(generics.span), def_kind),
@@ -2608,6 +2629,10 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
},
|this| visit::walk_item(this, item),
);
+
+ for (id, path) in define_opaques.iter().flatten() {
+ self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques);
+ }
}
ItemKind::Enum(_, ref generics)
@@ -3078,8 +3103,12 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
},
);
}
- AssocItemKind::Fn(box Fn { generics, .. }) => {
+ AssocItemKind::Fn(box Fn { generics, define_opaques, .. }) => {
walk_assoc_item(self, generics, LifetimeBinderKind::Function, item);
+
+ for (id, path) in define_opaques.iter().flatten() {
+ self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques);
+ }
}
AssocItemKind::Delegation(delegation) => {
self.with_generic_param_rib(
@@ -3288,7 +3317,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
},
);
}
- AssocItemKind::Fn(box Fn { generics, .. }) => {
+ AssocItemKind::Fn(box Fn { generics, define_opaques, .. }) => {
debug!("resolve_implementation AssocItemKind::Fn");
// We also need a new scope for the impl item type parameters.
self.with_generic_param_rib(
@@ -3315,6 +3344,10 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
visit::walk_assoc_item(this, item, AssocCtxt::Impl)
},
);
+
+ for (id, path) in define_opaques.iter().flatten() {
+ self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques);
+ }
}
AssocItemKind::Type(box TyAlias { generics, .. }) => {
self.diag_metadata.in_non_gat_assoc_type = Some(generics.params.is_empty());
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 501c9039f2de9..662bf059cc758 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -776,6 +776,7 @@ symbols! {
default_method_body_is_const,
default_type_parameter_fallback,
default_type_params,
+ define_opaques,
delayed_bug_from_inside_query,
deny,
deprecated,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
index 514615735a507..34852654525b1 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
@@ -395,10 +395,16 @@ impl Trait for X {
let sp = tcx
.def_ident_span(body_owner_def_id)
.unwrap_or_else(|| tcx.def_span(body_owner_def_id));
+ let mut alias_def_id = opaque_ty.def_id;
+ while let DefKind::OpaqueTy = tcx.def_kind(alias_def_id) {
+ alias_def_id = tcx.parent(alias_def_id);
+ }
+ let opaque_path = tcx.def_path_str(alias_def_id);
+ // FIXME(type_alias_impl_trait): make this a structured suggestion
diag.span_note(
sp,
- "this item must have the opaque type in its signature in order to \
- be able to register hidden types",
+ format!("this item must have a `#[define_opaques({opaque_path})]` attribute to be able \
+ to define hidden types"),
);
}
// If two if arms can be coerced to a trait object, provide a structured
diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml
index 4c7a57f2931bf..7e96b64408c19 100644
--- a/compiler/rustc_ty_utils/Cargo.toml
+++ b/compiler/rustc_ty_utils/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2024"
# tidy-alphabetical-start
itertools = "0.12"
rustc_abi = { path = "../rustc_abi" }
+rustc_attr_parsing = { path = "../rustc_attr_parsing" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
index 98881905bcf88..d63e559c63391 100644
--- a/compiler/rustc_ty_utils/src/opaque_types.rs
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -1,8 +1,9 @@
+use rustc_attr_parsing::{AttributeKind, find_attr};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit;
use rustc_hir::intravisit::Visitor;
-use rustc_hir::{CRATE_HIR_ID, intravisit};
use rustc_middle::bug;
use rustc_middle::query::Providers;
use rustc_middle::ty::util::{CheckRegions, NotUniqueParam};
@@ -30,14 +31,21 @@ enum CollectionMode {
/// For impl trait in assoc types we only permit collecting them from
/// associated types of the same impl block.
ImplTraitInAssocTypes,
- TypeAliasImplTraitTransition,
+ /// When collecting for an explicit `#[define_opaques]` attribute, find all TAITs
+ Taits,
+ /// The default case, only collect RPITs and AsyncFn return types, as these are
+ /// always defined by the current item.
+ RpitAndAsyncFnOnly,
}
impl<'tcx> OpaqueTypeCollector<'tcx> {
fn new(tcx: TyCtxt<'tcx>, item: LocalDefId) -> Self {
- let mode = match tcx.def_kind(tcx.local_parent(item)) {
- DefKind::Impl { of_trait: true } => CollectionMode::ImplTraitInAssocTypes,
- _ => CollectionMode::TypeAliasImplTraitTransition,
+ let mode = match tcx.def_kind(item) {
+ DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy => {
+ CollectionMode::ImplTraitInAssocTypes
+ }
+ DefKind::TyAlias => CollectionMode::Taits,
+ _ => CollectionMode::RpitAndAsyncFnOnly,
};
Self { tcx, opaques: Vec::new(), item, seen: Default::default(), span: None, mode }
}
@@ -73,40 +81,6 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
}
}
- /// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `self.item`.
- ///
- /// Example:
- /// ```ignore UNSOLVED (is this a bug?)
- /// # #![feature(type_alias_impl_trait)]
- /// pub mod foo {
- /// pub mod bar {
- /// pub trait Bar { /* ... */ }
- /// pub type Baz = impl Bar;
- ///
- /// # impl Bar for () {}
- /// fn f1() -> Baz { /* ... */ }
- /// }
- /// fn f2() -> bar::Baz { /* ... */ }
- /// }
- /// ```
- ///
- /// and `opaque_def_id` is the `DefId` of the definition of the opaque type `Baz`.
- /// For the above example, this function returns `true` for `f1` and `false` for `f2`.
- #[instrument(level = "trace", skip(self), ret)]
- fn check_tait_defining_scope(&self, opaque_def_id: LocalDefId) -> bool {
- let mut hir_id = self.tcx.local_def_id_to_hir_id(self.item);
- let opaque_hir_id = self.tcx.local_def_id_to_hir_id(opaque_def_id);
-
- // Named opaque types can be defined by any siblings or children of siblings.
- let scope = self.tcx.hir_get_defining_scope(opaque_hir_id);
- // We walk up the node tree until we hit the root or the scope of the opaque type.
- while hir_id != scope && hir_id != CRATE_HIR_ID {
- hir_id = self.tcx.hir_get_parent_item(hir_id).into();
- }
- // Syntactically, we are allowed to define the concrete type if:
- hir_id == scope
- }
-
#[instrument(level = "trace", skip(self))]
fn collect_taits_declared_in_body(&mut self) {
let body = self.tcx.hir_body_owned_by(self.item).value;
@@ -139,18 +113,25 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
}
// TAITs outside their defining scopes are ignored.
- let origin = self.tcx.local_opaque_ty_origin(alias_ty.def_id.expect_local());
- trace!(?origin);
- match origin {
+ match self.tcx.local_opaque_ty_origin(alias_ty.def_id.expect_local()) {
rustc_hir::OpaqueTyOrigin::FnReturn { .. }
| rustc_hir::OpaqueTyOrigin::AsyncFn { .. } => {}
- rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty, .. } => {
- if !in_assoc_ty && !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) {
- return;
+ rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty, .. } => match self.mode {
+ CollectionMode::ImplTraitInAssocTypes => {
+ if !in_assoc_ty {
+ return;
+ }
}
- }
+ CollectionMode::Taits => {
+ if in_assoc_ty {
+ return;
+ }
+ }
+ CollectionMode::RpitAndAsyncFnOnly => return,
+ },
}
+ trace!(?alias_ty, "adding");
self.opaques.push(alias_ty.def_id.expect_local());
let parent_count = self.tcx.generics_of(alias_ty.def_id).parent_count;
@@ -192,6 +173,29 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
}
}
}
+
+ /// Returns true if a define_opaques attr with entries was found
+ #[instrument(level = "trace", skip(self))]
+ fn collect_taits_from_defines_attr(&mut self) {
+ let Some(defines) =
+ find_attr!(self.tcx.get_all_attrs(self.item), AttributeKind::DefineOpaques(r) => r)
+ else {
+ return;
+ };
+ for &(span, define) in defines {
+ trace!(?define);
+ let mode = std::mem::replace(&mut self.mode, CollectionMode::Taits);
+ let n = self.opaques.len();
+ super::sig_types::walk_types(self.tcx, define, self);
+ if n == self.opaques.len() {
+ self.tcx.dcx().span_err(span, "item does not contain any opaque types");
+ }
+ self.mode = mode;
+ }
+ // Allow using `#[define_opaques]` on assoc methods and type aliases to override the default collection mode in
+ // case it was capturing too much.
+ self.mode = CollectionMode::RpitAndAsyncFnOnly;
+ }
}
impl<'tcx> super::sig_types::SpannedTypeVisitor<'tcx> for OpaqueTypeCollector<'tcx> {
@@ -210,6 +214,7 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> {
self.visit_opaque_ty(alias_ty);
}
// Skips type aliases, as they are meant to be transparent.
+ // FIXME(type_alias_impl_trait): can we reqauire mentioning nested type aliases explicitly?
ty::Alias(ty::Weak, alias_ty) if alias_ty.def_id.is_local() => {
self.tcx
.type_of(alias_ty.def_id)
@@ -283,28 +288,6 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> {
self.visit_opaque_ty(alias_ty);
}
}
- ty::Adt(def, _) if def.did().is_local() => {
- if let CollectionMode::ImplTraitInAssocTypes = self.mode {
- return;
- }
- if !self.seen.insert(def.did().expect_local()) {
- return;
- }
- for variant in def.variants().iter() {
- for field in variant.fields.iter() {
- // Don't use the `ty::Adt` args, we either
- // * found the opaque in the args
- // * will find the opaque in the uninstantiated fields
- // The only other situation that can occur is that after instantiating,
- // some projection resolves to an opaque that we would have otherwise
- // not found. While we could instantiate and walk those, that would mean we
- // would have to walk all generic parameters of an Adt, which can quickly
- // degenerate into looking at an exponential number of types.
- let ty = self.tcx.type_of(field.did).instantiate_identity();
- self.visit_spanned(self.tcx.def_span(field.did), ty);
- }
- }
- }
_ => trace!(kind=?t.kind()),
}
}
@@ -317,7 +300,9 @@ fn opaque_types_defined_by<'tcx>(
let kind = tcx.def_kind(item);
trace!(?kind);
let mut collector = OpaqueTypeCollector::new(tcx, item);
+ collector.collect_taits_from_defines_attr();
super::sig_types::walk_types(tcx, item, &mut collector);
+
match kind {
DefKind::AssocFn
| DefKind::Fn
@@ -350,8 +335,7 @@ fn opaque_types_defined_by<'tcx>(
| DefKind::GlobalAsm
| DefKind::Impl { .. }
| DefKind::SyntheticCoroutineBody => {}
- // Closures and coroutines are type checked with their parent, so we need to allow all
- // opaques from the closure signature *and* from the parent body.
+ // Closures and coroutines are type checked with their parent
DefKind::Closure | DefKind::InlineConst => {
collector.opaques.extend(tcx.opaque_types_defined_by(tcx.local_parent(item)));
}
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 16200184422b9..7d60917e01886 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1743,6 +1743,21 @@ pub(crate) mod builtin {
/* compiler built-in */
}
+ /// Provide a list of type aliases and other opaque-type-containing type definitions.
+ /// This list will be used in the body of the item it is applied to to define opaque
+ /// types' hidden types.
+ /// Can only be applied to things that have bodies.
+ #[unstable(
+ feature = "type_alias_impl_trait",
+ issue = "63063",
+ reason = "`type_alias_impl_trait` has open design concerns"
+ )]
+ #[rustc_builtin_macro]
+ #[cfg(not(bootstrap))]
+ pub macro define_opaques($($tt:tt)*) {
+ /* compiler built-in */
+ }
+
/// Unstable placeholder for type ascription.
#[allow_internal_unstable(builtin_syntax)]
#[unstable(
diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs
index 50fd67e839557..593334c53dde7 100644
--- a/library/core/src/prelude/v1.rs
+++ b/library/core/src/prelude/v1.rs
@@ -111,3 +111,11 @@ pub use crate::macros::builtin::type_ascribe;
reason = "placeholder syntax for deref patterns"
)]
pub use crate::macros::builtin::deref;
+
+#[unstable(
+ feature = "type_alias_impl_trait",
+ issue = "63063",
+ reason = "`type_alias_impl_trait` has open design concerns"
+)]
+#[cfg(not(bootstrap))]
+pub use crate::macros::builtin::define_opaques;
diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs
index fc333d7ff3f95..b98b637977dfc 100644
--- a/library/std/src/backtrace.rs
+++ b/library/std/src/backtrace.rs
@@ -432,6 +432,7 @@ mod helper {
use super::*;
pub(super) type LazyResolve = impl (FnOnce() -> Capture) + Send + Sync + UnwindSafe;
+ #[cfg_attr(not(bootstrap), define_opaques(LazyResolve))]
pub(super) fn lazy_resolve(mut capture: Capture) -> LazyResolve {
move || {
// Use the global backtrace lock to synchronize this as it's a
diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs
index 5b324b2e91671..6245769119041 100644
--- a/library/std/src/prelude/v1.rs
+++ b/library/std/src/prelude/v1.rs
@@ -103,6 +103,15 @@ pub use core::prelude::v1::type_ascribe;
)]
pub use core::prelude::v1::deref;
+// Do not `doc(no_inline)` either.
+#[unstable(
+ feature = "type_alias_impl_trait",
+ issue = "63063",
+ reason = "`type_alias_impl_trait` has open design concerns"
+)]
+#[cfg(not(bootstrap))]
+pub use core::prelude::v1::define_opaques;
+
// The file so far is equivalent to core/src/prelude/v1.rs. It is duplicated
// rather than glob imported because we want docs to show these re-exports as
// pointing to within `std`.
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index ce9c42c01cc73..3db09ed627105 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -274,7 +274,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
match item.kind {
- ItemKind::Static(_, _, _)
+ ItemKind::Static(..)
| ItemKind::Const(_, _, _)
| ItemKind::Fn { .. }
| ItemKind::Macro(_, _)
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
index ab5f97199ce33..268dbeff42df3 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
@@ -364,6 +364,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
generics: lg,
contract: lc,
body: lb,
+ define_opaques: _,
}),
Fn(box ast::Fn {
defaultness: rd,
@@ -371,6 +372,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
generics: rg,
contract: rc,
body: rb,
+ define_opaques: _,
}),
) => {
eq_defaultness(*ld, *rd)
@@ -502,6 +504,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
generics: lg,
contract: lc,
body: lb,
+ define_opaques: _,
}),
Fn(box ast::Fn {
defaultness: rd,
@@ -509,6 +512,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
generics: rg,
contract: rc,
body: rb,
+ define_opaques: _,
}),
) => {
eq_defaultness(*ld, *rd)
@@ -567,6 +571,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
generics: lg,
contract: lc,
body: lb,
+ define_opaques: _,
}),
Fn(box ast::Fn {
defaultness: rd,
@@ -574,6 +579,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
generics: rg,
contract: rc,
body: rb,
+ define_opaques: _,
}),
) => {
eq_defaultness(*ld, *rd)
diff --git a/tests/crashes/120016.rs b/tests/crashes/120016.rs
index 09175689256a7..cfc6c2abfbce6 100644
--- a/tests/crashes/120016.rs
+++ b/tests/crashes/120016.rs
@@ -6,6 +6,7 @@
struct Bug {
V1: [(); {
type F = impl std::future::Future