diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 5b7545b339663..fd27be2132614 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3535,6 +3535,7 @@ pub struct StaticItem { pub safety: Safety, pub mutability: Mutability, pub expr: Option>, + pub define_opaque: Option>, } #[derive(Clone, Encodable, Decodable, Debug)] @@ -3543,6 +3544,7 @@ pub struct ConstItem { pub generics: Generics, pub ty: P, pub expr: Option>, + pub define_opaque: Option>, } // Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 4edd086430000..b8d85958bfd76 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -987,10 +987,7 @@ fn walk_fn(vis: &mut T, kind: FnKind<'_>) { } vis.visit_span(span); - for (id, path) in define_opaque.iter_mut().flatten() { - vis.visit_id(id); - vis.visit_path(path) - } + walk_define_opaques(vis, define_opaque); } FnKind::Closure(binder, coroutine_kind, decl, body) => { vis.visit_closure_binder(binder); @@ -1258,12 +1255,19 @@ impl WalkItemKind for ItemKind { match self { ItemKind::ExternCrate(_orig_name) => {} ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree), - ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { + ItemKind::Static(box StaticItem { + ty, + safety: _, + mutability: _, + expr, + define_opaque, + }) => { vis.visit_ty(ty); visit_opt(expr, |expr| vis.visit_expr(expr)); + walk_define_opaques(vis, define_opaque); } ItemKind::Const(item) => { - visit_const_item(item, vis); + walk_const_item(vis, item); } ItemKind::Fn(func) => { vis.visit_fn(FnKind::Fn(FnCtxt::Free, ident, visibility, &mut *func), span, id); @@ -1382,7 +1386,7 @@ impl WalkItemKind for AssocItemKind { ) { match self { AssocItemKind::Const(item) => { - visit_const_item(item, visitor); + walk_const_item(visitor, item); } AssocItemKind::Fn(func) => { visitor.visit_fn( @@ -1442,14 +1446,13 @@ impl WalkItemKind for AssocItemKind { } } -fn visit_const_item( - ConstItem { defaultness, generics, ty, expr }: &mut ConstItem, - visitor: &mut T, -) { - visit_defaultness(visitor, defaultness); - visitor.visit_generics(generics); - visitor.visit_ty(ty); - visit_opt(expr, |expr| visitor.visit_expr(expr)); +fn walk_const_item(vis: &mut T, item: &mut ConstItem) { + let ConstItem { defaultness, generics, ty, expr, define_opaque } = item; + visit_defaultness(vis, defaultness); + vis.visit_generics(generics); + vis.visit_ty(ty); + visit_opt(expr, |expr| vis.visit_expr(expr)); + walk_define_opaques(vis, define_opaque); } fn walk_fn_header(vis: &mut T, header: &mut FnHeader) { @@ -1526,9 +1529,16 @@ impl WalkItemKind for ForeignItemKind { visitor: &mut impl MutVisitor, ) { match self { - ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => { + ForeignItemKind::Static(box StaticItem { + ty, + mutability: _, + expr, + safety: _, + define_opaque, + }) => { visitor.visit_ty(ty); visit_opt(expr, |expr| visitor.visit_expr(expr)); + walk_define_opaques(visitor, define_opaque); } ForeignItemKind::Fn(func) => { visitor.visit_fn( @@ -1929,6 +1939,18 @@ fn walk_capture_by(vis: &mut T, capture_by: &mut CaptureBy) { } } +fn walk_define_opaques( + vis: &mut T, + define_opaque: &mut Option>, +) { + if let Some(define_opaque) = define_opaque { + for (id, path) in define_opaque { + vis.visit_id(id); + vis.visit_path(path) + } + } +} + /// Some value for the AST node that is valid but possibly meaningless. Similar /// to `Default` but not intended for wide use. The value will never be used /// meaningfully, it exists just to support unwinding in `visit_clobber` in the diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ce8d6df75afb2..8c0be6f483993 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -16,6 +16,7 @@ pub use rustc_ast_ir::visit::VisitorResult; pub use rustc_ast_ir::{try_visit, visit_opt, walk_list, walk_visitable_list}; use rustc_span::{Ident, Span}; +use thin_vec::ThinVec; use crate::ast::*; use crate::ptr::P; @@ -371,14 +372,28 @@ impl WalkItemKind for ItemKind { match self { ItemKind::ExternCrate(_rename) => {} ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, id, false)), - ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { + ItemKind::Static(box StaticItem { + ty, + safety: _, + mutability: _, + expr, + define_opaque, + }) => { try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); + try_visit!(walk_define_opaques(visitor, define_opaque)); } - ItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => { + ItemKind::Const(box ConstItem { + defaultness: _, + generics, + ty, + expr, + define_opaque, + }) => { try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); + try_visit!(walk_define_opaques(visitor, define_opaque)); } ItemKind::Fn(func) => { let kind = FnKind::Fn(FnCtxt::Free, ident, vis, &*func); @@ -729,9 +744,16 @@ impl WalkItemKind for ForeignItemKind { visitor: &mut V, ) -> V::Result { match self { - ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => { + ForeignItemKind::Static(box StaticItem { + ty, + mutability: _, + expr, + safety: _, + define_opaque, + }) => { try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); + try_visit!(walk_define_opaques(visitor, define_opaque)); } ForeignItemKind::Fn(func) => { let kind = FnKind::Fn(FnCtxt::Foreign, ident, vis, &*func); @@ -907,9 +929,7 @@ 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_opaque.iter().flatten() { - try_visit!(visitor.visit_path(path, *id)) - } + try_visit!(walk_define_opaques(visitor, define_opaque)); } FnKind::Closure(binder, coroutine_kind, decl, body) => { try_visit!(visitor.visit_closure_binder(binder)); @@ -933,10 +953,17 @@ impl WalkItemKind for AssocItemKind { visitor: &mut V, ) -> V::Result { match self { - AssocItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => { + AssocItemKind::Const(box ConstItem { + defaultness: _, + generics, + ty, + expr, + define_opaque, + }) => { try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); + try_visit!(walk_define_opaques(visitor, define_opaque)); } AssocItemKind::Fn(func) => { let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, vis, &*func); @@ -1337,3 +1364,15 @@ pub fn walk_attr_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a AttrArgs) - } V::Result::output() } + +fn walk_define_opaques<'a, V: Visitor<'a>>( + visitor: &mut V, + define_opaque: &'a Option>, +) -> V::Result { + if let Some(define_opaque) = define_opaque { + for (id, path) in define_opaque { + try_visit!(visitor.visit_path(path, *id)); + } + } + V::Result::output() +} diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 219bf62c916dd..c3031a65dd21d 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -188,14 +188,21 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_use_tree(use_tree, &prefix, id, vis_span, attrs) } - ItemKind::Static(box ast::StaticItem { ty: t, safety: _, mutability: m, expr: e }) => { + ItemKind::Static(box ast::StaticItem { + ty: t, + safety: _, + mutability: m, + expr: e, + define_opaque, + }) => { debug_assert_ne!(ident.name, kw::Empty); let ident = self.lower_ident(ident); let (ty, body_id) = self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy); + self.lower_define_opaque(hir_id, define_opaque); hir::ItemKind::Static(ident, ty, *m, body_id) } - ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { + ItemKind::Const(box ast::ConstItem { generics, ty, expr, define_opaque, .. }) => { debug_assert_ne!(ident.name, kw::Empty); let ident = self.lower_ident(ident); let (generics, (ty, body_id)) = self.lower_generics( @@ -206,6 +213,7 @@ impl<'hir> LoweringContext<'_, 'hir> { this.lower_const_item(ty, span, expr.as_deref(), ImplTraitPosition::ConstTy) }, ); + self.lower_define_opaque(hir_id, &define_opaque); hir::ItemKind::Const(ident, ty, generics, body_id) } ItemKind::Fn(box Fn { @@ -243,7 +251,7 @@ impl<'hir> LoweringContext<'_, 'hir> { header: this.lower_fn_header(*header, hir::Safety::Safe, attrs), span: this.lower_span(*fn_sig_span), }; - this.lower_define_opaque(hir_id, &define_opaque); + this.lower_define_opaque(hir_id, define_opaque); let ident = this.lower_ident(ident); hir::ItemKind::Fn { ident, @@ -662,7 +670,7 @@ impl<'hir> LoweringContext<'_, 'hir> { owner_id, ident: self.lower_ident(i.ident), kind: match &i.kind { - ForeignItemKind::Fn(box Fn { sig, generics, .. }) => { + ForeignItemKind::Fn(box Fn { sig, generics, define_opaque, .. }) => { let fdec = &sig.decl; let itctx = ImplTraitContext::Universal; let (generics, (decl, fn_args)) = @@ -683,17 +691,31 @@ impl<'hir> LoweringContext<'_, 'hir> { // Unmarked safety in unsafe block defaults to unsafe. let header = self.lower_fn_header(sig.header, hir::Safety::Unsafe, attrs); + if define_opaque.is_some() { + self.dcx().span_err(i.span, "foreign functions cannot define opaque types"); + } + hir::ForeignItemKind::Fn( hir::FnSig { header, decl, span: self.lower_span(sig.span) }, fn_args, generics, ) } - ForeignItemKind::Static(box StaticItem { ty, mutability, expr: _, safety }) => { + ForeignItemKind::Static(box StaticItem { + ty, + mutability, + expr: _, + safety, + define_opaque, + }) => { let ty = self .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); let safety = self.lower_safety(*safety, hir::Safety::Unsafe); + if define_opaque.is_some() { + self.dcx().span_err(i.span, "foreign statics cannot define opaque types"); + } + hir::ForeignItemKind::Static(ty, *mutability, safety) } ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type, @@ -801,7 +823,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let trait_item_def_id = hir_id.expect_owner(); let (generics, kind, has_default) = match &i.kind { - AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => { + AssocItemKind::Const(box ConstItem { generics, ty, expr, define_opaque, .. }) => { let (generics, kind) = self.lower_generics( generics, i.id, @@ -814,6 +836,18 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::TraitItemKind::Const(ty, body) }, ); + + if define_opaque.is_some() { + if expr.is_some() { + self.lower_define_opaque(hir_id, &define_opaque); + } else { + self.dcx().span_err( + i.span, + "only trait consts with default bodies can define opaque types", + ); + } + } + (generics, kind, expr.is_some()) } AssocItemKind::Fn(box Fn { sig, generics, body: None, define_opaque, .. }) => { @@ -951,18 +985,20 @@ impl<'hir> LoweringContext<'_, 'hir> { let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); let (generics, kind) = match &i.kind { - AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics( - generics, - i.id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), - |this| { - let ty = - this.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - let body = this.lower_const_body(i.span, expr.as_deref()); - - hir::ImplItemKind::Const(ty, body) - }, - ), + AssocItemKind::Const(box ConstItem { generics, ty, expr, define_opaque, .. }) => self + .lower_generics( + generics, + i.id, + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + |this| { + let ty = this + .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let body = this.lower_const_body(i.span, expr.as_deref()); + this.lower_define_opaque(hir_id, &define_opaque); + + hir::ImplItemKind::Const(ty, body) + }, + ), AssocItemKind::Fn(box Fn { sig, generics, body, contract, define_opaque, .. }) => { let body_id = self.lower_maybe_coroutine_body( sig.span, diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 6236f8ecfb524..d406a56c05da0 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -37,18 +37,23 @@ impl<'a> State<'a> { ast::ForeignItemKind::Fn(func) => { self.print_fn_full(ident, vis, attrs, &*func); } - ast::ForeignItemKind::Static(box ast::StaticItem { ty, mutability, expr, safety }) => { - self.print_item_const( - ident, - Some(*mutability), - &ast::Generics::default(), - ty, - expr.as_deref(), - vis, - *safety, - ast::Defaultness::Final, - ) - } + ast::ForeignItemKind::Static(box ast::StaticItem { + ty, + mutability, + expr, + safety, + define_opaque, + }) => self.print_item_const( + ident, + Some(*mutability), + &ast::Generics::default(), + ty, + expr.as_deref(), + vis, + *safety, + ast::Defaultness::Final, + define_opaque.as_deref(), + ), ast::ForeignItemKind::TyAlias(box ast::TyAlias { defaultness, generics, @@ -86,7 +91,9 @@ impl<'a> State<'a> { vis: &ast::Visibility, safety: ast::Safety, defaultness: ast::Defaultness, + define_opaque: Option<&[(ast::NodeId, ast::Path)]>, ) { + self.print_define_opaques(define_opaque); self.head(""); self.print_visibility(vis); self.print_safety(safety); @@ -174,7 +181,13 @@ impl<'a> State<'a> { self.print_use_tree(tree); self.word(";"); } - ast::ItemKind::Static(box StaticItem { ty, safety, mutability: mutbl, expr: body }) => { + ast::ItemKind::Static(box StaticItem { + ty, + safety, + mutability: mutbl, + expr: body, + define_opaque, + }) => { self.print_safety(*safety); self.print_item_const( item.ident, @@ -185,9 +198,16 @@ impl<'a> State<'a> { &item.vis, ast::Safety::Default, ast::Defaultness::Final, + define_opaque.as_deref(), ); } - ast::ItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => { + ast::ItemKind::Const(box ast::ConstItem { + defaultness, + generics, + ty, + expr, + define_opaque, + }) => { self.print_item_const( item.ident, None, @@ -197,6 +217,7 @@ impl<'a> State<'a> { &item.vis, ast::Safety::Default, *defaultness, + define_opaque.as_deref(), ); } ast::ItemKind::Fn(func) => { @@ -537,7 +558,13 @@ impl<'a> State<'a> { ast::AssocItemKind::Fn(func) => { self.print_fn_full(ident, vis, attrs, &*func); } - ast::AssocItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => { + ast::AssocItemKind::Const(box ast::ConstItem { + defaultness, + generics, + ty, + expr, + define_opaque, + }) => { self.print_item_const( ident, None, @@ -547,6 +574,7 @@ impl<'a> State<'a> { vis, ast::Safety::Default, *defaultness, + define_opaque.as_deref(), ); } ast::AssocItemKind::Type(box ast::TyAlias { @@ -652,13 +680,7 @@ impl<'a> State<'a> { ) { let ast::Fn { defaultness, generics, sig, contract, body, define_opaque } = func; - if let Some(define_opaque) = define_opaque { - for (_, path) in define_opaque { - self.word("define opaques from "); - self.print_path(path, false, 0); - self.word(","); - } - } + self.print_define_opaques(define_opaque.as_deref()); if body.is_some() { self.head(""); @@ -678,6 +700,21 @@ impl<'a> State<'a> { } } + fn print_define_opaques(&mut self, define_opaque: Option<&[(ast::NodeId, ast::Path)]>) { + if let Some(define_opaque) = define_opaque { + self.word("#[define_opaque("); + for (i, (_, path)) in define_opaque.iter().enumerate() { + if i != 0 { + self.word_space(","); + } + + self.print_path(path, false, 0); + } + self.word(")]"); + } + self.hardbreak_if_not_bol(); + } + fn print_contract(&mut self, contract: &ast::FnContract) { if let Some(pred) = &contract.requires { self.word("rustc_requires"); diff --git a/compiler/rustc_builtin_macros/src/define_opaque.rs b/compiler/rustc_builtin_macros/src/define_opaque.rs index 9777e772cf208..cd02e81f5689c 100644 --- a/compiler/rustc_builtin_macros/src/define_opaque.rs +++ b/compiler/rustc_builtin_macros/src/define_opaque.rs @@ -11,15 +11,20 @@ pub(crate) fn expand( let define_opaque = match &mut item { Annotatable::Item(p) => match &mut p.kind { ast::ItemKind::Fn(f) => Some(&mut f.define_opaque), + ast::ItemKind::Const(ct) => Some(&mut ct.define_opaque), + ast::ItemKind::Static(si) => Some(&mut si.define_opaque), _ => None, }, Annotatable::AssocItem(i, _assoc_ctxt) => match &mut i.kind { ast::AssocItemKind::Fn(func) => Some(&mut func.define_opaque), + ast::AssocItemKind::Const(ct) => Some(&mut ct.define_opaque), _ => None, }, Annotatable::Stmt(s) => match &mut s.kind { ast::StmtKind::Item(p) => match &mut p.kind { ast::ItemKind::Fn(f) => Some(&mut f.define_opaque), + ast::ItemKind::Const(ct) => Some(&mut ct.define_opaque), + ast::ItemKind::Static(si) => Some(&mut si.define_opaque), _ => None, }, _ => None, @@ -47,7 +52,10 @@ pub(crate) fn expand( .collect(), ); } else { - ecx.dcx().span_err(meta_item.span, "only functions and methods can define opaque types"); + ecx.dcx().span_err( + meta_item.span, + "only functions, statics, and consts can define opaque types", + ); } vec![item] diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index a05fff2dcd1c1..239f8657284d5 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -285,6 +285,7 @@ pub(crate) fn expand_test_or_bench( defaultness: ast::Defaultness::Final, generics: ast::Generics::default(), ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), + define_opaque: None, // test::TestDescAndFn { expr: Some( cx.expr_struct( diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index ee7f68cc2f01c..2c9b5f40d0dfe 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -698,8 +698,14 @@ impl<'a> ExtCtxt<'a> { name, AttrVec::new(), ast::ItemKind::Static( - ast::StaticItem { ty, safety: ast::Safety::Default, mutability, expr: Some(expr) } - .into(), + ast::StaticItem { + ty, + safety: ast::Safety::Default, + mutability, + expr: Some(expr), + define_opaque: None, + } + .into(), ), ) } @@ -723,6 +729,7 @@ impl<'a> ExtCtxt<'a> { generics: ast::Generics::default(), ty, expr: Some(expr), + define_opaque: None, } .into(), ), diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index f4df4044dd2ea..38a2eab5544f6 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -265,6 +265,7 @@ impl<'a> Parser<'a> { generics, ty, expr, + define_opaque: None, })), ) } @@ -980,13 +981,20 @@ impl<'a> Parser<'a> { let kind = match AssocItemKind::try_from(kind) { Ok(kind) => kind, Err(kind) => match kind { - ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { + ItemKind::Static(box StaticItem { + ty, + safety: _, + mutability: _, + expr, + define_opaque, + }) => { self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span }); AssocItemKind::Const(Box::new(ConstItem { defaultness: Defaultness::Final, generics: Generics::default(), ty, expr, + define_opaque, })) } _ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"), @@ -1254,6 +1262,7 @@ impl<'a> Parser<'a> { mutability: Mutability::Not, expr, safety: Safety::Default, + define_opaque: None, })) } _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"), @@ -1397,7 +1406,7 @@ impl<'a> Parser<'a> { self.expect_semi()?; - Ok((ident, StaticItem { ty, safety, mutability, expr })) + Ok((ident, StaticItem { ty, safety, mutability, expr, define_opaque: None })) } /// Parse a constant item with the prefix `"const"` already parsed. diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 33f529851ae4f..fcb638a117e31 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -244,7 +244,13 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { let def_kind = match fi.kind { - ForeignItemKind::Static(box StaticItem { ty: _, mutability, expr: _, safety }) => { + ForeignItemKind::Static(box StaticItem { + ty: _, + mutability, + expr: _, + safety, + define_opaque: _, + }) => { let safety = match safety { ast::Safety::Unsafe(_) | ast::Safety::Default => hir::Safety::Unsafe, ast::Safety::Safe(_) => hir::Safety::Safe, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f8808582353ad..9cbdb83a30fa2 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -36,6 +36,7 @@ use rustc_session::parse::feature_err; use rustc_span::source_map::{Spanned, respan}; use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym}; use smallvec::{SmallVec, smallvec}; +use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; use crate::{ @@ -2662,10 +2663,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }, |this| visit::walk_item(this, item), ); - - for (id, path) in define_opaque.iter().flatten() { - self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques); - } + self.resolve_define_opaques(define_opaque); } ItemKind::Enum(_, ref generics) @@ -2751,7 +2749,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }); } - ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) => { + ItemKind::Static(box ast::StaticItem { + ref ty, ref expr, ref define_opaque, .. + }) => { self.with_static_rib(def_kind, |this| { this.with_lifetime_rib( LifetimeRibKind::Elided(LifetimeRes::Static { @@ -2767,9 +2767,16 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.resolve_const_body(expr, Some((item.ident, ConstantItemKind::Static))); } }); + self.resolve_define_opaques(define_opaque); } - ItemKind::Const(box ast::ConstItem { ref generics, ref ty, ref expr, .. }) => { + ItemKind::Const(box ast::ConstItem { + ref generics, + ref ty, + ref expr, + ref define_opaque, + .. + }) => { self.with_generic_param_rib( &generics.params, RibKind::Item( @@ -2803,6 +2810,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } }, ); + self.resolve_define_opaques(define_opaque); } ItemKind::Use(ref use_tree) => { @@ -3102,7 +3110,13 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { for item in trait_items { self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id)); match &item.kind { - AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { + AssocItemKind::Const(box ast::ConstItem { + generics, + ty, + expr, + define_opaque, + .. + }) => { self.with_generic_param_rib( &generics.params, RibKind::AssocItem, @@ -3135,13 +3149,13 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ) }, ); + + self.resolve_define_opaques(define_opaque); } AssocItemKind::Fn(box Fn { generics, define_opaque, .. }) => { walk_assoc_item(self, generics, LifetimeBinderKind::Function, item); - for (id, path) in define_opaque.iter().flatten() { - self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques); - } + self.resolve_define_opaques(define_opaque); } AssocItemKind::Delegation(delegation) => { self.with_generic_param_rib( @@ -3306,7 +3320,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { use crate::ResolutionError::*; self.resolve_doc_links(&item.attrs, MaybeExported::ImplItem(trait_id.ok_or(&item.vis))); match &item.kind { - AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { + AssocItemKind::Const(box ast::ConstItem { + generics, ty, expr, define_opaque, .. + }) => { debug!("resolve_implementation AssocItemKind::Const"); self.with_generic_param_rib( &generics.params, @@ -3350,6 +3366,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); }, ); + self.resolve_define_opaques(define_opaque); } AssocItemKind::Fn(box Fn { generics, define_opaque, .. }) => { debug!("resolve_implementation AssocItemKind::Fn"); @@ -3379,9 +3396,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }, ); - for (id, path) in define_opaque.iter().flatten() { - self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques); - } + self.resolve_define_opaques(define_opaque); } AssocItemKind::Type(box TyAlias { generics, .. }) => { self.diag_metadata.in_non_gat_assoc_type = Some(generics.params.is_empty()); @@ -5103,6 +5118,14 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }); } } + + fn resolve_define_opaques(&mut self, define_opaque: &Option>) { + if let Some(define_opaque) = define_opaque { + for (id, path) in define_opaque { + self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques); + } + } + } } /// Walks the whole crate in DFS order, visiting each item, counting the declared number of 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 54261079fcad8..6023ae9cc7b16 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -336,12 +336,14 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { mutability: lm, expr: le, safety: ls, + define_opaque: _, }), Static(box StaticItem { ty: rt, mutability: rm, expr: re, safety: rs, + define_opaque: _, }), ) => lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()), ( @@ -350,12 +352,14 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { generics: lg, ty: lt, expr: le, + define_opaque: _, }), Const(box ConstItem { defaultness: rd, generics: rg, ty: rt, expr: re, + define_opaque: _, }), ) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()), ( @@ -490,12 +494,14 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { mutability: lm, expr: le, safety: ls, + define_opaque: _, }), Static(box StaticItem { ty: rt, mutability: rm, expr: re, safety: rs, + define_opaque: _, }), ) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()) && ls == rs, ( @@ -557,12 +563,14 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { generics: lg, ty: lt, expr: le, + define_opaque: _, }), Const(box ConstItem { defaultness: rd, generics: rg, ty: rt, expr: re, + define_opaque: _, }), ) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()), ( diff --git a/tests/ui/impl-trait/define-via-const.rs b/tests/ui/impl-trait/define-via-const.rs new file mode 100644 index 0000000000000..a4b9123654c45 --- /dev/null +++ b/tests/ui/impl-trait/define-via-const.rs @@ -0,0 +1,12 @@ +//@ check-pass + +#![feature(type_alias_impl_trait)] + +type Closure = impl Fn(u32) -> u32; + +#[define_opaque(Closure)] +const ADDER: Closure = |x| x + 1; + +fn main() { + let z = (ADDER)(1); +} diff --git a/tests/ui/impl-trait/define-via-extern.rs b/tests/ui/impl-trait/define-via-extern.rs new file mode 100644 index 0000000000000..599c31ff917fc --- /dev/null +++ b/tests/ui/impl-trait/define-via-extern.rs @@ -0,0 +1,16 @@ +#![feature(type_alias_impl_trait)] + +type Hi = impl Sized; + +extern "C" { + #[define_opaque(Hi)] fn foo(); + //~^ ERROR only functions, statics, and consts can define opaque types + + #[define_opaque(Hi)] static HI: Hi; + //~^ ERROR only functions, statics, and consts can define opaque types +} + +#[define_opaque(Hi)] +fn main() { + let _: Hi = 0; +} diff --git a/tests/ui/impl-trait/define-via-extern.stderr b/tests/ui/impl-trait/define-via-extern.stderr new file mode 100644 index 0000000000000..4a0ca5edd47d0 --- /dev/null +++ b/tests/ui/impl-trait/define-via-extern.stderr @@ -0,0 +1,14 @@ +error: only functions, statics, and consts can define opaque types + --> $DIR/define-via-extern.rs:6:5 + | +LL | #[define_opaque(Hi)] fn foo(); + | ^^^^^^^^^^^^^^^^^^^^ + +error: only functions, statics, and consts can define opaque types + --> $DIR/define-via-extern.rs:9:5 + | +LL | #[define_opaque(Hi)] static HI: Hi; + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/type-alias-impl-trait/issue-53092-2.rs b/tests/ui/type-alias-impl-trait/issue-53092-2.rs index 5f44a9aa2dfa9..1a530d27971a5 100644 --- a/tests/ui/type-alias-impl-trait/issue-53092-2.rs +++ b/tests/ui/type-alias-impl-trait/issue-53092-2.rs @@ -2,14 +2,15 @@ #![allow(dead_code)] type Bug = impl Fn(T) -> U + Copy; +//~^ ERROR cycle detected when computing type of `Bug::{opaque#0}` #[define_opaque(Bug)] -//~^ ERROR: only functions and methods can define opaque types const CONST_BUG: Bug = unsafe { std::mem::transmute(|_: u8| ()) }; +//~^ ERROR item does not constrain `Bug::{opaque#0}` #[define_opaque(Bug)] fn make_bug>() -> Bug { - |x| x.into() //~ ERROR is not satisfied + |x| x.into() } fn main() { diff --git a/tests/ui/type-alias-impl-trait/issue-53092-2.stderr b/tests/ui/type-alias-impl-trait/issue-53092-2.stderr index 5739662ff80bc..3062e55dc4909 100644 --- a/tests/ui/type-alias-impl-trait/issue-53092-2.stderr +++ b/tests/ui/type-alias-impl-trait/issue-53092-2.stderr @@ -1,25 +1,42 @@ -error: only functions and methods can define opaque types - --> $DIR/issue-53092-2.rs:6:1 +error[E0391]: cycle detected when computing type of `Bug::{opaque#0}` + --> $DIR/issue-53092-2.rs:4:18 | -LL | #[define_opaque(Bug)] - | ^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `U: From` is not satisfied - --> $DIR/issue-53092-2.rs:12:5 +LL | type Bug = impl Fn(T) -> U + Copy; + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires computing type of opaque `Bug::{opaque#0}`... + --> $DIR/issue-53092-2.rs:4:18 + | +LL | type Bug = impl Fn(T) -> U + Copy; + | ^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `CONST_BUG`... + --> $DIR/issue-53092-2.rs:8:1 | -LL | |x| x.into() - | ^^^^^^^^^^^^ the trait `From` is not implemented for `U` +LL | const CONST_BUG: Bug = unsafe { std::mem::transmute(|_: u8| ()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which requires computing layout of `Bug`... + = note: ...which requires normalizing `Bug`... + = note: ...which again requires computing type of `Bug::{opaque#0}`, completing the cycle +note: cycle used when checking that `Bug::{opaque#0}` is well-formed + --> $DIR/issue-53092-2.rs:4:18 + | +LL | type Bug = impl Fn(T) -> U + Copy; + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: item does not constrain `Bug::{opaque#0}` + --> $DIR/issue-53092-2.rs:8:7 | -note: required by a bound in `make_bug` - --> $DIR/issue-53092-2.rs:11:19 +LL | const CONST_BUG: Bug = unsafe { std::mem::transmute(|_: u8| ()) }; + | ^^^^^^^^^ | -LL | fn make_bug>() -> Bug { - | ^^^^^^^ required by this bound in `make_bug` -help: consider restricting type parameter `U` with trait `From` + = note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]` +note: this opaque type is supposed to be constrained + --> $DIR/issue-53092-2.rs:4:18 | -LL | type Bug> = impl Fn(T) -> U + Copy; - | +++++++++++++++++++++++ +LL | type Bug = impl Fn(T) -> U + Copy; + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs index b5533eeecba5f..e21627e14b098 100644 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs @@ -1,19 +1,15 @@ +//@ check-pass + #![feature(type_alias_impl_trait)] -// Ensures that `const` items can not constrain an opaque `impl Trait`. use std::fmt::Debug; pub type Foo = impl Debug; -//~^ ERROR unconstrained opaque type #[define_opaque(Foo)] -//~^ ERROR only functions and methods can define opaque types const _FOO: Foo = 5; -//~^ ERROR mismatched types #[define_opaque(Foo)] -//~^ ERROR only functions and methods can define opaque types -static _BAR: Foo = 22_u32; -//~^ ERROR mismatched types +static _BAR: Foo = 22_i32; fn main() {} diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.stderr deleted file mode 100644 index dc15da665f325..0000000000000 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.stderr +++ /dev/null @@ -1,57 +0,0 @@ -error: only functions and methods can define opaque types - --> $DIR/type-alias-impl-trait-const.rs:9:1 - | -LL | #[define_opaque(Foo)] - | ^^^^^^^^^^^^^^^^^^^^^ - -error: only functions and methods can define opaque types - --> $DIR/type-alias-impl-trait-const.rs:14:1 - | -LL | #[define_opaque(Foo)] - | ^^^^^^^^^^^^^^^^^^^^^ - -error: unconstrained opaque type - --> $DIR/type-alias-impl-trait-const.rs:6:16 - | -LL | pub type Foo = impl Debug; - | ^^^^^^^^^^ - | - = note: `Foo` must be used in combination with a concrete type within the same crate - -error[E0308]: mismatched types - --> $DIR/type-alias-impl-trait-const.rs:11:19 - | -LL | pub type Foo = impl Debug; - | ---------- the expected opaque type -... -LL | const _FOO: Foo = 5; - | ^ expected opaque type, found integer - | - = note: expected opaque type `Foo` - found type `{integer}` -note: this item must have a `#[define_opaque(Foo)]` attribute to be able to define hidden types - --> $DIR/type-alias-impl-trait-const.rs:11:7 - | -LL | const _FOO: Foo = 5; - | ^^^^ - -error[E0308]: mismatched types - --> $DIR/type-alias-impl-trait-const.rs:16:20 - | -LL | pub type Foo = impl Debug; - | ---------- the expected opaque type -... -LL | static _BAR: Foo = 22_u32; - | ^^^^^^ expected opaque type, found `u32` - | - = note: expected opaque type `Foo` - found type `u32` -note: this item must have a `#[define_opaque(Foo)]` attribute to be able to define hidden types - --> $DIR/type-alias-impl-trait-const.rs:16:8 - | -LL | static _BAR: Foo = 22_u32; - | ^^^^ - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0308`.