       (setq el-patch--feature nil)
       (eval (el-patch--function-to-advice
              (el-patch--resolve-definition patch-definition t)))
-      (unless (fboundp function-name)
-        (fset function-name #'el-patch-unloaded-function))
+      ;; FIXME should not require `el-patch-feature' directive if the
+      ;; function is autoloaded
+      (unless (and (fboundp function-name)
+                   (not (autoloadp (symbol-function function-name))))
+        (unless el-patch--feature
+          (error "You must specify an `el-patch-feature' directive for `%S'"
+                 function-name))
+        (el-patch--stealthy-defun
+         function-name
+         (el-patch--autoload-function function-name el-patch--feature)))
       (advice-add function-name :override advice-name))))
 
 ;;;###autoload

  "Return the Lisp form that defines the function NAME.
Return nil if such a definition cannot be found. (That would
happen if the definition were generated dynamically, or the
function is defined in the C code.)"
  (if (or (fboundp name)
          el-patch--feature)
      (progn
        (when el-patch--feature
          (require el-patch--feature))
        (if (fboundp name)
            (let* ((buffer-point (ignore-errors
                                   ;; Just in case we get an error because the
                                   ;; function is defined in the C code, we
                                   ;; ignore it and return nil.
                                   (save-excursion
                                     ;; This horrifying bit of hackery
                                     ;; prevents `find-function-noselect' from
                                     ;; returning an existing buffer, so that
                                     ;; later on when we jump to the
                                     ;; definition, we don't temporarily
                                     ;; scroll the window if the definition
                                     ;; happens to be in the *current* buffer.
                                     (prog2
                                         (advice-add #'get-file-buffer :override
                                                     #'ignore)
                                         (find-function-noselect name 'lisp-only)
                                       (advice-remove #'get-file-buffer #'ignore)))))
                   (defun-buffer (car buffer-point))
                   (defun-point (cdr buffer-point)))
              (and defun-buffer
                   defun-point
                   (with-current-buffer defun-buffer
                     (save-excursion
                       (goto-char defun-point)
                       (read defun-buffer)))))
          (ignore
           (display-warning
            'el-patch
            (format (concat "`%S' is not defined, are you sure it is provided "
                            "by feature `%S'?")
                    name el-patch--feature)))))
    (ignore
     (display-warning
      'el-patch
      (format (concat "`%S' is not defined, you must specify a feature "
                      "in the patch")
              name)))))

;;;###autoload
(defun el-patch-validate (patch-definition &optional nomsg)

s-expression. Resolve in favor of the original version if NEW is
nil; otherwise resolve in favor of the new version. TABLE is a
hash table of `el-patch-let' bindings, which maps symbols to
their bindings. Set `el-patch--feature' to the last value
specified in a `el-patch-feature' directive."
  (let ((table (or table (make-hash-table :test 'equal))))
    (if (listp form)
        (let* ((directive (nth 0 form))
