diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 38b77f317413..8a6f23974092 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -846,7 +846,7 @@ dwarf_expr_context::dwarf_call (cu_offset die_cu_off)
   /* DW_OP_call_ref is currently not supported.  */
   gdb_assert (block.per_cu == this->m_per_cu);
 
-  this->eval (block.expr ());
+  this->eval (block.expr);
 }
 
 /* See expr.h.  */
diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c
index 5bf863e13d53..afc175c54fa9 100644
--- a/gdb/dwarf2/loc.c
+++ b/gdb/dwarf2/loc.c
@@ -376,10 +376,8 @@ dwarf2_find_location_expression (const dwarf2_loclist_baton *baton,
   CORE_ADDR text_offset = baton->per_objfile->objfile->text_section_offset ();
   unrelocated_addr unrel_pc = (unrelocated_addr) (pc - text_offset);
   unrelocated_addr base_address = baton->base_address;
-  const gdb_byte *loc_ptr, *buf_end;
-
-  loc_ptr = baton->data;
-  buf_end = baton->data + baton->size;
+  const gdb_byte *loc_ptr = baton->loclist.data ();
+  const gdb_byte *buf_end = loc_ptr + baton->loclist.size ();
 
   while (1)
     {
@@ -487,7 +485,7 @@ locexpr_find_frame_base_location (struct symbol *framefunc, CORE_ADDR pc)
   struct dwarf2_locexpr_baton *symbaton
     = (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (framefunc);
 
-  return symbaton->expr ();
+  return symbaton->expr;
 }
 
 /* Implement the struct symbol_block_ops::get_frame_base method for
@@ -678,8 +676,7 @@ call_site_target::iterate_over_addresses (gdbarch *call_site_gdbarch,
 	caller_arch = get_frame_arch (caller_frame);
 	caller_core_addr_type = builtin_type (caller_arch)->builtin_func_ptr;
 	val = dwarf2_evaluate_loc_desc (caller_core_addr_type, caller_frame,
-					dwarf_block->expr (),
-					dwarf_block->per_cu,
+					dwarf_block->expr, dwarf_block->per_cu,
 					dwarf_block->per_objfile);
 	/* DW_AT_call_target is a DWARF expression, not a DWARF location.  */
 	if (val->lval () == lval_memory)
@@ -1462,10 +1459,9 @@ indirect_synthetic_pointer (sect_offset die, LONGEST byte_offset,
   /* If pointed-to DIE has a DW_AT_location, evaluate it and return the
      resulting value.  Otherwise, it may have a DW_AT_const_value instead,
      or it may've been optimized out.  */
-  auto expr = baton.expr ();
-  if (!expr.empty ())
-    return dwarf2_evaluate_loc_desc_full (orig_type, frame, expr, baton.per_cu,
-					  baton.per_objfile,
+  if (!baton.expr.empty ())
+    return dwarf2_evaluate_loc_desc_full (orig_type, frame, baton.expr,
+					  baton.per_cu, baton.per_objfile,
 					  type->target_type (), byte_offset);
   else
     return fetch_const_value_from_synthetic_pointer (die, byte_offset, per_cu,
@@ -1572,7 +1568,7 @@ dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
 			   gdb::array_view<CORE_ADDR> push_values,
 			   bool *is_reference)
 {
-  if (dlbaton->size == 0)
+  if (dlbaton->expr.empty ())
     return false;
 
   dwarf2_per_objfile *per_objfile = dlbaton->per_objfile;
@@ -1588,8 +1584,7 @@ dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
 
   try
     {
-      result = ctx.evaluate (dlbaton->expr (), true, per_cu, frame,
-			     addr_stack);
+      result = ctx.evaluate (dlbaton->expr, true, per_cu, frame, addr_stack);
     }
   catch (const gdb_exception_error &ex)
     {
@@ -1645,7 +1640,7 @@ dwarf2_evaluate_property (const dynamic_prop *prop,
     {
     case PROP_LOCEXPR:
       {
-	const struct dwarf2_property_baton *baton = prop->baton ();
+	const dwarf2_locexpr_property_baton *baton = prop->locexpr ();
 	gdb_assert (baton->property_type != NULL);
 
 	bool is_reference = baton->locexpr.is_reference;
@@ -1687,7 +1682,7 @@ dwarf2_evaluate_property (const dynamic_prop *prop,
 
     case PROP_LOCLIST:
       {
-	const dwarf2_property_baton *baton = prop->baton ();
+	const dwarf2_loclist_property_baton *baton = prop->loclist ();
 	CORE_ADDR pc;
 	struct value *val;
 
@@ -1716,7 +1711,7 @@ dwarf2_evaluate_property (const dynamic_prop *prop,
 
     case PROP_FIELD:
       {
-	const dwarf2_property_baton *baton = prop->baton ();
+	const dwarf2_field_property_baton *baton = prop->field ();
 	const struct property_addr_info *pinfo;
 
 	for (pinfo = addr_stack; pinfo != NULL; pinfo = pinfo->next)
@@ -1791,14 +1786,15 @@ dwarf2_compile_property_to_c (string_file *stream,
 			      struct symbol *sym)
 {
 #if defined (HAVE_COMPILE)
-  const dwarf2_property_baton *baton = prop->baton ();
   gdb::array_view<const gdb_byte> expr;
   dwarf2_per_cu *per_cu;
   dwarf2_per_objfile *per_objfile;
 
   if (prop->kind () == PROP_LOCEXPR)
     {
-      expr = baton->locexpr.expr ();
+      const dwarf2_locexpr_property_baton *baton = prop->locexpr ();
+
+      expr = baton->locexpr.expr;
       per_cu = baton->locexpr.per_cu;
       per_objfile = baton->locexpr.per_objfile;
     }
@@ -1806,6 +1802,8 @@ dwarf2_compile_property_to_c (string_file *stream,
     {
       gdb_assert (prop->kind () == PROP_LOCLIST);
 
+      const dwarf2_loclist_property_baton *baton = prop->loclist ();
+
       expr = dwarf2_find_location_expression (&baton->loclist, pc);
       per_cu = baton->loclist.per_cu;
       per_objfile = baton->loclist.per_objfile;
@@ -2166,7 +2164,7 @@ dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
 	      {
 		gdbarch *arch = baton.per_objfile->objfile->arch ();
 		symbol_needs
-		  = dwarf2_get_symbol_read_needs (baton.expr (),
+		  = dwarf2_get_symbol_read_needs (baton.expr,
 						  baton.per_cu,
 						  baton.per_objfile,
 						  gdbarch_byte_order (arch),
@@ -2217,7 +2215,7 @@ dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
 	      {
 		gdbarch *arch = baton.per_objfile->objfile->arch ();
 		symbol_needs
-		  = dwarf2_get_symbol_read_needs (baton.expr (),
+		  = dwarf2_get_symbol_read_needs (baton.expr,
 						  baton.per_cu,
 						  baton.per_objfile,
 						  gdbarch_byte_order (arch),
@@ -3007,7 +3005,6 @@ dwarf2_compile_expr_to_ax (struct agent_expr *ax, struct axs_value *loc,
 	case DW_OP_call2:
 	case DW_OP_call4:
 	  {
-	    struct dwarf2_locexpr_baton block;
 	    int size = (op == DW_OP_call2 ? 2 : 4);
 
 	    uoffset = extract_unsigned_integer (op_ptr, size, byte_order);
@@ -3018,14 +3015,15 @@ dwarf2_compile_expr_to_ax (struct agent_expr *ax, struct axs_value *loc,
 		return ax->scope;
 	      };
 	    cu_offset cuoffset = (cu_offset) uoffset;
-	    block = dwarf2_fetch_die_loc_cu_off (cuoffset, per_cu, per_objfile,
-						 get_frame_pc_from_expr);
+	    dwarf2_locexpr_baton block
+	      = dwarf2_fetch_die_loc_cu_off (cuoffset, per_cu, per_objfile,
+					     get_frame_pc_from_expr);
 
 	    /* DW_OP_call_ref is currently not supported.  */
 	    gdb_assert (block.per_cu == per_cu);
 
-	    dwarf2_compile_expr_to_ax (ax, loc, addr_size, block.expr (),
-				       per_cu, per_objfile);
+	    dwarf2_compile_expr_to_ax (ax, loc, addr_size, block.expr, per_cu,
+				       per_objfile);
 	  }
 	  break;
 
@@ -3058,12 +3056,9 @@ locexpr_read_variable (struct symbol *symbol, const frame_info_ptr &frame)
 {
   struct dwarf2_locexpr_baton *dlbaton
     = (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (symbol);
-  struct value *val;
 
-  val = dwarf2_evaluate_loc_desc (symbol->type (), frame, dlbaton->expr (),
-				  dlbaton->per_cu, dlbaton->per_objfile);
-
-  return val;
+  return dwarf2_evaluate_loc_desc (symbol->type (), frame, dlbaton->expr,
+				   dlbaton->per_cu, dlbaton->per_objfile);
 }
 
 /* Return the value of SYMBOL in FRAME at (callee) FRAME's function
@@ -3076,7 +3071,7 @@ locexpr_read_variable_at_entry (struct symbol *symbol, const frame_info_ptr &fra
   struct dwarf2_locexpr_baton *dlbaton
     = (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (symbol);
 
-  return value_of_dwarf_block_entry (symbol->type (), frame, dlbaton->expr ());
+  return value_of_dwarf_block_entry (symbol->type (), frame, dlbaton->expr);
 }
 
 /* Implementation of get_symbol_read_needs from
@@ -3090,7 +3085,7 @@ locexpr_get_symbol_read_needs (struct symbol *symbol)
 
   gdbarch *arch = dlbaton->per_objfile->objfile->arch ();
 
-  return dwarf2_get_symbol_read_needs (dlbaton->expr (), dlbaton->per_cu,
+  return dwarf2_get_symbol_read_needs (dlbaton->expr, dlbaton->per_cu,
 				       dlbaton->per_objfile,
 				       gdbarch_byte_order (arch),
 				       dlbaton->per_cu->addr_size (),
@@ -3825,10 +3820,9 @@ locexpr_describe_location (struct symbol *symbol, CORE_ADDR addr,
   unsigned int addr_size = dlbaton->per_cu->addr_size ();
   int offset_size = dlbaton->per_cu->offset_size ();
 
-  locexpr_describe_location_1 (symbol, addr, stream,
-			       dlbaton->expr (),
-			       addr_size, offset_size,
-			       dlbaton->per_cu, dlbaton->per_objfile);
+  locexpr_describe_location_1 (symbol, addr, stream, dlbaton->expr, addr_size,
+			       offset_size, dlbaton->per_cu,
+			       dlbaton->per_objfile);
 }
 
 /* Describe the location of SYMBOL as an agent value in VALUE, generating
@@ -3842,10 +3836,10 @@ locexpr_tracepoint_var_ref (struct symbol *symbol, struct agent_expr *ax,
     = (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (symbol);
   unsigned int addr_size = dlbaton->per_cu->addr_size ();
 
-  if (dlbaton->size == 0)
+  if (dlbaton->expr.empty ())
     value->optimized_out = 1;
   else
-    dwarf2_compile_expr_to_ax (ax, value, addr_size, dlbaton->expr (),
+    dwarf2_compile_expr_to_ax (ax, value, addr_size, dlbaton->expr,
 			       dlbaton->per_cu, dlbaton->per_objfile);
 }
 
@@ -3861,7 +3855,7 @@ locexpr_generate_c_location (struct symbol *sym, string_file *stream,
   struct dwarf2_locexpr_baton *dlbaton
     = (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (sym);
   unsigned int addr_size = dlbaton->per_cu->addr_size ();
-  auto expr = dlbaton->expr ();
+  auto expr = dlbaton->expr;
 
   if (expr.empty ())
     error (_("symbol \"%s\" is optimized out"), sym->natural_name ());
@@ -3954,7 +3948,6 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
 {
   struct dwarf2_loclist_baton *dlbaton
     = (struct dwarf2_loclist_baton *) SYMBOL_LOCATION_BATON (symbol);
-  const gdb_byte *loc_ptr, *buf_end;
   dwarf2_per_objfile *per_objfile = dlbaton->per_objfile;
   struct objfile *objfile = per_objfile->objfile;
   struct gdbarch *gdbarch = objfile->arch ();
@@ -3964,9 +3957,8 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
   int signed_addr_p = bfd_get_sign_extend_vma (objfile->obfd.get ());
   unrelocated_addr base_address = dlbaton->base_address;
   int done = 0;
-
-  loc_ptr = dlbaton->data;
-  buf_end = dlbaton->data + dlbaton->size;
+  const gdb_byte *loc_ptr = dlbaton->loclist.data ();
+  const gdb_byte *buf_end = loc_ptr + dlbaton->loclist.size ();
 
   gdb_printf (stream, _("multi-location:\n"));
 
diff --git a/gdb/dwarf2/loc.h b/gdb/dwarf2/loc.h
index 192e53318d67..4a04bdccc600 100644
--- a/gdb/dwarf2/loc.h
+++ b/gdb/dwarf2/loc.h
@@ -124,42 +124,27 @@ void dwarf2_compile_property_to_c (string_file *stream,
    expression; "struct dwarf2_loclist_baton" is for a symbol with a
    location list.  */
 
-struct dwarf2_locexpr_baton
+struct dwarf2_locexpr_baton : allocate_on_obstack<dwarf2_locexpr_baton>
 {
-  /* Return the expression in this baton.  */
-  gdb::array_view<const gdb_byte> expr () const
-  { return gdb::make_array_view (data, size); }
-
-  /* Set the expression in this baton from EXPR.  */
-  void set_expr (gdb::array_view<const gdb_byte> expr)
+  dwarf2_locexpr_baton (gdb::array_view<const gdb_byte> expr,
+			dwarf2_per_objfile &per_objfile, dwarf2_per_cu &per_cu)
+    : expr (expr),
+      per_objfile (&per_objfile),
+      per_cu (&per_cu)
   {
-    data = expr.data ();
-    size = expr.size ();
   }
 
-  /* Set the expression in this baton from BLOCK.  */
-  void set_expr (const dwarf_block &block)
-  {
-    data = block.data;
-    size = block.size;
-  }
-
-  /* Pointer to the start of the location expression.  nullptr for optimized
-     out expressions.  */
-  const gdb_byte *data;
-
-  /* Length of the location expression.  For optimized out expressions it is
-     zero.  */
-  size_t size;
+  /* The location expression.  Empty for optimized out expressions.  */
+  gdb::array_view<const gdb_byte> expr;
 
   /* When true this location expression is a reference and actually
      describes the address at which the value of the attribute can be
      found.  When false the expression provides the value of the attribute
      directly.  */
-  bool is_reference;
+  bool is_reference = false;
 
   /* True if this object is actually a dwarf2_field_location_baton.  */
-  bool is_field_location;
+  bool is_field_location = false;
 
   /* The objfile that was used when creating this.  */
   dwarf2_per_objfile *per_objfile;
@@ -176,31 +161,48 @@ struct dwarf2_locexpr_baton
    'is_field_location' member in dwarf2_locexpr_baton.  See also
    apply_bit_offset_to_field.  */
 
-struct dwarf2_field_location_baton : public dwarf2_locexpr_baton
+struct dwarf2_field_location_baton
+  : dwarf2_locexpr_baton,
+    allocate_on_obstack<dwarf2_field_location_baton>
 {
+  using allocate_on_obstack<dwarf2_field_location_baton>::operator new;
+  using allocate_on_obstack<dwarf2_field_location_baton>::operator delete;
+
+  dwarf2_field_location_baton (gdb::array_view<const gdb_byte> expr,
+			       dwarf2_per_objfile &per_objfile,
+			       dwarf2_per_cu &per_cu, LONGEST bit_offset,
+			       LONGEST explicit_byte_size)
+    : dwarf2_locexpr_baton (expr, per_objfile, per_cu),
+      bit_offset (bit_offset),
+      explicit_byte_size (explicit_byte_size)
+  {
+    is_field_location = true;
+  }
+
   /* The bit offset, coming from DW_AT_bit_offset.  */
-  LONGEST bit_offset;
+  LONGEST bit_offset = 0;
 
   /* The DW_AT_byte_size of the field.  If no explicit byte size was
      specified, this is 0.  */
-  LONGEST explicit_byte_size;
+  LONGEST explicit_byte_size = 0;
 };
 
-struct dwarf2_loclist_baton
+struct dwarf2_loclist_baton : allocate_on_obstack<dwarf2_loclist_baton>
 {
-  /* Return the location list in this baton.  */
-  gdb::array_view<const gdb_byte> expr () const
-  { return gdb::make_array_view (data, size); }
+  dwarf2_loclist_baton (gdb::array_view<const gdb_byte> loclist,
+			dwarf2_per_objfile &per_objfile, dwarf2_per_cu &per_cu)
+    : loclist (loclist),
+      per_objfile (&per_objfile),
+      per_cu (&per_cu)
+  {
+  }
 
   /* The initial base address for the location list, based on the compilation
      unit.  */
-  unrelocated_addr base_address;
+  unrelocated_addr base_address {};
 
-  /* Pointer to the start of the location list.  */
-  const gdb_byte *data;
-
-  /* Length of the location list.  */
-  size_t size;
+  /* The location list.  */
+  gdb::array_view<const gdb_byte> loclist;
 
   /* The objfile that was used when creating this.  */
   dwarf2_per_objfile *per_objfile;
@@ -211,10 +213,10 @@ struct dwarf2_loclist_baton
 
   /* Non-zero if the location list lives in .debug_loc.dwo.
      The format of entries in this section are different.  */
-  unsigned char from_dwo;
+  unsigned char from_dwo = 0;
 
   /* The version of DWARF this loclist comes from.  */
-  unsigned char dwarf_version;
+  unsigned char dwarf_version = 0;
 };
 
 /* A dynamic property is either expressed as a single location expression
@@ -225,23 +227,57 @@ struct dwarf2_loclist_baton
 
 struct dwarf2_property_baton
 {
+  dwarf2_property_baton (type &property_type)
+    : property_type (&property_type)
+  {
+  }
+
   /* If the property is an indirection, we need to evaluate the location
      in the context of the type PROPERTY_TYPE.  If the property is supplied
      by value then it will be of PROPERTY_TYPE.  This field should never be
      NULL.  */
   struct type *property_type;
-  union
+};
+
+struct dwarf2_locexpr_property_baton
+  : dwarf2_property_baton,
+    allocate_on_obstack<dwarf2_locexpr_property_baton>
+{
+  dwarf2_locexpr_property_baton (type &property_type,
+				 const dwarf2_locexpr_baton &locexpr)
+    : dwarf2_property_baton (property_type),
+      locexpr (locexpr)
   {
-    /* Location expression either evaluated in the context of
-       PROPERTY_TYPE, or a value of type PROPERTY_TYPE.  */
-    struct dwarf2_locexpr_baton locexpr;
+  }
 
-    /* Location list to be evaluated in the context of PROPERTY_TYPE.  */
-    struct dwarf2_loclist_baton loclist;
+  /* Location expression either evaluated in the context of
+     PROPERTY_TYPE, or a value of type PROPERTY_TYPE.  */
+  dwarf2_locexpr_baton locexpr;
+};
 
-    /* The location is stored in a field of PROPERTY_TYPE.  */
-    struct field field;
-  };
+struct dwarf2_loclist_property_baton
+  : dwarf2_property_baton,
+    allocate_on_obstack<dwarf2_loclist_property_baton>
+{
+  dwarf2_loclist_property_baton (type &property_type,
+				 const dwarf2_loclist_baton &loclist)
+    : dwarf2_property_baton (property_type),
+      loclist (loclist)
+  {
+  }
+
+  /* Location list to be evaluated in the context of PROPERTY_TYPE.  */
+  dwarf2_loclist_baton loclist;
+};
+
+struct dwarf2_field_property_baton
+  : dwarf2_property_baton,
+    allocate_on_obstack<dwarf2_field_property_baton>
+{
+  using dwarf2_property_baton::dwarf2_property_baton;
+
+  /* The field of PROPERTY_TYPE that contains the property value.  */
+  struct field field {};
 };
 
 extern const struct symbol_computed_ops dwarf2_locexpr_funcs;
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index efe96f6510da..f28c26090b39 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -907,9 +907,8 @@ static struct dwarf_block *dwarf_alloc_block (struct dwarf2_cu *);
 
 static void dwarf_decode_macros (struct dwarf2_cu *, unsigned int, int);
 
-static void fill_in_loclist_baton (struct dwarf2_cu *cu,
-				   struct dwarf2_loclist_baton *baton,
-				   const struct attribute *attr);
+static dwarf2_loclist_baton make_loclist_baton (struct dwarf2_cu *cu,
+						const struct attribute *attr);
 
 static void dwarf2_symbol_mark_computed (const struct attribute *attr,
 					 struct symbol *sym,
@@ -5268,8 +5267,7 @@ dwarf2_compute_name (const char *name,
 		      struct value_print_options opts;
 
 		      if (baton != NULL)
-			v = dwarf2_evaluate_loc_desc (type, NULL,
-						      baton->expr (),
+			v = dwarf2_evaluate_loc_desc (type, NULL, baton->expr,
 						      baton->per_cu,
 						      baton->per_objfile);
 		      else if (bytes != NULL)
@@ -8101,12 +8099,9 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
     /* Keep NULL DWARF_BLOCK.  */;
   else if (attr->form_is_block ())
     {
-      dwarf2_locexpr_baton *dlbaton
-	= OBSTACK_ZALLOC (&objfile->objfile_obstack, dwarf2_locexpr_baton);
-
-      dlbaton->set_expr (*attr->as_block ());
-      dlbaton->per_objfile = per_objfile;
-      dlbaton->per_cu = cu->per_cu;
+      auto dlbaton = new (&objfile->objfile_obstack)
+	dwarf2_locexpr_baton (attr->as_block ()->view (), *per_objfile,
+			      *cu->per_cu);
 
       call_site->target.set_loc_dwarf_block (dlbaton);
     }
@@ -9370,28 +9365,21 @@ handle_member_location (struct die_info *die, struct dwarf2_cu *cu,
 	      dwarf2_per_objfile *per_objfile = cu->per_objfile;
 	      struct objfile *objfile = per_objfile->objfile;
 	      struct dwarf2_locexpr_baton *dlbaton;
-	      if (has_bit_offset)
-		{
-		  dwarf2_field_location_baton *flbaton
-		    = OBSTACK_ZALLOC (&objfile->objfile_obstack,
-				      dwarf2_field_location_baton);
-		  flbaton->is_field_location = true;
-		  flbaton->bit_offset = bit_offset;
-		  flbaton->explicit_byte_size = anonymous_size;
-		  dlbaton = flbaton;
-		}
-	      else
-		dlbaton = OBSTACK_ZALLOC (&objfile->objfile_obstack,
-					  struct dwarf2_locexpr_baton);
+	      gdb::array_view<const gdb_byte> expr
+		= data_member_location_attr->as_block ()->view ();
 
-	      dlbaton->set_expr (*data_member_location_attr->as_block ());
+	      if (has_bit_offset)
+		dlbaton = new (&objfile->objfile_obstack)
+		  dwarf2_field_location_baton (expr, *per_objfile, *cu->per_cu,
+					       bit_offset, anonymous_size);
+	      else
+		dlbaton = new (&objfile->objfile_obstack)
+		  dwarf2_locexpr_baton (expr, *per_objfile, *cu->per_cu);
 
 	      /* When using this baton, we want to compute the address
 		 of the field, not the value.  This is why
 		 is_reference is set to false here.  */
 	      dlbaton->is_reference = false;
-	      dlbaton->per_objfile = per_objfile;
-	      dlbaton->per_cu = cu->per_cu;
 
 	      field->set_loc_dwarf_block_addr (dlbaton);
 	    }
@@ -9415,13 +9403,9 @@ handle_member_location (struct die_info *die, struct dwarf2_cu *cu,
 	      /* This is a DWARF extension.  See
 		 https://dwarfstd.org/issues/250501.1.html.  */
 	      dwarf2_per_objfile *per_objfile = cu->per_objfile;
-	      dwarf2_locexpr_baton *dlbaton
-		= OBSTACK_ZALLOC (&per_objfile->objfile->objfile_obstack,
-				  dwarf2_locexpr_baton);
-
-	      dlbaton->set_expr (*data_bit_offset_attr->as_block ());
-	      dlbaton->per_objfile = per_objfile;
-	      dlbaton->per_cu = cu->per_cu;
+	      auto dlbaton = new (&per_objfile->objfile->objfile_obstack)
+		dwarf2_locexpr_baton ((data_bit_offset_attr->as_block ()
+				       ->view ()), *per_objfile, *cu->per_cu);
 
 	      field->set_loc_dwarf_block_bitpos (dlbaton);
 	    }
@@ -10738,21 +10722,6 @@ handle_struct_member_die (struct die_info *child_die, struct type *type,
     handle_variant (child_die, type, fi, template_args, cu);
 }
 
-/* Create a property baton for a field.  DIE is the field's DIE.  The
-   baton's "field" member is filled in, but the other members of the
-   baton are not.  The new property baton is returned.  */
-
-static dwarf2_property_baton *
-find_field_create_baton (dwarf2_cu *cu, die_info *die)
-{
-  dwarf2_property_baton *result
-    = XOBNEW (&cu->per_objfile->objfile->objfile_obstack,
-	      struct dwarf2_property_baton);
-  memset (&result->field, 0, sizeof (result->field));
-  compute_field_location (cu, die, &result->field);
-  return result;
-}
-
 /* Finish creating a structure or union type, including filling in its
    members and creating a symbol for it. This function also handles Fortran
    namelist variables, their items or members and creating a symbol for
@@ -11749,7 +11718,6 @@ mark_common_block_symbol_computed (struct symbol *sym,
 {
   dwarf2_per_objfile *per_objfile = cu->per_objfile;
   struct objfile *objfile = per_objfile->objfile;
-  struct dwarf2_locexpr_baton *baton;
   unsigned int cu_off;
   enum bfd_endian byte_order = gdbarch_byte_order (objfile->arch ());
   LONGEST offset = 0;
@@ -11759,12 +11727,6 @@ mark_common_block_symbol_computed (struct symbol *sym,
   gdb_assert (member_loc->form_is_block ()
 	      || member_loc->form_is_constant ());
 
-  baton = OBSTACK_ZALLOC (&objfile->objfile_obstack,
-			  struct dwarf2_locexpr_baton);
-  baton->per_objfile = per_objfile;
-  baton->per_cu = cu->per_cu;
-  gdb_assert (baton->per_cu);
-
   std::size_t size = 5 /* DW_OP_call4 */ + 1 /* DW_OP_plus */;
 
   if (member_loc->form_is_constant ())
@@ -11802,7 +11764,9 @@ mark_common_block_symbol_computed (struct symbol *sym,
   *ptr++ = DW_OP_plus;
   gdb_assert (ptr - start == size);
 
-  baton->set_expr (gdb::make_array_view (start, size));
+  auto baton = new (&objfile->objfile_obstack)
+    dwarf2_locexpr_baton (gdb::make_array_view (start, size), *per_objfile,
+			  *cu->per_cu);
 
   SYMBOL_LOCATION_BATON (sym) = baton;
   sym->set_loc_class_index (dwarf2_locexpr_index);
@@ -13403,7 +13367,6 @@ attr_to_dynamic_prop (const struct attribute *attr, struct die_info *die,
 		      struct dwarf2_cu *cu, struct dynamic_prop *prop,
 		      struct type *default_type)
 {
-  struct dwarf2_property_baton *baton;
   dwarf2_per_objfile *per_objfile = cu->per_objfile;
   struct objfile *objfile = per_objfile->objfile;
   struct obstack *obstack = &objfile->objfile_obstack;
@@ -13415,27 +13378,26 @@ attr_to_dynamic_prop (const struct attribute *attr, struct die_info *die,
 
   if (attr->form_is_block ())
     {
-      baton = XOBNEW (obstack, struct dwarf2_property_baton);
-      baton->property_type = default_type;
-      baton->locexpr.per_cu = cu->per_cu;
-      baton->locexpr.per_objfile = per_objfile;
+      gdb::array_view<const gdb_byte> expr;
 
-      struct dwarf_block block;
       if (attr->form == DW_FORM_data16)
 	{
-	  size_t data_size = 16;
-	  block.size = (data_size
-			+ 2 /* Extra bytes for DW_OP and arg.  */);
-	  gdb_byte *data = XOBNEWVEC (obstack, gdb_byte, block.size);
-	  data[0] = DW_OP_implicit_value;
-	  data[1] = data_size;
-	  memcpy (&data[2], attr->as_block ()->data, data_size);
-	  block.data = data;
+	  std::size_t data_size = 16;
+	  std::size_t expr_size = (data_size
+				   + 2 /* Extra bytes for DW_OP and arg.  */);
+	  gdb_byte *expr_data = XOBNEWVEC (obstack, gdb_byte, expr_size);
+	  expr_data[0] = DW_OP_implicit_value;
+	  expr_data[1] = data_size;
+	  memcpy (&expr_data[2], attr->as_block ()->data, data_size);
+	  expr = gdb::make_array_view (expr_data, expr_size);
 	}
       else
-	block = *attr->as_block ();
+	expr = attr->as_block ()->view ();
+
+      auto baton = new (obstack)
+	dwarf2_locexpr_property_baton (*default_type,
+				       {expr, *per_objfile, *cu->per_cu});
 
-      baton->locexpr.set_expr (block);
       switch (attr->name)
 	{
 	case DW_AT_string_length:
@@ -13447,7 +13409,6 @@ attr_to_dynamic_prop (const struct attribute *attr, struct die_info *die,
 	}
 
       prop->set_locexpr (baton);
-      gdb_assert (prop->baton () != NULL);
     }
   else if (attr->form_is_ref ())
     {
@@ -13479,22 +13440,21 @@ attr_to_dynamic_prop (const struct attribute *attr, struct die_info *die,
 	  case DW_AT_location:
 	    if (target_attr->form_is_section_offset ())
 	      {
-		baton = XOBNEW (obstack, struct dwarf2_property_baton);
-		baton->property_type = die_type (target_die, target_cu);
-		fill_in_loclist_baton (cu, &baton->loclist, target_attr);
+		type *property_type = die_type (target_die, target_cu);
+		auto baton = new (obstack) dwarf2_loclist_property_baton
+		  (*property_type, make_loclist_baton (cu, target_attr));
 		prop->set_loclist (baton);
-		gdb_assert (prop->baton () != NULL);
 	      }
 	    else if (target_attr->form_is_block ())
 	      {
-		baton = XOBNEW (obstack, struct dwarf2_property_baton);
-		baton->property_type = die_type (target_die, target_cu);
-		baton->locexpr.per_cu = cu->per_cu;
-		baton->locexpr.per_objfile = per_objfile;
-		baton->locexpr.set_expr (*target_attr->as_block ());
+		type *property_type = die_type (target_die, target_cu);
+		auto baton = new (obstack)
+		  dwarf2_locexpr_property_baton (*property_type,
+						 {(target_attr->as_block ()
+						   ->view()), *per_objfile,
+						  *cu->per_cu});
 		baton->locexpr.is_reference = true;
 		prop->set_locexpr (baton);
-		gdb_assert (prop->baton () != NULL);
 	      }
 	    else
 	      {
@@ -13506,12 +13466,12 @@ attr_to_dynamic_prop (const struct attribute *attr, struct die_info *die,
 	  case DW_AT_data_member_location:
 	  case DW_AT_data_bit_offset:
 	    {
-	      baton = find_field_create_baton (cu, target_die);
-	      if (baton == nullptr)
-		return false;
+	      type *property_type = read_type_die (target_die->parent,
+						   target_cu);
+	      auto baton = new (&cu->per_objfile->objfile->objfile_obstack)
+		dwarf2_field_property_baton (*property_type);
 
-	      baton->property_type = read_type_die (target_die->parent,
-						    target_cu);
+	      compute_field_location (cu, target_die, &baton->field);
 	      prop->set_field (baton);
 	      break;
 	    }
@@ -13524,12 +13484,13 @@ attr_to_dynamic_prop (const struct attribute *attr, struct die_info *die,
       switch (attr->name)
 	{
 	case DW_AT_string_length:
-	  baton = XOBNEW (obstack, struct dwarf2_property_baton);
-	  baton->property_type = default_type;
-	  fill_in_loclist_baton (cu, &baton->loclist, attr);
-	  prop->set_loclist (baton);
-	  gdb_assert (prop->baton () != NULL);
-	  break;
+	  {
+	    auto baton = new (obstack)
+	      dwarf2_loclist_property_baton (*default_type,
+					     make_loclist_baton (cu, attr));
+	    prop->set_loclist (baton);
+	    break;
+	  }
 	default:
 	  goto invalid;
 	}
@@ -16002,8 +15963,6 @@ dwarf2_const_value_attr (const struct attribute *attr, struct type *type,
     case DW_FORM_addrx:
     case DW_FORM_GNU_addr_index:
       {
-	gdb_byte *data;
-
 	if (type->length () != cu_header->addr_size)
 	  dwarf2_const_value_length_mismatch_complaint (name,
 							cu_header->addr_size,
@@ -16011,14 +15970,11 @@ dwarf2_const_value_attr (const struct attribute *attr, struct type *type,
 	/* Symbols of this form are reasonably rare, so we just
 	   piggyback on the existing location code rather than writing
 	   a new implementation of symbol_computed_ops.  */
-	*baton = OBSTACK_ZALLOC (obstack, struct dwarf2_locexpr_baton);
-	(*baton)->per_objfile = per_objfile;
-	(*baton)->per_cu = cu->per_cu;
-	gdb_assert ((*baton)->per_cu);
-
 	std::size_t size = 2 + cu_header->addr_size;
-	data = (gdb_byte *) obstack_alloc (obstack, size);
-	(*baton)->set_expr (gdb::make_array_view (data, size));
+	auto data = (gdb_byte *) obstack_alloc (obstack, size);
+	*baton = new (obstack)
+	  dwarf2_locexpr_baton (gdb::make_array_view (data, size),
+				*per_objfile, *cu->per_cu);
 
 	data[0] = DW_OP_addr;
 	store_unsigned_integer (&data[1], cu_header->addr_size,
@@ -17029,7 +16985,6 @@ dwarf2_fetch_die_loc_sect_off (sect_offset sect_off, dwarf2_per_cu *per_cu,
 			       bool resolve_abstract_p)
 {
   struct attribute *attr;
-  struct dwarf2_locexpr_baton retval;
   struct objfile *objfile = per_objfile->objfile;
 
   dwarf2_cu *cu = per_objfile->get_cu (per_cu);
@@ -17079,19 +17034,18 @@ dwarf2_fetch_die_loc_sect_off (sect_offset sect_off, dwarf2_per_cu *per_cu,
 	}
     }
 
+  gdb::array_view<const gdb_byte> expr;
+
   if (!attr)
     {
       /* DWARF: "If there is no such attribute, then there is no effect.".  */
-      retval.set_expr (gdb::array_view<const gdb_byte> ());
     }
   else if (attr->form_is_section_offset ())
     {
-      struct dwarf2_loclist_baton loclist_baton;
+      dwarf2_loclist_baton loclist_baton = make_loclist_baton (cu, attr);
       CORE_ADDR pc = get_frame_pc ();
 
-      fill_in_loclist_baton (cu, &loclist_baton, attr);
-
-      retval.set_expr (dwarf2_find_location_expression (&loclist_baton, pc));
+      expr = dwarf2_find_location_expression (&loclist_baton, pc);
     }
   else
     {
@@ -17101,10 +17055,10 @@ dwarf2_fetch_die_loc_sect_off (sect_offset sect_off, dwarf2_per_cu *per_cu,
 		 " [in module %s]"),
 	       sect_offset_str (sect_off), objfile_name (objfile));
 
-      retval.set_expr (*attr->as_block ());
+      expr = attr->as_block ()->view ();
     }
-  retval.per_objfile = per_objfile;
-  retval.per_cu = cu->per_cu;
+
+  dwarf2_locexpr_baton retval (expr, *per_objfile, *cu->per_cu);
 
   per_objfile->age_comp_units ();
 
@@ -17854,29 +17808,30 @@ cu_debug_rnglists_section (struct dwarf2_cu *cu, dwarf_tag tag)
 
 /* A helper function that fills in a dwarf2_loclist_baton.  */
 
-static void
-fill_in_loclist_baton (struct dwarf2_cu *cu,
-		       struct dwarf2_loclist_baton *baton,
-		       const struct attribute *attr)
+static dwarf2_loclist_baton
+make_loclist_baton (struct dwarf2_cu *cu, const struct attribute *attr)
 {
   dwarf2_per_objfile *per_objfile = cu->per_objfile;
   struct dwarf2_section_info *section = cu_debug_loc_section (cu);
 
   section->read (per_objfile->objfile);
 
-  baton->per_objfile = per_objfile;
-  baton->per_cu = cu->per_cu;
-  gdb_assert (baton->per_cu);
   /* We don't know how long the location list is, but make sure we
      don't run off the edge of the section.  */
-  baton->size = section->size - attr->as_unsigned ();
-  baton->data = section->buffer + attr->as_unsigned ();
+  std::size_t loclist_size = section->size - attr->as_unsigned ();
+  const gdb_byte *loclist_data = section->buffer + attr->as_unsigned ();
+
+  dwarf2_loclist_baton baton (gdb::make_array_view (loclist_data,
+						    loclist_size),
+			      *per_objfile, *cu->per_cu);
+
   if (cu->base_address.has_value ())
-    baton->base_address = *cu->base_address;
-  else
-    baton->base_address = {};
-  baton->from_dwo = cu->dwo_unit != NULL;
-  baton->dwarf_version = cu->header.version;
+    baton.base_address = *cu->base_address;
+
+  baton.from_dwo = cu->dwo_unit != NULL;
+  baton.dwarf_version = cu->header.version;
+
+  return baton;
 }
 
 static void
@@ -17893,11 +17848,8 @@ dwarf2_symbol_mark_computed (const struct attribute *attr, struct symbol *sym,
 	 other branch.  */
       && attr->as_unsigned () < section->size)
     {
-      struct dwarf2_loclist_baton *baton;
-
-      baton = XOBNEW (&objfile->objfile_obstack, struct dwarf2_loclist_baton);
-
-      fill_in_loclist_baton (cu, baton, attr);
+      auto baton = new (&objfile->objfile_obstack)
+	dwarf2_loclist_baton (make_loclist_baton (cu, attr));
 
       if (!cu->base_address.has_value ())
 	complaint (_("Location list used without "
@@ -17910,13 +17862,7 @@ dwarf2_symbol_mark_computed (const struct attribute *attr, struct symbol *sym,
     }
   else
     {
-      struct dwarf2_locexpr_baton *baton;
-
-      baton = OBSTACK_ZALLOC (&objfile->objfile_obstack,
-			      struct dwarf2_locexpr_baton);
-      baton->per_objfile = per_objfile;
-      baton->per_cu = cu->per_cu;
-      gdb_assert (baton->per_cu);
+      gdb::array_view<const gdb_byte> expr;
 
       if (attr->form_is_block ())
 	{
@@ -17925,18 +17871,18 @@ dwarf2_symbol_mark_computed (const struct attribute *attr, struct symbol *sym,
 	     info_buffer for SYM's objfile; right now we never release
 	     that buffer, but when we do clean up properly this may
 	     need to change.  */
-	  baton->set_expr (*attr->as_block ());
+	  expr = attr->as_block ()->view ();
 	}
       else
-	{
-	  dwarf2_invalid_attrib_class_complaint ("location description",
-						 sym->natural_name ());
-	  baton->size = 0;
-	}
+	dwarf2_invalid_attrib_class_complaint ("location description",
+					       sym->natural_name ());
 
-      sym->set_loc_class_index ((is_block
-			      ? dwarf2_locexpr_block_index
-			      : dwarf2_locexpr_index));
+      auto baton = new (&objfile->objfile_obstack)
+	dwarf2_locexpr_baton (expr, *per_objfile, *cu->per_cu);
+
+      sym->set_loc_class_index (is_block
+				? dwarf2_locexpr_block_index
+				: dwarf2_locexpr_index);
       SYMBOL_LOCATION_BATON (sym) = baton;
     }
 }
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 2f566583509e..2d577b09359e 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -797,9 +797,11 @@ operator== (const dynamic_prop &l, const dynamic_prop &r)
     case PROP_CONST:
       return l.const_val () == r.const_val ();
     case PROP_FIELD:
+      return l.field () == r.field ();
     case PROP_LOCEXPR:
+      return l.locexpr () == r.locexpr ();
     case PROP_LOCLIST:
-      return l.baton () == r.baton ();
+      return l.loclist () == r.loclist ();
     case PROP_VARIANT_PARTS:
       return l.variant_parts () == r.variant_parts ();
     case PROP_TYPE:
@@ -2666,12 +2668,9 @@ resolve_dynamic_field (struct field &field,
 
   if (field.loc_is_dwarf_block ())
     {
-      dwarf2_locexpr_baton *field_loc
-	= field.loc_dwarf_block ();
-
-      struct dwarf2_property_baton baton;
-      baton.property_type = lookup_pointer_type (field.type ());
-      baton.locexpr = *field_loc;
+      dwarf2_locexpr_baton *field_loc = field.loc_dwarf_block ();
+      dwarf2_locexpr_property_baton baton
+	(*lookup_pointer_type (field.type ()), *field_loc);
 
       struct dynamic_prop prop;
       prop.set_locexpr (&baton);
@@ -4221,8 +4220,7 @@ check_types_equal (struct type *type1, struct type *type2,
 		block1 = field1->loc_dwarf_block ();
 		block2 = field2->loc_dwarf_block ();
 		if (block1->per_cu != block2->per_cu
-		    || block1->size != block2->size
-		    || memcmp (block1->data, block2->data, block1->size) != 0)
+		    || block1->expr != block2->expr)
 		  return false;
 	      }
 	      break;
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index b32056ce530c..010df3fda7ea 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -59,6 +59,9 @@ struct language_defn;
 struct dwarf2_per_cu;
 struct dwarf2_per_objfile;
 struct dwarf2_property_baton;
+struct dwarf2_locexpr_property_baton;
+struct dwarf2_loclist_property_baton;
+struct dwarf2_field_property_baton;
 
 /* * Different kinds of data types are distinguished by the `code'
    field.  */
@@ -344,31 +347,49 @@ struct dynamic_prop
   bool is_constant () const
   { return m_kind == PROP_CONST; }
 
-  const dwarf2_property_baton *baton () const
-  {
-    gdb_assert (m_kind == PROP_LOCEXPR
-		|| m_kind == PROP_LOCLIST
-		|| m_kind == PROP_FIELD);
+  /* We need to use reinterpret_cast below instead of static_cast below, because
+     the baton types are not complete, and including dwarf2/loc.h would cause a
+     cyclic dependency.  */
 
-    return m_data.baton;
+  const dwarf2_locexpr_property_baton *locexpr () const
+  {
+    gdb_assert (m_kind == PROP_LOCEXPR);
+
+    return (reinterpret_cast<const dwarf2_locexpr_property_baton *>
+	    (m_data.baton));
   }
 
-  void set_locexpr (const dwarf2_property_baton *baton)
+  const dwarf2_loclist_property_baton *loclist () const
+  {
+    gdb_assert (m_kind == PROP_LOCLIST);
+
+    return (reinterpret_cast<const dwarf2_loclist_property_baton *>
+	    (m_data.baton));
+  }
+
+  const dwarf2_field_property_baton *field () const
+  {
+    gdb_assert (m_kind == PROP_FIELD);
+
+    return reinterpret_cast<const dwarf2_field_property_baton *> (m_data.baton);
+  }
+
+  void set_locexpr (const dwarf2_locexpr_property_baton *baton)
   {
     m_kind = PROP_LOCEXPR;
-    m_data.baton = baton;
+    m_data.baton = reinterpret_cast<const dwarf2_property_baton *> (baton);
   }
 
-  void set_loclist (const dwarf2_property_baton *baton)
+  void set_loclist (const dwarf2_loclist_property_baton *baton)
   {
     m_kind = PROP_LOCLIST;
-    m_data.baton = baton;
+    m_data.baton = reinterpret_cast<const dwarf2_property_baton *> (baton);
   }
 
-  void set_field (const dwarf2_property_baton *baton)
+  void set_field (const dwarf2_field_property_baton *baton)
   {
     m_kind = PROP_FIELD;
-    m_data.baton = baton;
+    m_data.baton = reinterpret_cast<const dwarf2_property_baton *> (baton);
   }
 
   const gdb::array_view<variant_part> *variant_parts () const
diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c
index 35910be0f06d..1270a5d34ba4 100644
--- a/gdb/gnu-v3-abi.c
+++ b/gdb/gnu-v3-abi.c
@@ -478,10 +478,10 @@ gnuv3_baseclass_offset (struct type *type, int index,
   /* If we have a DWARF expression for the offset, evaluate it.  */
   if (type->field (index).loc_kind () == FIELD_LOC_KIND_DWARF_BLOCK_ADDR)
     {
-      struct dwarf2_property_baton baton;
-      baton.property_type
+      struct type *property_type
 	= lookup_pointer_type (type->field (index).type ());
-      baton.locexpr = *type->field (index).loc_dwarf_block ();
+      dwarf2_locexpr_baton *locexpr = type->field (index).loc_dwarf_block ();
+      dwarf2_locexpr_property_baton baton (*property_type, *locexpr);
 
       struct dynamic_prop prop;
       prop.set_locexpr (&baton);
