diff --git a/gcc/rust/ast/rust-ast-dump.cc b/gcc/rust/ast/rust-ast-dump.cc
index 58eb35ad1db..10fb313c2c7 100644
--- a/gcc/rust/ast/rust-ast-dump.cc
+++ b/gcc/rust/ast/rust-ast-dump.cc
@@ -1678,6 +1678,10 @@ void
 Dump::visit (SlicePattern &)
 {}
 
+void
+Dump::visit (AltPattern &)
+{}
+
 // rust-stmt.h
 void
 Dump::visit (EmptyStmt &)
diff --git a/gcc/rust/ast/rust-ast-dump.h b/gcc/rust/ast/rust-ast-dump.h
index 56918f5fc98..dfe6db0dd96 100644
--- a/gcc/rust/ast/rust-ast-dump.h
+++ b/gcc/rust/ast/rust-ast-dump.h
@@ -293,6 +293,7 @@ private:
   void visit (TuplePattern &pattern);
   void visit (GroupedPattern &pattern);
   void visit (SlicePattern &pattern);
+  void visit (AltPattern &pattern);
 
   // rust-stmt.h
   void visit (EmptyStmt &stmt);
diff --git a/gcc/rust/ast/rust-ast-full-decls.h b/gcc/rust/ast/rust-ast-full-decls.h
index 58b12a1be0e..9d7b00ac5a2 100644
--- a/gcc/rust/ast/rust-ast-full-decls.h
+++ b/gcc/rust/ast/rust-ast-full-decls.h
@@ -249,6 +249,7 @@ class TuplePatternItemsRanged;
 class TuplePattern;
 class GroupedPattern;
 class SlicePattern;
+class AltPattern;
 
 // rust-type.h
 class TraitBound;
diff --git a/gcc/rust/ast/rust-ast-visitor.h b/gcc/rust/ast/rust-ast-visitor.h
index aa59a115ee6..1083e834770 100644
--- a/gcc/rust/ast/rust-ast-visitor.h
+++ b/gcc/rust/ast/rust-ast-visitor.h
@@ -203,6 +203,7 @@ public:
   virtual void visit (TuplePattern &pattern) = 0;
   virtual void visit (GroupedPattern &pattern) = 0;
   virtual void visit (SlicePattern &pattern) = 0;
+  virtual void visit (AltPattern &pattern) = 0;
 
   // rust-stmt.h
   virtual void visit (EmptyStmt &stmt) = 0;
diff --git a/gcc/rust/ast/rust-ast.cc b/gcc/rust/ast/rust-ast.cc
index 972cba2e7bb..07983b7da06 100644
--- a/gcc/rust/ast/rust-ast.cc
+++ b/gcc/rust/ast/rust-ast.cc
@@ -2704,6 +2704,17 @@ SlicePattern::as_string () const
   return str;
 }
 
+std::string
+AltPattern::as_string () const
+{
+  std::string str ("AltPattern: ");
+
+  for (const auto &pattern : alts)
+    str += "\n " + pattern->as_string ();
+
+  return str;
+}
+
 std::string
 TuplePatternItemsMultiple::as_string () const
 {
@@ -5649,6 +5660,12 @@ SlicePattern::accept_vis (ASTVisitor &vis)
   vis.visit (*this);
 }
 
+void
+AltPattern::accept_vis (ASTVisitor &vis)
+{
+  vis.visit (*this);
+}
+
 void
 EmptyStmt::accept_vis (ASTVisitor &vis)
 {
diff --git a/gcc/rust/ast/rust-pattern.h b/gcc/rust/ast/rust-pattern.h
index 0e2f56e3216..a62e9b98d93 100644
--- a/gcc/rust/ast/rust-pattern.h
+++ b/gcc/rust/ast/rust-pattern.h
@@ -1563,6 +1563,72 @@ protected:
   }
 };
 
