Subject: bug#16585: c-invalidate-state-cache fails if called when narrowed

From: Alan Mackenzie <[email-masked]>
Date: Sat, 8 Feb 2014 22:37:17 +0000

Hi, Daniel.

On Tue, Jan 28, 2014 at 06:09:04PM -0800, Daniel Colascione wrote:
> c-invalidate-state-cache can fail if called in a narrowed region: we end 
> up calling c-clear-char-property for bob even if that's before 
> point-min, causing remote-text-properties to raise (args-out-of-range 1 2).

> We get into this situation when expanding yasnippet snippets; we're 
> calling c-invalidate-state-cache from c-before-change.

> To repro manually, first write this to some buffer.

> #include <stdio.h>

> void foo() {

> }

> Then (this is important) run M-x c-mode. After starting the mode, move 
> point to inside foo's body and eval (save-restriction (narrow-to-region 
> (point-at-bol) (point-at-eol)) (c-invalidate-state-cache (point))). You 
> should break into the debugger.

Thanks for this crystal clear bug report, and for taking the trouble to
debug it.

> The patch below seems correct and fixes the problem for me, but it'd be 
> nice if Alan could take a look at it before I push it to trunk. The 
> version of c-invalidate-state-cache in cc-mode trunk is very different.

I don't think (but I'm not quite sure) that this patch is correct, since
it leaves c-invalidate-state-cache-1 running widened.  That might well
lead to incorrect "state cache" manipulations.  Instead I've widened the
buffer around the two calls which clear and set the text properties.
Would you please try out the following patch, which should fix the
problem.

=== modified file 'lisp/progmodes/cc-defs.el'
*** lisp/progmodes/cc-defs.el	2014-02-02 10:25:29 +0000
--- lisp/progmodes/cc-defs.el	2014-02-08 22:21:01 +0000
***************
*** 1293,1302 ****
    ;; suppressed.
    `(unwind-protect
         (c-save-buffer-state ()
! 	 (c-clear-cpp-delimiters ,beg ,end)
  	 ,`(c-with-cpps-commented-out ,@forms))
       (c-save-buffer-state ()
!        (c-set-cpp-delimiters ,beg ,end))))
  
  (defsubst c-intersect-lists (list alist)
    ;; return the element of ALIST that matches the first element found
--- 1293,1306 ----
    ;; suppressed.
    `(unwind-protect
         (c-save-buffer-state ()
! 	 (save-restriction
! 	   (widen)
! 	   (c-clear-cpp-delimiters ,beg ,end))
  	 ,`(c-with-cpps-commented-out ,@forms))
       (c-save-buffer-state ()
!        (save-restriction
! 	 (widen)
! 	 (c-set-cpp-delimiters ,beg ,end)))))
  
  (defsubst c-intersect-lists (list alist)
    ;; return the element of ALIST that matches the first element found

-- 
Alan Mackenzie (Nuremberg, Germany).