* bug#64133: CC Mode 5.35.2 (C/*l); incorrect indentation for an arrays of structs.
@ 2023-06-17 15:03 Jeff Norden
2023-06-17 15:14 ` Eli Zaretskii
0 siblings, 1 reply; 12+ messages in thread
From: Jeff Norden @ 2023-06-17 15:03 UTC (permalink / raw)
To: 64133
I've verified the following behavior with c-version 5.35.2 (emacs-29,
and emacs-30 from git) and with 5.35.1 (emacs 28.2).
Place the following text into a file with a ".c" extension, and load
it with "emacs -Q".
==========================================
#include <stdio.h>
struct three_ints {
int a, b, c;
};
int main () {
struct three_ints numbers[]= {
{0,1,2},
{3,4,5},
{6,7,8}
};
for (int i=0; i<numbers[2].a; i++) {
printf("ack ");
}
printf("\n");
}
==========================================
Move the cursor to the beginning of the line with {3,4,5} and press
<tab> to indent the line. It will be incorrectly indented 2 spaces
more than the previous line. Move to the next line, press <tab>,
and you'll see:
struct three_ints numbers[]= {
{0,1,2},
{3,4,5},
{6,7,8}
};
Just using <tab> to re-indent the lines will not change anything.
But, if you add or delete white-space before {0,1,2} or {3,4,5} and
press <tab>, it *may* fix things. It seems to depend on just what you
delete and where the cursor is. The pattern isn't clear to me.
Once fixed, you get:
struct three_ints numbers[]= {
{0,1,2},
{3,4,5},
{6,7,8}
};
At this point it is stable, and <tab> will work correctly. If you
restart c-mode with "M-x c-mode", the problem re-occurs.
This bug only seems to occur when a loop or similar construct occurs
after the array declaration/initialization. It doesn't need to
immediately follow, though.
When incorrectly indenting, "C-c C-s" shows 'defun-block-intro' syntax
for the {0,1,2} line, and 'substatement-open' for {3,4,5} and {4,5,6}.
Once it gets fixed, this changes to 'brace-list-intro' and
'brace-entry-open'.
==========================================
For a more "real world" example, start with the example program at the
end of the getopt_long(3) man page:
https://linux.die.net/man/3/getopt_long
and move the declaration of long_options[] from inside the while loop
to before it. (This makes long_options a global variable, instead of
local to the loop).
==========================================
I'm afraid I can't offer a patch or suggestion for a fix. My own
attempts at "parsing" the lisp in cc-engine.el come to an abrupt halt
when my brain receives an urgent "Warning! Meltdown imminent!"
message from my subconscious -- just kidding :-).
However, I did stumble upon the following in the comments for the
`c-inside-bracelist-p' function:
;; CONTAINING-SEXP is the buffer pos of the innermost containing
;; paren. NO IT ISN'T!!! [This function is badly designed, and
;; probably needs reformulating without its first argument, ...
Thanks,
-Jeff
----------------------------
If believing that "function is more important than form" and that "people
are more important than technology" makes me a Luddite, then so be it!
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#64133: CC Mode 5.35.2 (C/*l); incorrect indentation for an arrays of structs.
2023-06-17 15:03 bug#64133: CC Mode 5.35.2 (C/*l); incorrect indentation for an arrays of structs Jeff Norden
@ 2023-06-17 15:14 ` Eli Zaretskii
[not found] ` <CAPbFCnniiTyPQBmayZpRwS46--JW6ipmmLAzMterB5cK9NEXCA@mail.gmail.com>
0 siblings, 1 reply; 12+ messages in thread
From: Eli Zaretskii @ 2023-06-17 15:14 UTC (permalink / raw)
To: Jeff Norden; +Cc: 64133
> From: Jeff Norden <norden.jeff@gmail.com>
> Date: Sat, 17 Jun 2023 10:03:24 -0500
>
> I've verified the following behavior with c-version 5.35.2 (emacs-29,
> and emacs-30 from git) and with 5.35.1 (emacs 28.2).
>
> Place the following text into a file with a ".c" extension, and load
> it with "emacs -Q".
> ==========================================
> #include <stdio.h>
> struct three_ints {
> int a, b, c;
> };
> int main () {
> struct three_ints numbers[]= {
> {0,1,2},
> {3,4,5},
> {6,7,8}
> };
> for (int i=0; i<numbers[2].a; i++) {
> printf("ack ");
> }
> printf("\n");
> }
> ==========================================
> Move the cursor to the beginning of the line with {3,4,5} and press
> <tab> to indent the line. It will be incorrectly indented 2 spaces
> more than the previous line. Move to the next line, press <tab>,
> and you'll see:
>
> struct three_ints numbers[]= {
> {0,1,2},
> {3,4,5},
> {6,7,8}
> };
This source code uses the 'linux' indentation style, so you should do
M-x c-set-style RET linux RET
after which the problem goes away, AFAICT.
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#64133: CC Mode 5.35.2 (C/*l); incorrect indentation for an arrays of structs.
[not found] ` <CAPbFCnniiTyPQBmayZpRwS46--JW6ipmmLAzMterB5cK9NEXCA@mail.gmail.com>
@ 2023-06-17 16:27 ` Eli Zaretskii
2023-06-17 17:36 ` Jeff Norden
0 siblings, 1 reply; 12+ messages in thread
From: Eli Zaretskii @ 2023-06-17 16:27 UTC (permalink / raw)
To: Jeff Norden, Alan Mackenzie; +Cc: 64133
> From: Jeff Norden <norden.jeff@gmail.com>
> Date: Sat, 17 Jun 2023 10:43:40 -0500
>
> > This source code uses the 'linux' indentation style, so you should do
> >
> > M-x c-set-style RET linux RET
> >
> > after which the problem goes away, AFAICT.
> Eli: Thanks for the quick response. Changing the style works for me,
> so this can be closed.
> I didn't realize that the style effects parsing, not just the way
> space, etc gets inserted by default.
Thanks, I will let Alan chime in and decide whether this should be
closed.
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#64133: CC Mode 5.35.2 (C/*l); incorrect indentation for an arrays of structs.
2023-06-17 16:27 ` Eli Zaretskii
@ 2023-06-17 17:36 ` Jeff Norden
2023-06-18 13:13 ` Alan Mackenzie
0 siblings, 1 reply; 12+ messages in thread
From: Jeff Norden @ 2023-06-17 17:36 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Alan Mackenzie, 64133
On Sat, Jun 17, 2023 at 11:27 AM Eli Zaretskii <eliz@gnu.org> wrote:
> Thanks, I will let Alan chime in and decide whether this should be
> closed.
Actually, I now think that changing the style works because the gnu
style has
(substatement-open . +)
in c-offsets-alist, while linux uses (substatement-open . 0). With
either style, I initially get substatemnt syntax from "C-c C-s", which
changes to brace-list when I delete space and re-indent.
This issue *doesn't* occur if the opening brace is on its own line,
and it looks like most styles other than gnu do not indent
sub-statements. So, I still think this bug can be closed, but maybe
the resolution could be "mostly harmless" :-).
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#64133: CC Mode 5.35.2 (C/*l); incorrect indentation for an arrays of structs.
2023-06-17 17:36 ` Jeff Norden
@ 2023-06-18 13:13 ` Alan Mackenzie
2023-06-18 16:10 ` Jeff Norden
2023-06-18 17:23 ` Jeff Norden
0 siblings, 2 replies; 12+ messages in thread
From: Alan Mackenzie @ 2023-06-18 13:13 UTC (permalink / raw)
To: Jeff Norden; +Cc: Eli Zaretskii, 64133
Hello, Jeff
Thanks for taking the trouble to report this bug.
On Sat, Jun 17, 2023 at 12:36:30 -0500, Jeff Norden wrote:
> On Sat, Jun 17, 2023 at 11:27 AM Eli Zaretskii <eliz@gnu.org> wrote:
> > Thanks, I will let Alan chime in and decide whether this should be
> > closed.
I think, not yet.
> Actually, I now think that changing the style works because the gnu
> style has
> (substatement-open . +)
> in c-offsets-alist, while linux uses (substatement-open . 0). With
> either style, I initially get substatemnt syntax from "C-c C-s", which
> changes to brace-list when I delete space and re-indent.
> This issue *doesn't* occur if the opening brace is on its own line,
> and it looks like most styles other than gnu do not indent
> sub-statements. So, I still think this bug can be closed, but maybe
> the resolution could be "mostly harmless" :-).
I've edebugged through c-guess-basic-syntax and subroutines, and it's
now clear there's a bug in the handling of a cache. The cache, called
c-laomib-cache (with "laomib" standing for "looking at or maybe in
bracelist") speeds up the handling of very large brace lists which
frequently occur in generated .h files. Without the cache, these would
have to be scanned over repeatedly, which made C Mode very slow for
these files.
I think I should be able to fix this in the next day or three.
--
Alan Mackenzie (Nuremberg, Germany).
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#64133: CC Mode 5.35.2 (C/*l); incorrect indentation for an arrays of structs.
2023-06-18 13:13 ` Alan Mackenzie
@ 2023-06-18 16:10 ` Jeff Norden
2023-06-18 17:23 ` Jeff Norden
1 sibling, 0 replies; 12+ messages in thread
From: Jeff Norden @ 2023-06-18 16:10 UTC (permalink / raw)
To: Alan Mackenzie; +Cc: Eli Zaretskii, 64133
On Sun, Jun 18, 2023 at 8:13 AM Alan Mackenzie wrote:
>...
> > > Thanks, I will let Alan chime in and decide whether this should be
> > > closed.
>
> I think, not yet.
>...
> I think I should be able to fix this in the next day or three.
Hi Alan
I don't know if this might help, but here is one more thing I found,
which I can't explain at all.
Tab is normally bound to c-indent-line-or-region. You can't directly
re-bind tab to c-indent-line. However, if you create an interactive
version with:
(defun cil() (interactive) (c-indent-line))
and bind it to tab, it has the exact same behavior. This eliminates
several levels of function calls between c-indent-line-or-region and
c-indent-line.
So, if you open the example with emacs -Q, define cil and bind it to
tab with "M-x local-set-key", you can "fix" the syntax by moving to
the beginning of the {3,4,5} line and pressing:
<tab><backspace><backspace><tab>
At this point "C-c C-s" shows brace-list syntax.
BUT, if you start again, and instead of defining "cil', just replace
each <tab> with "M-: (c-indent-line)<ret>", it does *not* change the
syntax that "C-c C-s" shows. For some reason that I don't understand,
it seems that the minibuffer read affects the behavior. To see this,
change the defun for "cil" by adding:
(read-from-minibuffer "press <ret>")
after (interactive). You now need to hit <ret> after each <tab>, but
I *cannot* get the syntax for the line to change with this function.
-Jeff
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#64133: CC Mode 5.35.2 (C/*l); incorrect indentation for an arrays of structs.
2023-06-18 13:13 ` Alan Mackenzie
2023-06-18 16:10 ` Jeff Norden
@ 2023-06-18 17:23 ` Jeff Norden
2023-06-19 11:46 ` Alan Mackenzie
1 sibling, 1 reply; 12+ messages in thread
From: Jeff Norden @ 2023-06-18 17:23 UTC (permalink / raw)
To: Alan Mackenzie; +Cc: Eli Zaretskii, 64133
The only reason the minibuffer-read affects things is timing. This
seems obvious now, but somehow it didn't occur to me until after I
sent the previous message. If I do
<tab><backspace><backspace> ..wait a few seconds.. <tab>
then the syntax does *not* change to brace-list. I tried changing
c-progress-interval, but that didn't seem to affect things. Maybe
there is another timer, or maybe a race condition involved somehow.
Hope this helps,
-Jeff
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#64133: CC Mode 5.35.2 (C/*l); incorrect indentation for an arrays of structs.
2023-06-18 17:23 ` Jeff Norden
@ 2023-06-19 11:46 ` Alan Mackenzie
2023-06-19 14:30 ` Jeff Norden
2023-06-21 10:39 ` Alan Mackenzie
0 siblings, 2 replies; 12+ messages in thread
From: Alan Mackenzie @ 2023-06-19 11:46 UTC (permalink / raw)
To: Jeff Norden; +Cc: acm, Eli Zaretskii, 64133
Hello, Jeff.
On Sun, Jun 18, 2023 at 12:23:58 -0500, Jeff Norden wrote:
> The only reason the minibuffer-read affects things is timing. This
> seems obvious now, but somehow it didn't occur to me until after I
> sent the previous message. If I do
> <tab><backspace><backspace> ..wait a few seconds.. <tab>
> then the syntax does *not* change to brace-list. I tried changing
> c-progress-interval, but that didn't seem to affect things. Maybe
> there is another timer, or maybe a race condition involved somehow.
No, I think it really is the cache bug I mentioned in my last post.
Caches are wonderful things when they work properly, but the utter devil
to debug when they don't.
I've currently got a CC Mode version with this cache corrected, such
that it parses your test file correctly, but I want to make sure the
correction is correct before I send you a patch and release the fix.
I'll be back again soon.
> Hope this helps,
> -Jeff
--
Alan Mackenzie (Nuremberg, Germany).
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#64133: CC Mode 5.35.2 (C/*l); incorrect indentation for an arrays of structs.
2023-06-19 11:46 ` Alan Mackenzie
@ 2023-06-19 14:30 ` Jeff Norden
2023-06-21 10:39 ` Alan Mackenzie
1 sibling, 0 replies; 12+ messages in thread
From: Jeff Norden @ 2023-06-19 14:30 UTC (permalink / raw)
To: Alan Mackenzie; +Cc: Eli Zaretskii, 64133
On Mon, Jun 19, 2023 at 6:46 AM Alan Mackenzie <acm@muc.de> wrote:
> No, I think it really is the cache bug I mentioned in my last post.
I agree. In fact, a "brute force" fix is to use advice-add to reset
c-laomib-cache to nil before each call to c-indent-line. What puzzled
me is that certain buffer changes also fix the issue, and that timing
makes a difference in when and how that happens. I'm now guessing
that the bug is triggered by calls from the fontification system. If
I start "emacs -Q", and do `M-x global-font-lock-mode' to turn all
fontifcation off, then "C-c C-s" shows correct syntax when I open the
example file.
Thanks again,
-Jeff
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#64133: CC Mode 5.35.2 (C/*l); incorrect indentation for an arrays of structs.
2023-06-19 11:46 ` Alan Mackenzie
2023-06-19 14:30 ` Jeff Norden
@ 2023-06-21 10:39 ` Alan Mackenzie
2023-06-21 18:43 ` Jeff Norden
1 sibling, 1 reply; 12+ messages in thread
From: Alan Mackenzie @ 2023-06-21 10:39 UTC (permalink / raw)
To: Jeff Norden; +Cc: Eli Zaretskii, 64133
Hello again, Jeff.
On Mon, Jun 19, 2023 at 11:46:32 +0000, Alan Mackenzie wrote:
> On Sun, Jun 18, 2023 at 12:23:58 -0500, Jeff Norden wrote:
> > The only reason the minibuffer-read affects things is timing. This
> > seems obvious now, but somehow it didn't occur to me until after I
> > sent the previous message. If I do
> > <tab><backspace><backspace> ..wait a few seconds.. <tab>
> > then the syntax does *not* change to brace-list. I tried changing
> > c-progress-interval, but that didn't seem to affect things. Maybe
> > there is another timer, or maybe a race condition involved somehow.
> No, I think it really is the cache bug I mentioned in my last post.
> Caches are wonderful things when they work properly, but the utter devil
> to debug when they don't.
> I've currently got a CC Mode version with this cache corrected, such
> that it parses your test file correctly, but I want to make sure the
> correction is correct before I send you a patch and release the fix.
> I'll be back again soon.
OK, here's the patch which I think fixes the bug completely. Would you
please apply this patch to your ..../lisp/progmodes/cc-engine.el,
byte-compile (or native-compile) that file, and then try it out on your
real code. (In the unlikely event that you want help with the patching
or compilation, feel free to send me personal email.) Then, please
confirm that the bug is fixed, or tell me what's still not working.
Thanks!
diff -r 2cd57c62754a cc-engine.el
--- a/cc-engine.el Sat Jun 17 12:45:10 2023 +0000
+++ b/cc-engine.el Wed Jun 21 10:27:21 2023 +0000
@@ -12816,11 +12816,19 @@
(defvar c-laomib-cache nil)
(make-variable-buffer-local 'c-laomib-cache)
-(defun c-laomib-get-cache (containing-sexp)
- ;; Get an element from `c-laomib-cache' matching CONTAINING-SEXP.
+(defun c-laomib-get-cache (containing-sexp start)
+ ;; Get an element from `c-laomib-cache' matching CONTAINING-SEXP, and which
+ ;; is suitable for start postiion START.
;; Return that element or nil if one wasn't found.
- (let ((elt (assq containing-sexp c-laomib-cache)))
- (when elt
+ (let ((ptr c-laomib-cache)
+ elt)
+ (while
+ (and ptr
+ (setq elt (car ptr))
+ (or (not (eq (car elt) containing-sexp))
+ (< start (car (cddr elt)))))
+ (setq ptr (cdr ptr)))
+ (when ptr
;; Move the fetched `elt' to the front of the cache.
(setq c-laomib-cache (delq elt c-laomib-cache))
(push elt c-laomib-cache)
@@ -12832,18 +12840,26 @@
;; the components of the new element (see comment for `c-laomib-cache').
;; The return value is of no significance.
(when lim
- (let ((old-elt (assq lim c-laomib-cache))
- ;; (elt (cons containing-sexp (cons start nil)))
+ (let (old-elt
(new-elt (list lim start end result))
big-ptr
(cur-ptr c-laomib-cache)
- togo (size 0) cur-size
- )
- (if old-elt (setq c-laomib-cache (delq old-elt c-laomib-cache)))
+ togo (size 0) cur-size)
+
+ ;; If there is an elt which overlaps with the new element, remove it.
+ (while
+ (and cur-ptr
+ (setq old-elt (car cur-ptr))
+ (or (not (eq (car old-elt) lim))
+ (not (and (> start (car (cddr old-elt)))
+ (<= start (cadr old-elt))))))
+ (setq cur-ptr (cdr cur-ptr)))
+ (when (and cur-ptr old-elt)
+ (setq c-laomib-cache (delq old-elt c-laomib-cache)))
(while (>= (length c-laomib-cache) 4)
;; We delete the least recently used elt which doesn't enclose START,
- ;; or..
+ ;; or ...
(dolist (elt c-laomib-cache)
(if (or (<= start (cadr elt))
(> start (car (cddr elt))))
@@ -12851,8 +12867,10 @@
;; ... delete the least recently used elt which isn't the biggest.
(when (not togo)
+ (setq cur-ptr c-laomib-cache)
(while (cdr cur-ptr)
- (setq cur-size (- (nth 2 (cadr cur-ptr)) (car (cadr cur-ptr))))
+ (setq cur-size (- (cadr (cadr cur-ptr))
+ (car (cddr (cadr cur-ptr)))))
(when (> cur-size size)
(setq size cur-size
big-ptr cur-ptr))
@@ -13044,7 +13062,7 @@
(goto-char pos)
(when (eq braceassignp 'dontknow)
(let* ((cache-entry (and containing-sexp
- (c-laomib-get-cache containing-sexp)))
+ (c-laomib-get-cache containing-sexp pos)))
(lim2 (or (cadr cache-entry) lim))
sub-bassign-p)
(if cache-entry
@@ -13066,6 +13084,8 @@
)
(setq braceassignp (nth 3 cache-entry))
(goto-char (nth 2 cache-entry)))
+ (c-laomib-put-cache containing-sexp
+ start (point) sub-bassign-p)
(setq braceassignp sub-bassign-p)))
(t))
> > Hope this helps,
> > -Jeff
--
Alan Mackenzie (Nuremberg, Germany).
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#64133: CC Mode 5.35.2 (C/*l); incorrect indentation for an arrays of structs.
2023-06-21 10:39 ` Alan Mackenzie
@ 2023-06-21 18:43 ` Jeff Norden
2023-06-27 20:19 ` Alan Mackenzie
0 siblings, 1 reply; 12+ messages in thread
From: Jeff Norden @ 2023-06-21 18:43 UTC (permalink / raw)
To: Alan Mackenzie; +Cc: Eli Zaretskii, 64133
On Wed, Jun 21, 2023 at 5:39 AM Alan Mackenzie <acm@muc.de> wrote:
> Hello again, Jeff.
>
> OK, here's the patch which I think fixes the bug completely. Would you
> please apply this patch ... Then, please confirm that the bug is fixed, or
> tell me what's still not working.
Hi Alan,
Thanks for taking care of this so quickly. The patch seems to work
perfectly for me. I've tried it with 29.0.91 (2nd emacs-29 pretest)
and with my current git build of emacs from the master branch (which
is from June 11). Patch gives differing "offset" messages, but all of
the "hunks" succeed in both cases. I haven't built the 3rd emacs-29
pretest yet, but I can't foresee that there will be a problem. I will
be using this some more over the next few days. I'll post again if I
notice any issues, but I don't expect to.
-Jeff
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#64133: CC Mode 5.35.2 (C/*l); incorrect indentation for an arrays of structs.
2023-06-21 18:43 ` Jeff Norden
@ 2023-06-27 20:19 ` Alan Mackenzie
0 siblings, 0 replies; 12+ messages in thread
From: Alan Mackenzie @ 2023-06-27 20:19 UTC (permalink / raw)
To: Jeff Norden; +Cc: acm, Eli Zaretskii, 64133-done
Hello, Jeff.
On Wed, Jun 21, 2023 at 13:43:20 -0500, Jeff Norden wrote:
> On Wed, Jun 21, 2023 at 5:39 AM Alan Mackenzie <acm@muc.de> wrote:
> > OK, here's the patch which I think fixes the bug completely. Would you
> > please apply this patch ... Then, please confirm that the bug is fixed, or
> > tell me what's still not working.
> Hi Alan,
> Thanks for taking care of this so quickly. The patch seems to work
> perfectly for me. I've tried it with 29.0.91 (2nd emacs-29 pretest)
> and with my current git build of emacs from the master branch (which
> is from June 11). Patch gives differing "offset" messages, but all of
> the "hunks" succeed in both cases. I haven't built the 3rd emacs-29
> pretest yet, but I can't foresee that there will be a problem. I will
> be using this some more over the next few days. I'll post again if I
> notice any issues, but I don't expect to.
Thanks for such comprehensive testing! I've now committed the patch to
the Emacs master branch (it is too intricate a patch to go to the
release branch at this late stage), and I'm closing the bug with this
post.
If any other problems become apparent in this area (or anywhere else),
feel free to raise another bug report.
> -Jeff
--
Alan Mackenzie (Nuremberg, Germany).
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2023-06-27 20:19 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-06-17 15:03 bug#64133: CC Mode 5.35.2 (C/*l); incorrect indentation for an arrays of structs Jeff Norden
2023-06-17 15:14 ` Eli Zaretskii
[not found] ` <CAPbFCnniiTyPQBmayZpRwS46--JW6ipmmLAzMterB5cK9NEXCA@mail.gmail.com>
2023-06-17 16:27 ` Eli Zaretskii
2023-06-17 17:36 ` Jeff Norden
2023-06-18 13:13 ` Alan Mackenzie
2023-06-18 16:10 ` Jeff Norden
2023-06-18 17:23 ` Jeff Norden
2023-06-19 11:46 ` Alan Mackenzie
2023-06-19 14:30 ` Jeff Norden
2023-06-21 10:39 ` Alan Mackenzie
2023-06-21 18:43 ` Jeff Norden
2023-06-27 20:19 ` Alan Mackenzie
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).