((:default-default *default-default*))
(error-fun 'error)
(wrap-block t))
+ (unless (listp lambda-list)
+ (bad-type lambda-list 'list "~S lambda-list is not a list: ~S"
+ context lambda-list))
(multiple-value-bind (forms declarations documentation)
(parse-body body :doc-string-allowed doc-string-allowed)
(let ((*arg-tests* ())
:error-fun error-fun
:anonymousp anonymousp)
(values `(let* (,@(nreverse *system-lets*))
+ #-sb-xc-host
+ (declare (muffle-conditions sb!ext:code-deletion-note))
,@(when *ignorable-vars*
`((declare (ignorable ,@*ignorable-vars*))))
,@*arg-tests*
;; Special case compiler-macros: if car of the form is FUNCALL,
;; skip over it for destructuring, pretending cdr of the form is
;; the actual form. Save original for &WHOLE.
- (when (eq context 'define-compiler-macro)
+ (when (and (not sublist) (eq context 'define-compiler-macro))
(push-let-binding compiler-macro-whole whole-var :system t)
(push compiler-macro-whole *ignorable-vars*)
(push-let-binding whole-var whole-var
:maximum ,explicit-maximum))))))
*arg-tests*))
(when key-seen
- (let ((problem (gensym "KEY-PROBLEM-"))
- (info (gensym "INFO-")))
+ (with-unique-names (problem info)
(push `(multiple-value-bind (,problem ,info)
(verify-keywords ,rest-name
',keys
- ',allow-other-keys-p)
+ ',allow-other-keys-p
+ ,(eq 'define-compiler-macro context))
(when ,problem
(,error-fun
'defmacro-lambda-list-broken-key-list-error
;;; We save space in macro definitions by calling this function.
(defun arg-count-error (context name args lambda-list minimum maximum)
(let (#-sb-xc-host
- (sb!debug:*stack-top-hint* (nth-value 1 (find-caller-name-and-frame))))
+ (sb!debug:*stack-top-hint* (or sb!debug:*stack-top-hint* 'arg-count-error)))
(error 'arg-count-error
:kind context
:name name
;;; Determine whether KEY-LIST is a valid list of keyword/value pairs.
;;; Do not signal the error directly, 'cause we don't know how it
;;; should be signaled.
-(defun verify-keywords (key-list valid-keys allow-other-keys)
+(defun verify-keywords (key-list valid-keys allow-other-keys &optional compiler-macro)
(do ((already-processed nil)
(unknown-keyword nil)
(remaining key-list (cddr remaining)))
(not (lookup-keyword :allow-other-keys key-list)))
(values :unknown-keyword (list unknown-keyword valid-keys))
(values nil nil)))
- (cond ((not (and (consp remaining) (listp (cdr remaining))))
- (return (values :dotted-list key-list)))
- ((null (cdr remaining))
- (return (values :odd-length key-list)))
- ((or (eq (car remaining) :allow-other-keys)
- (member (car remaining) valid-keys))
- (push (car remaining) already-processed))
- (t
- (setq unknown-keyword (car remaining))))))
+ (let ((key (when (consp remaining)
+ (car remaining))))
+ (cond ((not (and (consp remaining) (listp (cdr remaining))))
+ (return (values :dotted-list key-list)))
+ ((null (cdr remaining))
+ (return (values :odd-length key-list))))
+ ;; Compiler-macro lambda lists are macro lambda lists -- meaning that
+ ;; &key ((a a) t) should match a literal A, not a form evaluating to A
+ ;; as in an ordinary lambda list.
+ ;;
+ ;; That, however, breaks the evaluation model unless A is also a
+ ;; constant evaluating to itself. So, signal a condition telling the
+ ;; compiler to punt on the expansion.
+ (when (and compiler-macro
+ (not (or (keywordp key)
+ (and (symbolp key)
+ (constantp key)
+ (eq key (symbol-value key))))))
+ (signal 'compiler-macro-keyword-problem :argument key))
+ (cond ((or (eq key :allow-other-keys)
+ (member key valid-keys))
+ (push key already-processed))
+ (t
+ (setq unknown-keyword key))))))
(defun lookup-keyword (keyword key-list)
(do ((remaining key-list (cddr remaining)))