Subject: new cc-mode <>-matching barfs in complex case

From: Daniel Colascione <[email-masked]>
Date: Fri, 26 Mar 2010 19:54:41 -0400

Note: Although the trace below is from Emacs 22, I'm using cc-mode from
HEAD. It doesn't affect the bug.

cc-mode seems to barf in certain cases on files with lots of template
brackets. I can't quite figure out what's wrong with it: the testcase
below is about as small as I could make it.

To reproduce: load the following file in c++-mode, position point at
line 3, column 6 (just after the "/*"), and press space. It's
important not to scroll around the buffer first. You'll see a
backtrace something like this:

  signal(error ("Invalid search bound (wrong side of point)"))
  (condition-case err (while (and ... ... ...)) (error (goto-char start)
(signal ... ...)))
  (let ((start ...) tmp search-pos state (state-pos ...) check-pos
check-state (last-token-end-pos ...) found) (condition-case err (while
...) (error ... ...)) (if found (progn ... ...) (if ... ... ...) nil))
  c-syntactic-re-search-forward("[;{}]" 2109 end)
  (let ((beg-lit-limits ...) (end-lit-limits ...)) (goto-char (if
beg-lit-limits ... beg)) (c-syntactic-skip-backward "^;{}" (max ...
...)) (while (c-search-forward-char-property ... ... beg)
(c-clear-<-pair-props-if-match-after beg ...)) (goto-char (if
end-lit-limits ... end)) (c-syntactic-re-search-forward "[;{}]" (min ...
...) (quote end)) (while (c-search-backward-char-property ... ... end)
(c-clear->-pair-props-if-match-before end)))
  (save-excursion (let (... ...) (goto-char ...)
(c-syntactic-skip-backward "^;{}" ...) (while ... ...) (goto-char ...)
(c-syntactic-re-search-forward "[;{}]" ... ...) (while ... ...)))
  c-before-change-check-<>-operators(61 61)
  funcall(c-before-change-check-<>-operators 61 61)
  (lambda (fn) (funcall fn beg end))(c-before-change-check-<>-operators)
  mapc((lambda (fn) (funcall fn beg end)) (c-extend-region-for-CPP
c-before-change-check-<>-operators))
  (if c-get-state-before-change-functions (mapc (lambda ... ...)
c-get-state-before-change-functions))
  (save-excursion (c-unfind-enclosing-token beg)
(c-unfind-enclosing-token end) (when (< beg end)
(c-unfind-coalesced-tokens beg end)) (let (lim type type-pos marked-id
term-pos ...) (when ... ... ... ...)) (setq c-new-BEG beg c-new-END end)
(if c-get-state-before-change-functions (mapc ...
c-get-state-before-change-functions)))
  (progn (widen) (save-excursion (c-unfind-enclosing-token beg)
(c-unfind-enclosing-token end) (when ... ...) (let ... ...) (setq
c-new-BEG beg c-new-END end) (if c-get-state-before-change-functions ...)))
  (unwind-protect (progn (widen) (save-excursion ... ... ... ... ...
...)) (set-match-data save-match-data-internal (quote evaporate)))
  (let ((save-match-data-internal ...)) (unwind-protect (progn ... ...)
(set-match-data save-match-data-internal ...)))
  (save-match-data (widen) (save-excursion (c-unfind-enclosing-token
beg) (c-unfind-enclosing-token end) (when ... ...) (let ... ...) (setq
c-new-BEG beg c-new-END end) (if c-get-state-before-change-functions ...)))
  (save-restriction (save-match-data (widen) (save-excursion ... ... ...
... ... ...)))
  c-before-change(61 61)

== BEGIN TESTCASE ==
void foo_impl::gc_mark(gc::mark_context mc) throw()
{
    /*
    if(mc.abandon) {
        this->shutdown();
    }

    gc_process(mc, &this->ack_fiber);
    gc_process(mc, &this->err);

    source::gc_mark(mc);
    sink::gc_mark(mc);
}

foo_id foo::get_id() const throw()
{
    if(this->impl()->chan) {
        return this->impl()->self_it->first;
    }

    return 0;
}

ptr<spam> foo::get_spam() const throw()
{
    return this->impl()->chan;
};

void foo_impl::on_ack_bytes(size_t howmany)
{
    // check for overflow
    if(this->remote_bufsz + howmany < this->remote_bufsz) {
        throw (peer_on_fire()
               << protocol_error_reason("impossible remote buffer size"));
    }

    this->remote_bufsz += howmany;
    this->remote_has_room.wake();
}

void foo_impl::tentative_add_bytes(size_t howmany, ptr<io::source> src)
{
    if(this->incoming.avail() < howmany) {
        throw peer_on_fire()
            << protocol_error_reason("peer overflowed buffer");
    }

    read_all(src, this->incoming.get_append_ptr(), howmany);
    this->incoming.note_written(howmany);
}

size_t foo_impl::confirm_add_bytes(size_t howmany) throw()
{
    assert(this->real_available <= this->incoming.size());
    assert(howmany <= this->incoming.size() - this->real_available);

    this->real_available += howmany;
    this->real_available_nonzero.wake();
    return this->incoming.size() - this->real_available;
}

void foo_impl::remove_new_bytes(size_t howmany) throw()
{
    assert(this->real_available <= this->incoming.size());
    assert(howmany <= this->incoming.size() - this->real_available);

    this->incoming.erase(this->incoming.end() - howmany,
                         this->incoming.end());
}

void foo_impl::shutdown()
{
    this->eof_from_peer = true;
    this->eof_to_peer   = true;
    this->stop_everything();
}

void foo_impl::shutdown_with_error(const ptr<error::base>& err)
{
    this->err = err;
    this->stop_everything();
}

void foo_impl::stop_everything() throw()
{
    this->ack_fiber->cancel();
    this->chan.reset();

    /* Readers and writers may be waiting on these */
    this->remote_has_room.wake();
}

