Fixes debbugs#19206.
cc-bytecomp.el (cc-bytecomp-compiling-or-loading): new function which
walks the stack to discover whether we're compiling or loading.
(cc-bytecomp-is-compiling): Reformulate, and move towards beginning.
(cc-bytecomp-is-loading): New defsubst.
(cc-bytecomp-setup-environment, cc-bytecomp-restore-environment): Use
the
above defsubsts.
(cc-require-when-compile, cc-bytecomp-defvar)
(cc-bytecomp-defun): Simplify conditionals.
cc-defs.el (cc-bytecomp-compiling-or-loading): "Borrow" this function
from cc-bytecomp.el.
(c-get-current-file): Reformulate using the above.
(c-lang-defconst): Prevent duplicate entries of file names in a symbol's
'source property.
(c-lang-const): Use cc-bytecomp-is-compiling.
cc-langs.el (c-make-init-lang-vars-fun): Use cc-bytecomp-is-compiling.
+2015-01-13 Alan Mackenzie <acm@muc.de>
+
+ Allow compilation during loading of Modes derived from a CC Mode mode.
+ Fixes debbugs#19206.
+
+ * progmodes/cc-bytecomp.el (cc-bytecomp-compiling-or-loading): new
+ function which walks the stack to discover whether we're compiling
+ or loading.
+ (cc-bytecomp-is-compiling): Reformulate, and move towards
+ beginning.
+ (cc-bytecomp-is-loading): New defsubst.
+ (cc-bytecomp-setup-environment, cc-bytecomp-restore-environment):
+ Use the above defsubsts.
+ (cc-require-when-compile, cc-bytecomp-defvar)
+ (cc-bytecomp-defun): Simplify conditionals.
+
+ * progmodes/cc-defs.el (cc-bytecomp-compiling-or-loading):
+ "Borrow" this function from cc-bytecomp.el.
+ (c-get-current-file): Reformulate using the above.
+ (c-lang-defconst): Prevent duplicate entries of file names in a
+ symbol's 'source property.
+ (c-lang-const): Use cc-bytecomp-is-compiling.
+
+ * progmodes/cc-langs.el (c-make-init-lang-vars-fun): Use
+ cc-bytecomp-is-compiling.
+
2015-01-13 Stefan Monnier <monnier@iro.umontreal.ca>
* emacs-lisp/eieio-core.el (eieio-defclass): Fix call to `defclass'
;;`(message ,@args)
)
+(defun cc-bytecomp-compiling-or-loading ()
+ ;; Determine whether byte-compilation or loading is currently active,
+ ;; returning 'compiling, 'loading or nil.
+ ;; If both are active, the "innermost" activity counts. Note that
+ ;; compilation can trigger loading (various `require' type forms)
+ ;; and loading can trigger compilation (the package manager does
+ ;; this). We walk the lisp stack if necessary.
+ (cond
+ ((and load-in-progress
+ (boundp 'byte-compile-dest-file)
+ (stringp byte-compile-dest-file))
+ (let ((n 0) elt)
+ (while (and
+ (setq elt (backtrace-frame n))
+ (not (and (car elt)
+ (memq (cadr elt)
+ '(load require
+ byte-compile-file byte-recompile-directory
+ batch-byte-compile)))))
+ (setq n (1+ n)))
+ (cond
+ ((memq (cadr elt) '(load require))
+ 'loading)
+ ((memq (cadr elt) '(byte-compile-file
+ byte-recompile-directory
+ batch-byte-compile))
+ 'compiling)
+ (t ; Can't happen.
+ (message "cc-bytecomp-compiling-or-loading: System flags spuriously set")
+ nil))))
+ (load-in-progress
+ ;; Being loaded.
+ 'loading)
+ ((and (boundp 'byte-compile-dest-file)
+ (stringp byte-compile-dest-file))
+ ;; Being compiled.
+ 'compiling)
+ (t
+ ;; Being evaluated interactively.
+ nil)))
+
+(defsubst cc-bytecomp-is-compiling ()
+ "Return non-nil if eval'ed during compilation."
+ (eq (cc-bytecomp-compiling-or-loading) 'compiling))
+
+(defsubst cc-bytecomp-is-loading ()
+ "Return non-nil if eval'ed during loading.
+Nil will be returned if we're in a compilation triggered by the loading."
+ (eq (cc-bytecomp-compiling-or-loading) 'loading))
+
(defun cc-bytecomp-setup-environment ()
;; Eval'ed during compilation to setup variables, functions etc
;; declared with `cc-bytecomp-defvar' et al.
- (if (not load-in-progress)
- ;; Look at `load-in-progress' to tell whether we're called
- ;; directly in the file being compiled or just from some file
- ;; being loaded during compilation.
+ (if (not (cc-bytecomp-is-loading))
(let (p)
(if cc-bytecomp-environment-set
(error "Byte compilation environment already set - \
(defun cc-bytecomp-restore-environment ()
;; Eval'ed during compilation to restore variables, functions etc
;; declared with `cc-bytecomp-defvar' et al.
- (if (not load-in-progress)
+ (if (not (cc-bytecomp-is-loading))
(let (p)
(setq p cc-bytecomp-unbound-variables)
(while p
`(eval-when-compile
(if (and (fboundp 'cc-bytecomp-is-compiling)
(cc-bytecomp-is-compiling))
- (if (or (not load-in-progress)
- (not (featurep ,cc-part)))
+ (if (not (featurep ,cc-part))
(cc-bytecomp-load (symbol-name ,cc-part)))
(require ,cc-part))))
(require ,feature)
(eval-when-compile (cc-bytecomp-setup-environment))))
-(defun cc-bytecomp-is-compiling ()
- "Return non-nil if eval'ed during compilation. Don't use outside
-`eval-when-compile'."
- (and (boundp 'byte-compile-dest-file)
- (stringp byte-compile-dest-file)))
-
(defmacro cc-bytecomp-defvar (var)
"Binds the symbol as a variable during compilation of the file,
to silence the byte compiler. Don't use within `eval-when-compile'."
"cc-bytecomp-defvar: Saving %s (as unbound)" ',var)
(setq cc-bytecomp-unbound-variables
(cons ',var cc-bytecomp-unbound-variables))))
- (if (and (cc-bytecomp-is-compiling)
- (not load-in-progress))
+ (if (cc-bytecomp-is-compiling)
(progn
(defvar ,var)
(set ',var (intern (concat "cc-bytecomp-ignore-var:"
(setq cc-bytecomp-original-functions
(cons (list ',fun nil 'unbound)
cc-bytecomp-original-functions))))
- (if (and (cc-bytecomp-is-compiling)
- (not load-in-progress))
+ (if (cc-bytecomp-is-compiling)
(progn
(fset ',fun (intern (concat "cc-bytecomp-ignore-fun:"
(symbol-name ',fun))))
(defvar c-lang-const-expansion nil)
+;; Ugly hack to pull in the definition of `cc-bytecomp-compiling-or-loading`
+;; from cc-bytecomp to make it available at loadtime. This is the same
+;; mechanism used in cc-mode.el for `c-populate-syntax-table'.
+(defalias 'cc-bytecomp-compiling-or-loading
+ (cc-eval-when-compile
+ (let ((f (symbol-function 'cc-bytecomp-compiling-or-loading)))
+ (if (byte-code-function-p f) f (byte-compile f)))))
+
(defsubst c-get-current-file ()
;; Return the base name of the current file.
- (let ((file (cond
- (load-in-progress
- ;; Being loaded.
- load-file-name)
- ((and (boundp 'byte-compile-dest-file)
- (stringp byte-compile-dest-file))
- ;; Being compiled.
- byte-compile-dest-file)
- (t
- ;; Being evaluated interactively.
- (buffer-file-name)))))
+ (let* ((c-or-l (cc-bytecomp-compiling-or-loading))
+ (file
+ (cond
+ ((eq c-or-l 'loading) load-file-name)
+ ((eq c-or-l 'compiling) byte-compile-dest-file)
+ ((null c-or-l) (buffer-file-name)))))
(and file
(file-name-sans-extension
(file-name-nondirectory file)))))
;; language constant source definitions.)
(c-lang-const-expansion 'call)
(c-langs-are-parametric t)
+ (file (intern
+ (or (c-get-current-file)
+ (error "`c-lang-defconst' can only be used in a file"))))
bindings
pre-files)
;; definitions for this symbol, to make sure the order in the
;; `source' property is correct even when files are loaded out of
;; order.
- (setq pre-files (nreverse
- ;; Reverse to get the right load order.
- (mapcar 'car (get sym 'source))))
+ (setq pre-files (mapcar 'car (get sym 'source)))
+ (if (memq file pre-files)
+ ;; This can happen when the source file (e.g. cc-langs.el) is first
+ ;; loaded as source, setting a 'source property entry, and then itself
+ ;; being compiled.
+ (setq pre-files (cdr (memq file pre-files))))
+ ;; Reverse to get the right load order.
+ (setq pre-files (nreverse pre-files))
`(eval-and-compile
(c-define-lang-constant ',name ,bindings
(if (or (eq c-lang-const-expansion 'call)
(and (not c-lang-const-expansion)
(not mode))
- load-in-progress
- (not (boundp 'byte-compile-dest-file))
- (not (stringp byte-compile-dest-file)))
+ (not (cc-bytecomp-is-compiling)))
;; Either a straight call is requested in the context, or
;; we're in an "uncontrolled" context and got no language,
;; or we're not being byte compiled so the compile time
from the language constants. Use the `c-init-language-vars' macro to
accomplish that conveniently."
- (if (and (not load-in-progress)
- (boundp 'byte-compile-dest-file)
- (stringp byte-compile-dest-file))
-
+ (if (cc-bytecomp-is-compiling)
;; No need to byte compile this lambda since the byte compiler is
;; smart enough to detect the `funcall' construct in the
;; `c-init-language-vars' macro below and compile it all straight