Rollback group of DDL statements
The error is happening because the error being thrown part of a recompile error due to deferred name resolution.  Looking at SQL BOL those aren't trapped when they happen at the same level as the try...catch.  However, if it's happening at a different level, either as dynamic SQL or a SP call, then it will get caught and rolled back.

Using Profiler you can see that the "alter table foo add x dog" statement recompiles before executing and then errors and bypasses the catch block.



If you wrap the statements in dynamic SQL the error isn't returned to Profiler and the transaction is rolled back