updated for version 7.0191
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 798262d..ec84844 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -3502,6 +3502,7 @@
 	case CMD_tag:
 	case CMD_stag:
 	case CMD_ptag:
+	case CMD_ltag:
 	case CMD_tselect:
 	case CMD_stselect:
 	case CMD_ptselect:
@@ -8801,6 +8802,16 @@
 		  break;
     }
 
+    if (name[0] == 'l')
+    {
+#ifndef FEAT_QUICKFIX
+	ex_ni(eap);
+	return;
+#else
+	cmd = DT_LTAG;
+#endif
+    }
+
     do_tag(eap->arg, cmd, eap->addr_count > 0 ? (int)eap->line2 : 1,
 							  eap->forceit, TRUE);
 }
diff --git a/src/fileio.c b/src/fileio.c
index 868b649..2b0df67 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -6953,6 +6953,7 @@
     {"QuickFixCmdPre",	EVENT_QUICKFIXCMDPRE},
     {"RemoteReply",	EVENT_REMOTEREPLY},
     {"SessionLoadPost",	EVENT_SESSIONLOADPOST},
+    {"SpellFileMissing",EVENT_SPELLFILEMISSING},
     {"StdinReadPost",	EVENT_STDINREADPOST},
     {"StdinReadPre",	EVENT_STDINREADPRE},
     {"Syntax",		EVENT_SYNTAX},
@@ -8406,6 +8407,7 @@
 	if (event == EVENT_FILETYPE
 		|| event == EVENT_SYNTAX
 		|| event == EVENT_REMOTEREPLY
+		|| event == EVENT_SPELLFILEMISSING
 		|| event == EVENT_QUICKFIXCMDPRE
 		|| event == EVENT_QUICKFIXCMDPOST)
 	    fname = vim_strsave(fname);
diff --git a/src/spell.c b/src/spell.c
index b9f3727..8c82a7e 100644
--- a/src/spell.c
+++ b/src/spell.c
@@ -2229,6 +2229,9 @@
     char_u	fname_enc[85];
     int		r;
     spelload_T	sl;
+#ifdef FEAT_AUTOCMD
+    int		round;
+#endif
 
     /* Copy the language name to pass it to spell_load_cb() as a cookie.
      * It's truncated when an error is detected. */
@@ -2236,24 +2239,41 @@
     sl.sl_slang = NULL;
     sl.sl_nobreak = FALSE;
 
-    /*
-     * Find the first spell file for "lang" in 'runtimepath' and load it.
-     */
-    vim_snprintf((char *)fname_enc, sizeof(fname_enc) - 5,
-					"spell/%s.%s.spl", lang, spell_enc());
-    r = do_in_runtimepath(fname_enc, FALSE, spell_load_cb, &sl);
-
-    if (r == FAIL && *sl.sl_lang != NUL)
+#ifdef FEAT_AUTOCMD
+    /* We may retry when no spell file is found for the language, an
+     * autocommand may load it then. */
+    for (round = 1; round <= 2; ++round)
+#endif
     {
-	/* Try loading the ASCII version. */
+	/*
+	 * Find the first spell file for "lang" in 'runtimepath' and load it.
+	 */
 	vim_snprintf((char *)fname_enc, sizeof(fname_enc) - 5,
-						  "spell/%s.ascii.spl", lang);
+					"spell/%s.%s.spl", lang, spell_enc());
 	r = do_in_runtimepath(fname_enc, FALSE, spell_load_cb, &sl);
+
+	if (r == FAIL && *sl.sl_lang != NUL)
+	{
+	    /* Try loading the ASCII version. */
+	    vim_snprintf((char *)fname_enc, sizeof(fname_enc) - 5,
+						  "spell/%s.ascii.spl", lang);
+	    r = do_in_runtimepath(fname_enc, FALSE, spell_load_cb, &sl);
+
+#ifdef FEAT_AUTOCMD
+	    if (r == FAIL && *sl.sl_lang != NUL && round == 1
+		    && apply_autocmds(EVENT_SPELLFILEMISSING, lang,
+					      curbuf->b_fname, FALSE, curbuf))
+		continue;
+	    break;
+#endif
+	}
     }
 
     if (r == FAIL)
