June 08
I was working on https://github.com/dlang/dmd/pull/8319 when I encountered the following problem.

I want to add the `deprecated` attribute to enum members.  However, in order for the deprecation message to appear for the location of where the enum is used and not where it is declared, I need to add the `checkDeprecated` message to the `expressionSemantic(VarExp)`, actually the `visit(VarExp)` implementation.

Unfortunately that results in the message being printed 3 times for each usage of the enum member because `visit(VarExp)` is being called redundantly.  The `DSymbol` class has a `PASS semanticrun` field to indicate whether or not semantic has already been run.  The `Expression` class does not.  I seem some classes checking `Expression.type` to determine if semantic has been run or not, but I don't know if that's uniformly valid.

If I add a check to see if semantic has already been run, then all hell breaks loose and a huge cascade of failures ensues, which reveals a larger problem:  Instead of using `Expression`'s constructor to initialize the object and then rely on `expressionSemantic` and the object's method calls to process the constructed object's data, users are manipulating the object's fields directly, leaving the object, at any given point in time, in a potentially invalid or incomplete state.  There's no encapsulation.

How can I fix this?