== END TESTCASE ==

In GNU Emacs 22.3.1 (i386-apple-darwin9.6.0, Carbon Version 1.6.0)
 of 2009-01-03 on seijiz.local
Windowing system distributor `Apple Inc.', version 10.6.2
configured using `configure
'--prefix=/Applications/Emacs.app/Contents/Resources' '--with-carbon'
'--without-x'
'--libexecdir=/Volumes/Emacs/Emacs.app/Contents/MacOS/libexec'
'CFLAGS=-Os -arch i386 -arch ppc7400 -DUSE_ATSUI -DUSE_MAC_TSM''

Important settings:
  value of $LC_ALL: en_US.UTF-8
  value of $LC_COLLATE: nil
  value of $LC_CTYPE: nil
  value of $LC_MESSAGES: nil
  value of $LC_MONETARY: nil
  value of $LC_NUMERIC: nil
  value of $LC_TIME: nil
  value of $LANG: en_US.UTF-8
  locale-coding-system: utf-8
  default-enable-multibyte-characters: t

Major mode: C++/l

Minor modes in effect:
  linum-mode: t
  yas/minor-mode: t
  cua-mode: t
  which-function-mode: t
  global-hi-lock-mode: t
  hi-lock-mode: t
  show-paren-mode: t
  savehist-mode: t
  mac-print-mode: t
  tooltip-mode: t
  mouse-wheel-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  unify-8859-on-encoding-mode: t
  utf-translate-cjk-mode: t
  auto-compression-mode: t
  column-number-mode: t
  line-number-mode: t
  transient-mark-mode: t
  abbrev-mode: t

Recent input:
o n v <return> f o o <return> ! M-< <down> <down> C-e
M-x c + + - m o d e <return> <up> <down> <backspace>
q <left> C-x C-s M-< M-% C-g M-% C-g <next> <down>
<down> <down> <down> <down> <down> <down> <down> <down>
<down> <wheel-up> <double-wheel-up> <triple-wheel-up>
<triple-wheel-up> <triple-wheel-up> <down-mouse-1>
<mouse-1> <down> C-e <backspace> C-x C-s M-x c + +
- - m o d e <return> <up> <down> SPC q <wheel-down> <double-wheel-down>
<wheel-down> <wheel-down> <wheel-down> <down-mouse-1>
<mouse-1> <wheel-down> <down-mouse-1> <mouse-1> <up>
C-a <S-down> <S-down> <S-down> <S-down> <S-down> <S-down>
<S-down> <delete> M-< <down> <down> C-e M-x c + + -
m o d e <return> SPC C-z M-x c + + - m o d e <return>
SPC C-z C-z C-z C-z C-x C-s <down-mouse-1> <mouse-movement>
<drag-mouse-1> <wheel-up> <double-wheel-up> <triple-wheel-up>
<triple-wheel-up> <down-mouse-1> <mouse-1> <wheel-up>
<double-wheel-up> <triple-wheel-up> <down-mouse-1>
<mouse-1> <wheel-down> <double-wheel-down> <triple-wheel-down>
<triple-wheel-down> <triple-wheel-down> <triple-wheel-down>
<triple-wheel-up> <triple-wheel-up> <wheel-up> <double-wheel-up>
<up> <down-mouse-1> <mouse-1> <wheel-up> <double-wheel-up>
<up> <up> <down> <down> <down> C-a C-k C-k <up> <up>
<up> <up> <up> <up> <up> <up> C-e M-x c + + - m o d
e <return> SPC C-z <up> C-z C-z C-z C-z C-x C-s M-<
M-x c + + - m o d e <return> <down> <down> C-e SPC
q <wheel-down> <double-wheel-down> <triple-wheel-down>
<wheel-down> <double-wheel-down> <wheel-up> <double-wheel-up>
<triple-wheel-up> <triple-wheel-up> <triple-wheel-up>
<triple-wheel-up> <down> <up> <wheel-down> <double-wheel-down>
<triple-wheel-down> <triple-wheel-down> M-< C-g C-g
C-g C-x C-s M-< M-% c h a n n e l <return> s p a m
m <backspace> <return> ! M-< <down> <down> C-e M-x
c + + - m o d e <return> SPC q C-x C-s C-x k C-x C-f
a <backspace> f o o . c p p <return> <down> <down>
C-e SPC q <left> <right> <right> <left> M-x r e p o
r t - e m <tab> <return>

Recent messages:
(No changes need to be saved)
Mark set [2 times]
Replaced 2 occurrences
Mark set
Entering debugger...
Back to top level.
Wrote /tmp/foo.cpp
Entering debugger...
Back to top level.
Loading emacsbug...done