+// AST node for alternate patterns
+// joins together what are technically 'PatternNoTopAlt's
+class AltPattern : public Pattern
+{
+  std::vector<std::unique_ptr<Pattern>> alts;
+  Location locus;
+  NodeId node_id;
+
+public:
+  std::string as_string () const override;
+
+  AltPattern (std::vector<std::unique_ptr<Pattern>> alts, Location locus)
+    : alts (std::move (alts)), locus (locus),
+      node_id (Analysis::Mappings::get ()->get_next_node_id ())
+  {}
+
+  // Copy constructor with vector clone
+  AltPattern (AltPattern const &other) : locus (other.locus)
+  {
+    node_id = other.node_id;
+    alts.reserve (other.alts.size ());
+    for (const auto &e : other.alts)
+      alts.push_back (e->clone_pattern ());
+  }
+
+  // Overloaded assignment operator to vector clone
+  AltPattern &operator= (AltPattern const &other)
+  {
+    locus = other.locus;
+    node_id = other.node_id;
+
+    alts.reserve (other.alts.size ());
+    for (const auto &e : other.alts)
+      alts.push_back (e->clone_pattern ());
+
+    return *this;
+  }
+
+  // move constructors
+  AltPattern (AltPattern &&other) = default;
+  AltPattern &operator= (AltPattern &&other) = default;
+
+  Location get_locus () const override final { return locus; }
+
+  void accept_vis (ASTVisitor &vis) override;
+
+  // TODO: seems kinda dodgy. Think of better way.
+  std::vector<std::unique_ptr<Pattern>> &get_alts () { return alts; }
+  const std::vector<std::unique_ptr<Pattern>> &get_alts () const
+  {
+    return alts;
+  }
+
+  NodeId get_node_id () const { return node_id; }
+
+  NodeId get_pattern_node_id () const override final { return node_id; }
+
+protected:
+  /* Use covariance to implement clone function as returning this object rather
+   * than base */
+  AltPattern *clone_pattern_impl () const override
+  {
+    return new AltPattern (*this);
+  }
+};
+
 // Moved definition to rust-path.h
 class PathPattern;
 
diff --git a/gcc/rust/checks/errors/rust-feature-gate.h b/gcc/rust/checks/errors/rust-feature-gate.h
index 05789cf4751..20af14719bb 100644
--- a/gcc/rust/checks/errors/rust-feature-gate.h
+++ b/gcc/rust/checks/errors/rust-feature-gate.h
@@ -169,6 +169,7 @@ public:
   void visit (AST::TuplePattern &pattern) override {}
   void visit (AST::GroupedPattern &pattern) override {}
   void visit (AST::SlicePattern &pattern) override {}
+  void visit (AST::AltPattern &pattern) override {}
   void visit (AST::EmptyStmt &stmt) override {}
   void visit (AST::LetStmt &stmt) override {}
   void visit (AST::ExprStmtWithoutBlock &stmt) override {}
diff --git a/gcc/rust/expand/rust-attribute-visitor.cc b/gcc/rust/expand/rust-attribute-visitor.cc
index 9abec9221ab..3a94699558d 100644
--- a/gcc/rust/expand/rust-attribute-visitor.cc
+++ b/gcc/rust/expand/rust-attribute-visitor.cc
@@ -3152,6 +3152,20 @@ AttrVisitor::visit (AST::SlicePattern &pattern)
       // TODO: quit stripping now? or keep going?
     }
 }
+void
+AttrVisitor::visit (AST::AltPattern &pattern)
+{
+  // can't strip individual patterns, only sub-patterns
+  for (auto &alt : pattern.get_alts ())
+    {
+      alt->accept_vis (*this);
+
+      if (alt->is_marked_for_strip ())
+	rust_error_at (alt->get_locus (),
+		       "cannot strip pattern in this position");
+      // TODO: quit stripping now? or keep going?
+    }
+}
 
 void
 AttrVisitor::visit (AST::EmptyStmt &)
diff --git a/gcc/rust/expand/rust-attribute-visitor.h b/gcc/rust/expand/rust-attribute-visitor.h
index 9b0e315fc08..2d10735436f 100644
--- a/gcc/rust/expand/rust-attribute-visitor.h
+++ b/gcc/rust/expand/rust-attribute-visitor.h
@@ -258,6 +258,7 @@ public:
   void visit (AST::TuplePattern &pattern) override;
   void visit (AST::GroupedPattern &pattern) override;
   void visit (AST::SlicePattern &pattern) override;
+  void visit (AST::AltPattern &pattern) override;
 
   void visit (AST::EmptyStmt &) override;
   void visit (AST::LetStmt &stmt) override;
diff --git a/gcc/rust/hir/rust-ast-lower-base.cc b/gcc/rust/hir/rust-ast-lower-base.cc
index 33795726b2f..5d7b5d21340 100644
--- a/gcc/rust/hir/rust-ast-lower-base.cc
+++ b/gcc/rust/hir/rust-ast-lower-base.cc
@@ -461,6 +461,9 @@ ASTLoweringBase::visit (AST::GroupedPattern &)
 void
 ASTLoweringBase::visit (AST::SlicePattern &)
 {}
+void
+ASTLoweringBase::visit (AST::AltPattern &)
+{}
 
 // rust-stmt.h
 void
