changeset 19805:2dc5e6ddeb4c v8.2.0459

patch 8.2.0459: cannot check if a function name is correct Commit: https://github.com/vim/vim/commit/15c476023f3c5fb32eb1936c5eb5f0f5f413f3c7 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Mar 26 22:16:48 2020 +0100 patch 8.2.0459: cannot check if a function name is correct Problem: Cannot check if a function name is correct. Solution: Add "?funcname" to exists().
author Bram Moolenaar <Bram@vim.org>
date Thu, 26 Mar 2020 22:30:03 +0100
parents 503120273ab7
children 4df7ed596e73
files runtime/doc/eval.txt src/evalfunc.c src/testdir/check.vim src/testdir/test_exists.vim src/version.c
diffstat 5 files changed, 323 insertions(+), 229 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -4102,8 +4102,12 @@ exists({expr})	The result is a Number, w
 					string)
 			*funcname	built-in function (see |functions|)
 					or user defined function (see
-					|user-functions|). Also works for a
-					variable that is a Funcref.
+					|user-functions|) that is implemented.
+					Also works for a variable that is a
+					Funcref.
+			?funcname	built-in function that could be
+					implemented; to be used to check if
+					"funcname" is valid
 			varname		internal variable (see
 					|internal-variables|).  Also works
 					for |curly-braces-names|, |Dictionary|
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -374,12 +374,51 @@ typedef struct
 #define FEARG_4    4	    // base is the fourth argument
 #define FEARG_LAST 9	    // base is the last argument
 
