Does this code look reasonable?
(Such as, can a CLOS stream redefine READ-CHAR to return arbitrary objects?)

;; Parts of the reader benefit from deriving that (READ-CHAR stream nil <x>)
;; returns (OR (EQL <x>) CHARACTER).
(defknown read-char (&optional stream-designator t t t) t (explicit-check)
  (lambda (call)
    ;; Could do something with the 'eof-error-p' too.
    ;; If true, then the return type is precisely CHARACTER.
    (type-union (let ((lvar (third (combination-args call))))
                  (if lvar
                      (lvar-type lvar)
                      (specifier-type 'null)))
                (specifier-type 'character))))

Relatedly, roughly half of the calls to read-char in 'reader' use (read-char stream nil nil) and half use (read-char stream nil *eof-object*) and a few use (read-char stream nil :eof).
Is there any reason to believe that is is necessary to use an unforgeable *eof-object* in lieu of plain old nil ?