+    {
 	smsg((char_u *)_("Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""),
 						     lang, spell_enc(), lang);
+    }
     else if (sl.sl_slang != NULL)
     {
 	/* At least one file was loaded, now load ALL the additions. */
diff --git a/src/tag.c b/src/tag.c
index a9d4d75..ed2889e 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -122,6 +122,7 @@
  * type == DT_SELECT:	":tselect [tag]", select tag from a list of all matches
  * type == DT_JUMP:	":tjump [tag]", jump to tag or select tag from a list
  * type == DT_CSCOPE:	use cscope to find the tag
+ * type == DT_LTAG:	use location list for displaying tag matches
  * type == DT_FREE:	free cached matches
  *
  * for cscope, returns TRUE if we jumped to tag or aborted, FALSE otherwise
@@ -215,6 +216,9 @@
 
 	/* new pattern, add to the tag stack */
 	if (*tag && (type == DT_TAG || type == DT_SELECT || type == DT_JUMP
+#ifdef FEAT_QUICKFIX
+		    || type == DT_LTAG
+#endif
 #ifdef FEAT_CSCOPE
 		    || type == DT_CSCOPE
 #endif
@@ -409,6 +413,9 @@
 		switch (type)
 		{
 		    case DT_FIRST: cur_match = count - 1; break;
+#ifdef FEAT_QUICKFIX
+		    case DT_LTAG: cur_match = 0; break;
+#endif
 		    case DT_SELECT:
 		    case DT_JUMP:
 #ifdef FEAT_CSCOPE
@@ -748,6 +755,148 @@
 		}
 		ask_for_selection = TRUE;
 	    }
+#if defined(FEAT_QUICKFIX) && defined(FEAT_EVAL)
+	    else
+	    if (type == DT_LTAG)
+	    {
+		list_T	*list;
+		char_u	tag_name[128 + 1];
+		char_u	fname[MAXPATHL + 1];
+		char_u	cmd[CMDBUFFSIZE + 1];
+
+		/*
+		 * Add the matching tags to the location list for the current
+		 * window.
+		 */
+
+		list = list_alloc();
+		if (list == NULL)
+		    goto end_do_tag;
+
+		for (i = 0; i < num_matches; ++i)
+		{
+		    int	    len, cmd_len;
+		    long    lnum;
+		    dict_T  *dict;
+
+		    parse_match(matches[i], &tagp);
+
+		    /* Save the tag name */
+		    len = tagp.tagname_end - tagp.tagname;
+		    if (len > 128)
+			len = 128;
+		    vim_strncpy(tag_name, tagp.tagname, len);
+		    tag_name[len] = NUL;
+
+		    /* Save the tag file name */
+		    p = tag_full_fname(&tagp);
+		    if (p == NULL)
+			continue;
+		    STRCPY(fname, p);
+		    vim_free(p);
+
+		    /*
+		     * Get the line number or the search pattern used to locate
+		     * the tag.
+		     */
+		    lnum = 0;
+		    if (isdigit(*tagp.command))
+			/* Line number is used to locate the tag */
+			lnum = atol((char *)tagp.command);
+		    else
+		    {
+			char_u *cmd_start, *cmd_end;
+
+			/* Search pattern is used to locate the tag */
+
+			/* Locate the end of the command */
+			cmd_start = tagp.command;
+			cmd_end = tagp.command_end;
+			if (cmd_end == NULL)
+			{
+			    for (p = tagp.command;
+				 *p && *p != '\r' && *p != '\n'; ++p)
+				;
+			    cmd_end = p;
+			}
+			/*
+			 * Now, cmd_end points to the character after the
+			 * command. Adjust it to point to the last
+			 * character of the command.
+			 */
+			cmd_end--;
+
+			/*
+			 * Skip the '/' and '?' characters at the
+			 * beginning and end of the search pattern.
+			 */
+			if (*cmd_start == '/' || *cmd_start == '?')
+			    cmd_start++;
+
+			if (*cmd_end == '/' || *cmd_end == '?')
+			    cmd_end--;
+
+			len = 0;
+			cmd[0] = NUL;
+
+			/*
+			 * If "^" is present in the tag search pattern, then
+			 * copy it first.
+			 */
+			if (*cmd_start == '^')
+			{
+			    STRCPY(cmd, "^");
+			    cmd_start++;
+			    len++;
+			}
+
+			/*
+			 * Precede the tag pattern with \V to make it very
+			 * nomagic.
+			 */
+			STRCAT(cmd, "\\V");
+			len += 2;
+
+			cmd_len = cmd_end - cmd_start + 1;
+			if (cmd_len > (CMDBUFFSIZE - 5))
+			    cmd_len = CMDBUFFSIZE - 5;
+			STRNCAT(cmd, cmd_start, cmd_len);
+			len += cmd_len;
+
+			if (cmd[len - 1] == '$')
+			{
+			    /* 
+			     * Replace '$' at the end of the search pattern
+			     * with '\$'
+			     */
+			    cmd[len - 1] = '\\';
+			    cmd[len] = '$';
+			    len++;
+			}
+
+			cmd[len] = NUL;
+		    }
+
+		    if ((dict = dict_alloc()) == NULL)
+			continue;
+		    if (list_append_dict(list, dict) == FAIL)
+		    {
+			vim_free(dict);
+			continue;
+		    }
+
+		    dict_add_nr_str(dict, "text", 0L, tag_name);
+		    dict_add_nr_str(dict, "filename", 0L, fname);
+		    dict_add_nr_str(dict, "lnum", lnum, NULL);
+		    if (lnum == 0)
+			dict_add_nr_str(dict, "pattern", 0L, cmd);
+		}
+
+		set_errorlist(curwin, list, ' ');
+
+		list_free(list);
+	    }
+#endif
 
 	    if (ask_for_selection == TRUE)
 	    {
diff --git a/src/vim.h b/src/vim.h
index bc0b334..7b79532 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -945,6 +945,7 @@
 #define DT_HELP		8	/* like DT_TAG, but no wildcards */
 #define DT_JUMP		9	/* jump to new tag or selection from list */
 #define DT_CSCOPE	10	/* cscope find command (like tjump) */
+#define DT_LTAG		11	/* tag using location list */
 #define DT_FREE		99	/* free cached matches */
 
 /*
@@ -1104,6 +1105,7 @@
     EVENT_FUNCUNDEFINED,	/* if calling a function which doesn't exist */
     EVENT_REMOTEREPLY,		/* upon string reception from a remote vim */
     EVENT_SWAPEXISTS,		/* found existing swap file */
+    EVENT_SPELLFILEMISSING,	/* spell file missing */
     NUM_EVENTS			/* MUST be the last one */
 };