diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -1065,7 +1065,9 @@ def _matchfiles(repo, subset, x):
             if rev is not None:
                 raise error.ParseError('_matchfiles expected at most one '
                                        'revision')
-            if value != '': # empty means working directory; leave rev as None
+            if value == '': # empty means working directory
+                rev = node.wdirrev
+            else:
                 rev = value
         elif prefix == 'd:':
             if default is not None:
@@ -1076,9 +1078,9 @@ def _matchfiles(repo, subset, x):
             raise error.ParseError('invalid _matchfiles prefix: %s' % prefix)
     if not default:
         default = 'glob'
+    hasset = any(matchmod.patkind(p) == 'set' for p in pats + inc + exc)
 
-    m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
-                       exclude=exc, ctx=repo[rev], default=default)
+    mcache = [None]
 
     # This directly read the changelog data as creating changectx for all
     # revisions is quite expensive.
@@ -1089,6 +1091,14 @@ def _matchfiles(repo, subset, x):
             files = repo[x].files()
         else:
             files = getfiles(x)
+
+        if not mcache[0] or (hasset and rev is None):
+            r = x if rev is None else rev
+            mcache[0] = matchmod.match(repo.root, repo.getcwd(), pats,
+                                       include=inc, exclude=exc, ctx=repo[r],
+                                       default=default)
+        m = mcache[0]
+
         for f in files:
             if m(f):
                 return True
diff --git a/tests/test-glog.t b/tests/test-glog.t
--- a/tests/test-glog.t
+++ b/tests/test-glog.t
@@ -1675,7 +1675,7 @@ Test falling back to slow path for non-e
       (string 'p:c')))
   <filteredset
     <spanset- 0:5>,
-    <matchfiles patterns=['a', 'c'], include=[] exclude=[], default='relpath', rev=None>>
+    <matchfiles patterns=['a', 'c'], include=[] exclude=[], default='relpath', rev=2147483647>>
 
 Test multiple --include/--exclude/paths
 
@@ -1694,7 +1694,7 @@ Test multiple --include/--exclude/paths
       (string 'x:e')))
   <filteredset
     <spanset- 0:5>,
-    <matchfiles patterns=['a', 'e'], include=['a', 'e'] exclude=['b', 'e'], default='relpath', rev=None>>
+    <matchfiles patterns=['a', 'e'], include=['a', 'e'] exclude=['b', 'e'], default='relpath', rev=2147483647>>
 
 Test glob expansion of pats
 
@@ -1732,7 +1732,7 @@ Test --follow on a directory
       (string 'p:dir')))
   <filteredset
     <generatorsetdesc->,
-    <matchfiles patterns=['dir'], include=[] exclude=[], default='relpath', rev=None>>
+    <matchfiles patterns=['dir'], include=[] exclude=[], default='relpath', rev=2147483647>>
   $ hg up -q tip
 
 Test --follow on file not in parent revision
@@ -1754,7 +1754,7 @@ Test --follow and patterns
       (string 'p:glob:*')))
   <filteredset
     <generatorsetdesc->,
-    <matchfiles patterns=['glob:*'], include=[] exclude=[], default='relpath', rev=None>>
+    <matchfiles patterns=['glob:*'], include=[] exclude=[], default='relpath', rev=2147483647>>
 
 Test --follow on a single rename
 
@@ -1875,7 +1875,7 @@ Test "set:..." and parent revision
       (string 'p:set:copied()')))
   <filteredset
     <spanset- 0:7>,
-    <matchfiles patterns=['set:copied()'], include=[] exclude=[], default='relpath', rev=None>>
+    <matchfiles patterns=['set:copied()'], include=[] exclude=[], default='relpath', rev=2147483647>>
   $ testlog --include "set:copied()"
   []
   (func
@@ -1886,11 +1886,13 @@ Test "set:..." and parent revision
       (string 'i:set:copied()')))
   <filteredset
     <spanset- 0:7>,
-    <matchfiles patterns=[], include=['set:copied()'] exclude=[], default='relpath', rev=None>>
+    <matchfiles patterns=[], include=['set:copied()'] exclude=[], default='relpath', rev=2147483647>>
   $ testlog -r "sort(file('set:copied()'), -rev)"
   ["sort(file('set:copied()'), -rev)"]
   []
-  <baseset []>
+  <filteredset
+    <fullreposet- 0:7>,
+    <matchfiles patterns=['set:copied()'], include=[] exclude=[], default='glob', rev=None>>
 
 Test --removed
 
@@ -1908,7 +1910,7 @@ Test --removed
       (string 'p:a')))
   <filteredset
     <spanset- 0:7>,
-    <matchfiles patterns=['a'], include=[] exclude=[], default='relpath', rev=None>>
+    <matchfiles patterns=['a'], include=[] exclude=[], default='relpath', rev=2147483647>>
   $ testlog --removed --follow a
   []
   (func
@@ -1919,7 +1921,7 @@ Test --removed
       (string 'p:a')))
   <filteredset
     <generatorsetdesc->,
-    <matchfiles patterns=['a'], include=[] exclude=[], default='relpath', rev=None>>
+    <matchfiles patterns=['a'], include=[] exclude=[], default='relpath', rev=2147483647>>
 
 Test --patch and --stat with --follow and --follow-first
 
@@ -2290,7 +2292,7 @@ Test subdir
       (string 'p:.')))
   <filteredset
     <spanset- 0:9>,
-    <matchfiles patterns=['.'], include=[] exclude=[], default='relpath', rev=None>>
+    <matchfiles patterns=['.'], include=[] exclude=[], default='relpath', rev=2147483647>>
   $ testlog ../b
   []
   (func
diff --git a/tests/test-largefiles-update.t b/tests/test-largefiles-update.t
--- a/tests/test-largefiles-update.t
+++ b/tests/test-largefiles-update.t
@@ -726,6 +726,20 @@ bit correctly on the platform being unaw
 
 #endif
 
+The fileset revset is evaluated for each revision, instead of once on wdir(),
+and then patterns matched on each revision.  Here, no exec bits are set in
+wdir(), but a matching revision is detected.
+
+(Teach large2 is not an executable. Maybe this is a bug of largefiles.)
+#if execbit
+  $ chmod -x .hglf/large2
+#endif
+
+  $ hg files 'set:exec()'
+  [1]
+  $ hg log -qr 'file("set:exec()")'
+  9:be1b433a65b1
+
 Test a fatal error interrupting an update. Verify that status report dirty
 files correctly after an interrupted update. Also verify that checking all
 hashes reveals it isn't clean.