about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-11-28 15:58:17 +0000
committerbors <bors@rust-lang.org>2024-11-28 15:58:17 +0000
commit7e565cce6a03340edb4b9f56228cf5e480e24806 (patch)
tree3e323860390d09842c459257e62d0e87152442a2
parent9b4d7c6a40b328d212095c28670c629facf1557d (diff)
parentd401a078e7839745c8e7d172527111134ad206dd (diff)
downloadrust-7e565cce6a03340edb4b9f56228cf5e480e24806.tar.gz
rust-7e565cce6a03340edb4b9f56228cf5e480e24806.zip
Auto merge of #133468 - lcnr:uwu4, r=BoxyUwU
always create `DefId`s for anon consts

but don't use them anywhere, we intentionally don't encode them in the crate metadata.

best reviewed by disabling whitespace.

This pretty much reimplements #133285 while adding the tests of #133455. Fixes #133064

r? `@BoxyUwU` `@compiler-errors`
-rw-r--r--compiler/rustc_ast/src/ast.rs7
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs19
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs110
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs73
-rw-r--r--compiler/rustc_hir/src/def.rs11
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs14
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs158
-rw-r--r--compiler/rustc_resolve/src/late.rs4
-rw-r--r--compiler/rustc_resolve/src/lib.rs13
-rw-r--r--tests/ui/const-generics/early/const_arg_trivial_macro_expansion-1.rs (renamed from tests/ui/const-generics/early/const_arg_trivial_macro_expansion.rs)287
-rw-r--r--tests/ui/const-generics/early/const_arg_trivial_macro_expansion-3-pass.rs46
-rw-r--r--tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.rs18
-rw-r--r--tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.stderr37
-rw-r--r--tests/ui/consts/issue-36163.stderr6
14 files changed, 485 insertions, 318 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index ecb6ef5a2a6..56b20e0ad89 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1184,14 +1184,15 @@ pub struct Expr {
 }
 
 impl Expr {
-    /// Is this expr either `N`, or `{ N }`.
+    /// Could this expr be either `N`, or `{ N }`, where `N` is a const parameter.
     ///
     /// If this is not the case, name resolution does not resolve `N` when using
     /// `min_const_generics` as more complex expressions are not supported.
     ///
     /// Does not ensure that the path resolves to a const param, the caller should check this.
-    pub fn is_potential_trivial_const_arg(&self, strip_identity_block: bool) -> bool {
-        let this = if strip_identity_block { self.maybe_unwrap_block() } else { self };
+    /// This also does not consider macros, so it's only correct after macro-expansion.
+    pub fn is_potential_trivial_const_arg(&self) -> bool {
+        let this = self.maybe_unwrap_block();
 
         if let ExprKind::Path(None, path) = &this.kind
             && path.is_potential_trivial_const_arg()
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index e85c69c9761..569a15b0e07 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -227,18 +227,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             };
 
                             // Wrap the expression in an AnonConst.
-                            let parent_def_id = self.current_def_id_parent;
+                            let parent_def_id = self.current_hir_id_owner.def_id;
                             let node_id = self.next_node_id();
-                            // HACK(min_generic_const_args): see lower_anon_const
-                            if !expr.is_potential_trivial_const_arg(true) {
-                                self.create_def(
-                                    parent_def_id,
-                                    node_id,
-                                    kw::Empty,
-                                    DefKind::AnonConst,
-                                    *op_sp,
-                                );
-                            }
+                            self.create_def(
+                                parent_def_id,
+                                node_id,
+                                kw::Empty,
+                                DefKind::AnonConst,
+                                *op_sp,
+                            );
                             let anon_const = AnonConst { id: node_id, value: P(expr) };
                             hir::InlineAsmOperand::SymFn {
                                 anon_const: self.lower_anon_const_to_anon_const(&anon_const),
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 3af29838b72..3032042ff9f 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -109,9 +109,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         hir::ConstBlock {
                             def_id,
                             hir_id: this.lower_node_id(c.id),
-                            body: this.with_def_id_parent(def_id, |this| {
-                                this.lower_const_body(c.value.span, Some(&c.value))
-                            }),
+                            body: this.lower_const_body(c.value.span, Some(&c.value)),
                         }
                     });
                     hir::ExprKind::ConstBlock(c)
@@ -452,15 +450,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let mut generic_args = ThinVec::new();
         for (idx, arg) in args.iter().cloned().enumerate() {
             if legacy_args_idx.contains(&idx) {
-                let parent_def_id = self.current_def_id_parent;
+                let parent_def_id = self.current_hir_id_owner.def_id;
                 let node_id = self.next_node_id();
-
-                // HACK(min_generic_const_args): see lower_anon_const
-                if !arg.is_potential_trivial_const_arg(true) {
-                    // Add a definition for the in-band const def.
-                    self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span);
-                }
-
+                self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span);
                 let mut visitor = WillCreateDefIdsVisitor {};
                 let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) {
                     AstP(Expr {
@@ -759,19 +751,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
             lifetime_elision_allowed: false,
         });
 
-        let body = self.with_def_id_parent(closure_def_id, move |this| {
-            this.lower_body(move |this| {
-                this.coroutine_kind = Some(coroutine_kind);
+        let body = self.lower_body(move |this| {
+            this.coroutine_kind = Some(coroutine_kind);
 
-                let old_ctx = this.task_context;
-                if task_context.is_some() {
-                    this.task_context = task_context;
-                }
-                let res = body(this);
-                this.task_context = old_ctx;
+            let old_ctx = this.task_context;
+            if task_context.is_some() {
+                this.task_context = task_context;
+            }
+            let res = body(this);
+            this.task_context = old_ctx;
 
-                (params, res)
-            })
+            (params, res)
         });
 
         // `static |<_task_context?>| -> <return_ty> { <body> }`:
@@ -1056,26 +1046,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let (binder_clause, generic_params) = self.lower_closure_binder(binder);
 
         let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| {
-            this.with_def_id_parent(closure_def_id, move |this| {
-                let mut coroutine_kind = if this
-                    .attrs
-                    .get(&closure_hir_id.local_id)
-                    .is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine)))
-                {
-                    Some(hir::CoroutineKind::Coroutine(Movability::Movable))
-                } else {
-                    None
-                };
-                let body_id = this.lower_fn_body(decl, |this| {
-                    this.coroutine_kind = coroutine_kind;
-                    let e = this.lower_expr_mut(body);
-                    coroutine_kind = this.coroutine_kind;
-                    e
-                });
-                let coroutine_option =
-                    this.closure_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability);
-                (body_id, coroutine_option)
-            })
+            let mut coroutine_kind = if this
+                .attrs
+                .get(&closure_hir_id.local_id)
+                .is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine)))
+            {
+                Some(hir::CoroutineKind::Coroutine(Movability::Movable))
+            } else {
+                None
+            };
+            let body_id = this.lower_fn_body(decl, |this| {
+                this.coroutine_kind = coroutine_kind;
+                let e = this.lower_expr_mut(body);
+                coroutine_kind = this.coroutine_kind;
+                e
+            });
+            let coroutine_option =
+                this.closure_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability);
+            (body_id, coroutine_option)
         });
 
         let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
