The way it treated the argument before was just confusing.
     ds_put_format (&text, _("`%s': "), fh_get_file_name (r->fh));
   ds_put_vformat (&text, format, args);
 
-  struct msg m = {
+  struct msg *m = xmalloc (sizeof *m);
+  *m = (struct msg) {
     .category = msg_class_to_category (class),
     .severity = msg_class_to_severity (class),
-    .text = ds_cstr (&text),
+    .text = ds_steal_cstr (&text),
   };
-  msg_emit (&m);
+  msg_emit (m);
 }
 
 /* Displays a warning for offset OFFSET in the file. */
 
   ds_put_vformat (&text, msg, args);
   va_end (args);
 
-  struct msg m = {
+  struct msg *m = xmalloc (sizeof *m);
+  *m = (struct msg) {
     .category = MSG_C_GENERAL,
     .severity = MSG_S_ERROR,
-    .text = ds_cstr (&text),
+    .text = ds_steal_cstr (&text),
   };
-  msg_emit (&m);
+  msg_emit (m);
 
   r->ok = false;
 
   ds_put_vformat (&text, msg, args);
   va_end (args);
 
-  struct msg m = {
+  struct msg *m = xmalloc (sizeof *m);
+  *m = (struct msg) {
     .category = MSG_C_GENERAL,
     .severity = MSG_S_WARNING,
-    .text = ds_cstr (&text),
+    .text = ds_steal_cstr (&text),
   };
-  msg_emit (&m);
+  msg_emit (m);
 }
 
 /* Close and destroy R.
 
     ds_put_format (&text, _("`%s': "), fh_get_file_name (r->fh));
   ds_put_vformat (&text, format, args);
 
-  struct msg m = {
+  struct msg *m = xmalloc (sizeof *m);
+  *m = (struct msg) {
     .category = msg_class_to_category (class),
     .severity = msg_class_to_severity (class),
-    .text = ds_cstr (&text),
+    .text = ds_steal_cstr (&text),
   };
-  msg_emit (&m);
+  msg_emit (m);
 }
 
 /* Displays a warning for offset OFFSET in the file. */
 
              int first_column, int last_column, char *error)
 {
   int line_number = dfm_get_line_number (reader);
-  const struct msg_location location = {
-    .file_name = CONST_CAST (char *, dfm_get_file_name (reader)),
+  struct msg_location *location = xmalloc (sizeof *location);
+  *location = (struct msg_location) {
+    .file_name = xstrdup (dfm_get_file_name (reader)),
     .first_line = line_number,
     .last_line = line_number + 1,
     .first_column = first_column,
     .last_column = last_column,
   };
-  struct msg m = {
+  struct msg *m = xmalloc (sizeof *m);
+  *m = (struct msg) {
     .category = MSG_C_DATA,
     .severity = MSG_S_WARNING,
-    .location = CONST_CAST (struct msg_location *, &location),
+    .location = location,
     .text = xasprintf (_("Data for variable %s is not valid as format %s: %s"),
                        field->name, fmt_name (field->format.type), error),
   };
-  msg_emit (&m);
+  msg_emit (m);
 
   free (error);
 }
 
   if (ds_last (&s) != '.')
     ds_put_byte (&s, '.');
 
-  struct msg_location location = {
-    .file_name = src->reader->file_name,
+  struct msg_location *location = xmalloc (sizeof *location);
+  *location = (struct msg_location) {
+    .file_name = xstrdup_if_nonnull (src->reader->file_name),
     .first_line = lex_source_get_first_line_number (src, n0),
     .last_line = lex_source_get_last_line_number (src, n1),
     .first_column = lex_source_get_first_column (src, n0),
     .last_column = lex_source_get_last_column (src, n1),
   };
-  struct msg m = {
+  struct msg *m = xmalloc (sizeof *m);
+  *m = (struct msg) {
     .category = MSG_C_SYNTAX,
     .severity = MSG_S_ERROR,
-    .location = &location,
+    .location = location,
     .text = ds_steal_cstr (&s),
   };
-  msg_emit (&m);
+  msg_emit (m);
 }
 
 static void PRINTF_FORMAT (2, 3)
 
 void
 vmsg (enum msg_class class, const char *format, va_list args)
 {
-  struct msg m = {
+  struct msg *m = xmalloc (sizeof *m);
+  *m = (struct msg) {
     .category = msg_class_to_category (class),
     .severity = msg_class_to_severity (class),
     .text = xvasprintf (format, args),
   };
-
-  msg_emit (&m);
+  msg_emit (m);
 }
 
 /* Writes error message in CLASS, with text FORMAT, formatted with
 {
   va_list args;
   va_start (args, format);
-  char *e = xvasprintf (format, args);
+  struct string s = DS_EMPTY_INITIALIZER;
+  ds_put_vformat (&s, format, args);
   va_end (args);
+  ds_put_format (&s, ": %s", strerror (errnum));
 
-  struct msg m = {
+  struct msg *m = xmalloc (sizeof *m);
+  *m = (struct msg) {
     .category = MSG_C_GENERAL,
     .severity = MSG_S_ERROR,
-    .text = xasprintf (_("%s: %s"), e, strerror (errnum)),
+    .text = ds_steal_cstr (&s),
   };
-  msg_emit (&m);
-
-  free (e);
+  msg_emit (m);
 }
 
 
 
 
 static void
-ship_message (struct msg *m)
+ship_message (const struct msg *m)
 {
   enum { MAX_STACK = 4 };
-  static struct msg *stack[MAX_STACK];
+  static const struct msg *stack[MAX_STACK];
   static size_t n;
 
   /* If we're recursing on a given message, or recursing deeply, drop it. */
   free (s);
 }
 
-
-
 static void
 process_msg (struct msg *m)
 {
 }
 
 
-/* Emits M as an error message.
-   Frees allocated data in M. */
+/* Emits M as an error message.  Takes ownership of M. */
 void
 msg_emit (struct msg *m)
 {
   if (!messages_disabled)
-     process_msg (m);
-
-  free (m->text);
-  free (m->command_name);
+    process_msg (m);
+  msg_destroy (m);
 }
 
 /* Disables message output until the next call to msg_enable.  If