code: func removeEmptyTrees(ctx context.Context, root string, empty stringset.Set) {
  	// If directory 'A/B/C' has potentially empty subtree, then so do 'A/B' and
  	// 'A' and '.'. Expand 'empty' set according to these rules. Note that 'root'
  	// itself is always is this set.
  	verboseEmpty := stringset.New(empty.Len())
  	verboseEmpty.Add(root)
  	empty.Iter(func(dir string) bool {
  		rel, err := filepath.Rel(root, dir)
  		if err != nil {
  			// Note: this should never really happen, since there are checks outside
  			// of this function.
  			logging.Warningf(ctx, "Can't compute %q relative to %q - %s", dir, root, err)
  			return true
  		}
  
  		// Here 'rel' has form 'A/B/C' or is '.' (but this is already handled).
  		if rel != "." {
  			for i, r := range rel {
  				if r == filepath.Separator && i > 0 {
  					verboseEmpty.Add(filepath.Join(root, rel[:i]))
  				}
  			}
  			verboseEmpty.Add(filepath.Join(root, rel))
  		}
  
  		return true
  	})
  
  	// Now we recursively walk through the root subtree, skipping trees we know
  	// can't be empty.
  	_, err := removeEmptyTree(root, func(candidate string) (shouldCheck bool) {
  		return verboseEmpty.Has(candidate)
  	})
  	if err != nil {
  		logging.Warningf(ctx, "Failed to cleanup empty directories under %q - %s", root, err)
  	}
  }
docs: // removeEmptyTrees recursively removes empty directory subtrees after some
  // files have been removed.
  //
  // It tries to avoid enumerating entire directory tree and instead recurses
  // only into directories with potentially empty subtrees. They are indicated by
  // 'empty' set with absolute paths to directories that had files removed from
  // them (so they MAY be empty now, but not necessarily).
  //
  // All paths are absolute, using native separators.
  //
  // Best effort, logs errors.