]> git.donarmstrong.com Git - lilypond.git/commitdiff
Issue 2010: \lyricsto may turn into a voice-mangling zombie
authorDavid Kastrup <dak@gnu.org>
Sun, 5 Oct 2014 22:31:58 +0000 (00:31 +0200)
committerDavid Kastrup <dak@gnu.org>
Thu, 9 Oct 2014 11:26:27 +0000 (13:26 +0200)
The problem here was that the simultaneous iterator might keep
rerhythmed lyrics around when the associated voice has died already,
blocking the simultaneous iterator.  The solution is that when removing
the last regular iterator to remove all remaining lyric-combined
iterators at the same time.

lily/simultaneous-music-iterator.cc

index 92bf91b25a7cae95c1b97a7200b84b6f1cd8f042..3e42ed96c07dd99685af09aa148df16b77485f1a 100644 (file)
@@ -82,23 +82,50 @@ Simultaneous_music_iterator::construct_children ()
     }
 }
 
+// If there are non-run-always iterators and all of them die, take the
+// rest of them along.
 void
 Simultaneous_music_iterator::process (Moment until)
 {
+  bool had_good = false;
+  bool had_bad = false;
   SCM *proc = &children_list_;
   while (scm_is_pair (*proc))
     {
       Music_iterator *i = Music_iterator::unsmob (scm_car (*proc));
-      if (i->run_always ()
-          || i->pending_moment () == until)
+      bool run_always = i->run_always ();
+      if (run_always || i->pending_moment () == until)
         i->process (until);
       if (!i->ok ())
         {
+          if (!run_always)
+            had_bad = true;
           i->quit ();
           *proc = scm_cdr (*proc);
         }
       else
-        proc = SCM_CDRLOC (*proc);
+        {
+          if (!run_always)
+            had_good = true;
+          proc = SCM_CDRLOC (*proc);
+        }
+    }
+  // If there were non-run-always iterators and all of them died, take
+  // the rest of the run-always iterators along with them.  They have
+  // likely lost their reference iterators.  Basing this on the actual
+  // music contexts is not reliable since something like
+  // \new Voice = blah {
+  //    << \context Voice = blah { c4 d }
+  //       \addlyrics { oh no }
+  //    >> e f
+  // }
+  // cannot wait for the death of context blah before ending the
+  // simultaneous iterator.
+  if (had_bad && !had_good)
+    {
+      for (SCM p = children_list_; scm_is_pair (p); p = scm_cdr (p))
+        Music_iterator::unsmob (scm_car (p))->quit ();
+      children_list_ = SCM_EOL;
     }
 }