A tag denotes a specific point in development history. It should not change, at all. Ideally, build should be reproducible. This means checking out a tag and building it should – bit-for-bit – produce the exact same artifact, every time. Changing the versions of the build tools involved will alter that. Thats mostly not even desired.
But there is an alternative: branches.
You can have a stable branch containing the current, stable production ready release of your software, a development branch that you are working on, and several branches for major versions, e.g:
If you ever need to change the tooling with which version 1.0 is built, you check out the release-1.0.x branch. Lets say its HEAD is also currently tagged v1.0.3.
If you update the build tooling and make sure it works, e.g. it build on a new OS version, then you tag that version 1.0.4 and release it as such, with a changelog denoting that these are compatibility changes for that new OS version. If you just change tooling versions, you’d put “maintenance changes” or something alike in the changelog.
“Updating” a tag seems ill-advised, as tags represent specific points in the development of the software, and thus shouldn’t just change or jump around.
With the aforementioned setup it is also easy to backport changes, e.g. security fixes, to older versions of your software.