+#ifdef FEAT_FLOAT
+# define FLOAT_FUNC(name) name
+#else
+# define FLOAT_FUNC(name) NULL
+#endif
+#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
+# define MATH_FUNC(name) name
+#else
+# define MATH_FUNC(name) NULL
+#endif
+#ifdef FEAT_TIMERS
+# define TIMER_FUNC(name) name
+#else
+# define TIMER_FUNC(name) NULL
+#endif
+#ifdef FEAT_JOB_CHANNEL
+# define JOB_FUNC(name) name
+#else
+# define JOB_FUNC(name) NULL
+#endif
+#ifdef FEAT_PROP_POPUP
+# define PROP_FUNC(name) name
+#else
+# define PROP_FUNC(name) NULL
+#endif
+#ifdef FEAT_SIGNS
+# define SIGN_FUNC(name) name
+#else
+# define SIGN_FUNC(name) NULL
+#endif
+#ifdef FEAT_SOUND
+# define SOUND_FUNC(name) name
+#else
+# define SOUND_FUNC(name) NULL
+#endif
+#ifdef FEAT_TERMINAL
+# define TERM_FUNC(name) name
+#else
+# define TERM_FUNC(name) NULL
+#endif
+
 static funcentry_T global_functions[] =
 {
-#ifdef FEAT_FLOAT
-    {"abs",		1, 1, FEARG_1,	  ret_any,	f_abs},
-    {"acos",		1, 1, FEARG_1,	  ret_float,	f_acos},	// WJMc
-#endif
+    {"abs",		1, 1, FEARG_1,	  ret_any,	FLOAT_FUNC(f_abs)},
+    {"acos",		1, 1, FEARG_1,	  ret_float,	FLOAT_FUNC(f_acos)},
     {"add",		2, 2, FEARG_1,	  ret_any,	f_add},
     {"and",		2, 2, FEARG_1,	  ret_number,	f_and},
     {"append",		2, 2, FEARG_LAST, ret_number,	f_append},
@@ -388,9 +427,7 @@ static funcentry_T global_functions[] =
     {"argidx",		0, 0, 0,	  ret_number,	f_argidx},
     {"arglistid",	0, 2, 0,	  ret_number,	f_arglistid},
     {"argv",		0, 2, 0,	  ret_any,	f_argv},
-#ifdef FEAT_FLOAT
-    {"asin",		1, 1, FEARG_1,	  ret_float,	f_asin},	// WJMc
-#endif
+    {"asin",		1, 1, FEARG_1,	  ret_float,	FLOAT_FUNC(f_asin)},
     {"assert_beeps",	1, 2, FEARG_1,	  ret_number,	f_assert_beeps},
     {"assert_equal",	2, 3, FEARG_2,	  ret_number,	f_assert_equal},
     {"assert_equalfile", 2, 2, FEARG_1,	  ret_number,	f_assert_equalfile},
@@ -403,17 +440,29 @@ static funcentry_T global_functions[] =
     {"assert_notmatch",	2, 3, FEARG_2,	  ret_number,	f_assert_notmatch},
     {"assert_report",	1, 1, FEARG_1,	  ret_number,	f_assert_report},
     {"assert_true",	1, 2, FEARG_1,	  ret_number,	f_assert_true},
-#ifdef FEAT_FLOAT
-    {"atan",		1, 1, FEARG_1,	  ret_float,	f_atan},
-    {"atan2",		2, 2, FEARG_1,	  ret_float,	f_atan2},
-#endif
+    {"atan",		1, 1, FEARG_1,	  ret_float,	FLOAT_FUNC(f_atan)},
+    {"atan2",		2, 2, FEARG_1,	  ret_float,	FLOAT_FUNC(f_atan2)},
+    {"balloon_gettext",	0, 0, 0,	  ret_string,
+#ifdef FEAT_BEVAL
+	    f_balloon_gettext
+#else
+	    NULL
+#endif
+			},
+    {"balloon_show",	1, 1, FEARG_1,	  ret_void,
 #ifdef FEAT_BEVAL
-    {"balloon_gettext",	0, 0, 0,	  ret_string,	f_balloon_gettext},
-    {"balloon_show",	1, 1, FEARG_1,	  ret_void,	f_balloon_show},
-# if defined(FEAT_BEVAL_TERM)
-    {"balloon_split",	1, 1, FEARG_1,	  ret_list_string, f_balloon_split},
-# endif
-#endif
+	    f_balloon_show
+#else
+	    NULL
+#endif
+			},
+    {"balloon_split",	1, 1, FEARG_1,	  ret_list_string,
+#if defined(FEAT_BEVAL_TERM)
+	    f_balloon_split
+#else
+	    NULL
+#endif
+			},
     {"browse",		4, 4, 0,	  ret_string,	f_browse},
     {"browsedir",	2, 2, 0,	  ret_string,	f_browsedir},
     {"bufadd",		1, 1, FEARG_1,	  ret_number,	f_bufadd},
@@ -432,29 +481,25 @@ static funcentry_T global_functions[] =
     {"byteidx",		2, 2, FEARG_1,	  ret_number,	f_byteidx},
     {"byteidxcomp",	2, 2, FEARG_1,	  ret_number,	f_byteidxcomp},
     {"call",		2, 3, FEARG_1,	  ret_any,	f_call},
-#ifdef FEAT_FLOAT
-    {"ceil",		1, 1, FEARG_1,	  ret_float,	f_ceil},
-#endif
-#ifdef FEAT_JOB_CHANNEL
-    {"ch_canread",	1, 1, FEARG_1,	  ret_number,	f_ch_canread},
-    {"ch_close",	1, 1, FEARG_1,	  ret_void,	f_ch_close},
-    {"ch_close_in",	1, 1, FEARG_1,	  ret_void,	f_ch_close_in},
-    {"ch_evalexpr",	2, 3, FEARG_1,	  ret_any,	f_ch_evalexpr},
-    {"ch_evalraw",	2, 3, FEARG_1,	  ret_any,	f_ch_evalraw},
-    {"ch_getbufnr",	2, 2, FEARG_1,	  ret_number,	f_ch_getbufnr},
-    {"ch_getjob",	1, 1, FEARG_1,	  ret_job,	f_ch_getjob},
-    {"ch_info",		1, 1, FEARG_1,	  ret_dict_any,	f_ch_info},
-    {"ch_log",		1, 2, FEARG_1,	  ret_void,	f_ch_log},
-    {"ch_logfile",	1, 2, FEARG_1,	  ret_void,	f_ch_logfile},
-    {"ch_open",		1, 2, FEARG_1,	  ret_channel,	f_ch_open},
-    {"ch_read",		1, 2, FEARG_1,	  ret_string,	f_ch_read},
-    {"ch_readblob",	1, 2, FEARG_1,	  ret_blob,	f_ch_readblob},
-    {"ch_readraw",	1, 2, FEARG_1,	  ret_string,	f_ch_readraw},
-    {"ch_sendexpr",	2, 3, FEARG_1,	  ret_void,	f_ch_sendexpr},
-    {"ch_sendraw",	2, 3, FEARG_1,	  ret_void,	f_ch_sendraw},
-    {"ch_setoptions",	2, 2, FEARG_1,	  ret_void,	f_ch_setoptions},
-    {"ch_status",	1, 2, FEARG_1,	  ret_string,	f_ch_status},
-#endif
+    {"ceil",		1, 1, FEARG_1,	  ret_float,	FLOAT_FUNC(f_ceil)},
+    {"ch_canread",	1, 1, FEARG_1,	  ret_number,	JOB_FUNC(f_ch_canread)},
+    {"ch_close",	1, 1, FEARG_1,	  ret_void,	JOB_FUNC(f_ch_close)},
+    {"ch_close_in",	1, 1, FEARG_1,	  ret_void,	JOB_FUNC(f_ch_close_in)},
+    {"ch_evalexpr",	2, 3, FEARG_1,	  ret_any,	JOB_FUNC(f_ch_evalexpr)},
+    {"ch_evalraw",	2, 3, FEARG_1,	  ret_any,	JOB_FUNC(f_ch_evalraw)},
+    {"ch_getbufnr",	2, 2, FEARG_1,	  ret_number,	JOB_FUNC(f_ch_getbufnr)},
+    {"ch_getjob",	1, 1, FEARG_1,	  ret_job,	JOB_FUNC(f_ch_getjob)},
+    {"ch_info",		1, 1, FEARG_1,	  ret_dict_any,	JOB_FUNC(f_ch_info)},
+    {"ch_log",		1, 2, FEARG_1,	  ret_void,	JOB_FUNC(f_ch_log)},
+    {"ch_logfile",	1, 2, FEARG_1,	  ret_void,	JOB_FUNC(f_ch_logfile)},
+    {"ch_open",		1, 2, FEARG_1,	  ret_channel,	JOB_FUNC(f_ch_open)},
+    {"ch_read",		1, 2, FEARG_1,	  ret_string,	JOB_FUNC(f_ch_read)},
+    {"ch_readblob",	1, 2, FEARG_1,	  ret_blob,	JOB_FUNC(f_ch_readblob)},
+    {"ch_readraw",	1, 2, FEARG_1,	  ret_string,	JOB_FUNC(f_ch_readraw)},
+    {"ch_sendexpr",	2, 3, FEARG_1,	  ret_void,	JOB_FUNC(f_ch_sendexpr)},
+    {"ch_sendraw",	2, 3, FEARG_1,	  ret_void,	JOB_FUNC(f_ch_sendraw)},
+    {"ch_setoptions",	2, 2, FEARG_1,	  ret_void,	JOB_FUNC(f_ch_setoptions)},
+    {"ch_status",	1, 2, FEARG_1,	  ret_string,	JOB_FUNC(f_ch_status)},
     {"changenr",	0, 0, 0,	  ret_number,	f_changenr},
     {"char2nr",		1, 2, FEARG_1,	  ret_number,	f_char2nr},
     {"chdir",		1, 1, FEARG_1,	  ret_string,	f_chdir},
@@ -467,16 +512,18 @@ static funcentry_T global_functions[] =
     {"complete_info",	0, 1, FEARG_1,	  ret_dict_any,	f_complete_info},
     {"confirm",		1, 4, FEARG_1,	  ret_number,	f_confirm},
     {"copy",		1, 1, FEARG_1,	  ret_any,	f_copy},
-#ifdef FEAT_FLOAT
-    {"cos",		1, 1, FEARG_1,	  ret_float,	f_cos},
-    {"cosh",		1, 1, FEARG_1,	  ret_float,	f_cosh},
-#endif
+    {"cos",		1, 1, FEARG_1,	  ret_float,	FLOAT_FUNC(f_cos)},
+    {"cosh",		1, 1, FEARG_1,	  ret_float,	FLOAT_FUNC(f_cosh)},
     {"count",		2, 4, FEARG_1,	  ret_number,	f_count},
     {"cscope_connection",0,3, 0,	  ret_number,	f_cscope_connection},
     {"cursor",		1, 3, FEARG_1,	  ret_number,	f_cursor},
+    {"debugbreak",	1, 1, FEARG_1,	  ret_number,
 #ifdef MSWIN
-    {"debugbreak",	1, 1, FEARG_1,	  ret_number,	f_debugbreak},
-#endif
+	    f_debugbreak
+#else
+	    NULL
+#endif
+			},
     {"deepcopy",	1, 2, FEARG_1,	  ret_any,	f_deepcopy},
     {"delete",		1, 2, FEARG_1,	  ret_number,	f_delete},
     {"deletebufline",	2, 3, FEARG_1,	  ret_number,	f_deletebufline},
@@ -493,9 +540,7 @@ static funcentry_T global_functions[] =
     {"execute",		1, 2, FEARG_1,	  ret_string,	f_execute},
     {"exepath",		1, 1, FEARG_1,	  ret_string,	f_exepath},
     {"exists",		1, 1, FEARG_1,	  ret_number,	f_exists},
-#ifdef FEAT_FLOAT
-    {"exp",		1, 1, FEARG_1,	  ret_float,	f_exp},
-#endif
+    {"exp",		1, 1, FEARG_1,	  ret_float,	FLOAT_FUNC(f_exp)},
     {"expand",		1, 3, FEARG_1,	  ret_any,	f_expand},
     {"expandcmd",	1, 1, FEARG_1,	  ret_string,	f_expandcmd},
     {"extend",		2, 3, FEARG_1,	  ret_any,	f_extend},
@@ -506,11 +551,9 @@ static funcentry_T global_functions[] =
     {"filter",		2, 2, FEARG_1,	  ret_any,	f_filter},
     {"finddir",		1, 3, FEARG_1,	  ret_string,	f_finddir},
     {"findfile",	1, 3, FEARG_1,	  ret_string,	f_findfile},
-#ifdef FEAT_FLOAT
-    {"float2nr",	1, 1, FEARG_1,	  ret_number,	f_float2nr},
-    {"floor",		1, 1, FEARG_1,	  ret_float,	f_floor},
-    {"fmod",		2, 2, FEARG_1,	  ret_float,	f_fmod},
-#endif
+    {"float2nr",	1, 1, FEARG_1,	  ret_number,	FLOAT_FUNC(f_float2nr)},
+    {"floor",		1, 1, FEARG_1,	  ret_float,	FLOAT_FUNC(f_floor)},
+    {"fmod",		2, 2, FEARG_1,	  ret_float,	FLOAT_FUNC(f_fmod)},
     {"fnameescape",	1, 1, FEARG_1,	  ret_string,	f_fnameescape},
     {"fnamemodify",	2, 2, FEARG_1,	  ret_string,	f_fnamemodify},
     {"foldclosed",	1, 1, FEARG_1,	  ret_number,	f_foldclosed},
@@ -592,22 +635,16 @@ static funcentry_T global_functions[] =
     {"interrupt",	0, 0, 0,	  ret_void,	f_interrupt},
     {"invert",		1, 1, FEARG_1,	  ret_number,	f_invert},
     {"isdirectory",	1, 1, FEARG_1,	  ret_number,	f_isdirectory},
-#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
-    {"isinf",		1, 1, FEARG_1,	  ret_number,	f_isinf},
-#endif
+    {"isinf",		1, 1, FEARG_1,	  ret_number,	MATH_FUNC(f_isinf)},
     {"islocked",	1, 1, FEARG_1,	  ret_number,	f_islocked},
-#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
-    {"isnan",		1, 1, FEARG_1,	  ret_number,	f_isnan},
-#endif
+    {"isnan",		1, 1, FEARG_1,	  ret_number,	MATH_FUNC(f_isnan)},
     {"items",		1, 1, FEARG_1,	  ret_list_any,	f_items},
-#ifdef FEAT_JOB_CHANNEL
-    {"job_getchannel",	1, 1, FEARG_1,	  ret_channel,	f_job_getchannel},
-    {"job_info",	0, 1, FEARG_1,	  ret_dict_any,	f_job_info},
-    {"job_setoptions",	2, 2, FEARG_1,	  ret_void,	f_job_setoptions},
-    {"job_start",	1, 2, FEARG_1,	  ret_job,	f_job_start},
-    {"job_status",	1, 1, FEARG_1,	  ret_string,	f_job_status},
-    {"job_stop",	1, 2, FEARG_1,	  ret_number,	f_job_stop},
-#endif
+    {"job_getchannel",	1, 1, FEARG_1,	  ret_channel,	JOB_FUNC(f_job_getchannel)},
+    {"job_info",	0, 1, FEARG_1,	  ret_dict_any,	JOB_FUNC(f_job_info)},
+    {"job_setoptions",	2, 2, FEARG_1,	  ret_void,	JOB_FUNC(f_job_setoptions)},
+    {"job_start",	1, 2, FEARG_1,	  ret_job,	JOB_FUNC(f_job_start)},
+    {"job_status",	1, 1, FEARG_1,	  ret_string,	JOB_FUNC(f_job_status)},
+    {"job_stop",	1, 2, FEARG_1,	  ret_number,	JOB_FUNC(f_job_stop)},
     {"join",		1, 2, FEARG_1,	  ret_string,	f_join},
     {"js_decode",	1, 1, FEARG_1,	  ret_any,	f_js_decode},
     {"js_encode",	1, 1, FEARG_1,	  ret_string,	f_js_encode},
@@ -626,13 +663,15 @@ static funcentry_T global_functions[] =
     {"listener_flush",	0, 1, FEARG_1,	  ret_void,	f_listener_flush},
     {"listener_remove",	1, 1, FEARG_1,	  ret_number,	f_listener_remove},
     {"localtime",	0, 0, 0,	  ret_number,	f_localtime},
-#ifdef FEAT_FLOAT
-    {"log",		1, 1, FEARG_1,	  ret_float,	f_log},
-    {"log10",		1, 1, FEARG_1,	  ret_float,	f_log10},
-#endif
+    {"log",		1, 1, FEARG_1,	  ret_float,	FLOAT_FUNC(f_log)},
+    {"log10",		1, 1, FEARG_1,	  ret_float,	FLOAT_FUNC(f_log10)},
+    {"luaeval",		1, 2, FEARG_1,	  ret_any,
 #ifdef FEAT_LUA
-    {"luaeval",		1, 2, FEARG_1,	  ret_any,	f_luaeval},
-#endif
+		f_luaeval
+#else
+		NULL
+#endif
+			},
     {"map",		2, 2, FEARG_1,	  ret_any,	f_map},
     {"maparg",		1, 4, FEARG_1,	  ret_string,	f_maparg},
     {"mapcheck",	1, 3, FEARG_1,	  ret_string,	f_mapcheck},
@@ -646,77 +685,93 @@ static funcentry_T global_functions[] =
     {"matchstr",	2, 4, FEARG_1,	  ret_string,	f_matchstr},
     {"matchstrpos",	2, 4, FEARG_1,	  ret_list_any,	f_matchstrpos},
     {"max",		1, 1, FEARG_1,	  ret_any,	f_max},
+    {"menu_info",	1, 2, FEARG_1,	  ret_dict_any,
 #ifdef FEAT_MENU
-    {"menu_info",	1, 2, FEARG_1,	  ret_dict_any,	f_menu_info},
-#endif
+	    f_menu_info
+#else
+	    NULL
+#endif
+			},
     {"min",		1, 1, FEARG_1,	  ret_any,	f_min},
     {"mkdir",		1, 3, FEARG_1,	  ret_number,	f_mkdir},
     {"mode",		0, 1, FEARG_1,	  ret_string,	f_mode},
+    {"mzeval",		1, 1, FEARG_1,	  ret_any,
 #ifdef FEAT_MZSCHEME
-    {"mzeval",		1, 1, FEARG_1,	  ret_any,	f_mzeval},
-#endif
+	    f_mzeval
+#else
+	    NULL
+#endif
+			},
     {"nextnonblank",	1, 1, FEARG_1,	  ret_number,	f_nextnonblank},
     {"nr2char",		1, 2, FEARG_1,	  ret_string,	f_nr2char},
     {"or",		2, 2, FEARG_1,	  ret_number,	f_or},
     {"pathshorten",	1, 1, FEARG_1,	  ret_string,	f_pathshorten},
+    {"perleval",	1, 1, FEARG_1,	  ret_any,
 #ifdef FEAT_PERL
-    {"perleval",	1, 1, FEARG_1,	  ret_any,	f_perleval},
-#endif
-#ifdef FEAT_PROP_POPUP
-    {"popup_atcursor",	2, 2, FEARG_1,	  ret_number,	f_popup_atcursor},
-    {"popup_beval",	2, 2, FEARG_1,	  ret_number,	f_popup_beval},
-    {"popup_clear",	0, 0, 0,	  ret_void,	f_popup_clear},
-    {"popup_close",	1, 2, FEARG_1,	  ret_void,	f_popup_close},
-    {"popup_create",	2, 2, FEARG_1,	  ret_number,	f_popup_create},
-    {"popup_dialog",	2, 2, FEARG_1,	  ret_number,	f_popup_dialog},
-    {"popup_filter_menu", 2, 2, 0,	  ret_number,	f_popup_filter_menu},
-    {"popup_filter_yesno", 2, 2, 0,	  ret_number,	f_popup_filter_yesno},
-    {"popup_findinfo",	0, 0, 0,	  ret_number,	f_popup_findinfo},
-    {"popup_findpreview", 0, 0, 0,	  ret_number,	f_popup_findpreview},
-    {"popup_getoptions", 1, 1, FEARG_1,	  ret_dict_any,	f_popup_getoptions},
-    {"popup_getpos",	1, 1, FEARG_1,	  ret_dict_any,	f_popup_getpos},
-    {"popup_hide",	1, 1, FEARG_1,	  ret_void,	f_popup_hide},
-    {"popup_locate",	2, 2, 0,	  ret_number,	f_popup_locate},
-    {"popup_menu",	2, 2, FEARG_1,	  ret_number,	f_popup_menu},
-    {"popup_move",	2, 2, FEARG_1,	  ret_void,	f_popup_move},
-    {"popup_notification", 2, 2, FEARG_1, ret_number,	f_popup_notification},
-    {"popup_setoptions", 2, 2, FEARG_1,	  ret_void,	f_popup_setoptions},
-    {"popup_settext",	2, 2, FEARG_1,	  ret_void,	f_popup_settext},
-    {"popup_show",	1, 1, FEARG_1,	  ret_void,	f_popup_show},
-#endif
-#ifdef FEAT_FLOAT
-    {"pow",		2, 2, FEARG_1,	  ret_float,	f_pow},
-#endif
+	    f_perleval
+#else
+	    NULL
+#endif
+			},
+    {"popup_atcursor",	2, 2, FEARG_1,	  ret_number,	PROP_FUNC(f_popup_atcursor)},
+    {"popup_beval",	2, 2, FEARG_1,	  ret_number,	PROP_FUNC(f_popup_beval)},
+    {"popup_clear",	0, 0, 0,	  ret_void,	PROP_FUNC(f_popup_clear)},
+    {"popup_close",	1, 2, FEARG_1,	  ret_void,	PROP_FUNC(f_popup_close)},
+    {"popup_create",	2, 2, FEARG_1,	  ret_number,	PROP_FUNC(f_popup_create)},
+    {"popup_dialog",	2, 2, FEARG_1,	  ret_number,	PROP_FUNC(f_popup_dialog)},
+    {"popup_filter_menu", 2, 2, 0,	  ret_number,	PROP_FUNC(f_popup_filter_menu)},
+    {"popup_filter_yesno", 2, 2, 0,	  ret_number,	PROP_FUNC(f_popup_filter_yesno)},
+    {"popup_findinfo",	0, 0, 0,	  ret_number,	PROP_FUNC(f_popup_findinfo)},
+    {"popup_findpreview", 0, 0, 0,	  ret_number,	PROP_FUNC(f_popup_findpreview)},
+    {"popup_getoptions", 1, 1, FEARG_1,	  ret_dict_any,	PROP_FUNC(f_popup_getoptions)},
+    {"popup_getpos",	1, 1, FEARG_1,	  ret_dict_any,	PROP_FUNC(f_popup_getpos)},
+    {"popup_hide",	1, 1, FEARG_1,	  ret_void,	PROP_FUNC(f_popup_hide)},
+    {"popup_locate",	2, 2, 0,	  ret_number,	PROP_FUNC(f_popup_locate)},
+    {"popup_menu",	2, 2, FEARG_1,	  ret_number,	PROP_FUNC(f_popup_menu)},
+    {"popup_move",	2, 2, FEARG_1,	  ret_void,	PROP_FUNC(f_popup_move)},
+    {"popup_notification", 2, 2, FEARG_1, ret_number,	PROP_FUNC(f_popup_notification)},
+    {"popup_setoptions", 2, 2, FEARG_1,	  ret_void,	PROP_FUNC(f_popup_setoptions)},
+    {"popup_settext",	2, 2, FEARG_1,	  ret_void,	PROP_FUNC(f_popup_settext)},
+    {"popup_show",	1, 1, FEARG_1,	  ret_void,	PROP_FUNC(f_popup_show)},
+    {"pow",		2, 2, FEARG_1,	  ret_float,	FLOAT_FUNC(f_pow)},
     {"prevnonblank",	1, 1, FEARG_1,	  ret_number,	f_prevnonblank},
     {"printf",		1, 19, FEARG_2,	  ret_string,	f_printf},
-#ifdef FEAT_JOB_CHANNEL
-    {"prompt_setcallback", 2, 2, FEARG_1, ret_void,	 f_prompt_setcallback},
-    {"prompt_setinterrupt", 2, 2, FEARG_1,ret_void,	 f_prompt_setinterrupt},
-    {"prompt_setprompt", 2, 2, FEARG_1,	  ret_void,	 f_prompt_setprompt},
-#endif
-#ifdef FEAT_PROP_POPUP
-    {"prop_add",	3, 3, FEARG_1,	  ret_void,	f_prop_add},
-    {"prop_clear",	1, 3, FEARG_1,	  ret_void,	f_prop_clear},
-    {"prop_find",	1, 2, FEARG_1,	  ret_dict_any,	f_prop_find},
-    {"prop_list",	1, 2, FEARG_1,	  ret_list_dict_any, f_prop_list},
-    {"prop_remove",	1, 3, FEARG_1,	  ret_number,	f_prop_remove},
-    {"prop_type_add",	2, 2, FEARG_1,	  ret_void,	f_prop_type_add},
-    {"prop_type_change", 2, 2, FEARG_1,	  ret_void,	f_prop_type_change},
-    {"prop_type_delete", 1, 2, FEARG_1,	  ret_void,	f_prop_type_delete},
-    {"prop_type_get",	1, 2, FEARG_1,	  ret_dict_any,	f_prop_type_get},
-    {"prop_type_list",	0, 1, FEARG_1,	  ret_list_string, f_prop_type_list},
-#endif
+    {"prompt_setcallback", 2, 2, FEARG_1, ret_void,	JOB_FUNC(f_prompt_setcallback)},
+    {"prompt_setinterrupt", 2, 2, FEARG_1,ret_void,	JOB_FUNC(f_prompt_setinterrupt)},
+    {"prompt_setprompt", 2, 2, FEARG_1,	  ret_void,	JOB_FUNC(f_prompt_setprompt)},
+    {"prop_add",	3, 3, FEARG_1,	  ret_void,	PROP_FUNC(f_prop_add)},
+    {"prop_clear",	1, 3, FEARG_1,	  ret_void,	PROP_FUNC(f_prop_clear)},
+    {"prop_find",	1, 2, FEARG_1,	  ret_dict_any,	PROP_FUNC(f_prop_find)},
+    {"prop_list",	1, 2, FEARG_1,	  ret_list_dict_any, PROP_FUNC(f_prop_list)},
+    {"prop_remove",	1, 3, FEARG_1,	  ret_number,	PROP_FUNC(f_prop_remove)},
+    {"prop_type_add",	2, 2, FEARG_1,	  ret_void,	PROP_FUNC(f_prop_type_add)},
+    {"prop_type_change", 2, 2, FEARG_1,	  ret_void,	PROP_FUNC(f_prop_type_change)},
+    {"prop_type_delete", 1, 2, FEARG_1,	  ret_void,	PROP_FUNC(f_prop_type_delete)},
+    {"prop_type_get",	1, 2, FEARG_1,	  ret_dict_any,	PROP_FUNC(f_prop_type_get)},
+    {"prop_type_list",	0, 1, FEARG_1,	  ret_list_string, PROP_FUNC(f_prop_type_list)},
     {"pum_getpos",	0, 0, 0,	  ret_dict_number, f_pum_getpos},
     {"pumvisible",	0, 0, 0,	  ret_number,	f_pumvisible},
+    {"py3eval",		1, 1, FEARG_1,	  ret_any,
 #ifdef FEAT_PYTHON3
-    {"py3eval",		1, 1, FEARG_1,	  ret_any,	f_py3eval},
-#endif
+	    f_py3eval
+#else
+	    NULL
+#endif
+	    },
+    {"pyeval",		1, 1, FEARG_1,	  ret_any,
 #ifdef FEAT_PYTHON
-    {"pyeval",		1, 1, FEARG_1,	  ret_any,	f_pyeval},
-#endif
+	    f_pyeval
+#else
+	    NULL
+#endif
+			},
+    {"pyxeval",		1, 1, FEARG_1,	  ret_any,
 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
-    {"pyxeval",		1, 1, FEARG_1,	  ret_any,	f_pyxeval},
-#endif
+	    f_pyxeval
+#else
+	    NULL
+#endif
+			},
     {"rand",		0, 1, FEARG_1,	  ret_number,	f_rand},
     {"range",		1, 3, FEARG_1,	  ret_list_number, f_range},
     {"readdir",		1, 2, FEARG_1,	  ret_list_string, f_readdir},
@@ -724,9 +779,7 @@ static funcentry_T global_functions[] =
     {"reg_executing",	0, 0, 0,	  ret_string,	f_reg_executing},
     {"reg_recording",	0, 0, 0,	  ret_string,	f_reg_recording},
     {"reltime",		0, 2, FEARG_1,	  ret_list_any,	f_reltime},
-#ifdef FEAT_FLOAT
-    {"reltimefloat",	1, 1, FEARG_1,	  ret_float,	f_reltimefloat},
-#endif
+    {"reltimefloat",	1, 1, FEARG_1,	  ret_float,	FLOAT_FUNC(f_reltimefloat)},
     {"reltimestr",	1, 1, FEARG_1,	  ret_string,	f_reltimestr},
     {"remote_expr",	2, 4, FEARG_1,	  ret_string,	f_remote_expr},
     {"remote_foreground", 1, 1, FEARG_1,  ret_string,	f_remote_foreground},
@@ -739,12 +792,14 @@ static funcentry_T global_functions[] =
     {"repeat",		2, 2, FEARG_1,	  ret_any,	f_repeat},
     {"resolve",		1, 1, FEARG_1,	  ret_string,	f_resolve},
     {"reverse",		1, 1, FEARG_1,	  ret_any,	f_reverse},
-#ifdef FEAT_FLOAT
-    {"round",		1, 1, FEARG_1,	  ret_float,	f_round},
-#endif
+    {"round",		1, 1, FEARG_1,	  ret_float,	FLOAT_FUNC(f_round)},
+    {"rubyeval",	1, 1, FEARG_1,	  ret_any,
 #ifdef FEAT_RUBY
-    {"rubyeval",	1, 1, FEARG_1,	  ret_any,	f_rubyeval},
-#endif
+	    f_rubyeval
+#else
+	    NULL
+#endif
+			},
     {"screenattr",	2, 2, FEARG_1,	  ret_number,	f_screenattr},
     {"screenchar",	2, 2, FEARG_1,	  ret_number,	f_screenchar},
     {"screenchars",	2, 2, FEARG_1,	  ret_list_number, f_screenchars},
@@ -775,62 +830,64 @@ static funcentry_T global_functions[] =
     {"settabwinvar",	4, 4, FEARG_4,	  ret_void,	f_settabwinvar},
     {"settagstack",	2, 3, FEARG_2,	  ret_number,	f_settagstack},
     {"setwinvar",	3, 3, FEARG_3,	  ret_void,	f_setwinvar},
+    {"sha256",		1, 1, FEARG_1,	  ret_string,
 #ifdef FEAT_CRYPT
-    {"sha256",		1, 1, FEARG_1,	  ret_string,	f_sha256},
-#endif
+	    f_sha256
+#else
+	    NULL
+#endif
+			},
     {"shellescape",	1, 2, FEARG_1,	  ret_string,	f_shellescape},
     {"shiftwidth",	0, 1, FEARG_1,	  ret_number,	f_shiftwidth},
-#ifdef FEAT_SIGNS
-    {"sign_define",	1, 2, FEARG_1,	  ret_any,	f_sign_define},
-    {"sign_getdefined",	0, 1, FEARG_1,	  ret_list_dict_any, f_sign_getdefined},
-    {"sign_getplaced",	0, 2, FEARG_1,	  ret_list_dict_any, f_sign_getplaced},
-    {"sign_jump",	3, 3, FEARG_1,	  ret_number,	f_sign_jump},
-    {"sign_place",	4, 5, FEARG_1,	  ret_number,	f_sign_place},
-    {"sign_placelist",	1, 1, FEARG_1,	  ret_list_number, f_sign_placelist},
-    {"sign_undefine",	0, 1, FEARG_1,	  ret_number,	f_sign_undefine},
-    {"sign_unplace",	1, 2, FEARG_1,	  ret_number,	f_sign_unplace},
-    {"sign_unplacelist", 1, 2, FEARG_1,	  ret_list_number, f_sign_unplacelist},
-#endif
+    {"sign_define",	1, 2, FEARG_1,	  ret_any,	SIGN_FUNC(f_sign_define)},
+    {"sign_getdefined",	0, 1, FEARG_1,	  ret_list_dict_any, SIGN_FUNC(f_sign_getdefined)},
+    {"sign_getplaced",	0, 2, FEARG_1,	  ret_list_dict_any, SIGN_FUNC(f_sign_getplaced)},
+    {"sign_jump",	3, 3, FEARG_1,	  ret_number,	SIGN_FUNC(f_sign_jump)},
+    {"sign_place",	4, 5, FEARG_1,	  ret_number,	SIGN_FUNC(f_sign_place)},
+    {"sign_placelist",	1, 1, FEARG_1,	  ret_list_number, SIGN_FUNC(f_sign_placelist)},
+    {"sign_undefine",	0, 1, FEARG_1,	  ret_number,	SIGN_FUNC(f_sign_undefine)},
+    {"sign_unplace",	1, 2, FEARG_1,	  ret_number,	SIGN_FUNC(f_sign_unplace)},
+    {"sign_unplacelist", 1, 2, FEARG_1,	  ret_list_number, SIGN_FUNC(f_sign_unplacelist)},
     {"simplify",	1, 1, 0,	  ret_string,	f_simplify},
-#ifdef FEAT_FLOAT
-    {"sin",		1, 1, FEARG_1,	  ret_float,	f_sin},
-    {"sinh",		1, 1, FEARG_1,	  ret_float,	f_sinh},
-#endif
+    {"sin",		1, 1, FEARG_1,	  ret_float,	FLOAT_FUNC(f_sin)},
+    {"sinh",		1, 1, FEARG_1,	  ret_float,	FLOAT_FUNC(f_sinh)},
     {"sort",		1, 3, FEARG_1,	  ret_list_any,	f_sort},
-#ifdef FEAT_SOUND
-    {"sound_clear",	0, 0, 0,	  ret_void,	f_sound_clear},
-    {"sound_playevent",	1, 2, FEARG_1,	  ret_number,	f_sound_playevent},
-    {"sound_playfile",	1, 2, FEARG_1,	  ret_number,	f_sound_playfile},
-    {"sound_stop",	1, 1, FEARG_1,	  ret_void,	f_sound_stop},
-#endif
+    {"sound_clear",	0, 0, 0,	  ret_void,	SOUND_FUNC(f_sound_clear)},
+    {"sound_playevent",	1, 2, FEARG_1,	  ret_number,	SOUND_FUNC(f_sound_playevent)},
+    {"sound_playfile",	1, 2, FEARG_1,	  ret_number,	SOUND_FUNC(f_sound_playfile)},
+    {"sound_stop",	1, 1, FEARG_1,	  ret_void,	SOUND_FUNC(f_sound_stop)},
     {"soundfold",	1, 1, FEARG_1,	  ret_string,	f_soundfold},
     {"spellbadword",	0, 1, FEARG_1,	  ret_list_string, f_spellbadword},
     {"spellsuggest",	1, 3, FEARG_1,	  ret_list_string, f_spellsuggest},
     {"split",		1, 3, FEARG_1,	  ret_list_string, f_split},
-#ifdef FEAT_FLOAT
-    {"sqrt",		1, 1, FEARG_1,	  ret_float,	f_sqrt},
-#endif
+    {"sqrt",		1, 1, FEARG_1,	  ret_float,	FLOAT_FUNC(f_sqrt)},
     {"srand",		0, 1, FEARG_1,	  ret_list_number, f_srand},
     {"state",		0, 1, FEARG_1,	  ret_string,	f_state},
-#ifdef FEAT_FLOAT
-    {"str2float",	1, 1, FEARG_1,	  ret_float,	f_str2float},
-#endif
+    {"str2float",	1, 1, FEARG_1,	  ret_float,	FLOAT_FUNC(f_str2float)},
     {"str2list",	1, 2, FEARG_1,	  ret_list_number, f_str2list},
     {"str2nr",		1, 3, FEARG_1,	  ret_number,	f_str2nr},
     {"strcharpart",	2, 3, FEARG_1,	  ret_string,	f_strcharpart},
     {"strchars",	1, 2, FEARG_1,	  ret_number,	f_strchars},
     {"strdisplaywidth",	1, 2, FEARG_1,	  ret_number,	f_strdisplaywidth},
+    {"strftime",	1, 2, FEARG_1,	  ret_string,
 #ifdef HAVE_STRFTIME
-    {"strftime",	1, 2, FEARG_1,	  ret_string,	f_strftime},
-#endif
+	    f_strftime
+#else
+	    NULL
+#endif
+			},
     {"strgetchar",	2, 2, FEARG_1,	  ret_number,	f_strgetchar},
     {"stridx",		2, 3, FEARG_1,	  ret_number,	f_stridx},
     {"string",		1, 1, FEARG_1,	  ret_string,	f_string},
     {"strlen",		1, 1, FEARG_1,	  ret_number,	f_strlen},
     {"strpart",		2, 3, FEARG_1,	  ret_string,	f_strpart},
+    {"strptime",	2, 2, FEARG_1,	  ret_number,
 #ifdef HAVE_STRPTIME
-    {"strptime",	2, 2, FEARG_1,	  ret_number,	f_strptime},
-#endif
+	    f_strptime
+#else
+	    NULL
+#endif
+			},
     {"strridx",		2, 3, FEARG_1,	  ret_number,	f_strridx},
     {"strtrans",	1, 1, FEARG_1,	  ret_string,	f_strtrans},
     {"strwidth",	1, 1, FEARG_1,	  ret_number,	f_strwidth},
@@ -850,41 +907,45 @@ static funcentry_T global_functions[] =
     {"tabpagewinnr",	1, 2, FEARG_1,	  ret_number,	f_tabpagewinnr},
     {"tagfiles",	0, 0, 0,	  ret_list_string, f_tagfiles},
     {"taglist",		1, 2, FEARG_1,	  ret_list_dict_any, f_taglist},
-#ifdef FEAT_FLOAT
-    {"tan",		1, 1, FEARG_1,	  ret_float,	f_tan},
-    {"tanh",		1, 1, FEARG_1,	  ret_float,	f_tanh},
-#endif
+    {"tan",		1, 1, FEARG_1,	  ret_float,	FLOAT_FUNC(f_tan)},
+    {"tanh",		1, 1, FEARG_1,	  ret_float,	FLOAT_FUNC(f_tanh)},
     {"tempname",	0, 0, 0,	  ret_string,	f_tempname},
-#ifdef FEAT_TERMINAL
-    {"term_dumpdiff",	2, 3, FEARG_1,	  ret_number,	f_term_dumpdiff},
-    {"term_dumpload",	1, 2, FEARG_1,	  ret_number,	f_term_dumpload},
-    {"term_dumpwrite",	2, 3, FEARG_2,	  ret_void,	f_term_dumpwrite},
-    {"term_getaltscreen", 1, 1, FEARG_1,  ret_number,	f_term_getaltscreen},
-# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
-    {"term_getansicolors", 1, 1, FEARG_1, ret_list_string, f_term_getansicolors},
-# endif
-    {"term_getattr",	2, 2, FEARG_1,	  ret_number,	f_term_getattr},
-    {"term_getcursor",	1, 1, FEARG_1,	  ret_list_any,	f_term_getcursor},
-    {"term_getjob",	1, 1, FEARG_1,	  ret_job,	f_term_getjob},
-    {"term_getline",	2, 2, FEARG_1,	  ret_string,	f_term_getline},
-    {"term_getscrolled", 1, 1, FEARG_1,	  ret_number,	f_term_getscrolled},
-    {"term_getsize",	1, 1, FEARG_1,	  ret_list_number, f_term_getsize},
-    {"term_getstatus",	1, 1, FEARG_1,	  ret_string,	f_term_getstatus},
-    {"term_gettitle",	1, 1, FEARG_1,	  ret_string,	f_term_gettitle},
-    {"term_gettty",	1, 2, FEARG_1,	  ret_string,	f_term_gettty},
-    {"term_list",	0, 0, 0,	  ret_list_number, f_term_list},
-    {"term_scrape",	2, 2, FEARG_1,	  ret_list_dict_any, f_term_scrape},
-    {"term_sendkeys",	2, 2, FEARG_1,	  ret_void,	f_term_sendkeys},
-# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
-    {"term_setansicolors", 2, 2, FEARG_1, ret_void,	f_term_setansicolors},
-# endif
-    {"term_setapi",	2, 2, FEARG_1,	  ret_void,	f_term_setapi},
-    {"term_setkill",	2, 2, FEARG_1,	  ret_void,	f_term_setkill},
-    {"term_setrestore",	2, 2, FEARG_1,	  ret_void,	f_term_setrestore},
-    {"term_setsize",	3, 3, FEARG_1,	  ret_void,	f_term_setsize},
-    {"term_start",	1, 2, FEARG_1,	  ret_number,	f_term_start},
-    {"term_wait",	1, 2, FEARG_1,	  ret_void,	f_term_wait},
-#endif
+    {"term_dumpdiff",	2, 3, FEARG_1,	  ret_number,	TERM_FUNC(f_term_dumpdiff)},
+    {"term_dumpload",	1, 2, FEARG_1,	  ret_number,	TERM_FUNC(f_term_dumpload)},
+    {"term_dumpwrite",	2, 3, FEARG_2,	  ret_void,	TERM_FUNC(f_term_dumpwrite)},
+    {"term_getaltscreen", 1, 1, FEARG_1,  ret_number,	TERM_FUNC(f_term_getaltscreen)},
+    {"term_getansicolors", 1, 1, FEARG_1, ret_list_string,
+#if defined(TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
+	    f_term_getansicolors
+#else
+	    NULL
+#endif
+			},
+    {"term_getattr",	2, 2, FEARG_1,	  ret_number,	TERM_FUNC(f_term_getattr)},
+    {"term_getcursor",	1, 1, FEARG_1,	  ret_list_any,	TERM_FUNC(f_term_getcursor)},
+    {"term_getjob",	1, 1, FEARG_1,	  ret_job,	TERM_FUNC(f_term_getjob)},
+    {"term_getline",	2, 2, FEARG_1,	  ret_string,	TERM_FUNC(f_term_getline)},
+    {"term_getscrolled", 1, 1, FEARG_1,	  ret_number,	TERM_FUNC(f_term_getscrolled)},
+    {"term_getsize",	1, 1, FEARG_1,	  ret_list_number, TERM_FUNC(f_term_getsize)},
+    {"term_getstatus",	1, 1, FEARG_1,	  ret_string,	TERM_FUNC(f_term_getstatus)},
+    {"term_gettitle",	1, 1, FEARG_1,	  ret_string,	TERM_FUNC(f_term_gettitle)},
+    {"term_gettty",	1, 2, FEARG_1,	  ret_string,	TERM_FUNC(f_term_gettty)},
+    {"term_list",	0, 0, 0,	  ret_list_number, TERM_FUNC(f_term_list)},
+    {"term_scrape",	2, 2, FEARG_1,	  ret_list_dict_any, TERM_FUNC(f_term_scrape)},
+    {"term_sendkeys",	2, 2, FEARG_1,	  ret_void,	TERM_FUNC(f_term_sendkeys)},
+    {"term_setansicolors", 2, 2, FEARG_1, ret_void,
+#if defined(TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
+	    f_term_setansicolors
+#else
+	    NULL
+#endif
+			},
+    {"term_setapi",	2, 2, FEARG_1,	  ret_void,	TERM_FUNC(f_term_setapi)},
+    {"term_setkill",	2, 2, FEARG_1,	  ret_void,	TERM_FUNC(f_term_setkill)},
+    {"term_setrestore",	2, 2, FEARG_1,	  ret_void,	TERM_FUNC(f_term_setrestore)},
+    {"term_setsize",	3, 3, FEARG_1,	  ret_void,	TERM_FUNC(f_term_setsize)},
+    {"term_start",	1, 2, FEARG_1,	  ret_number,	TERM_FUNC(f_term_start)},
+    {"term_wait",	1, 2, FEARG_1,	  ret_void,	TERM_FUNC(f_term_wait)},
     {"test_alloc_fail",	3, 3, FEARG_1,	  ret_void,	f_test_alloc_fail},
     {"test_autochdir",	0, 0, 0,	  ret_void,	f_test_autochdir},
     {"test_feedinput",	1, 1, FEARG_1,	  ret_void,	f_test_feedinput},
@@ -893,41 +954,37 @@ static funcentry_T global_functions[] =
     {"test_getvalue",	1, 1, FEARG_1,	  ret_number,	f_test_getvalue},
     {"test_ignore_error", 1, 1, FEARG_1,  ret_void,	f_test_ignore_error},
     {"test_null_blob",	0, 0, 0,	  ret_blob,	f_test_null_blob},
-#ifdef FEAT_JOB_CHANNEL
-    {"test_null_channel", 0, 0, 0,	  ret_channel,	f_test_null_channel},
-#endif
+    {"test_null_channel", 0, 0, 0,	  ret_channel,	JOB_FUNC(f_test_null_channel)},
     {"test_null_dict",	0, 0, 0,	  ret_dict_any,	f_test_null_dict},
-#ifdef FEAT_JOB_CHANNEL
-    {"test_null_job",	0, 0, 0,	  ret_job,	f_test_null_job},
-#endif
+    {"test_null_job",	0, 0, 0,	  ret_job,	JOB_FUNC(f_test_null_job)},
     {"test_null_list",	0, 0, 0,	  ret_list_any,	f_test_null_list},
     {"test_null_partial", 0, 0, 0,	  ret_partial_void, f_test_null_partial},
     {"test_null_string", 0, 0, 0,	  ret_string,	f_test_null_string},
     {"test_option_not_set", 1, 1, FEARG_1,ret_void,	 f_test_option_not_set},
     {"test_override",	2, 2, FEARG_2,	  ret_void,	f_test_override},
     {"test_refcount",	1, 1, FEARG_1,	  ret_number,	f_test_refcount},
+    {"test_scrollbar",	3, 3, FEARG_2,	  ret_void,
 #ifdef FEAT_GUI
-    {"test_scrollbar",	3, 3, FEARG_2,	  ret_void,	f_test_scrollbar},
-#endif
+	f_test_scrollbar
+#else
+	NULL
+#endif
+			},
     {"test_setmouse",	2, 2, 0,	  ret_void,	f_test_setmouse},
     {"test_settime",	1, 1, FEARG_1,	  ret_void,	f_test_settime},
     {"test_srand_seed",	0, 1, FEARG_1,	  ret_void,	f_test_srand_seed},
     {"test_unknown",	0, 0, 0,	  ret_any,	f_test_unknown},
     {"test_void",	0, 0, 0,	  ret_any,	f_test_void},
-#ifdef FEAT_TIMERS
-    {"timer_info",	0, 1, FEARG_1,	  ret_list_dict_any, f_timer_info},
-    {"timer_pause",	2, 2, FEARG_1,	  ret_void,	f_timer_pause},
-    {"timer_start",	2, 3, FEARG_1,	  ret_number,	f_timer_start},
-    {"timer_stop",	1, 1, FEARG_1,	  ret_void,	f_timer_stop},
-    {"timer_stopall",	0, 0, 0,	  ret_void,	f_timer_stopall},
-#endif
+    {"timer_info",	0, 1, FEARG_1,	  ret_list_dict_any, TIMER_FUNC(f_timer_info)},
+    {"timer_pause",	2, 2, FEARG_1,	  ret_void,	TIMER_FUNC(f_timer_pause)},
+    {"timer_start",	2, 3, FEARG_1,	  ret_number,	TIMER_FUNC(f_timer_start)},
+    {"timer_stop",	1, 1, FEARG_1,	  ret_void,	TIMER_FUNC(f_timer_stop)},
+    {"timer_stopall",	0, 0, 0,	  ret_void,	TIMER_FUNC(f_timer_stopall)},
     {"tolower",		1, 1, FEARG_1,	  ret_string,	f_tolower},
     {"toupper",		1, 1, FEARG_1,	  ret_string,	f_toupper},
     {"tr",		3, 3, FEARG_1,	  ret_string,	f_tr},
     {"trim",		1, 2, FEARG_1,	  ret_string,	f_trim},
-#ifdef FEAT_FLOAT
-    {"trunc",		1, 1, FEARG_1,	  ret_float,	f_trunc},
-#endif
+    {"trunc",		1, 1, FEARG_1,	  ret_float,	FLOAT_FUNC(f_trunc)},
     {"type",		1, 1, FEARG_1,	  ret_number,	f_type},
     {"undofile",	1, 1, FEARG_1,	  ret_string,	f_undofile},
     {"undotree",	0, 0, 0,	  ret_dict_any,	f_undotree},
@@ -1014,10 +1071,11 @@ get_expr_name(expand_T *xp, int idx)
 
 /*
  * Find internal function "name" in table "global_functions".
- * Return index, or -1 if not found
- */
-    int
-find_internal_func(char_u *name)
+ * Return index, or -1 if not found or "implemented" is TRUE and the function
+ * is not implemented.
+ */
+    static int
+find_internal_func_opt(char_u *name, int implemented)
 {
     int		first = 0;
     int		last;
@@ -1035,16 +1093,34 @@ find_internal_func(char_u *name)
 	    last = x - 1;
 	else if (cmp > 0)
 	    first = x + 1;
+	else if (implemented && global_functions[x].f_func == NULL)
+	    break;
 	else
 	    return x;
     }
     return -1;
 }
 
