diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index 81c051b8f35e4..1b16ecb5ec2d6 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -273,16 +273,23 @@ impl<'a> Parser<'a> {
         let cursor_snapshot_next_calls = cursor_snapshot.num_next_calls;
         let mut end_pos = self.token_cursor.num_next_calls;
 
+        let mut captured_trailing = false;
+
         // Capture a trailing token if requested by the callback 'f'
         match trailing {
             TrailingToken::None => {}
+            TrailingToken::Gt => {
+                assert_eq!(self.token.kind, token::Gt);
+            }
             TrailingToken::Semi => {
                 assert_eq!(self.token.kind, token::Semi);
                 end_pos += 1;
+                captured_trailing = true;
             }
             TrailingToken::MaybeComma => {
                 if self.token.kind == token::Comma {
                     end_pos += 1;
+                    captured_trailing = true;
                 }
             }
         }
@@ -292,11 +299,7 @@ impl<'a> Parser<'a> {
         // was not actually bumped past it. When the `LazyAttrTokenStream` gets converted
         // into an `AttrTokenStream`, we will create the proper token.
         if self.token_cursor.break_last_token {
-            assert_eq!(
-                trailing,
-                TrailingToken::None,
-                "Cannot set `break_last_token` and have trailing token"
-            );
+            assert!(!captured_trailing, "Cannot set break_last_token and have trailing token");
             end_pos += 1;
         }
 
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index afa116ce1bccd..d9d20195c5f81 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -3080,6 +3080,8 @@ impl<'a> Parser<'a> {
                 && this.token.kind == token::Semi
             {
                 TrailingToken::Semi
+            } else if this.token.kind == token::Gt {
+                TrailingToken::Gt
             } else {
                 // FIXME - pass this through from the place where we know
                 // we need a comma, rather than assuming that `#[attr] expr,`
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index b934e087608a5..89c24920f857d 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -79,6 +79,7 @@ pub enum ForceCollect {
 pub enum TrailingToken {
     None,
     Semi,
+    Gt,
     /// If the trailing token is a comma, then capture it
     /// Otherwise, ignore the trailing token
     MaybeComma,
diff --git a/src/test/ui/parser/issue-103143.rs b/src/test/ui/parser/issue-103143.rs
new file mode 100644
index 0000000000000..a584274c40514
--- /dev/null
+++ b/src/test/ui/parser/issue-103143.rs
@@ -0,0 +1,5 @@
+fn main() {
+    x::<#[a]y::<z>>
+    //~^ ERROR invalid const generic expression
+    //~| ERROR cannot find value `x` in this scope
+}
diff --git a/src/test/ui/parser/issue-103143.stderr b/src/test/ui/parser/issue-103143.stderr
new file mode 100644
index 0000000000000..4035c69afa712
--- /dev/null
+++ b/src/test/ui/parser/issue-103143.stderr
@@ -0,0 +1,20 @@
+error: invalid const generic expression
+  --> $DIR/issue-103143.rs:2:13
+   |
+LL |     x::<#[a]y::<z>>
+   |             ^^^^^^
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     x::<#[a]{ y::<z> }>
+   |             +        +
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/issue-103143.rs:2:5
+   |
+LL |     x::<#[a]y::<z>>
+   |     ^ not found in this scope
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0425`.