i use implicit call hierarchy and state variables to control program flow.
so runprog runs the main game menu (continue, tutorial, new, load, help, quit) which in turn calls rungame (the main game loop). so those "state changes" are already handled implicitly by call order. but the main game loop can be in FPS mode, or SIMs-style do-an-action mode, which is indicated by a state variable. FPS and action modes each have their own render, input, and update routines. but the popup in-game menu for example is simply called by the input handler, its not a separate "state".
i tend to use states when something needs to run in more than one mode, with different input, render, and/or update methods for its various modes.
but when the state transitions (control flow) are simply "call subroutine and return control to caller when done", implicit call hierarchy handles that automatically without the need for state variables. same idea for call sub1, then sub2, then sub3. call order implicitly defines the state transitions (control flow) from sub1 to sub2 to sub3.
a good acid test might be "is control flow variable?" if yes, then a state variable may be called for, if not, odds are its overkill.
note that almost any program could be written entirely as states - its a general method for abstract handing of control flow in a program. but just the same way that everything in a game should not necessarily be an object, everything in a game should not necessarily be a "game state".
when i think of "game state", i think of total war's strategic map mode, vs it's tactical battle engine. now that's an example of a game with two true "game states". or like FPSRPG mode and TheSIMs mode in Caveman v3.0.
multiple simultaneous state variables (a variation on hierarchical finite state machines) can be very useful for things like the multi-state editing in unity. I use them a lot in AI programming. the advantage is that you can be in more than one state at once - i'm sitting _and_ talking, etc. or i'm in FPS mode, and location = cave | cavern | outside | upatree (all of which have different render, input, and/or update methods).