Howdy all.
I've discovered a little bug in cc-mode v5.27 (found in current XEmacs
packages) and v5.28 (downloaded directly from the cc-mode web site) involving
indentation within a switch statement. It did not occur with the v5.25 which
is the default in Emacs 20.7.
Here a sample file 'parentest.cc' that triggers it (repeatable with v5.27 and
v5.28 under XEmacs 21.1.14 and 21.2.46 with the -vanilla switch, and Emacs
20.7):
======================================================================
void
foo(int a)
{
switch (a)
{
case 1: // Example: "1:2:3"
{
}
break; // "unbalanced paren" error occurs here
}
}
void
foo2(int a)
{
switch (a)
{
case 1: // Example: "123"
{
}
break; // no error now, but wrong indent level
}
}
void
foo3(int a)
{
switch (a)
{
case 1: // Example - "123"
{
}
break; // no error, correct indent level
}
}
======================================================================
Hit TAB on each of the 'break' statements and watch what happens. The first
func refuses to indent at that break statement due to an "unbalanced paren"
error. The 2nd func indents, but at the wrong indent level. The 3rd func
works correctly. Note that the only difference between each one is the
contents of the comment, specifically the presence of colons...
Running c-show-syntactic-information anywhere on that case: in foo() shows
that it does think that it's a case-label. Running it on the break in foo2()
says it's a (statement . 189) and on the break on foo3() reveals (statement
. 373).
Below is the lisp backtrace for the actual error situation (against cc-mode
v5.28). I'd continue digging further, but some moderately important work
related stuff just came up that I have to look into and I figure it'd be much
easier for someone more intimiately familiar with the cc-mode code anyways.
I'm not on the cc-mode mailing list anymore (at least I don't think so). I
copied the XEmacs beta mailing list (which I am on) to warn them that this bug
exists in the provided cc-mode package, just in case others start hitting it.
Thanks,
Chuck
--
Charles K. Hines <ckh(a)requesttech.com> <hines(a)gderome.com>
Principal Scientist at ReQuest Technologies Inc (
http://www.ReQuestTech.com/)
Martial Arts Instructor [Modern Arnis and Balintawak Escrima]
"Go back to sleep, Chuck. You're just havin' a nightmare
-- of course, we ARE still in Hell." (Gary Larson)
======================================================================
Signaling: (error "Unbalanced parentheses")
scan-lists(67 -1 1)
up-list(-1)
backward-up-list(1)
(if firstp (backward-up-list 1) (goto-char last-begin))
(progn (if firstp (backward-up-list 1) (goto-char last-begin)) (save-excursion
(c-backward-syntactic-ws lim) (skip-chars-backward "-+!*&:.~@ \n") (if ...
...)) (goto-char last-begin) (setq donep t))
(if (not (c-safe ...)) (progn (if firstp ... ...) (save-excursion ... ... ...)
(goto-char last-begin) (setq donep t)))
(if (bobp) (setq donep t) (if (not ...) (progn ... ... ... ...)) (setq c-maybe-labelp
nil) (cond (donep) (... ...) (...) (... ... ... ... ... ...) (...) (firstp ...) (... ...)
(...) (... ...) (... ...)))
(while (not donep) (if (bobp) (setq donep t) (if ... ...) (setq c-maybe-labelp nil)
(cond ... ... ... ... ... ... ... ... ... ...)))
(if (and (progn ... ...) (c-safe ...) (progn ... ...)) (setq last-begin saved)
(goto-char last-begin) (while (not donep) (if ... ... ... ... ...)))
(let ((firstp t) (substmt-p t) donep c-in-literal-cache saved (last-begin ...)) (if (and
... ... ...) (setq last-begin saved) (goto-char last-begin) (while ... ...)) (goto-char
last-begin) (let (...) (skip-chars-backward "-+!*&~@`# \n" ...)
(skip-chars-forward " \n" lim)))
c-beginning-of-statement-1(37)
(while (and (not done) (<= safepos ...) (/= relpos ...)) (c-beginning-of-statement-1
safepos) (if (= relpos ...) (setq done t)) (setq relpos (c-point ...)))
(let ((safepos ...) relpos done) (goto-char indent-point) (c-beginning-of-statement-1
safepos) (if (and ... ...) (c-beginning-of-statement-1 safepos)) (if (and inswitch-p ...)
(progn ... ...)) (setq relpos (c-point ...)) (while (and ... ... ...)
(c-beginning-of-statement-1 safepos) (if ... ...) (setq relpos ...)) (c-add-syntax (quote
statement) relpos) (if (eq char-after-ip ?{) (c-add-syntax ...)))
(cond ((and inswitch-p ...) (goto-char indent-point) (skip-chars-forward " ")
(if ... ... ...)) ((eq char-before-ip ?\,) (goto-char indent-point)
(c-beginning-of-closest-statement) (c-add-syntax ... ...)) ((or ... ...) (goto-char
indent-point) (c-beginning-of-closest-statement) (c-add-syntax ... ...)) ((< ...
indent-point) (let ... ... ... ... ... ... ... ... ...)) ((setq placeholder ...)
(goto-char containing-sexp) (back-to-indentation) (let ... ...) (if ... ...))
((save-excursion ...) (goto-char containing-sexp) (if ... ...) (c-add-syntax ... ...))
((and ... ...) (c-add-syntax ... ...)) (t (goto-char containing-sexp) (if ... ...)
(c-add-syntax ... ...) (if ... ...)))
(cond ((memq literal ...) (c-add-syntax ... ...)) ((memq literal ...) (c-add-syntax
literal ...)) ((and ... ...) (c-add-syntax ... placeholder)) ((and ... ...) (setq
tmpsymbol ...) (if tmpsymbol ... ...) (goto-char ...) (back-to-indentation) (c-add-syntax
tmpsymbol ...) (unless ... ...)) ((null containing-sexp) (cond ... ... ... ... ... ... ...
... ... ... ... ... ...)) ((not ...) (c-backward-syntactic-ws containing-sexp) (cond ...
... ... ... ... ... ...)) ((and c-baseclass-key ...) (goto-char indent-point)
(skip-chars-forward " ") (cond ... ... ...)) ((setq special-brace-list ...)
(cond ... ... ...)) ((and ... ... ... ...) (goto-char indent-point) (skip-chars-forward
" ") (let ... ...)) ((looking-at "\\<else\\>[^_]")
(c-backward-to-start-of-if containing-sexp) (c-add-syntax ... ...)) ((progn ... ... ...)
(goto-char placeholder) (c-add-syntax ... ...)) ((save-excursion ...) (c-add-syntax ...
placeholder)) ((looking-at c-switch-label-key) (goto-char containing-sexp) (if !
..!
. ...) (c-add-syntax ... ...)) ((looking-at c-label-key) (goto-char containing-sexp) (if
... ...) (c-add-syntax ... ...)) ((eq char-after-ip ?}) (let* ... ...)) (t (goto-char
containing-sexp) (forward-char 1) (c-forward-syntactic-ws indent-point) (while ... ...)
(while ... ...) (cond ... ... ... ... ... ... ... ...)))
(let* ((indent-point ...) (case-fold-search nil) (fullstate ...) (state fullstate)
literal containing-sexp char-before-ip char-after-ip lim syntax placeholder
c-in-literal-cache inswitch-p tmpsymbol keyword injava-inher special-brace-list (inclass-p
...) inenclosing-p) (save-excursion (save-restriction ... ...)) (save-excursion (goto-char
indent-point) (skip-chars-forward " }") (skip-chars-backward " ")
(while ... ... ...)) (setq lim (or containing-sexp ... ...)) (goto-char indent-point)
(skip-chars-forward " ") (setq char-after-ip (char-after))
(c-backward-syntactic-ws lim) (setq char-before-ip (char-before)) (goto-char indent-point)
(skip-chars-forward " ") (setq literal (c-in-literal lim)) (cond (... ...) (...
...) (... ...) (... ... ... ... ... ... ...) (... ...) (... ... ...) (... ... ... ...)
(... ...) (... ... ... ...) (... ... ...) (... ... ...) (... ...) (... ... ... ...) (...
... ... ...) (... ...) (t ... ... ... ... ... ...)) (goto-char indent-point) (skip-c!
ha!
rs-forward " ") (cond (... ...) (... ...) (... ...)) syntax)
(save-restriction (beginning-of-line) (let* (... ... ... ... literal containing-sexp
char-before-ip char-after-ip lim syntax placeholder c-in-literal-cache inswitch-p
tmpsymbol keyword injava-inher special-brace-list ... inenclosing-p) (save-excursion ...)
(save-excursion ... ... ... ...) (setq lim ...) (goto-char indent-point)
(skip-chars-forward " ") (setq char-after-ip ...) (c-backward-syntactic-ws lim)
(setq char-before-ip ...) (goto-char indent-point) (skip-chars-forward " ")
(setq literal ...) (cond ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...)
(goto-char indent-point) (skip-chars-forward " ") (cond ... ... ...) syntax))
(save-excursion (save-restriction (beginning-of-line) (let* ... ... ... ... ... ... ...
... ... ... ... ... ... ... ... ... syntax)))
c-guess-basic-syntax()
(or syntax c-syntactic-context (c-guess-basic-syntax))
(let* ((c-parsing-error nil) (c-syntactic-context ...) (indent ...)) (and (not ...)
c-echo-syntactic-information-p (message "syntax: %s, indent: %d"
c-syntactic-context indent)) (setq shift-amt (- indent ...)) (c-shift-line-indentation
shift-amt) (run-hooks (quote c-special-indent-hook)) c-parsing-error)
(or (let* (... ... ...) (and ... c-echo-syntactic-information-p ...) (setq shift-amt
...) (c-shift-line-indentation shift-amt) (run-hooks ...) c-parsing-error)
c-parsing-error)
(setq c-parsing-error (or (let* ... ... ... ... ... c-parsing-error) c-parsing-error))
(if c-syntactic-indentation (setq c-parsing-error (or ... c-parsing-error)) (let (...)
(save-excursion ...) (setq shift-amt ...) (c-shift-line-indentation shift-amt)))
(let (shift-amt) (if c-syntactic-indentation (setq c-parsing-error ...) (let ... ... ...
...)) shift-amt)
c-indent-line()
#<compiled-function nil "...(3)" [indent-line-function] 1 937352 nil>()
funcall(#<compiled-function nil "...(3)" [indent-line-function] 1 937352
nil>)
(cond ((not c-tab-always-indent) (if ... ... ...)) ((eq c-tab-always-indent t) (funcall
indent-function)) (t (if ... ...) (funcall indent-function)))
(if (and c-syntactic-indentation current-prefix-arg) (let (... beg end) (c-indent-line)
(setq shift-amt ...) (save-excursion ... ... ... ... ... ... ...) (if ... ...)) (cond (...
...) (... ...) (t ... ...)))
(let ((bod ...) (indent-function ...)) (if (and c-syntactic-indentation
current-prefix-arg) (let ... ... ... ... ...) (cond ... ... ...)))
c-indent-command(1)
call-interactively(c-indent-command)
======================================================================