diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 91d6bfbea4d..41ed8163cd8 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1324,6 +1324,7 @@ ANALYZER_OBJS = \
 	analyzer/program-point.o \
 	analyzer/program-state.o \
 	analyzer/ranges.o \
+	analyzer/record-layout.o \
 	analyzer/region.o \
 	analyzer/region-model.o \
 	analyzer/region-model-asm.o \
diff --git a/gcc/analyzer/record-layout.cc b/gcc/analyzer/record-layout.cc
new file mode 100644
index 00000000000..1369bfb5eff
--- /dev/null
+++ b/gcc/analyzer/record-layout.cc
@@ -0,0 +1,125 @@
+/* Implementation of class record_layout.
+   Copyright (C) 2022-2023 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#define INCLUDE_MEMORY
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "function.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "diagnostic.h"
+#include "tree-diagnostic.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/record-layout.h"
+
+#if ENABLE_ANALYZER
+
+namespace ana {
+
+/* class record_layout.  */
+
+record_layout::record_layout (tree record_type)
+{
+  gcc_assert (TREE_CODE (record_type) == RECORD_TYPE);
+
+  for (tree iter = TYPE_FIELDS (record_type); iter != NULL_TREE;
+       iter = DECL_CHAIN (iter))
+    {
+      if (TREE_CODE (iter) == FIELD_DECL)
+	{
+	  int iter_field_offset = int_bit_position (iter);
+	  bit_size_t size_in_bits;
+	  if (!int_size_in_bits (TREE_TYPE (iter), &size_in_bits))
+	    size_in_bits = 0;
+
+	  maybe_pad_to (iter_field_offset);
+
+	  /* Add field.  */
+	  m_items.safe_push (item (bit_range (iter_field_offset,
+					      size_in_bits),
+				   iter, false));
+	}
+    }
+
+  /* Add any trailing padding.  */
+  bit_size_t size_in_bits;
+  if (int_size_in_bits (record_type, &size_in_bits))
+    maybe_pad_to (size_in_bits);
+}
+
+void
+record_layout::dump_to_pp (pretty_printer *pp) const
+{
+  unsigned i;
+  item *it;
+  FOR_EACH_VEC_ELT (m_items, i, it)
+    {
+      it->dump_to_pp (pp);
+      pp_newline (pp);
+    }
+}
+
+void
+record_layout::dump () const
+{
+  pretty_printer pp;
+  pp_format_decoder (&pp) = default_tree_printer;
+  pp.buffer->stream = stderr;
+  dump_to_pp (&pp);
+  pp_flush (&pp);
+}
+
+const record_layout::item *
+record_layout::get_item_at (bit_offset_t offset) const
+{
+  unsigned i;
+  item *it;
+  FOR_EACH_VEC_ELT (m_items, i, it)
+    if (it->contains_p (offset))
+      return it;
+  return NULL;
+}
+
+/* Subroutine of ctor.  Add padding item to NEXT_OFFSET if necessary.  */
+
+void
+record_layout::maybe_pad_to (bit_offset_t next_offset)
+{
+  if (m_items.length () > 0)
+    {
+      const item &last_item = m_items[m_items.length () - 1];
+      bit_offset_t offset_after_last_item
+	= last_item.get_next_bit_offset ();
+      if (next_offset > offset_after_last_item)
+	{
+	  bit_size_t padding_size
+	    = next_offset - offset_after_last_item;
+	  m_items.safe_push (item (bit_range (offset_after_last_item,
+					      padding_size),
+				   last_item.m_field, true));
+	}
+    }
+}
+
+} // namespace ana
+
+#endif /* #if ENABLE_ANALYZER  */
diff --git a/gcc/analyzer/record-layout.h b/gcc/analyzer/record-layout.h
new file mode 100644
index 00000000000..b63e7b00e48
--- /dev/null
+++ b/gcc/analyzer/record-layout.h
@@ -0,0 +1,91 @@
+/* Declaration of class record_layout.
+   Copyright (C) 2022-2023 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_ANALYZER_RECORD_LAYOUT_H
+#define GCC_ANALYZER_RECORD_LAYOUT_H
+
+#include "analyzer/store.h"
+
+namespace ana {
+
+/* Information of the layout of a RECORD_TYPE, capturing it as a vector
+   of items, where each item is either a field or padding.  */
+
+class record_layout
+{
+public:
+  /* An item within a record; either a field, or padding after a field.  */
+  struct item
+  {
+  public:
+    item (const bit_range &br,
+	  tree field,
+	  bool is_padding)
+    : m_bit_range (br),
+      m_field (field),
+      m_is_padding (is_padding)
+    {
+    }
+
+    bit_offset_t get_start_bit_offset () const
+    {
+      return m_bit_range.get_start_bit_offset ();
+    }
+    bit_offset_t get_next_bit_offset () const
+    {
+      return m_bit_range.get_next_bit_offset ();
+    }
+
+    bool contains_p (bit_offset_t offset) const
+    {
+      return m_bit_range.contains_p (offset);
+    }
+
+    void dump_to_pp (pretty_printer *pp) const
+    {
+      if (m_is_padding)
+	pp_printf (pp, "padding after %qD", m_field);
+      else
+	pp_printf (pp, "%qD", m_field);
+      pp_string (pp, ", ");
+      m_bit_range.dump_to_pp (pp);
+    }
+
+    bit_range m_bit_range;
+    tree m_field;
+    bool m_is_padding;
+  };
+
+  record_layout (tree record_type);
+
+  void dump_to_pp (pretty_printer *pp) const;
+  DEBUG_FUNCTION void dump () const;
+
+  const record_layout::item *get_item_at (bit_offset_t offset) const;
+
+private:
+  void maybe_pad_to (bit_offset_t next_offset);
+
+  auto_vec<item> m_items;
+};
+
+} // namespace ana
+
+#endif /* GCC_ANALYZER_RECORD_LAYOUT_H */
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 067347ef845..9479bcf380c 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -78,6 +78,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "analyzer/checker-event.h"
 #include "analyzer/checker-path.h"
 #include "analyzer/feasible-graph.h"
