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<P<Expr>>,
+    pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
 }
 
 #[derive(Clone, Encodable, Decodable, Debug)]
@@ -3543,6 +3544,7 @@ pub struct ConstItem {
     pub generics: Generics,
     pub ty: P<Ty>,
     pub expr: Option<P<Expr>>,
+    pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
 }
 
 // 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<T: MutVisitor>(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<T: MutVisitor>(
-    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<T: MutVisitor>(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<T: MutVisitor>(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<T: MutVisitor>(vis: &mut T, capture_by: &mut CaptureBy) {
     }
 }
 
+fn walk_define_opaques<T: MutVisitor>(
+    vis: &mut T,
+    define_opaque: &mut Option<ThinVec<(NodeId, Path)>>,
+) {
+    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<ThinVec<(NodeId, Path)>>,
+) -> 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<ThinVec<(NodeId, Path)>>) {
+        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<T, U> = 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<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
+//~^ ERROR item does not constrain `Bug::{opaque#0}`
 
 #[define_opaque(Bug)]
 fn make_bug<T, U: From<T>>() -> Bug<T, U> {
-    |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<T>` is not satisfied
-  --> $DIR/issue-53092-2.rs:12:5
+LL | type Bug<T, U> = 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<T, U> = 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<T>` is not implemented for `U`
+LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which requires computing layout of `Bug<u8, ()>`...
+   = note: ...which requires normalizing `Bug<u8, ()>`...
+   = 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<T, U> = 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<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
+   |       ^^^^^^^^^
    |
-LL | fn make_bug<T, U: From<T>>() -> Bug<T, U> {
-   |                   ^^^^^^^ 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<T, U: std::convert::From<T>> = impl Fn(T) -> U + Copy;
-   |              +++++++++++++++++++++++
+LL | type Bug<T, U> = 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`.