The only way would be what you suggest:

- extract the attributes from the internal i
- store them in a specially-crafted struct
- return that
- in the external code, catch the returned struct
- extract the artificially stored attributes
- generate a new value with the same attributes.

You can perhaps encapsulate this in a mixin?

That would mean two mixins, one internal and one external. Plus, that means every function where I want to propagate UDA has to be crafted exactly for this need.

This is a drag. It seems natural to me that

int foo(int i) { return i;}

should forward i attributes. But maybe I need a shift my way to think about attributes. They are attached to declarations, not values...

That's too bad, because declaring UDA is simple, and receiving them with arguments is easy also. There is a fundamental imbalance in having having propagating attributes through functions so difficult.