+#include "analyzer/record-layout.h"
 
 #if ENABLE_ANALYZER
 
@@ -6123,137 +6124,6 @@ region_model::unset_dynamic_extents (const region *reg)
   m_dynamic_extents.remove (reg);
 }
 
-/* Information of the layout of a RECORD_TYPE, capturing it as a vector
-   of items, where each item is either a field or padding.  */
-
-class record_layout
-{
-public:
-  /* An item within a record; either a field, or padding after a field.  */
-  struct item
-  {
-  public:
-    item (const bit_range &br,
-	  tree field,
-	  bool is_padding)
-    : m_bit_range (br),
-      m_field (field),
-      m_is_padding (is_padding)
-    {
-    }
-
-    bit_offset_t get_start_bit_offset () const
-    {
-      return m_bit_range.get_start_bit_offset ();
-    }
-    bit_offset_t get_next_bit_offset () const
-    {
-      return m_bit_range.get_next_bit_offset ();
-    }
-
-    bool contains_p (bit_offset_t offset) const
-    {
-      return m_bit_range.contains_p (offset);
-    }
-
-    void dump_to_pp (pretty_printer *pp) const
-    {
-      if (m_is_padding)
-	pp_printf (pp, "padding after %qD", m_field);
-      else
-	pp_printf (pp, "%qD", m_field);
-      pp_string (pp, ", ");
-      m_bit_range.dump_to_pp (pp);
-    }
-
-    bit_range m_bit_range;
-    tree m_field;
-    bool m_is_padding;
-  };
-
-  record_layout (tree record_type)
-  {
-    gcc_assert (TREE_CODE (record_type) == RECORD_TYPE);
-
-    for (tree iter = TYPE_FIELDS (record_type); iter != NULL_TREE;
-	 iter = DECL_CHAIN (iter))
-      {
-	if (TREE_CODE (iter) == FIELD_DECL)
-	  {
-	    int iter_field_offset = int_bit_position (iter);
-	    bit_size_t size_in_bits;
-	    if (!int_size_in_bits (TREE_TYPE (iter), &size_in_bits))
-	      size_in_bits = 0;
-
-	    maybe_pad_to (iter_field_offset);
-
-	    /* Add field.  */
-	    m_items.safe_push (item (bit_range (iter_field_offset,
-						size_in_bits),
-				     iter, false));
-	  }
-      }
-
-    /* Add any trailing padding.  */
-    bit_size_t size_in_bits;
-    if (int_size_in_bits (record_type, &size_in_bits))
-      maybe_pad_to (size_in_bits);
-  }
-
-  void dump_to_pp (pretty_printer *pp) const
-  {
-    unsigned i;
-    item *it;
-    FOR_EACH_VEC_ELT (m_items, i, it)
-      {
-	it->dump_to_pp (pp);
-	pp_newline (pp);
-      }
-  }
-
-  DEBUG_FUNCTION void dump () const
-  {
-    pretty_printer pp;
-    pp_format_decoder (&pp) = default_tree_printer;
-    pp.buffer->stream = stderr;
-    dump_to_pp (&pp);
-    pp_flush (&pp);
-  }
-
-  const record_layout::item *get_item_at (bit_offset_t offset) const
-  {
-    unsigned i;
-    item *it;
-    FOR_EACH_VEC_ELT (m_items, i, it)
-      if (it->contains_p (offset))
-	return it;
-    return NULL;
-  }
-
-private:
-  /* Subroutine of ctor.  Add padding item to NEXT_OFFSET if necessary.  */
-
-  void maybe_pad_to (bit_offset_t next_offset)
-  {
-    if (m_items.length () > 0)
-      {
-	const item &last_item = m_items[m_items.length () - 1];
-	bit_offset_t offset_after_last_item
-	  = last_item.get_next_bit_offset ();
-	if (next_offset > offset_after_last_item)
-	  {
-	    bit_size_t padding_size
-	      = next_offset - offset_after_last_item;
-	    m_items.safe_push (item (bit_range (offset_after_last_item,
-						padding_size),
-				     last_item.m_field, true));
-	  }
-      }
-  }
-
-  auto_vec<item> m_items;
-};
-
 /* A subclass of pending_diagnostic for complaining about uninitialized data
    being copied across a trust boundary to an untrusted output
    (e.g. copy_to_user infoleaks in the Linux kernel).  */
