diff --git a/doc/visudo.cat b/doc/visudo.cat
index 2eb83ce97..98fd31aab 100644
--- a/doc/visudo.cat
+++ b/doc/visudo.cat
@@ -135,34 +135,47 @@ FFIILLEESS
      _/_e_t_c_/_s_u_d_o_e_r_s_._t_m_p          Lock file for visudo
 
 DDIIAAGGNNOOSSTTIICCSS
+     In addition to reporting _s_u_d_o_e_r_s parse errors, vviissuuddoo may produce the
+     following messages:
+
      sudoers file busy, try again later.
            Someone else is currently editing the _s_u_d_o_e_r_s file.
 
      /etc/sudoers.tmp: Permission denied
            You didn't run vviissuuddoo as root.
 
-     Can't find you in the passwd database
-           Your user ID does not appear in the system passwd file.
+     you do not exist in the passwd database
+           Your user ID does not appear in the system passwd database.
 
-     Warning: {User,Runas,Host,Cmnd}_Alias referenced but not defined
+     {User,Runas,Host,Cmnd}_Alias referenced but not defined
            Either you are trying to use an undeclared
            {User,Runas,Host,Cmnd}_Alias or you have a user or host name listed
            that consists solely of uppercase letters, digits, and the
            underscore (`_') character.  In the latter case, you can ignore the
-           warnings (ssuuddoo will not complain).  In --ss (strict) mode these are
-           errors, not warnings.
+           warnings (ssuuddoo will not complain).  The message is prefixed with
+           the path name of the _s_u_d_o_e_r_s file and the line number where the
+           undefined alias was used.  In --ss (strict) mode these are errors,
+           not warnings.
 
-     Warning: unused {User,Runas,Host,Cmnd}_Alias
+     unused {User,Runas,Host,Cmnd}_Alias
            The specified {User,Runas,Host,Cmnd}_Alias was defined but never
-           used.  You may wish to comment out or remove the unused alias.
+           used.  The message is prefixed with the path name of the _s_u_d_o_e_r_s
+           file and the line number where the unused alias was defined.  You
+           may wish to comment out or remove the unused alias.
 
-     Warning: cycle in {User,Runas,Host,Cmnd}_Alias
+     cycle in {User,Runas,Host,Cmnd}_Alias
            The specified {User,Runas,Host,Cmnd}_Alias includes a reference to
-           itself, either directly or through an alias it includes.  This is
-           only a warning by default as ssuuddoo will ignore cycles when parsing
-           the _s_u_d_o_e_r_s file.
+           itself, either directly or through an alias it includes.  The
+           message is prefixed with the path name of the _s_u_d_o_e_r_s file and the
+           line number where the cycle was detected.  This is only a warning
+           unless vviissuuddoo is run in --ss (strict) mode as ssuuddoo will ignore cycles
+           when parsing the _s_u_d_o_e_r_s file.
 
-     visudo: /etc/sudoers: input and output files must be different
+     unknown defaults entry "name"
+           The _s_u_d_o_e_r_s file contains a Defaults variable not recognized by
+           vviissuuddoo.
+
+     /etc/sudoers: input and output files must be different
            The --xx flag was used and the specified _o_u_t_p_u_t___f_i_l_e has the same
            path name as the _s_u_d_o_e_r_s file to export.
 
@@ -199,4 +212,4 @@ DDIISSCCLLAAIIMMEERR
      file distributed with ssuuddoo or https://www.sudo.ws/license.html for
      complete details.
 
-Sudo 1.8.18                    November 20, 2015                   Sudo 1.8.18
+Sudo 1.8.19                    November 12, 2016                   Sudo 1.8.19
diff --git a/doc/visudo.man.in b/doc/visudo.man.in
index 86d19a096..eb9a64e2e 100644
--- a/doc/visudo.man.in
+++ b/doc/visudo.man.in
@@ -21,7 +21,7 @@
 .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
 .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
 .\"
-.TH "VISUDO" "8" "November 20, 2015" "Sudo @PACKAGE_VERSION@" "System Manager's Manual"
+.TH "VISUDO" "8" "November 12, 2016" "Sudo @PACKAGE_VERSION@" "System Manager's Manual"
 .nh
 .if n .ad l
 .SH "NAME"
@@ -324,6 +324,11 @@ List of who can run what
 \fI@sysconfdir@/sudoers.tmp\fR
 Lock file for visudo
 .SH "DIAGNOSTICS"
+In addition to reporting
+\fIsudoers\fR
+parse errors,
+\fBvisudo\fR
+may produce the following messages:
 .TP 6n
 \fRsudoers file busy, try again later.\fR
 Someone else is currently editing the
@@ -335,10 +340,10 @@ You didn't run
 \fBvisudo\fR
 as root.
 .TP 6n
-\fRCan't find you in the passwd database\fR
-Your user ID does not appear in the system passwd file.
+\fRyou do not exist in the passwd database\fR
+Your user ID does not appear in the system passwd database.
 .TP 6n
-\fRWarning: {User,Runas,Host,Cmnd}_Alias referenced but not defined\fR
+\fR{User,Runas,Host,Cmnd}_Alias referenced but not defined\fR
 Either you are trying to use an undeclared {User,Runas,Host,Cmnd}_Alias
 or you have a user or host name listed that consists solely of
 uppercase letters, digits, and the underscore
@@ -348,26 +353,47 @@ In the latter case, you can ignore the warnings
 (\fBsudo\fR
 will not complain)
 \&.
+The message is prefixed with the path name of the
+\fIsudoers\fR
+file and the line number where the undefined alias was used.
 In
 \fB\-s\fR
 (strict) mode these are errors, not warnings.
 .TP 6n
-\fRWarning: unused {User,Runas,Host,Cmnd}_Alias\fR
+\fRunused {User,Runas,Host,Cmnd}_Alias\fR
 The specified {User,Runas,Host,Cmnd}_Alias was defined but never
 used.
+The message is prefixed with the path name of the
+\fIsudoers\fR
+file and the line number where the unused alias was defined.
 You may wish to comment out or remove the unused alias.
 .TP 6n
-\fRWarning: cycle in {User,Runas,Host,Cmnd}_Alias\fR
+\fRcycle in {User,Runas,Host,Cmnd}_Alias\fR
 The specified {User,Runas,Host,Cmnd}_Alias includes a reference to
 itself, either directly or through an alias it includes.
-This is only a warning by default as
+The message is prefixed with the path name of the
+\fIsudoers\fR
+file and the line number where the cycle was detected.
+This is only a warning unless
+\fBvisudo\fR
+is run in
+\fB\-s\fR
+(strict) mode as
 \fBsudo\fR
 will ignore cycles when parsing
 the
 \fIsudoers\fR
 file.
 .TP 6n
-\fRvisudo: @sysconfdir@/sudoers: input and output files must be different\fR
+\fRunknown defaults entry \&"name\&"\fR
+The
+\fIsudoers\fR
+file contains a
+\fRDefaults\fR
+variable not recognized by
+\fBvisudo\fR.
+.TP 6n
+\fR@sysconfdir@/sudoers: input and output files must be different\fR
 The
 \fB\-x\fR
 flag was used and the specified
diff --git a/doc/visudo.mdoc.in b/doc/visudo.mdoc.in
index e271a84b4..6f9bb28cf 100644
--- a/doc/visudo.mdoc.in
+++ b/doc/visudo.mdoc.in
@@ -19,7 +19,7 @@
 .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
 .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
 .\"
-.Dd November 20, 2015
+.Dd November 12, 2016
 .Dt VISUDO @mansectsu@
 .Os Sudo @PACKAGE_VERSION@
 .Sh NAME
@@ -310,6 +310,11 @@ List of who can run what
 Lock file for visudo
 .El
 .Sh DIAGNOSTICS
+In addition to reporting
+.Em sudoers
+parse errors,
+.Nm
+may produce the following messages:
 .Bl -tag -width 4n
 .It Li sudoers file busy, try again later.
 Someone else is currently editing the
@@ -319,9 +324,9 @@ file.
 You didn't run
 .Nm
 as root.
-.It Li Can't find you in the passwd database
-Your user ID does not appear in the system passwd file.
-.It Li Warning: {User,Runas,Host,Cmnd}_Alias referenced but not defined
+.It Li you do not exist in the passwd database
+Your user ID does not appear in the system passwd database.
+.It Li {User,Runas,Host,Cmnd}_Alias referenced but not defined
 Either you are trying to use an undeclared {User,Runas,Host,Cmnd}_Alias
 or you have a user or host name listed that consists solely of
 uppercase letters, digits, and the underscore
@@ -332,23 +337,43 @@ In the latter case, you can ignore the warnings
 .Nm sudo
 will not complain
 .Pc .
+The message is prefixed with the path name of the
+.Em sudoers
+file and the line number where the undefined alias was used.
 In
 .Fl s
 (strict) mode these are errors, not warnings.
-.It Li Warning: unused {User,Runas,Host,Cmnd}_Alias
+.It Li unused {User,Runas,Host,Cmnd}_Alias
 The specified {User,Runas,Host,Cmnd}_Alias was defined but never
 used.
+The message is prefixed with the path name of the
+.Em sudoers
+file and the line number where the unused alias was defined.
 You may wish to comment out or remove the unused alias.
-.It Li Warning: cycle in {User,Runas,Host,Cmnd}_Alias
+.It Li cycle in {User,Runas,Host,Cmnd}_Alias
 The specified {User,Runas,Host,Cmnd}_Alias includes a reference to
 itself, either directly or through an alias it includes.
-This is only a warning by default as
+The message is prefixed with the path name of the
+.Em sudoers
+file and the line number where the cycle was detected.
+This is only a warning unless
+.Nm
+is run in
+.Fl s
+(strict) mode as
 .Nm sudo
 will ignore cycles when parsing
 the
 .Em sudoers
 file.
-.It Li visudo: @sysconfdir@/sudoers: input and output files must be different
+.It Li unknown defaults entry \&"name\&"
+The
+.Em sudoers
+file contains a
+.Li Defaults
+variable not recognized by
+.Nm .
+.It Li @sysconfdir@/sudoers: input and output files must be different
 The
 .Fl x
 flag was used and the specified
diff --git a/plugins/sudoers/alias.c b/plugins/sudoers/alias.c
index b0615376a..afc462476 100644
--- a/plugins/sudoers/alias.c
+++ b/plugins/sudoers/alias.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2005, 2007-2015
+ * Copyright (c) 2004-2005, 2007-2016
  *	Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -109,10 +109,11 @@ alias_put(struct alias *a)
 
 /*
  * Add an alias to the aliases redblack tree.
+ * Note that "file" must be a reference-counted string.
  * Returns NULL on success and an error string on failure.
  */
 const char *
-alias_add(char *name, int type, struct member *members)
+alias_add(char *name, int type, char *file, int lineno, struct member *members)
 {
     static char errbuf[512];
     struct alias *a;
@@ -126,6 +127,8 @@ alias_add(char *name, int type, struct member *members)
     a->name = name;
     a->type = type;
     /* a->used = false; */
+    a->file = rcstr_addref(file);
+    a->lineno = lineno;
     HLTQ_TO_TAILQ(&a->members, members, entries);
     switch (rbinsert(aliases, a, NULL)) {
     case 1:
@@ -173,6 +176,7 @@ alias_free(void *v)
     debug_decl(alias_free, SUDOERS_DEBUG_ALIAS)
 
     free(a->name);
+    rcstr_delref(a->file);
     free_members(&a->members);
     free(a);
 
diff --git a/plugins/sudoers/gram.c b/plugins/sudoers/gram.c
index 896cb0b0d..e622bdd37 100644
--- a/plugins/sudoers/gram.c
+++ b/plugins/sudoers/gram.c
@@ -87,6 +87,9 @@
 #include "parse.h"
 #include "toke.h"
 
+/* If we last saw a newline the entry is on the preceding line. */
+#define this_lineno	(last_token == COMMENT ? sudolineno - 1 : sudolineno)
+
 /*
  * Globals
  */
@@ -106,7 +109,7 @@ static bool add_userspec(struct member *, struct privilege *);
 static struct defaults *new_default(char *, char *, short);
 static struct member *new_member(char *, int);
 static struct sudo_digest *new_digest(int, const char *);
-#line 73 "gram.y"
+#line 76 "gram.y"
 #ifndef YYSTYPE_DEFINED
 #define YYSTYPE_DEFINED
 typedef union {
@@ -124,7 +127,7 @@ typedef union {
     int tok;
 } YYSTYPE;
 #endif /* YYSTYPE_DEFINED */
-#line 127 "gram.c"
+#line 130 "gram.c"
 #define COMMAND 257
 #define ALIAS 258
 #define DEFVAR 259
@@ -689,19 +692,15 @@ short *yysslim;
 YYSTYPE *yyvs;
 unsigned int yystacksize;
 int yyparse(void);
-#line 849 "gram.y"
+#line 856 "gram.y"
 void
 sudoerserror(const char *s)
 {
     debug_decl(sudoerserror, SUDOERS_DEBUG_PARSER)
 
-    /* If we last saw a newline the error is on the preceding line. */
-    if (last_token == COMMENT)
-	sudolineno--;
-
     /* Save the line the first error occurred on. */
     if (errorlineno == -1) {
-	errorlineno = sudolineno;
+	errorlineno = this_lineno;
 	rcstr_delref(errorfile);
 	errorfile = rcstr_addref(sudoers);
     }
@@ -714,7 +713,7 @@ sudoerserror(const char *s)
 
 	    /* Warnings are displayed in the user's locale. */
 	    sudoers_setlocale(SUDOERS_LOCALE_USER, &oldlocale);
-	    sudo_printf(SUDO_CONV_ERROR_MSG, _(fmt), sudoers, _(s), sudolineno);
+	    sudo_printf(SUDO_CONV_ERROR_MSG, _(fmt), sudoers, _(s), this_lineno);
 	    sudoers_setlocale(oldlocale, NULL);
 	}
 #endif
@@ -740,7 +739,7 @@ new_default(char *var, char *val, short op)
     /* d->type = 0; */
     d->op = op;
     /* d->binding = NULL */
-    d->lineno = last_token == COMMENT ? sudolineno - 1 : sudolineno;
+    d->lineno = this_lineno;
     d->file = rcstr_addref(sudoers);
     HLTQ_INIT(d, entries);
 
@@ -847,6 +846,8 @@ add_userspec(struct member *members, struct privilege *privs)
 	    "unable to allocate memory");
 	debug_return_bool(false);
     }
+    u->lineno = this_lineno;
+    u->file = rcstr_addref(sudoers);
     HLTQ_TO_TAILQ(&u->users, members, entries);
     HLTQ_TO_TAILQ(&u->privileges, privs, entries);
     TAILQ_INSERT_TAIL(&userspecs, u, entries);
@@ -887,6 +888,7 @@ init_parser(const char *path, bool quiet)
     bool ret = true;
     debug_decl(init_parser, SUDOERS_DEBUG_PARSER)
 
+    /* XXX - move into a free function */
     TAILQ_FOREACH_SAFE(us, &userspecs, entries, us_next) {
 	struct member *m, *m_next;
 	struct privilege *priv, *priv_next;
@@ -961,6 +963,7 @@ init_parser(const char *path, bool quiet)
 	    }
 	    free(priv);
 	}
+	rcstr_delref(us->file);
 	free(us);
     }
     TAILQ_INIT(&userspecs);
@@ -1004,7 +1007,7 @@ init_parser(const char *path, bool quiet)
 
     debug_return_bool(ret);
 }
-#line 955 "gram.c"
+#line 958 "gram.c"
 /* allocate initial stack or double stack size, up to YYMAXDEPTH */
 #if defined(__cplusplus) || defined(__STDC__)
 static int yygrowstack(void)
@@ -1213,23 +1216,23 @@ yyreduce:
     switch (yyn)
     {
 case 1:
-#line 167 "gram.y"
+#line 170 "gram.y"
 { ; }
 break;
 case 5:
-#line 175 "gram.y"
+#line 178 "gram.y"
 {
 			    ;
 			}
 break;
 case 6:
-#line 178 "gram.y"
+#line 181 "gram.y"
 {
 			    yyerrok;
 			}
 break;
 case 7:
-#line 181 "gram.y"
+#line 184 "gram.y"
 {
 			    if (!add_userspec(yyvsp[-1].member, yyvsp[0].privilege)) {
 				sudoerserror(N_("unable to allocate memory"));
@@ -1238,73 +1241,73 @@ case 7:
 			}
 break;
 case 8:
-#line 187 "gram.y"
-{
-			    ;
-			}
-break;
-case 9:
 #line 190 "gram.y"
 {
 			    ;
 			}
 break;
-case 10:
+case 9:
 #line 193 "gram.y"
 {
 			    ;
 			}
 break;
-case 11:
+case 10:
 #line 196 "gram.y"
 {
 			    ;
 			}
 break;
-case 12:
+case 11:
 #line 199 "gram.y"
+{
+			    ;
+			}
+break;
+case 12:
+#line 202 "gram.y"
 {
 			    if (!add_defaults(DEFAULTS, NULL, yyvsp[0].defaults))
 				YYERROR;
 			}
 break;
 case 13:
-#line 203 "gram.y"
+#line 206 "gram.y"
 {
 			    if (!add_defaults(DEFAULTS_USER, yyvsp[-1].member, yyvsp[0].defaults))
 				YYERROR;
 			}
 break;
 case 14:
-#line 207 "gram.y"
+#line 210 "gram.y"
 {
 			    if (!add_defaults(DEFAULTS_RUNAS, yyvsp[-1].member, yyvsp[0].defaults))
 				YYERROR;
 			}
 break;
 case 15:
-#line 211 "gram.y"
+#line 214 "gram.y"
 {
 			    if (!add_defaults(DEFAULTS_HOST, yyvsp[-1].member, yyvsp[0].defaults))
 				YYERROR;
 			}
 break;
 case 16:
-#line 215 "gram.y"
+#line 218 "gram.y"
 {
 			    if (!add_defaults(DEFAULTS_CMND, yyvsp[-1].member, yyvsp[0].defaults))
 				YYERROR;
 			}
 break;
 case 18:
-#line 222 "gram.y"
+#line 225 "gram.y"
 {
 			    HLTQ_CONCAT(yyvsp[-2].defaults, yyvsp[0].defaults, entries);
 			    yyval.defaults = yyvsp[-2].defaults;
 			}
 break;
 case 19:
-#line 228 "gram.y"
+#line 231 "gram.y"
 {
 			    yyval.defaults = new_default(yyvsp[0].string, NULL, true);
 			    if (yyval.defaults == NULL) {
@@ -1314,7 +1317,7 @@ case 19:
 			}
 break;
 case 20:
-#line 235 "gram.y"
+#line 238 "gram.y"
 {
 			    yyval.defaults = new_default(yyvsp[0].string, NULL, false);
 			    if (yyval.defaults == NULL) {
@@ -1324,7 +1327,7 @@ case 20:
 			}
 break;
 case 21:
-#line 242 "gram.y"
+#line 245 "gram.y"
 {
 			    yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, true);
 			    if (yyval.defaults == NULL) {
@@ -1334,7 +1337,7 @@ case 21:
 			}
 break;
 case 22:
-#line 249 "gram.y"
+#line 252 "gram.y"
 {
 			    yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '+');
 			    if (yyval.defaults == NULL) {
@@ -1344,7 +1347,7 @@ case 22:
 			}
 break;
 case 23:
-#line 256 "gram.y"
+#line 259 "gram.y"
 {
 			    yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '-');
 			    if (yyval.defaults == NULL) {
@@ -1354,14 +1357,14 @@ case 23:
 			}
 break;
 case 25:
-#line 266 "gram.y"
+#line 269 "gram.y"
 {
 			    HLTQ_CONCAT(yyvsp[-2].privilege, yyvsp[0].privilege, entries);
 			    yyval.privilege = yyvsp[-2].privilege;
 			}
 break;
 case 26:
-#line 272 "gram.y"
+#line 275 "gram.y"
 {
 			    struct privilege *p = calloc(1, sizeof(*p));
 			    if (p == NULL) {
@@ -1375,21 +1378,21 @@ case 26:
 			}
 break;
 case 27:
-#line 285 "gram.y"
+#line 288 "gram.y"
 {
 			    yyval.member = yyvsp[0].member;
 			    yyval.member->negated = false;
 			}
 break;
 case 28:
-#line 289 "gram.y"
+#line 292 "gram.y"
 {
 			    yyval.member = yyvsp[0].member;
 			    yyval.member->negated = true;
 			}
 break;
 case 29:
-#line 295 "gram.y"
+#line 298 "gram.y"
 {
 			    yyval.member = new_member(yyvsp[0].string, ALIAS);
 			    if (yyval.member == NULL) {
@@ -1399,7 +1402,7 @@ case 29:
 			}
 break;
 case 30:
-#line 302 "gram.y"
+#line 305 "gram.y"
 {
 			    yyval.member = new_member(NULL, ALL);
 			    if (yyval.member == NULL) {
@@ -1409,7 +1412,7 @@ case 30:
 			}
 break;
 case 31:
-#line 309 "gram.y"
+#line 312 "gram.y"
 {
 			    yyval.member = new_member(yyvsp[0].string, NETGROUP);
 			    if (yyval.member == NULL) {
@@ -1419,7 +1422,7 @@ case 31:
 			}
 break;
 case 32:
-#line 316 "gram.y"
+#line 319 "gram.y"
 {
 			    yyval.member = new_member(yyvsp[0].string, NTWKADDR);
 			    if (yyval.member == NULL) {
@@ -1429,7 +1432,7 @@ case 32:
 			}
 break;
 case 33:
-#line 323 "gram.y"
+#line 326 "gram.y"
 {
 			    yyval.member = new_member(yyvsp[0].string, WORD);
 			    if (yyval.member == NULL) {
@@ -1439,7 +1442,7 @@ case 33:
 			}
 break;
 case 35:
-#line 333 "gram.y"
+#line 336 "gram.y"
 {
 			    struct cmndspec *prev;
 			    prev = HLTQ_LAST(yyvsp[-2].cmndspec, cmndspec, entries);
@@ -1485,7 +1488,7 @@ case 35:
 			}
 break;
 case 36:
-#line 378 "gram.y"
+#line 381 "gram.y"
 {
 			    struct cmndspec *cs = calloc(1, sizeof(*cs));
 			    if (cs == NULL) {
@@ -1534,7 +1537,7 @@ case 36:
 			}
 break;
 case 37:
-#line 426 "gram.y"
+#line 429 "gram.y"
 {
 			    yyval.digest = new_digest(SUDO_DIGEST_SHA224, yyvsp[0].string);
 			    if (yyval.digest == NULL) {
@@ -1544,7 +1547,7 @@ case 37:
 			}
 break;
 case 38:
-#line 433 "gram.y"
+#line 436 "gram.y"
 {
 			    yyval.digest = new_digest(SUDO_DIGEST_SHA256, yyvsp[0].string);
 			    if (yyval.digest == NULL) {
@@ -1554,7 +1557,7 @@ case 38:
 			}
 break;
 case 39:
-#line 440 "gram.y"
+#line 443 "gram.y"
 {
 			    yyval.digest = new_digest(SUDO_DIGEST_SHA384, yyvsp[0].string);
 			    if (yyval.digest == NULL) {
@@ -1564,7 +1567,7 @@ case 39:
 			}
 break;
 case 40:
-#line 447 "gram.y"
+#line 450 "gram.y"
 {
 			    yyval.digest = new_digest(SUDO_DIGEST_SHA512, yyvsp[0].string);
 			    if (yyval.digest == NULL) {
@@ -1574,13 +1577,13 @@ case 40:
 			}
 break;
 case 41:
-#line 456 "gram.y"
+#line 459 "gram.y"
 {
 			    yyval.member = yyvsp[0].member;
 			}
 break;
 case 42:
-#line 459 "gram.y"
+#line 462 "gram.y"
 {
 			    if (yyvsp[0].member->type != COMMAND) {
 				sudoerserror(N_("a digest requires a path name"));
@@ -1592,127 +1595,127 @@ case 42:
 			}
 break;
 case 43:
-#line 470 "gram.y"
+#line 473 "gram.y"
 {
 			    yyval.member = yyvsp[0].member;
 			    yyval.member->negated = false;
 			}
 break;
 case 44:
-#line 474 "gram.y"
+#line 477 "gram.y"
 {
 			    yyval.member = yyvsp[0].member;
 			    yyval.member->negated = true;
 			}
 break;
 case 45:
-#line 480 "gram.y"
+#line 483 "gram.y"
 {
 			    yyval.string = yyvsp[0].string;
 			}
 break;
 case 46:
-#line 485 "gram.y"
+#line 488 "gram.y"
 {
 			    yyval.string = yyvsp[0].string;
 			}
 break;
 case 47:
-#line 490 "gram.y"
+#line 493 "gram.y"
 {
 			    yyval.seinfo.role = NULL;
 			    yyval.seinfo.type = NULL;
 			}
 break;
 case 48:
-#line 494 "gram.y"
+#line 497 "gram.y"
 {
 			    yyval.seinfo.role = yyvsp[0].string;
 			    yyval.seinfo.type = NULL;
 			}
 break;
 case 49:
-#line 498 "gram.y"
+#line 501 "gram.y"
 {
 			    yyval.seinfo.type = yyvsp[0].string;
 			    yyval.seinfo.role = NULL;
 			}
 break;
 case 50:
-#line 502 "gram.y"
+#line 505 "gram.y"
 {
 			    yyval.seinfo.role = yyvsp[-1].string;
 			    yyval.seinfo.type = yyvsp[0].string;
 			}
 break;
 case 51:
-#line 506 "gram.y"
+#line 509 "gram.y"
 {
 			    yyval.seinfo.type = yyvsp[-1].string;
 			    yyval.seinfo.role = yyvsp[0].string;
 			}
 break;
 case 52:
-#line 512 "gram.y"
+#line 515 "gram.y"
 {
 			    yyval.string = yyvsp[0].string;
 			}
 break;
 case 53:
-#line 516 "gram.y"
+#line 519 "gram.y"
 {
 			    yyval.string = yyvsp[0].string;
 			}
 break;
 case 54:
-#line 521 "gram.y"
+#line 524 "gram.y"
 {
 			    yyval.privinfo.privs = NULL;
 			    yyval.privinfo.limitprivs = NULL;
 			}
 break;
 case 55:
-#line 525 "gram.y"
+#line 528 "gram.y"
 {
 			    yyval.privinfo.privs = yyvsp[0].string;
 			    yyval.privinfo.limitprivs = NULL;
 			}
 break;
 case 56:
-#line 529 "gram.y"
+#line 532 "gram.y"
 {
 			    yyval.privinfo.privs = NULL;
 			    yyval.privinfo.limitprivs = yyvsp[0].string;
 			}
 break;
 case 57:
-#line 533 "gram.y"
+#line 536 "gram.y"
 {
 			    yyval.privinfo.privs = yyvsp[-1].string;
 			    yyval.privinfo.limitprivs = yyvsp[0].string;
 			}
 break;
 case 58:
-#line 537 "gram.y"
+#line 540 "gram.y"
 {
 			    yyval.privinfo.limitprivs = yyvsp[-1].string;
 			    yyval.privinfo.privs = yyvsp[0].string;
 			}
 break;
 case 59:
-#line 543 "gram.y"
+#line 546 "gram.y"
 {
 			    yyval.runas = NULL;
 			}
 break;
 case 60:
-#line 546 "gram.y"
+#line 549 "gram.y"
 {
 			    yyval.runas = yyvsp[-1].runas;
 			}
 break;
 case 61:
-#line 551 "gram.y"
+#line 554 "gram.y"
 {
 			    yyval.runas = calloc(1, sizeof(struct runascontainer));
 			    if (yyval.runas != NULL) {
@@ -1730,7 +1733,7 @@ case 61:
 			}
 break;
 case 62:
-#line 566 "gram.y"
+#line 569 "gram.y"
 {
 			    yyval.runas = calloc(1, sizeof(struct runascontainer));
 			    if (yyval.runas == NULL) {
@@ -1742,7 +1745,7 @@ case 62:
 			}
 break;
 case 63:
-#line 575 "gram.y"
+#line 578 "gram.y"
 {
 			    yyval.runas = calloc(1, sizeof(struct runascontainer));
 			    if (yyval.runas == NULL) {
@@ -1754,7 +1757,7 @@ case 63:
 			}
 break;
 case 64:
-#line 584 "gram.y"
+#line 587 "gram.y"
 {
 			    yyval.runas = calloc(1, sizeof(struct runascontainer));
 			    if (yyval.runas == NULL) {
@@ -1766,7 +1769,7 @@ case 64:
 			}
 break;
 case 65:
-#line 593 "gram.y"
+#line 596 "gram.y"
 {
 			    yyval.runas = calloc(1, sizeof(struct runascontainer));
 			    if (yyval.runas != NULL) {
@@ -1784,97 +1787,97 @@ case 65:
 			}
 break;
 case 66:
-#line 610 "gram.y"
+#line 613 "gram.y"
 {
 			    TAGS_INIT(yyval.tag);
 			}
 break;
 case 67:
-#line 613 "gram.y"
+#line 616 "gram.y"
 {
 			    yyval.tag.nopasswd = true;
 			}
 break;
 case 68:
-#line 616 "gram.y"
+#line 619 "gram.y"
 {
 			    yyval.tag.nopasswd = false;
 			}
 break;
 case 69:
-#line 619 "gram.y"
+#line 622 "gram.y"
 {
 			    yyval.tag.noexec = true;
 			}
 break;
 case 70:
-#line 622 "gram.y"
+#line 625 "gram.y"
 {
 			    yyval.tag.noexec = false;
 			}
 break;
 case 71:
-#line 625 "gram.y"
+#line 628 "gram.y"
 {
 			    yyval.tag.setenv = true;
 			}
 break;
 case 72:
-#line 628 "gram.y"
+#line 631 "gram.y"
 {
 			    yyval.tag.setenv = false;
 			}
 break;
 case 73:
-#line 631 "gram.y"
+#line 634 "gram.y"
 {
 			    yyval.tag.log_input = true;
 			}
 break;
 case 74:
-#line 634 "gram.y"
+#line 637 "gram.y"
 {
 			    yyval.tag.log_input = false;
 			}
 break;
 case 75:
-#line 637 "gram.y"
+#line 640 "gram.y"
 {
 			    yyval.tag.log_output = true;
 			}
 break;
 case 76:
-#line 640 "gram.y"
+#line 643 "gram.y"
 {
 			    yyval.tag.log_output = false;
 			}
 break;
 case 77:
-#line 643 "gram.y"
+#line 646 "gram.y"
 {
 			    yyval.tag.follow = true;
 			}
 break;
 case 78:
-#line 646 "gram.y"
+#line 649 "gram.y"
 {
 			    yyval.tag.follow = false;
 			}
 break;
 case 79:
-#line 649 "gram.y"
+#line 652 "gram.y"
 {
 			    yyval.tag.send_mail = true;
 			}
 break;
 case 80:
-#line 652 "gram.y"
+#line 655 "gram.y"
 {
 			    yyval.tag.send_mail = false;
 			}
 break;
 case 81:
-#line 657 "gram.y"
+#line 660 "gram.y"
 {
 			    yyval.member = new_member(NULL, ALL);
 			    if (yyval.member == NULL) {
@@ -1884,7 +1887,7 @@ case 81:
 			}
 break;
 case 82:
-#line 664 "gram.y"
+#line 667 "gram.y"
 {
 			    yyval.member = new_member(yyvsp[0].string, ALIAS);
 			    if (yyval.member == NULL) {
@@ -1894,7 +1897,7 @@ case 82:
 			}
 break;
 case 83:
-#line 671 "gram.y"
+#line 674 "gram.y"
 {
 			    struct sudo_command *c = calloc(1, sizeof(*c));
 			    if (c == NULL) {
@@ -1912,82 +1915,86 @@ case 83:
 			}
 break;
 case 86:
-#line 692 "gram.y"
+#line 695 "gram.y"
 {
 			    const char *s;
-			    if ((s = alias_add(yyvsp[-2].string, HOSTALIAS, yyvsp[0].member)) != NULL) {
+			    s = alias_add(yyvsp[-2].string, HOSTALIAS, sudoers, this_lineno, yyvsp[0].member);
+			    if (s != NULL) {
 				sudoerserror(s);
 				YYERROR;
 			    }
 			}
 break;
 case 88:
-#line 702 "gram.y"
+#line 706 "gram.y"
 {
 			    HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries);
 			    yyval.member = yyvsp[-2].member;
 			}
 break;
 case 91:
-#line 712 "gram.y"
+#line 716 "gram.y"
 {
 			    const char *s;
-			    if ((s = alias_add(yyvsp[-2].string, CMNDALIAS, yyvsp[0].member)) != NULL) {
+			    s = alias_add(yyvsp[-2].string, CMNDALIAS, sudoers, this_lineno, yyvsp[0].member);
+			    if (s != NULL) {
 				sudoerserror(s);
 				YYERROR;
 			    }
 			}
 break;
 case 93:
-#line 722 "gram.y"
+#line 727 "gram.y"
 {
 			    HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries);
 			    yyval.member = yyvsp[-2].member;
 			}
 break;
 case 96:
-#line 732 "gram.y"
+#line 737 "gram.y"
 {
 			    const char *s;
-			    if ((s = alias_add(yyvsp[-2].string, RUNASALIAS, yyvsp[0].member)) != NULL) {
+			    s = alias_add(yyvsp[-2].string, RUNASALIAS, sudoers, this_lineno, yyvsp[0].member);
+			    if (s != NULL) {
 				sudoerserror(s);
 				YYERROR;
 			    }
 			}
 break;
 case 99:
-#line 745 "gram.y"
+#line 751 "gram.y"
 {
 			    const char *s;
-			    if ((s = alias_add(yyvsp[-2].string, USERALIAS, yyvsp[0].member)) != NULL) {
+			    s = alias_add(yyvsp[-2].string, USERALIAS, sudoers, this_lineno, yyvsp[0].member);
+			    if (s != NULL) {
 				sudoerserror(s);
 				YYERROR;
 			    }
 			}
 break;
 case 101:
-#line 755 "gram.y"
+#line 762 "gram.y"
 {
 			    HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries);
 			    yyval.member = yyvsp[-2].member;
 			}
 break;
 case 102:
-#line 761 "gram.y"
+#line 768 "gram.y"
 {
 			    yyval.member = yyvsp[0].member;
 			    yyval.member->negated = false;
 			}
 break;
 case 103:
-#line 765 "gram.y"
+#line 772 "gram.y"
 {
 			    yyval.member = yyvsp[0].member;
 			    yyval.member->negated = true;
 			}
 break;
 case 104:
-#line 771 "gram.y"
+#line 778 "gram.y"
 {
 			    yyval.member = new_member(yyvsp[0].string, ALIAS);
 			    if (yyval.member == NULL) {
@@ -1997,7 +2004,7 @@ case 104:
 			}
 break;
 case 105:
-#line 778 "gram.y"
+#line 785 "gram.y"
 {
 			    yyval.member = new_member(NULL, ALL);
 			    if (yyval.member == NULL) {
@@ -2007,7 +2014,7 @@ case 105:
 			}
 break;
 case 106:
-#line 785 "gram.y"
+#line 792 "gram.y"
 {
 			    yyval.member = new_member(yyvsp[0].string, NETGROUP);
 			    if (yyval.member == NULL) {
@@ -2017,7 +2024,7 @@ case 106:
 			}
 break;
 case 107:
-#line 792 "gram.y"
+#line 799 "gram.y"
 {
 			    yyval.member = new_member(yyvsp[0].string, USERGROUP);
 			    if (yyval.member == NULL) {
@@ -2027,7 +2034,7 @@ case 107:
 			}
 break;
 case 108:
-#line 799 "gram.y"
+#line 806 "gram.y"
 {
 			    yyval.member = new_member(yyvsp[0].string, WORD);
 			    if (yyval.member == NULL) {
@@ -2037,28 +2044,28 @@ case 108:
 			}
 break;
 case 110:
-#line 809 "gram.y"
+#line 816 "gram.y"
 {
 			    HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries);
 			    yyval.member = yyvsp[-2].member;
 			}
 break;
 case 111:
-#line 815 "gram.y"
+#line 822 "gram.y"
 {
 			    yyval.member = yyvsp[0].member;
 			    yyval.member->negated = false;
 			}
 break;
 case 112:
-#line 819 "gram.y"
+#line 826 "gram.y"
 {
 			    yyval.member = yyvsp[0].member;
 			    yyval.member->negated = true;
 			}
 break;
 case 113:
-#line 825 "gram.y"
+#line 832 "gram.y"
 {
 			    yyval.member = new_member(yyvsp[0].string, ALIAS);
 			    if (yyval.member == NULL) {
@@ -2068,7 +2075,7 @@ case 113:
 			}
 break;
 case 114:
-#line 832 "gram.y"
+#line 839 "gram.y"
 {
 			    yyval.member = new_member(NULL, ALL);
 			    if (yyval.member == NULL) {
@@ -2078,7 +2085,7 @@ case 114:
 			}
 break;
 case 115:
-#line 839 "gram.y"
+#line 846 "gram.y"
 {
 			    yyval.member = new_member(yyvsp[0].string, WORD);
 			    if (yyval.member == NULL) {
@@ -2087,7 +2094,7 @@ case 115:
 			    }
 			}
 break;
-#line 2038 "gram.c"
+#line 2045 "gram.c"
     }
     yyssp -= yym;
     yystate = *yyssp;
diff --git a/plugins/sudoers/gram.y b/plugins/sudoers/gram.y
index c58aeeb09..2f68a4254 100644
--- a/plugins/sudoers/gram.y
+++ b/plugins/sudoers/gram.y
@@ -49,6 +49,9 @@
 #include "parse.h"
 #include "toke.h"
 
+/* If we last saw a newline the entry is on the preceding line. */
+#define this_lineno	(last_token == COMMENT ? sudolineno - 1 : sudolineno)
+
 /*
  * Globals
  */
@@ -691,7 +694,8 @@ hostaliases	:	hostalias
 
 hostalias	:	ALIAS '=' hostlist {
 			    const char *s;
-			    if ((s = alias_add($1, HOSTALIAS, $3)) != NULL) {
+			    s = alias_add($1, HOSTALIAS, sudoers, this_lineno, $3);
+			    if (s != NULL) {
 				sudoerserror(s);
 				YYERROR;
 			    }
@@ -711,7 +715,8 @@ cmndaliases	:	cmndalias
 
 cmndalias	:	ALIAS '=' cmndlist {
 			    const char *s;
-			    if ((s = alias_add($1, CMNDALIAS, $3)) != NULL) {
+			    s = alias_add($1, CMNDALIAS, sudoers, this_lineno, $3);
+			    if (s != NULL) {
 				sudoerserror(s);
 				YYERROR;
 			    }
@@ -731,7 +736,8 @@ runasaliases	:	runasalias
 
 runasalias	:	ALIAS '=' userlist {
 			    const char *s;
-			    if ((s = alias_add($1, RUNASALIAS, $3)) != NULL) {
+			    s = alias_add($1, RUNASALIAS, sudoers, this_lineno, $3);
+			    if (s != NULL) {
 				sudoerserror(s);
 				YYERROR;
 			    }
@@ -744,7 +750,8 @@ useraliases	:	useralias
 
 useralias	:	ALIAS '=' userlist {
 			    const char *s;
-			    if ((s = alias_add($1, USERALIAS, $3)) != NULL) {
+			    s = alias_add($1, USERALIAS, sudoers, this_lineno, $3);
+			    if (s != NULL) {
 				sudoerserror(s);
 				YYERROR;
 			    }
@@ -851,13 +858,9 @@ sudoerserror(const char *s)
 {
     debug_decl(sudoerserror, SUDOERS_DEBUG_PARSER)
 
-    /* If we last saw a newline the error is on the preceding line. */
-    if (last_token == COMMENT)
-	sudolineno--;
-
     /* Save the line the first error occurred on. */
     if (errorlineno == -1) {
-	errorlineno = sudolineno;
+	errorlineno = this_lineno;
 	rcstr_delref(errorfile);
 	errorfile = rcstr_addref(sudoers);
     }
@@ -870,7 +873,7 @@ sudoerserror(const char *s)
 
 	    /* Warnings are displayed in the user's locale. */
 	    sudoers_setlocale(SUDOERS_LOCALE_USER, &oldlocale);
-	    sudo_printf(SUDO_CONV_ERROR_MSG, _(fmt), sudoers, _(s), sudolineno);
+	    sudo_printf(SUDO_CONV_ERROR_MSG, _(fmt), sudoers, _(s), this_lineno);
 	    sudoers_setlocale(oldlocale, NULL);
 	}
 #endif
@@ -896,7 +899,7 @@ new_default(char *var, char *val, short op)
     /* d->type = 0; */
     d->op = op;
     /* d->binding = NULL */
-    d->lineno = last_token == COMMENT ? sudolineno - 1 : sudolineno;
+    d->lineno = this_lineno;
     d->file = rcstr_addref(sudoers);
     HLTQ_INIT(d, entries);
 
@@ -1003,6 +1006,8 @@ add_userspec(struct member *members, struct privilege *privs)
 	    "unable to allocate memory");
 	debug_return_bool(false);
     }
+    u->lineno = this_lineno;
+    u->file = rcstr_addref(sudoers);
     HLTQ_TO_TAILQ(&u->users, members, entries);
     HLTQ_TO_TAILQ(&u->privileges, privs, entries);
     TAILQ_INSERT_TAIL(&userspecs, u, entries);
@@ -1043,6 +1048,7 @@ init_parser(const char *path, bool quiet)
     bool ret = true;
     debug_decl(init_parser, SUDOERS_DEBUG_PARSER)
 
+    /* XXX - move into a free function */
     TAILQ_FOREACH_SAFE(us, &userspecs, entries, us_next) {
 	struct member *m, *m_next;
 	struct privilege *priv, *priv_next;
@@ -1117,6 +1123,7 @@ init_parser(const char *path, bool quiet)
 	    }
 	    free(priv);
 	}
+	rcstr_delref(us->file);
 	free(us);
     }
     TAILQ_INIT(&userspecs);
diff --git a/plugins/sudoers/parse.h b/plugins/sudoers/parse.h
index 684dfeedf..64881fd4d 100644
--- a/plugins/sudoers/parse.h
+++ b/plugins/sudoers/parse.h
@@ -159,6 +159,8 @@ struct userspec {
     TAILQ_ENTRY(userspec) entries;
     struct member_list users;		/* list of users */
     struct privilege_list privileges;	/* list of privileges */
+    int lineno;
+    char *file;
 };
 
 /*
@@ -209,7 +211,9 @@ struct runascontainer {
 struct alias {
     char *name;				/* alias name */
     unsigned short type;		/* {USER,HOST,RUNAS,CMND}ALIAS */
-    bool used;				/* "used" flag for cycle detection */
+    short used;				/* "used" flag for cycle detection */
+    int lineno;				/* line number of alias entry */
+    char *file;				/* file the alias entry was in */
     struct member_list members;		/* list of alias members */
 };
 
@@ -236,7 +240,7 @@ extern struct defaults_list defaults;
 
 /* alias.c */
 bool no_aliases(void);
-const char *alias_add(char *name, int type, struct member *members);
+const char *alias_add(char *name, int type, char *file, int lineno, struct member *members);
 int alias_compare(const void *a1, const void *a2);
 struct alias *alias_get(char *name, int type);
 struct alias *alias_remove(char *name, int type);
diff --git a/plugins/sudoers/regress/visudo/test2.err.ok b/plugins/sudoers/regress/visudo/test2.err.ok
index e036dd048..e2b191ced 100644
--- a/plugins/sudoers/regress/visudo/test2.err.ok
+++ b/plugins/sudoers/regress/visudo/test2.err.ok
@@ -1 +1 @@
-visudo: Error: cycle in User_Alias "FOO"
+visudo: stdin:1 cycle in User_Alias "FOO"
diff --git a/plugins/sudoers/regress/visudo/test3.err.ok b/plugins/sudoers/regress/visudo/test3.err.ok
index 4209fa242..0e5a24ad5 100644
--- a/plugins/sudoers/regress/visudo/test3.err.ok
+++ b/plugins/sudoers/regress/visudo/test3.err.ok
@@ -1,2 +1,2 @@
-visudo: Warning: unused User_Alias "A"
-visudo: Warning: unused User_Alias "B"
+visudo: stdin:1 unused User_Alias "A"
+visudo: stdin:2 unused User_Alias "B"
diff --git a/plugins/sudoers/visudo.c b/plugins/sudoers/visudo.c
index c7bf710fd..9f1c4e91d 100644
--- a/plugins/sudoers/visudo.c
+++ b/plugins/sudoers/visudo.c
@@ -89,7 +89,7 @@ TAILQ_HEAD(sudoersfile_list, sudoersfile);
 static void quit(int);
 static void get_hostname(void);
 static int whatnow(void);
-static int check_aliases(bool, bool);
+static int check_aliases(bool strict, bool quiet);
 static char *get_editor(int *editor_argc, char ***editor_argv);
 static bool check_syntax(const char *, bool, bool, bool);
 static bool edit_sudoers(struct sudoersfile *, char *, int, char **, int);
@@ -1114,7 +1114,7 @@ alias_type_to_string(int alias_type)
 }
 
 static int
-check_alias(char *name, int type, int strict, int quiet)
+check_alias(char *name, int type, char *file, int lineno, bool quiet)
 {
     struct member *m;
     struct alias *a;
@@ -1124,22 +1124,19 @@ check_alias(char *name, int type, int strict, int quiet)
     if ((a = alias_get(name, type)) != NULL) {
 	/* check alias contents */
 	TAILQ_FOREACH(m, &a->members, entries) {
-	    if (m->type == ALIAS)
-		errors += check_alias(m->name, type, strict, quiet);
+	    if (m->type != ALIAS)
+		continue;
+	    errors += check_alias(m->name, type, a->file, a->lineno, quiet);
 	}
 	alias_put(a);
     } else {
 	if (!quiet) {
 	    if (errno == ELOOP) {
-		sudo_warnx(strict ?
-		    U_("Error: cycle in %s \"%s\"") :
-		    U_("Warning: cycle in %s \"%s\""),
-		    alias_type_to_string(type), name);
+		sudo_warnx(U_("%s:%d cycle in %s \"%s\""),
+		    file, lineno, alias_type_to_string(type), name);
 	    } else {
-		sudo_warnx(strict ?
-		    U_("Error: %s \"%s\" referenced but not defined") :
-		    U_("Warning: %s \"%s\" referenced but not defined"),
-		    alias_type_to_string(type), name);
+		sudo_warnx(U_("%s:%d %s \"%s\" referenced but not defined"),
+		    file, lineno, alias_type_to_string(type), name);
 	    }
 	}
 	errors++;
@@ -1173,32 +1170,37 @@ check_aliases(bool strict, bool quiet)
     TAILQ_FOREACH(us, &userspecs, entries) {
 	TAILQ_FOREACH(m, &us->users, entries) {
 	    if (m->type == ALIAS) {
-		errors += check_alias(m->name, USERALIAS, strict, quiet);
+		errors += check_alias(m->name, USERALIAS,
+		    us->file, us->lineno, quiet);
 	    }
 	}
 	TAILQ_FOREACH(priv, &us->privileges, entries) {
 	    TAILQ_FOREACH(m, &priv->hostlist, entries) {
 		if (m->type == ALIAS) {
-		    errors += check_alias(m->name, HOSTALIAS, strict, quiet);
+		    errors += check_alias(m->name, HOSTALIAS,
+			us->file, us->lineno, quiet);
 		}
 	    }
 	    TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
 		if (cs->runasuserlist != NULL) {
 		    TAILQ_FOREACH(m, cs->runasuserlist, entries) {
 			if (m->type == ALIAS) {
-			    errors += check_alias(m->name, RUNASALIAS, strict, quiet);
+			    errors += check_alias(m->name, RUNASALIAS,
+				us->file, us->lineno, quiet);
 			}
 		    }
 		}
 		if (cs->runasgrouplist != NULL) {
 		    TAILQ_FOREACH(m, cs->runasgrouplist, entries) {
 			if (m->type == ALIAS) {
-			    errors += check_alias(m->name, RUNASALIAS, strict, quiet);
+			    errors += check_alias(m->name, RUNASALIAS,
+				us->file, us->lineno, quiet);
 			}
 		    }
 		}
 		if ((m = cs->cmnd)->type == ALIAS) {
-		    errors += check_alias(m->name, CMNDALIAS, strict, quiet);
+		    errors += check_alias(m->name, CMNDALIAS,
+			us->file, us->lineno, quiet);
 		}
 	    }
 	}
@@ -1281,8 +1283,8 @@ print_unused(void *v1, void *v2)
 {
     struct alias *a = (struct alias *)v1;
 
-    sudo_warnx_nodebug(U_("Warning: unused %s \"%s\""),
-	alias_type_to_string(a->type), a->name);
+    sudo_warnx_nodebug(U_("%s:%d unused %s \"%s\""),
+	a->file, a->lineno, alias_type_to_string(a->type), a->name);
     return 0;
 }
 