@@ -1165,28 +1153,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
         );
 
         let body = self.with_new_scopes(fn_decl_span, |this| {
-            this.with_def_id_parent(closure_def_id, |this| {
-                let inner_decl =
-                    FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
-
-                // Transform `async |x: u8| -> X { ... }` into
-                // `|x: u8| || -> X { ... }`.
-                let body_id = this.lower_body(|this| {
-                    let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
-                        &inner_decl,
-                        |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
-                        fn_decl_span,
-                        body.span,
-                        coroutine_kind,
-                        hir::CoroutineSource::Closure,
-                    );
+            let inner_decl =
+                FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
+
+            // Transform `async |x: u8| -> X { ... }` into
+            // `|x: u8| || -> X { ... }`.
+            let body_id = this.lower_body(|this| {
+                let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
+                    &inner_decl,
+                    |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
+                    fn_decl_span,
+                    body.span,
+                    coroutine_kind,
+                    hir::CoroutineSource::Closure,
+                );
 
-                    this.maybe_forward_track_caller(body.span, closure_hir_id, expr.hir_id);
+                this.maybe_forward_track_caller(body.span, closure_hir_id, expr.hir_id);
 
-                    (parameters, expr)
-                });
-                body_id
-            })
+                (parameters, expr)
+            });
+            body_id
         });
 
         let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index dae816663e0..96546239f4c 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -117,18 +117,6 @@ struct LoweringContext<'a, 'hir> {
     is_in_dyn_type: bool,
 
     current_hir_id_owner: hir::OwnerId,
-    /// Why do we need this in addition to [`Self::current_hir_id_owner`]?
-    ///
-    /// Currently (as of June 2024), anonymous constants are not HIR owners; however,
-    /// they do get their own DefIds. Some of these DefIds have to be created during
-    /// AST lowering, rather than def collection, because we can't tell until after
-    /// name resolution whether an anonymous constant will end up instead being a
-    /// [`hir::ConstArgKind::Path`]. However, to compute which generics are
-    /// available to an anonymous constant nested inside another, we need to make
-    /// sure that the parent is recorded as the parent anon const, not the enclosing
-    /// item. So we need to track parent defs differently from HIR owners, since they
-    /// will be finer-grained in the case of anon consts.
-    current_def_id_parent: LocalDefId,
     item_local_id_counter: hir::ItemLocalId,
     trait_map: ItemLocalMap<Box<[TraitCandidate]>>,
 
@@ -161,7 +149,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             attrs: SortedMap::default(),
             children: Vec::default(),
             current_hir_id_owner: hir::CRATE_OWNER_ID,
-            current_def_id_parent: CRATE_DEF_ID,
             item_local_id_counter: hir::ItemLocalId::ZERO,
             ident_and_label_to_local_id: Default::default(),
             #[cfg(debug_assertions)]
@@ -565,7 +552,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             debug_assert_eq!(_old, None);
         }
 
-        let item = self.with_def_id_parent(def_id, f);
+        let item = f(self);
         debug_assert_eq!(def_id, item.def_id().def_id);
         // `f` should have consumed all the elements in these vectors when constructing `item`.
         debug_assert!(self.impl_trait_defs.is_empty());
@@ -590,13 +577,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         self.children.push((def_id, hir::MaybeOwner::Owner(info)));
     }
 
-    fn with_def_id_parent<T>(&mut self, parent: LocalDefId, f: impl FnOnce(&mut Self) -> T) -> T {
-        let current_def_id_parent = std::mem::replace(&mut self.current_def_id_parent, parent);
-        let result = f(self);
-        self.current_def_id_parent = current_def_id_parent;
-        result
-    }
-
     fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> {
         let attrs = std::mem::take(&mut self.attrs);
         let mut bodies = std::mem::take(&mut self.bodies);
@@ -773,7 +753,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             LifetimeRes::Fresh { param, kind, .. } => {
                 // Late resolution delegates to us the creation of the `LocalDefId`.
                 let _def_id = self.create_def(
-                    self.current_hir_id_owner.def_id, // FIXME: should this use self.current_def_id_parent?
+                    self.current_hir_id_owner.def_id,
                     param,
                     kw::UnderscoreLifetime,
                     DefKind::LifetimeParam,
@@ -1466,17 +1446,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let opaque_ty_hir_id = self.lower_node_id(opaque_ty_node_id);
         debug!(?opaque_ty_def_id, ?opaque_ty_hir_id);
 
-        let opaque_ty_def = self.with_def_id_parent(opaque_ty_def_id, |this| {
-            let bounds = lower_item_bounds(this);
-            let opaque_ty_def = hir::OpaqueTy {
-                hir_id: opaque_ty_hir_id,
-                def_id: opaque_ty_def_id,
-                bounds,
-                origin,
-                span: this.lower_span(opaque_ty_span),
-            };
-            this.arena.alloc(opaque_ty_def)
-        });
+        let bounds = lower_item_bounds(self);
+        let opaque_ty_def = hir::OpaqueTy {
+            hir_id: opaque_ty_hir_id,
+            def_id: opaque_ty_def_id,
+            bounds,
+            origin,
+            span: self.lower_span(opaque_ty_span),
+        };
+        let opaque_ty_def = self.arena.alloc(opaque_ty_def);
 
         hir::TyKind::OpaqueDef(opaque_ty_def)
     }
@@ -2084,7 +2062,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         } else {
             // Construct an AnonConst where the expr is the "ty"'s path.
 
-            let parent_def_id = self.current_def_id_parent;
+            let parent_def_id = self.current_hir_id_owner.def_id;
             let node_id = self.next_node_id();
             let span = self.lower_span(span);
 
@@ -2108,9 +2086,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 self.arena.alloc(hir::AnonConst {
                     def_id,
                     hir_id,
-                    body: this.with_def_id_parent(def_id, |this| {
-                        this.lower_const_body(path_expr.span, Some(&path_expr))
-                    }),
+                    body: this.lower_const_body(path_expr.span, Some(&path_expr)),
                     span,
                 })
             });
@@ -2159,7 +2135,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 None,
             );
 
-            return ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath) };
+            return ConstArg {
+                hir_id: self.lower_node_id(anon.id),
+                kind: hir::ConstArgKind::Path(qpath),
+            };
         }
 
         let lowered_anon = self.lower_anon_const_to_anon_const(anon);
