After some effort, I convinced both the clang compiler and clang-tidy (static analyzer) to warn of a use-after-move situation. (see https://stackoverflow.com/a/74250567/225186)
int main(int, char**) {
a_class a;
auto b = std::move(a);
a.f(); // warns here, for example "invalid invocation of method 'f' on object 'a' while it is in the 'consumed' state [-Werror,-Wconsumed]"
}
However, if I make the variable global (or static or lazily static), there is no more warning.
a_class a;
int main(int, char**) {
auto b = std::move(a);
a.f(); // no warns here!
}
See here: https://godbolt.org/z/3zW61qYfY
Is it possible to generalize some sort of use-after-move detection at compile-time for global variables? Or is it impossible, even in principle?
Note: please don't make this discussion about global object (I know it is a bad idea) or about the legality of using moved objects (I know some class are designed for that to be ok). The question is technical, about the compiler and tools to detect a certain bug-prone pattern in the program.
Full working code, compile with clang ... -Wconsumed -Werror -std=c++11
or use clang-tidy
.
The clang annotation (extensions) help the compiler detect the patterns.
#include<cassert>
#include<memory>
class [[clang::consumable(unconsumed)]] a_class {
std::unique_ptr<int> p_;
public:
[[clang::callable_when(unconsumed)]]
void f() {}
// private: [[clang::set_typestate(consumed)]] void invalidate() {} // not needed but good to know
};
a_class a;
int main(int, char**) {
// a_class a;
auto b = std::move(a);
a.f(); // global doesn't warn here
}
Most of the information I could find about this clang extension is from here: Andrea Kling's blog https://awesomekling.github.io/Catching-use-after-move-bugs-with-Clang-consumed-annotations/