diff --git a/gcc/rust/hir/rust-ast-lower-base.h b/gcc/rust/hir/rust-ast-lower-base.h
index 1af44aa239f..85343aacdab 100644
--- a/gcc/rust/hir/rust-ast-lower-base.h
+++ b/gcc/rust/hir/rust-ast-lower-base.h
@@ -231,6 +231,7 @@ public:
   virtual void visit (AST::TuplePattern &pattern);
   virtual void visit (AST::GroupedPattern &pattern);
   virtual void visit (AST::SlicePattern &pattern);
+  virtual void visit (AST::AltPattern &pattern);
 
   // rust-stmt.h
   virtual void visit (AST::EmptyStmt &stmt);
diff --git a/gcc/rust/resolve/rust-ast-resolve-base.cc b/gcc/rust/resolve/rust-ast-resolve-base.cc
index 0a78d26bcd4..5b3f4a0ae11 100644
--- a/gcc/rust/resolve/rust-ast-resolve-base.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-base.cc
@@ -582,6 +582,10 @@ void
 ResolverBase::visit (AST::SlicePattern &)
 {}
 
+void
+ResolverBase::visit (AST::AltPattern &)
+{}
+
 void
 ResolverBase::visit (AST::EmptyStmt &)
 {}
diff --git a/gcc/rust/resolve/rust-ast-resolve-base.h b/gcc/rust/resolve/rust-ast-resolve-base.h
index 9d88f8fd5d3..aab1324c454 100644
--- a/gcc/rust/resolve/rust-ast-resolve-base.h
+++ b/gcc/rust/resolve/rust-ast-resolve-base.h
@@ -178,6 +178,7 @@ public:
   void visit (AST::TuplePattern &);
   void visit (AST::GroupedPattern &);
   void visit (AST::SlicePattern &);
+  void visit (AST::AltPattern &);
 
   void visit (AST::EmptyStmt &);
   void visit (AST::LetStmt &);
diff --git a/gcc/rust/resolve/rust-early-name-resolver.cc b/gcc/rust/resolve/rust-early-name-resolver.cc
index 5f11ae239bd..f5054f964c7 100644
--- a/gcc/rust/resolve/rust-early-name-resolver.cc
+++ b/gcc/rust/resolve/rust-early-name-resolver.cc
@@ -1052,6 +1052,13 @@ EarlyNameResolver::visit (AST::SlicePattern &pattern)
     item->accept_vis (*this);
 }
 
+void
+EarlyNameResolver::visit (AST::AltPattern &pattern)
+{
+  for (auto &alt : pattern.get_alts ())
+    alt->accept_vis (*this);
+}
+
 void
 EarlyNameResolver::visit (AST::EmptyStmt &)
 {}
diff --git a/gcc/rust/resolve/rust-early-name-resolver.h b/gcc/rust/resolve/rust-early-name-resolver.h
index 21b92e9b7a4..84ee518e23b 100644
--- a/gcc/rust/resolve/rust-early-name-resolver.h
+++ b/gcc/rust/resolve/rust-early-name-resolver.h
@@ -249,6 +249,7 @@ private:
   virtual void visit (AST::TuplePattern &pattern);
   virtual void visit (AST::GroupedPattern &pattern);
   virtual void visit (AST::SlicePattern &pattern);
+  virtual void visit (AST::AltPattern &pattern);
   virtual void visit (AST::EmptyStmt &stmt);
   virtual void visit (AST::LetStmt &stmt);
   virtual void visit (AST::ExprStmtWithoutBlock &stmt);
diff --git a/gcc/rust/util/rust-attributes.cc b/gcc/rust/util/rust-attributes.cc
index 0458f6902b7..4f63dd09dac 100644
--- a/gcc/rust/util/rust-attributes.cc
+++ b/gcc/rust/util/rust-attributes.cc
@@ -767,6 +767,10 @@ void
 AttributeChecker::visit (AST::SlicePattern &)
 {}
 
+void
+AttributeChecker::visit (AST::AltPattern &)
+{}
+
 // rust-stmt.h
 void
 AttributeChecker::visit (AST::EmptyStmt &)
diff --git a/gcc/rust/util/rust-attributes.h b/gcc/rust/util/rust-attributes.h
index c08378cf774..805e3a8f40a 100644
--- a/gcc/rust/util/rust-attributes.h
+++ b/gcc/rust/util/rust-attributes.h
@@ -242,6 +242,7 @@ private:
   void visit (AST::TuplePattern &pattern);
   void visit (AST::GroupedPattern &pattern);
   void visit (AST::SlicePattern &pattern);
+  void visit (AST::AltPattern &pattern);
 
   // rust-stmt.h
   void visit (AST::EmptyStmt &stmt);