@@ -2169,29 +2148,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// See [`hir::ConstArg`] for when to use this function vs
     /// [`Self::lower_anon_const_to_const_arg`].
     fn lower_anon_const_to_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst {
-        if c.value.is_potential_trivial_const_arg(true) {
-            // HACK(min_generic_const_args): see DefCollector::visit_anon_const
-            // Over there, we guess if this is a bare param and only create a def if
-            // we think it's not. However we may can guess wrong (see there for example)
-            // in which case we have to create the def here.
-            self.create_def(
-                self.current_def_id_parent,
-                c.id,
-                kw::Empty,
-                DefKind::AnonConst,
-                c.value.span,
-            );
-        }
-
         self.arena.alloc(self.with_new_scopes(c.value.span, |this| {
             let def_id = this.local_def_id(c.id);
             let hir_id = this.lower_node_id(c.id);
             hir::AnonConst {
                 def_id,
                 hir_id,
-                body: this.with_def_id_parent(def_id, |this| {
-                    this.lower_const_body(c.value.span, Some(&c.value))
-                }),
+                body: this.lower_const_body(c.value.span, Some(&c.value)),
                 span: this.lower_span(c.value.span),
             }
         }))
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 3276f516a52..0b7ffc4af45 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -109,7 +109,16 @@ pub enum DefKind {
     Use,
     /// An `extern` block.
     ForeignMod,
-    /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]`
+    /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]`.
+    ///
+    /// Not all anon-consts are actually still relevant in the HIR. We lower
+    /// trivial const-arguments directly to `hir::ConstArgKind::Path`, at which
+    /// point the definition for the anon-const ends up unused and incomplete.
+    ///
+    /// We do not provide any a `Span` for the definition and pretty much all other
+    /// queries also ICE when using this `DefId`. Given that the `DefId` of such
+    /// constants should only be reachable by iterating all definitions of a
+    /// given crate, you should not have to worry about this.
     AnonConst,
     /// An inline constant, e.g. `const { 1 + 2 }`
     InlineConst,
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index dd149af5205..068a5d31a8e 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1383,6 +1383,20 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             let def_id = local_id.to_def_id();
             let def_kind = tcx.def_kind(local_id);
             self.tables.def_kind.set_some(def_id.index, def_kind);
+
+            // The `DefCollector` will sometimes create unnecessary `DefId`s
+            // for trivial const arguments which are directly lowered to
+            // `ConstArgKind::Path`. We never actually access this `DefId`
+            // anywhere so we don't need to encode it for other crates.
+            if def_kind == DefKind::AnonConst
+                && matches!(
+                    tcx.hir_node_by_def_id(local_id),
+                    hir::Node::ConstArg(hir::ConstArg { kind: hir::ConstArgKind::Path(..), .. })
+                )
+            {
+                continue;
+            }
+
             if should_encode_span(def_kind) {
                 let def_span = tcx.def_span(local_id);
                 record!(self.tables.def_span[def_id] <- def_span);
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 7536869e2fe..66492842581 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -12,23 +12,16 @@ use rustc_span::hygiene::LocalExpnId;
 use rustc_span::symbol::{Symbol, kw, sym};
 use tracing::debug;
 
-use crate::{ImplTraitContext, InvocationParent, PendingAnonConstInfo, Resolver};
+use crate::{ImplTraitContext, InvocationParent, Resolver};
 
 pub(crate) fn collect_definitions(
     resolver: &mut Resolver<'_, '_>,
     fragment: &AstFragment,
     expansion: LocalExpnId,
 ) {
-    let InvocationParent { parent_def, pending_anon_const_info, impl_trait_context, in_attr } =
+    let InvocationParent { parent_def, impl_trait_context, in_attr } =
         resolver.invocation_parents[&expansion];
-    let mut visitor = DefCollector {
-        resolver,
-        parent_def,
-        pending_anon_const_info,
-        expansion,
-        impl_trait_context,
-        in_attr,
-    };
+    let mut visitor = DefCollector { resolver, parent_def, expansion, impl_trait_context, in_attr };
     fragment.visit_with(&mut visitor);
 }
 
@@ -36,13 +29,6 @@ pub(crate) fn collect_definitions(
 struct DefCollector<'a, 'ra, 'tcx> {
     resolver: &'a mut Resolver<'ra, 'tcx>,
     parent_def: LocalDefId,
-    /// If we have an anon const that consists of a macro invocation, e.g. `Foo<{ m!() }>`,
-    /// we need to wait until we know what the macro expands to before we create the def for
-    /// the anon const. That's because we lower some anon consts into `hir::ConstArgKind::Path`,
-    /// which don't have defs.
-    ///
-    /// See `Self::visit_anon_const()`.
-    pending_anon_const_info: Option<PendingAnonConstInfo>,
     impl_trait_context: ImplTraitContext,
     in_attr: bool,
     expansion: LocalExpnId,
@@ -110,61 +96,13 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
 
     fn visit_macro_invoc(&mut self, id: NodeId) {
         let id = id.placeholder_to_expn_id();
-        let pending_anon_const_info = self.pending_anon_const_info.take();
         let old_parent = self.resolver.invocation_parents.insert(id, InvocationParent {
             parent_def: self.parent_def,
-            pending_anon_const_info,
             impl_trait_context: self.impl_trait_context,
             in_attr: self.in_attr,
         });
         assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation");
     }
-
-    /// Determines whether the const argument `AnonConst` is a simple macro call, optionally
-    /// surrounded with braces.
-    ///
-    /// If this const argument *is* a trivial macro call then the id for the macro call is
-    /// returned along with the information required to build the anon const's def if
-    /// the macro call expands to a non-trivial expression.
-    fn is_const_arg_trivial_macro_expansion(
-        &self,
-        anon_const: &'a AnonConst,
-    ) -> Option<(PendingAnonConstInfo, NodeId)> {
-        anon_const.value.optionally_braced_mac_call(false).map(|(block_was_stripped, id)| {
-            (
-                PendingAnonConstInfo {
-                    id: anon_const.id,
-                    span: anon_const.value.span,
-                    block_was_stripped,
-                },
-                id,
-            )
-        })
-    }
-
-    /// Determines whether the expression `const_arg_sub_expr` is a simple macro call, sometimes
-    /// surrounded with braces if a set of braces has not already been entered. This is required
-    /// as `{ N }` is treated as equivalent to a bare parameter `N` whereas `{{ N }}` is treated as
-    /// a real block expression and is lowered to an anonymous constant which is not allowed to use
-    /// generic parameters.
-    ///
-    /// If this expression is a trivial macro call then the id for the macro call is
-    /// returned along with the information required to build the anon const's def if
-    /// the macro call expands to a non-trivial expression.
-    fn is_const_arg_sub_expr_trivial_macro_expansion(
-        &self,
-        const_arg_sub_expr: &'a Expr,
-    ) -> Option<(PendingAnonConstInfo, NodeId)> {
-        let pending_anon = self.pending_anon_const_info.unwrap_or_else(||
-            panic!("Checking expr is trivial macro call without having entered anon const: `{const_arg_sub_expr:?}`"),
-        );
-
-        const_arg_sub_expr.optionally_braced_mac_call(pending_anon.block_was_stripped).map(
-            |(block_was_stripped, id)| {
-                (PendingAnonConstInfo { block_was_stripped, ..pending_anon }, id)
-            },
-        )
-    }
 }
 
 impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
@@ -376,78 +314,34 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
     }
 
     fn visit_anon_const(&mut self, constant: &'a AnonConst) {
-        // HACK(min_generic_const_args): don't create defs for anon consts if we think they will
-        // later be turned into ConstArgKind::Path's. because this is before resolve is done, we
-        // may accidentally identify a construction of a unit struct as a param and not create a
-        // def. we'll then create a def later in ast lowering in this case. the parent of nested
-        // items will be messed up, but that's ok because there can't be any if we're just looking
-        // for bare idents.
-
-        if let Some((pending_anon, macro_invoc)) =
-            self.is_const_arg_trivial_macro_expansion(constant)
-        {
-            self.pending_anon_const_info = Some(pending_anon);
-            return self.visit_macro_invoc(macro_invoc);
-        } else if constant.value.is_potential_trivial_const_arg(true) {
-            return visit::walk_anon_const(self, constant);
-        }
-
-        let def = self.create_def(constant.id, kw::Empty, DefKind::AnonConst, constant.value.span);
-        self.with_parent(def, |this| visit::walk_anon_const(this, constant));
+        let parent =
+            self.create_def(constant.id, kw::Empty, DefKind::AnonConst, constant.value.span);
+        self.with_parent(parent, |this| visit::walk_anon_const(this, constant));
     }
 
     fn visit_expr(&mut self, expr: &'a Expr) {
-        // If we're visiting the expression of a const argument that was a macro call then
-        // check if it is *still* unknown whether it is a trivial const arg or not. If so
-        // recurse into the macro call and delay creating the anon const def until expansion.
-        if self.pending_anon_const_info.is_some()
-            && let Some((pending_anon, macro_invoc)) =
-                self.is_const_arg_sub_expr_trivial_macro_expansion(expr)
-        {
-            self.pending_anon_const_info = Some(pending_anon);
-            return self.visit_macro_invoc(macro_invoc);
-        }
-
-        // See self.pending_anon_const_info for explanation
-        let parent_def = self
-            .pending_anon_const_info
-            .take()
-            // If we already stripped away a set of braces then do not do it again when determining
-            // if the macro expanded to a trivial const arg. This arises in cases such as:
-            // `Foo<{ bar!() }>` where `bar!()` expands to `{ N }`. This should not be considered a
-            // trivial const argument even though `{ N }` by itself *is*.
-            .filter(|pending_anon| {
-                !expr.is_potential_trivial_const_arg(!pending_anon.block_was_stripped)
-            })
-            .map(|pending_anon| {
-                self.create_def(pending_anon.id, kw::Empty, DefKind::AnonConst, pending_anon.span)
-            })
-            .unwrap_or(self.parent_def);
-
-        self.with_parent(parent_def, |this| {
-            let parent_def = match expr.kind {
-                ExprKind::MacCall(..) => return this.visit_macro_invoc(expr.id),
-                ExprKind::Closure(..) | ExprKind::Gen(..) => {
-                    this.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span)
-                }
-                ExprKind::ConstBlock(ref constant) => {
-                    for attr in &expr.attrs {
-                        visit::walk_attribute(this, attr);
-                    }
-                    let def = this.create_def(
-                        constant.id,
-                        kw::Empty,
-                        DefKind::InlineConst,
-                        constant.value.span,
-                    );
-                    this.with_parent(def, |this| visit::walk_anon_const(this, constant));
-                    return;
+        let parent_def = match expr.kind {
+            ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id),
+            ExprKind::Closure(..) | ExprKind::Gen(..) => {
+                self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span)
+            }
+            ExprKind::ConstBlock(ref constant) => {
+                for attr in &expr.attrs {
+                    visit::walk_attribute(self, attr);
                 }
-                _ => this.parent_def,
-            };
+                let def = self.create_def(
+                    constant.id,
+                    kw::Empty,
+                    DefKind::InlineConst,
+                    constant.value.span,
+                );
+                self.with_parent(def, |this| visit::walk_anon_const(this, constant));
+                return;
+            }
+            _ => self.parent_def,
+        };
 
-            this.with_parent(parent_def, |this| visit::walk_expr(this, expr))
-        })
+        self.with_parent(parent_def, |this| visit::walk_expr(this, expr))
     }
 
     fn visit_ty(&mut self, ty: &'a Ty) {
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 60815ffdb1b..fc92dc8b4ed 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -4521,7 +4521,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         );
 
         self.resolve_anon_const_manual(
-            constant.value.is_potential_trivial_const_arg(true),
+            constant.value.is_potential_trivial_const_arg(),
             anon_const_kind,
             |this| this.resolve_expr(&constant.value, None),
         )
