The fix_unused_unsafe transform fixes unused unsafe by removing the unsafe keyword from unsafe blocks, but it leaves the blocks in place. In many cases it would be more idiomatic to remove the block entirely, preserving the block's contents. So for code like unsafe { foo(); }, we currently transform that to { foo(); }, but it would be better to generate just foo();.
There are some edge cases to keep in mind here:
- Blocks can have comments attached, and deleting the block would take the comment along with it. If the block has a comment we need to make sure we move the comment to the first statement in the block to make sure it's not lost. If the block is empty such that there's nowhere to move the comment to, we should probably leave the block there so as to preserve the comment (a human or an LLM may be needed to make the judgement of what to do with the comment).
- If the block is used as an expression, i.e. if it's returning a value, we probably want to keep the block in place and just remove the
unsafe keyword (which is the current behavior).
- If the block has anything inside it that requires
Drop, we should leave the block in place so as not to alter drop order (this is another place where human or LLM judgement is necessary to decide if the changed drop order matters). This is maybe not a big concern because c2rust-transpile won't generate any code that relies on Drop, but could be a problem if fix_unused_unsafe is used later in the lifting process after other changes have been made. If it's easy to detect this case we should support it, but if drop analysis would be difficult or complex we can probably disregard this case for now.
- Some blocks are labeled, and shouldn't be removed as the labels are needed for control flow. These blocks generally shouldn't be
unsafe, but depending on how we implement this logic that might be something that needs to be kept in mind.
I also think we should start by making this extra logic a part of fix_unused_unsafe, rather than pulling this out into its own transform. We have a few other transforms generating blocks in different ways, but it's not yet clear that any of them need this extra "remove unnecessary blocks" step. For now let's keep this cleanup logic part of fix_unused_unsafe to keep the use case narrow until we have a more concrete idea of where else this functionality would be useful.
The fix_unused_unsafe transform fixes unused unsafe by removing the
unsafekeyword from unsafe blocks, but it leaves the blocks in place. In many cases it would be more idiomatic to remove the block entirely, preserving the block's contents. So for code likeunsafe { foo(); }, we currently transform that to{ foo(); }, but it would be better to generate justfoo();.There are some edge cases to keep in mind here:
unsafekeyword (which is the current behavior).Drop, we should leave the block in place so as not to alter drop order (this is another place where human or LLM judgement is necessary to decide if the changed drop order matters). This is maybe not a big concern because c2rust-transpile won't generate any code that relies onDrop, but could be a problem if fix_unused_unsafe is used later in the lifting process after other changes have been made. If it's easy to detect this case we should support it, but if drop analysis would be difficult or complex we can probably disregard this case for now.unsafe, but depending on how we implement this logic that might be something that needs to be kept in mind.I also think we should start by making this extra logic a part of fix_unused_unsafe, rather than pulling this out into its own transform. We have a few other transforms generating blocks in different ways, but it's not yet clear that any of them need this extra "remove unnecessary blocks" step. For now let's keep this cleanup logic part of fix_unused_unsafe to keep the use case narrow until we have a more concrete idea of where else this functionality would be useful.