In case anyone has the same issue, I gave up in the end and wrote a custom module since I find views a pain in the ass.
My module uses nested queries which is embarassing, but it's still fast to run (unless you have a massive list of taxononomy terms) so it doesn't matter too much for this purposes.
The module outputs a Drupal block, the content of which comes from this function:
function list_of_resource_tags(){
// Retrieve the logged in user
global $user;
// Select all "Metadata" terms for the nodes the logged in user
// has permission to see
$sql_terms = '
SELECT DISTINCT(term_data.tid) AS term_id, term_data.name, term_hierarchy.parent, term_data.weight
FROM node_access
INNER JOIN node ON node_access.nid = node.nid
INNER JOIN term_node ON node.nid = term_node.nid
INNER JOIN term_data ON term_node.tid = term_data.tid
INNER JOIN term_hierarchy ON term_data.tid = term_hierarchy.tid
WHERE node_access.grant_view = 1
AND node.status = 1 /* Published nodes */
AND term_data.vid = 9 /* Taxonomy terms of "Metadata" vocabulary only */
AND node_access.gid IN (SELECT rid AS roles FROM users_roles WHERE uid = %d) /* Logged-in user is granted permission to these nodes */
ORDER BY term_data.weight';
$result_terms = db_query($sql_terms, $user->uid);
$displayed_terms = array();
$output = '';
while ($row = db_fetch_object($result_terms)) {
// If tag is top-level, just display and put in array
if ($row->parent == 0 && in_array($row->term_id, $displayed_terms) == FALSE){
$output .= '<div class="views-row"><a href="taxonomy/term/'.$row->term_id.'">'.$row->name.'</a></div>';
$displayed_terms[] = $row->term_id;
}
// Test if we've already displayed the tags parent, if not, retrieve it
else if (in_array($row->parent, $displayed_terms) == FALSE){
$sql_parent = '
SELECT *
FROM term_data
WHERE tid = %d';
$result_parent = db_query($sql_parent, $row->parent);
$row_parent = db_fetch_object($result_parent);
$output .= '<div class="views-row"><a href="taxonomy/term/'.$row_parent->tid.'">'.$row_parent->name.'</div>';
$displayed_terms[] = $row_parent->tid;
}
}
return $output;
}