+/*
+ * Find internal function "name" in table "global_functions".
+ * Return index, or -1 if not found or the function is not implemented.
+ */
+    int
+find_internal_func(char_u *name)
+{
+    return find_internal_func_opt(name, TRUE);
+}
+
     int
 has_internal_func(char_u *name)
 {
-    return find_internal_func(name) >= 0;
+    return find_internal_func_opt(name, TRUE) >= 0;
+}
+
+    static int
+has_internal_func_name(char_u *name)
+{
+    return find_internal_func_opt(name, FALSE) >= 0;
 }
 
     char *
@@ -2288,6 +2364,10 @@ f_exists(typval_T *argvars, typval_T *re
     {
 	n = function_exists(p + 1, FALSE);
     }
+    else if (*p == '?')			// internal function only
+    {
+	n = has_internal_func_name(p + 1);
+    }
     else if (*p == ':')
     {
 	n = cmd_exists(p + 1);
--- a/src/testdir/check.vim
+++ b/src/testdir/check.vim
@@ -25,9 +25,12 @@ func CheckOption(name)
   endif
 endfunc
 
-" Command to check for the presence of a function.
+" Command to check for the presence of a built-in function.
 command -nargs=1 CheckFunction call CheckFunction(<f-args>)
 func CheckFunction(name)
+  if !exists('?' .. a:name)
+    throw 'Checking for non-existent function ' .. a:name
+  endif
   if !exists('*' .. a:name)
     throw 'Skipped: ' .. a:name .. ' function missing'
   endif
--- a/src/testdir/test_exists.vim
+++ b/src/testdir/test_exists.vim
@@ -92,6 +92,11 @@ func Test_exists()
   " Function that may be created by script autoloading
   call assert_equal(0, exists('*footest#F'))
 
+  call assert_equal(has('float'), exists('*acos'))
+  call assert_equal(1, exists('?acos'))
+  call assert_equal(has('win32'), exists('*debugbreak'))
+  call assert_equal(1, exists('?debugbreak'))
+
   " Valid internal command (full match)
   call assert_equal(2, exists(':edit'))
   " Valid internal command (full match) with garbage
--- a/src/version.c
+++ b/src/version.c
@@ -739,6 +739,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    459,
+/**/
     458,
 /**/
     457,