+ for(map<Statement *, VariableInfo>::const_iterator i=variables.begin(); i!=variables.end(); ++i)
+ if(i->second.output)
+ referenced(i->first, call);
+ }
+}
+
+void UnusedVariableRemover::record_assignment(const Assignment::Target &target, Node &node)
+{
+ assignments.push_back(AssignmentInfo());
+ AssignmentInfo &assign_info = assignments.back();
+ assign_info.node = &node;
+ assign_info.target = target;
+
+ /* An assignment to the target hides any assignments to the same target or
+ its subfields. */
+ VariableInfo &var_info = variables[target.declaration];
+ for(unsigned i=0; i<var_info.assignments.size(); ++i)
+ {
+ const Assignment::Target &t = var_info.assignments[i]->target;
+
+ bool subfield = (t.chain_len>=target.chain_len);
+ for(unsigned j=0; (subfield && j<target.chain_len); ++j)
+ subfield = (t.chain[j]==target.chain[j]);
+
+ if(subfield)
+ var_info.assignments.erase(var_info.assignments.begin()+i);
+ else
+ ++i;
+ }
+
+ var_info.assignments.push_back(&assign_info);
+}
+
+void UnusedVariableRemover::visit(ExpressionStatement &expr)
+{
+ r_assignment = 0;
+ r_side_effects = false;
+ TraversingVisitor::visit(expr);
+ if(r_assignment && r_assignment->target.declaration)
+ record_assignment(r_assignment->target, expr);
+ if(!r_side_effects)
+ unused_nodes.insert(&expr);
+}
+
+void UnusedVariableRemover::visit(StructDeclaration &strct)
+{
+ SetFlag set_struct(in_struct);
+ TraversingVisitor::visit(strct);
+}
+
+void UnusedVariableRemover::visit(VariableDeclaration &var)
+{
+ TraversingVisitor::visit(var);
+
+ if(in_struct)
+ return;
+
+ VariableInfo &var_info = variables[&var];
+ var_info.interface_block = interface_block;
+
+ /* Mark variables as output if they're used by the next stage or the
+ graphics API. */
+ if(interface_block)
+ var_info.output = (interface_block->interface=="out" && (interface_block->linked_block || !interface_block->block_name.compare(0, 3, "gl_")));
+ else
+ var_info.output = (var.interface=="out" && (stage->type==Stage::FRAGMENT || var.linked_declaration || !var.name.compare(0, 3, "gl_")));
+
+ if(var.init_expression)
+ {
+ var_info.initialized = true;
+ record_assignment(&var, *var.init_expression);
+ }
+}
+
+void UnusedVariableRemover::visit(InterfaceBlock &iface)
+{
+ VariableInfo &var_info = variables[&iface];
+ var_info.output = (iface.interface=="out" && (iface.linked_block || !iface.block_name.compare(0, 3, "gl_")));
+}
+
+void UnusedVariableRemover::merge_variables(const BlockVariableMap &other_vars)
+{
+ for(BlockVariableMap::const_iterator i=other_vars.begin(); i!=other_vars.end(); ++i)
+ {
+ BlockVariableMap::iterator j = variables.find(i->first);
+ if(j!=variables.end())