The following code does not expected to work, I think, but it works without 'volatile'.
Anything changed or I missed something ?
I am using Arduino program 1.8.9.
I would expect it to work just fine in this case.
The code you have is too simple to see any difference with the variable state.
The loop() function is called and then returns.
Each time loop() is called it must refetch state from memory into a register(s) in order to use it so there is no issue as it behaves just like volatile for that simple code.
i.e. the value of variables are not cached in registers between calls to a function so they must be refectched from RAM each time the function is called.
If you did something like have a loop inside the loop() function that tested and waited for state to change, then there would be an issue since the compiler was not told that code outside the local scope could be modifying the value of state.