@@ -4685,7 +4685,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                     // that is how they will be later lowered to HIR.
                     if const_args.contains(&idx) {
                         self.resolve_anon_const_manual(
-                            argument.is_potential_trivial_const_arg(true),
+                            argument.is_potential_trivial_const_arg(),
                             AnonConstKind::ConstArg(IsRepeatExpr::No),
                             |this| this.resolve_expr(argument, None),
                         );
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index e382295b8f6..094871ad268 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -174,7 +174,6 @@ impl<'ra> ParentScope<'ra> {
 #[derive(Copy, Debug, Clone)]
 struct InvocationParent {
     parent_def: LocalDefId,
-    pending_anon_const_info: Option<PendingAnonConstInfo>,
     impl_trait_context: ImplTraitContext,
     in_attr: bool,
 }
@@ -182,24 +181,12 @@ struct InvocationParent {
 impl InvocationParent {
     const ROOT: Self = Self {
         parent_def: CRATE_DEF_ID,
-        pending_anon_const_info: None,
         impl_trait_context: ImplTraitContext::Existential,
         in_attr: false,
     };
 }
 
 #[derive(Copy, Debug, Clone)]
-struct PendingAnonConstInfo {
-    // A const arg is only a "trivial" const arg if it has at *most* one set of braces
-    // around the argument. We track whether we have stripped an outter brace so that
-    // if a macro expands to a braced expression *and* the macro was itself inside of
-    // some braces then we can consider it to be a non-trivial const argument.
-    block_was_stripped: bool,
-    id: NodeId,
-    span: Span,
-}
-
-#[derive(Copy, Debug, Clone)]
 enum ImplTraitContext {
     Existential,
     Universal,
diff --git a/tests/ui/const-generics/early/const_arg_trivial_macro_expansion.rs b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-1.rs
index 2fdd703ab6f..5ea445520f1 100644
--- a/tests/ui/const-generics/early/const_arg_trivial_macro_expansion.rs
+++ b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-1.rs
@@ -85,6 +85,14 @@ macro_rules! braced_braced_expr {
     () => {{ braced_expr!() }};
 }
 
+macro_rules! closure {
+    () => { |()| () };
+}
+
+macro_rules! empty {
+    () => {};
+}
+
 #[rustfmt::skip]
 mod array_paren_call {
     // Arrays where the expanded result is a `Res::Err`
@@ -128,6 +136,14 @@ mod array_paren_call {
     fn array_33() -> [(); braced_expr!()] { loop {} }
     fn array_34() -> [(); { unbraced_expr!() }] { loop {} }
     fn array_35() -> [(); { braced_expr!() }] { loop {} }
+
+    // Arrays whose expanded form contains a nested definition
+    fn array_36() -> [(); closure!()] { loop {} }
+    fn array_37() -> [(); { closure!() }] { loop {} }
+
+    // Arrays whose macro expansion is empty
+    fn array_38() -> [(); empty!()] { loop {} }
+    fn array_39() -> [(); { empty!() }] { loop {} }
 }
 
 #[rustfmt::skip]
@@ -173,6 +189,14 @@ mod array_brace_call {
     fn array_33() -> [(); braced_expr!{}] { loop {} }
     fn array_34() -> [(); { unbraced_expr!{} }] { loop {} }
     fn array_35() -> [(); { braced_expr!{} }] { loop {} }
+
+    // Arrays whose expanded form contains a nested definition
+    fn array_36() -> [(); closure!{}] { loop {} }
+    fn array_37() -> [(); { closure!{} }] { loop {} }
+
+    // Arrays whose macro expansion is empty
+    fn array_38() -> [(); empty!{}] { loop {} }
+    fn array_39() -> [(); { empty!{} }] { loop {} }
 }
 
 #[rustfmt::skip]
@@ -218,6 +242,14 @@ mod array_square_call {
     fn array_33() -> [(); braced_expr![]] { loop {} }
     fn array_34() -> [(); { unbraced_expr![] }] { loop {} }
     fn array_35() -> [(); { braced_expr![] }] { loop {} }
+
+    // Arrays whose expanded form contains a nested definition
+    fn array_36() -> [(); closure![]] { loop {} }
+    fn array_37() -> [(); { closure![] }] { loop {} }
+
+    // Arrays whose macro expansion is empty
+    fn array_38() -> [(); empty![]] { loop {} }
+    fn array_39() -> [(); { empty![] }] { loop {} }
 }
 
 struct Foo<const N: usize>;
@@ -255,18 +287,26 @@ mod adt_paren_call {
     fn adt_23<const ident: usize>() -> Foo<{ braced_ident!() }> { loop {} }
 
     // An ADT where the expanded result is a complex expr
-    fn array_24() -> Foo<unbraced_unbraced_expr!()> { loop {} }
-    fn array_25() -> Foo<braced_unbraced_expr!()> { loop {} }
-    fn array_26() -> Foo<unbraced_braced_expr!()> { loop {} }
-    fn array_27() -> Foo<braced_braced_expr!()> { loop {} }
-    fn array_28() -> Foo<{ unbraced_unbraced_expr!() }> { loop {} }
-    fn array_29() -> Foo<{ braced_unbraced_expr!() }> { loop {} }
-    fn array_30() -> Foo<{ unbraced_braced_expr!() }> { loop {} }
-    fn array_31() -> Foo<{ braced_braced_expr!() }> { loop {} }
-    fn array_32() -> Foo<unbraced_expr!()> { loop {} }
-    fn array_33() -> Foo<braced_expr!()> { loop {} }
-    fn array_34() -> Foo<{ unbraced_expr!() }> { loop {} }
-    fn array_35() -> Foo<{ braced_expr!() }> { loop {} }
+    fn adt_24() -> Foo<unbraced_unbraced_expr!()> { loop {} }
+    fn adt_25() -> Foo<braced_unbraced_expr!()> { loop {} }
+    fn adt_26() -> Foo<unbraced_braced_expr!()> { loop {} }
+    fn adt_27() -> Foo<braced_braced_expr!()> { loop {} }
+    fn adt_28() -> Foo<{ unbraced_unbraced_expr!() }> { loop {} }
+    fn adt_29() -> Foo<{ braced_unbraced_expr!() }> { loop {} }
+    fn adt_30() -> Foo<{ unbraced_braced_expr!() }> { loop {} }
+    fn adt_31() -> Foo<{ braced_braced_expr!() }> { loop {} }
+    fn adt_32() -> Foo<unbraced_expr!()> { loop {} }
+    fn adt_33() -> Foo<braced_expr!()> { loop {} }
+    fn adt_34() -> Foo<{ unbraced_expr!() }> { loop {} }
+    fn adt_35() -> Foo<{ braced_expr!() }> { loop {} }
+
+    // An ADT whose expanded form contains a nested definition
+    fn adt_36() -> Foo<closure!()> { loop {} }
+    fn adt_37() -> Foo<{ closure!() }> { loop {} }
+
+    // An ADT whose macro expansion is empty
+    fn adt_38() -> Foo<empty!()> { loop {} }
+    fn adt_39() -> Foo<{ empty!() }> { loop {} }
 }
 
 #[rustfmt::skip]
@@ -302,18 +342,26 @@ mod adt_brace_call {
     fn adt_23<const ident: usize>() -> Foo<{ braced_ident!{} }> { loop {} }
 
     // An ADT where the expanded result is a complex expr
-    fn array_24() -> Foo<unbraced_unbraced_expr!{}> { loop {} }
-    fn array_25() -> Foo<braced_unbraced_expr!{}> { loop {} }
-    fn array_26() -> Foo<unbraced_braced_expr!{}> { loop {} }
-    fn array_27() -> Foo<braced_braced_expr!{}> { loop {} }
-    fn array_28() -> Foo<{ unbraced_unbraced_expr!{} }> { loop {} }
-    fn array_29() -> Foo<{ braced_unbraced_expr!{} }> { loop {} }
-    fn array_30() -> Foo<{ unbraced_braced_expr!{} }> { loop {} }
-    fn array_31() -> Foo<{ braced_braced_expr!{} }> { loop {} }
-    fn array_32() -> Foo<unbraced_expr!{}> { loop {} }
-    fn array_33() -> Foo<braced_expr!{}> { loop {} }
-    fn array_34() -> Foo<{ unbraced_expr!{} }> { loop {} }
-    fn array_35() -> Foo<{ braced_expr!{} }> { loop {} }
+    fn adt_24() -> Foo<unbraced_unbraced_expr!{}> { loop {} }
+    fn adt_25() -> Foo<braced_unbraced_expr!{}> { loop {} }
+    fn adt_26() -> Foo<unbraced_braced_expr!{}> { loop {} }
+    fn adt_27() -> Foo<braced_braced_expr!{}> { loop {} }
+    fn adt_28() -> Foo<{ unbraced_unbraced_expr!{} }> { loop {} }
+    fn adt_29() -> Foo<{ braced_unbraced_expr!{} }> { loop {} }
+    fn adt_30() -> Foo<{ unbraced_braced_expr!{} }> { loop {} }
+    fn adt_31() -> Foo<{ braced_braced_expr!{} }> { loop {} }
+    fn adt_32() -> Foo<unbraced_expr!{}> { loop {} }
+    fn adt_33() -> Foo<braced_expr!{}> { loop {} }
+    fn adt_34() -> Foo<{ unbraced_expr!{} }> { loop {} }
+    fn adt_35() -> Foo<{ braced_expr!{} }> { loop {} }
+
+    // An ADT whose expanded form contains a nested definition
+    fn adt_36() -> Foo<closure!{}> { loop {} }
+    fn adt_37() -> Foo<{ closure!{} }> { loop {} }
+
+    // An ADT whose macro expansion is empty
+    fn adt_38() -> Foo<empty!{}> { loop {} }
+    fn adt_39() -> Foo<{ empty!{} }> { loop {} }
 }
 
 #[rustfmt::skip]
@@ -349,18 +397,185 @@ mod adt_square_call {
     fn adt_23<const ident: usize>() -> Foo<{ braced_ident![] }> { loop {} }
 
     // An ADT where the expanded result is a complex expr
-    fn array_24() -> Foo<unbraced_unbraced_expr![]> { loop {} }
-    fn array_25() -> Foo<braced_unbraced_expr![]> { loop {} }
-    fn array_26() -> Foo<unbraced_braced_expr![]> { loop {} }
-    fn array_27() -> Foo<braced_braced_expr![]> { loop {} }
-    fn array_28() -> Foo<{ unbraced_unbraced_expr![] }> { loop {} }
-    fn array_29() -> Foo<{ braced_unbraced_expr![] }> { loop {} }
-    fn array_30() -> Foo<{ unbraced_braced_expr![] }> { loop {} }
-    fn array_31() -> Foo<{ braced_braced_expr![] }> { loop {} }
-    fn array_32() -> Foo<unbraced_expr![]> { loop {} }
-    fn array_33() -> Foo<braced_expr![]> { loop {} }
-    fn array_34() -> Foo<{ unbraced_expr![] }> { loop {} }
-    fn array_35() -> Foo<{ braced_expr![] }> { loop {} }
+    fn adt_24() -> Foo<unbraced_unbraced_expr![]> { loop {} }
+    fn adt_25() -> Foo<braced_unbraced_expr![]> { loop {} }
+    fn adt_26() -> Foo<unbraced_braced_expr![]> { loop {} }
+    fn adt_27() -> Foo<braced_braced_expr![]> { loop {} }
+    fn adt_28() -> Foo<{ unbraced_unbraced_expr![] }> { loop {} }
+    fn adt_29() -> Foo<{ braced_unbraced_expr![] }> { loop {} }
+    fn adt_30() -> Foo<{ unbraced_braced_expr![] }> { loop {} }
+    fn adt_31() -> Foo<{ braced_braced_expr![] }> { loop {} }
+    fn adt_32() -> Foo<unbraced_expr![]> { loop {} }
+    fn adt_33() -> Foo<braced_expr![]> { loop {} }
+    fn adt_34() -> Foo<{ unbraced_expr![] }> { loop {} }
+    fn adt_35() -> Foo<{ braced_expr![] }> { loop {} }
+
+    // An ADT whose expanded form contains a nested definition
+    fn adt_36() -> Foo<closure![]> { loop {} }
+    fn adt_37() -> Foo<{ closure![] }> { loop {} }
+
+    // An ADT whose macro expansion is empty
+    fn adt_38() -> Foo<empty![]> { loop {} }
+    fn adt_39() -> Foo<{ empty![] }> { loop {} }
+}
+
+#[rustfmt::skip]
+mod repeat_paren_call {
+    // A repeat expr where the expanded result is a `Res::Err`
+    fn repeat_0() { [(); unbraced_unbraced_ident!()]; }
+    fn repeat_1() { [(); braced_unbraced_ident!()]; }
+    fn repeat_2() { [(); unbraced_braced_ident!()]; }
+    fn repeat_3() { [(); braced_braced_ident!()]; }
+    fn repeat_4() { [(); { unbraced_unbraced_ident!() }]; }
+    fn repeat_5() { [(); { braced_unbraced_ident!() }]; }
+    fn repeat_6() { [(); { unbraced_braced_ident!() }]; }
+    fn repeat_7() { [(); { braced_braced_ident!() }]; }
+    fn repeat_8() { [(); unbraced_ident!()]; }
+    fn repeat_9() { [(); braced_ident!()]; }
+    fn repeat_10() { [(); { unbraced_ident!() }]; }
+    fn repeat_11() { [(); { braced_ident!() }]; }
+
+    // A repeat expr where the expanded result is a `Res::ConstParam`
+    fn repeat_12<const ident: usize>() { [(); unbraced_unbraced_ident!()]; }
+    fn repeat_13<const ident: usize>() { [(); braced_unbraced_ident!()]; }
+    fn repeat_14<const ident: usize>() { [(); unbraced_braced_ident!()]; }
+    fn repeat_15<const ident: usize>() { [(); braced_braced_ident!()]; }
+    fn repeat_16<const ident: usize>() { [(); { unbraced_unbraced_ident!() }]; }
+    fn repeat_17<const ident: usize>() { [(); { braced_unbraced_ident!() }]; }
+    fn repeat_18<const ident: usize>() { [(); { unbraced_braced_ident!() }]; }
+    fn repeat_19<const ident: usize>() { [(); { braced_braced_ident!() }]; }
+    fn repeat_20<const ident: usize>() { [(); unbraced_ident!()]; }
+    fn repeat_21<const ident: usize>() { [(); braced_ident!()]; }
+    fn repeat_22<const ident: usize>() { [(); { unbraced_ident!() }]; }
+    fn repeat_23<const ident: usize>() { [(); { braced_ident!() }]; }
+
+    // A repeat expr where the expanded result is a complex expr
+    fn repeat_24() { [(); unbraced_unbraced_expr!()]; }
+    fn repeat_25() { [(); braced_unbraced_expr!()]; }
+    fn repeat_26() { [(); unbraced_braced_expr!()]; }
+    fn repeat_27() { [(); braced_braced_expr!()]; }
+    fn repeat_28() { [(); { unbraced_unbraced_expr!() }]; }
+    fn repeat_29() { [(); { braced_unbraced_expr!() }]; }
+    fn repeat_30() { [(); { unbraced_braced_expr!() }]; }
+    fn repeat_31() { [(); { braced_braced_expr!() }]; }
+    fn repeat_32() { [(); unbraced_expr!()]; }
+    fn repeat_33() { [(); braced_expr!()]; }
+    fn repeat_34() { [(); { unbraced_expr!() }]; }
+    fn repeat_35() { [(); { braced_expr!() }]; }
+
+    // A repeat expr whose expanded form contains a nested definition
+    fn repeat_36() { [(); closure!()] }
+    fn repeat_37() { [(); { closure!() }] }
+
+    // A repeat expr whose macro expansion is empty
+    fn repeat_38() { [(); empty!()] }
+    fn repeat_39() { [(); { empty!() }] }
+}
+
+#[rustfmt::skip]
+mod repeat_brace_call {
+    // A repeat expr where the expanded result is a `Res::Err`
+    fn repeat_0() { [(); unbraced_unbraced_ident!{}]; }
+    fn repeat_1() { [(); braced_unbraced_ident!{}]; }
+    fn repeat_2() { [(); unbraced_braced_ident!{}]; }
+    fn repeat_3() { [(); braced_braced_ident!{}]; }
+    fn repeat_4() { [(); { unbraced_unbraced_ident!{} }]; }
+    fn repeat_5() { [(); { braced_unbraced_ident!{} }]; }
+    fn repeat_6() { [(); { unbraced_braced_ident!{} }]; }
+    fn repeat_7() { [(); { braced_braced_ident!{} }]; }
+    fn repeat_8() { [(); unbraced_ident!{}]; }
+    fn repeat_9() { [(); braced_ident!{}]; }
+    fn repeat_10() { [(); { unbraced_ident!{} }]; }
+    fn repeat_11() { [(); { braced_ident!{} }]; }
+
+    // A repeat expr where the expanded result is a `Res::ConstParam`
+    fn repeat_12<const ident: usize>() { [(); unbraced_unbraced_ident!{}]; }
+    fn repeat_13<const ident: usize>() { [(); braced_unbraced_ident!{}]; }
+    fn repeat_14<const ident: usize>() { [(); unbraced_braced_ident!{}]; }
+    fn repeat_15<const ident: usize>() { [(); braced_braced_ident!{}]; }
+    fn repeat_16<const ident: usize>() { [(); { unbraced_unbraced_ident!{} }]; }
+    fn repeat_17<const ident: usize>() { [(); { braced_unbraced_ident!{} }]; }
+    fn repeat_18<const ident: usize>() { [(); { unbraced_braced_ident!{} }]; }
+    fn repeat_19<const ident: usize>() { [(); { braced_braced_ident!{} }]; }
+    fn repeat_20<const ident: usize>() { [(); unbraced_ident!{}]; }
+    fn repeat_21<const ident: usize>() { [(); braced_ident!{}]; }
+    fn repeat_22<const ident: usize>() { [(); { unbraced_ident!{} }]; }
+    fn repeat_23<const ident: usize>() { [(); { braced_ident!{} }]; }
+
+    // A repeat expr where the expanded result is a complex expr
+    fn repeat_24() { [(); unbraced_unbraced_expr!{}]; }
+    fn repeat_25() { [(); braced_unbraced_expr!{}]; }
+    fn repeat_26() { [(); unbraced_braced_expr!{}]; }
+    fn repeat_27() { [(); braced_braced_expr!{}]; }
+    fn repeat_28() { [(); { unbraced_unbraced_expr!{} }]; }
+    fn repeat_29() { [(); { braced_unbraced_expr!{} }]; }
+    fn repeat_30() { [(); { unbraced_braced_expr!{} }]; }
+    fn repeat_31() { [(); { braced_braced_expr!{} }]; }
+    fn repeat_32() { [(); unbraced_expr!{}]; }
+    fn repeat_33() { [(); braced_expr!{}]; }
+    fn repeat_34() { [(); { unbraced_expr!{} }]; }
+    fn repeat_35() { [(); { braced_expr!{} }]; }
+
+    // A repeat expr whose expanded form contains a nested definition
+    fn repeat_36() { [(); closure!{}] }
+    fn repeat_37() { [(); { closure!{} }] }
+
+    // A repeat expr whose macro expansion is empty
+    fn repeat_38() { [(); empty!{}] }
+    fn repeat_39() { [(); { empty!{} }] }
+}
+
+#[rustfmt::skip]
+mod repeat_square_call {
+    // A repeat expr where the expanded result is a `Res::Err`
+    fn repeat_0() { [(); unbraced_unbraced_ident![]]; }
+    fn repeat_1() { [(); braced_unbraced_ident![]]; }
+    fn repeat_2() { [(); unbraced_braced_ident![]]; }
+    fn repeat_3() { [(); braced_braced_ident![]]; }
+    fn repeat_4() { [(); { unbraced_unbraced_ident![] }]; }
+    fn repeat_5() { [(); { braced_unbraced_ident![] }]; }
+    fn repeat_6() { [(); { unbraced_braced_ident![] }]; }
+    fn repeat_7() { [(); { braced_braced_ident![] }]; }
+    fn repeat_8() { [(); unbraced_ident![]]; }
+    fn repeat_9() { [(); braced_ident![]]; }
+    fn repeat_10() { [(); { unbraced_ident![] }]; }
+    fn repeat_11() { [(); { braced_ident![] }]; }
+
+    // A repeat expr where the expanded result is a `Res::ConstParam`
+    fn repeat_12<const ident: usize>() { [(); unbraced_unbraced_ident![]]; }
+    fn repeat_13<const ident: usize>() { [(); braced_unbraced_ident![]]; }
+    fn repeat_14<const ident: usize>() { [(); unbraced_braced_ident![]]; }
+    fn repeat_15<const ident: usize>() { [(); braced_braced_ident![]]; }
+    fn repeat_16<const ident: usize>() { [(); { unbraced_unbraced_ident![] }]; }
+    fn repeat_17<const ident: usize>() { [(); { braced_unbraced_ident![] }]; }
+    fn repeat_18<const ident: usize>() { [(); { unbraced_braced_ident![] }]; }
+    fn repeat_19<const ident: usize>() { [(); { braced_braced_ident![] }]; }
+    fn repeat_20<const ident: usize>() { [(); unbraced_ident![]]; }
+    fn repeat_21<const ident: usize>() { [(); braced_ident![]]; }
+    fn repeat_22<const ident: usize>() { [(); { unbraced_ident![] }]; }
+    fn repeat_23<const ident: usize>() { [(); { braced_ident![] }]; }
+
+    // A repeat expr where the expanded result is a complex expr
+    fn repeat_24() { [(); unbraced_unbraced_expr![]]; }
+    fn repeat_25() { [(); braced_unbraced_expr![]]; }
+    fn repeat_26() { [(); unbraced_braced_expr![]]; }
+    fn repeat_27() { [(); braced_braced_expr![]]; }
+    fn repeat_28() { [(); { unbraced_unbraced_expr![] }]; }
+    fn repeat_29() { [(); { braced_unbraced_expr![] }]; }
+    fn repeat_30() { [(); { unbraced_braced_expr![] }]; }
+    fn repeat_31() { [(); { braced_braced_expr![] }]; }
+    fn repeat_32() { [(); unbraced_expr![]]; }
+    fn repeat_33() { [(); braced_expr![]]; }
+    fn repeat_34() { [(); { unbraced_expr![] }]; }
+    fn repeat_35() { [(); { braced_expr![] }]; }
+
+    // A repeat expr whose expanded form contains a nested definition
+    fn repeat_36() { [(); closure![]] }
+    fn repeat_37() { [(); { closure![] }] }
+
+    // A repeat expr whose macro expansion is empty
+    fn repeat_38() { [(); empty![]] }
+    fn repeat_39() { [(); { empty![] }] }
 }
 
 fn main() {}
diff --git a/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-3-pass.rs b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-3-pass.rs
new file mode 100644
index 00000000000..fb6190324c6
--- /dev/null
+++ b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-3-pass.rs
@@ -0,0 +1,46 @@
+// Additional checks for macro expansion in const args
+
+//@ check-pass
+
+macro_rules! closure {
+    () => { |()| () };
+}
+
+macro_rules! indir_semi {
+    ($nested:ident) => { $nested!(); };
+}
+
+macro_rules! indir {
+    ($nested:ident) => { $nested!() };
+}
+
+macro_rules! empty {
+    () => {};
+}
+
+macro_rules! arg {
+    () => { N };
+}
+
+struct Adt<const N: usize>;
+
+fn array1() -> [(); { closure!(); 0 }] { loop {} }
+fn array2() -> [(); { indir!(closure); 0}] { loop {} }
+fn array3() -> [(); { indir_semi!{ closure } 0 }] { loop {} }
+fn array4<const N: usize>() -> [(); { indir!{ empty } arg!{} }] { loop {} }
+fn array5<const N: usize>() -> [(); { empty!{} arg!() }] { loop {} }
+fn array6<const N: usize>() -> [(); { empty!{} N }] { loop {} }
+fn array7<const N: usize>() -> [(); { arg!{} empty!{} }] { loop {} }
+fn array8<const N: usize>() -> [(); { empty!{} arg!{} empty!{} }] { loop {} }
+
+fn adt1() -> Adt<{ closure!(); 0 }> { loop {} }
+fn adt2() -> Adt<{ indir!(closure); 0}> { loop {} }
+fn adt3() -> Adt<{ indir_semi!{ closure } 0 }> { loop {} }
+fn adt4<const N: usize>() -> Adt<{ indir!{ empty } arg!{} }> { loop {} }
+fn adt5<const N: usize>() -> Adt<{ empty!{} arg!() }> { loop {} }
+fn adt6<const N: usize>() -> Adt<{ empty!{} N }> { loop {} }
+fn adt7<const N: usize>() -> Adt<{ arg!{} empty!{} }> { loop {} }
+fn adt8<const N: usize>() -> Adt<{ empty!{} arg!{} empty!{} }> { loop {} }
+
+
+fn main() {}
diff --git a/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.rs b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.rs
new file mode 100644
index 00000000000..3353d6cf2da
--- /dev/null
+++ b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.rs
@@ -0,0 +1,18 @@
+macro_rules! empty {
+    () => {};
+}
+
+macro_rules! arg {
+    () => {
+        N
+        //~^ ERROR generic parameters may not be used in const operations
+        //~| ERROR generic parameters may not be used in const operations
+    };
+}
+
+struct Foo<const N: usize>;
+fn foo<const N: usize>() -> Foo<{ arg!{} arg!{} }> { loop {} }
+fn bar<const N: usize>() -> [(); { empty!{}; N }] { loop {} }
+//~^ ERROR generic parameters may not be used in const operations
+
+fn main() {}
diff --git a/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.stderr b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.stderr
new file mode 100644
index 00000000000..4722968b203
--- /dev/null
+++ b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.stderr
@@ -0,0 +1,37 @@
+error: generic parameters may not be used in const operations
+  --> $DIR/const_arg_trivial_macro_expansion-4.rs:7:9
+   |
+LL |         N
+   |         ^ cannot perform const operation using `N`
+...
+LL | fn foo<const N: usize>() -> Foo<{ arg!{} arg!{} }> { loop {} }
+   |                                   ------ in this macro invocation
+   |
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
+   = note: this error originates in the macro `arg` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generic parameters may not be used in const operations
+  --> $DIR/const_arg_trivial_macro_expansion-4.rs:7:9
+   |
+LL |         N
+   |         ^ cannot perform const operation using `N`
+...
+LL | fn foo<const N: usize>() -> Foo<{ arg!{} arg!{} }> { loop {} }
+   |                                          ------ in this macro invocation
+   |
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
+   = note: this error originates in the macro `arg` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generic parameters may not be used in const operations
+  --> $DIR/const_arg_trivial_macro_expansion-4.rs:15:46
+   |
+LL | fn bar<const N: usize>() -> [(); { empty!{}; N }] { loop {} }
+   |                                              ^ cannot perform const operation using `N`
+   |
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/consts/issue-36163.stderr b/tests/ui/consts/issue-36163.stderr
index 52d3e003f0a..8a7a0981f41 100644
--- a/tests/ui/consts/issue-36163.stderr
+++ b/tests/ui/consts/issue-36163.stderr
@@ -1,10 +1,10 @@
-error[E0391]: cycle detected when simplifying constant for the type system `Foo::{constant#0}`
+error[E0391]: cycle detected when simplifying constant for the type system `Foo::B::{constant#0}`
   --> $DIR/issue-36163.rs:4:9
    |
 LL |     B = A,
    |         ^
    |
-note: ...which requires const-evaluating + checking `Foo::{constant#0}`...
+note: ...which requires const-evaluating + checking `Foo::B::{constant#0}`...
   --> $DIR/issue-36163.rs:4:9
    |
 LL |     B = A,
@@ -19,7 +19,7 @@ note: ...which requires const-evaluating + checking `A`...
    |
 LL | const A: isize = Foo::B as isize;
    |                  ^^^^^^^^^^^^^^^
-   = note: ...which again requires simplifying constant for the type system `Foo::{constant#0}`, completing the cycle
+   = note: ...which again requires simplifying constant for the type system `Foo::B::{constant#0}`, completing the cycle
 note: cycle used when checking that `Foo` is well-formed
   --> $DIR/issue-36163.rs:3:1
    |