clang-tidy对boost::variant报未初始化误报的排查咨询
This looks like a false positive from the Clang Static Analyzer (the engine behind clang-tidy's core.uninitialized.Assign check), not an issue with your code or Boost. Let's break down what's happening:
Your Code Context
First, let's recap your minimal example for clarity:
#include <boost/variant.hpp> class Size { public: Size() = default; Size(const Size &sz) : width(sz.width) {} // Custom copy ctor matching cv::Size's behavior int width{0}; }; struct B { Size size; }; struct A { Size size; uint32_t id{0}; // Explicit in-class initializer for 'id' }; int main() { using T = boost::variant<A, B>; T config = B(); // Only constructing a B instance in the variant }
Why the False Positive Happens
The analyzer's error trace shows it incorrectly thinks the implicit move constructor of A is being called during the variant's initialization—but your code never constructs an A!
The root cause stems from two factors working together:
- Boost.Variant's internal implementation: The variant type reserves storage for all possible alternative types (both
AandBhere). The analyzer's path exploration gets confused by the template-heavy logic in Boost.Variant and mistakenly follows a code path that assumesAis being constructed. - Custom copy constructor for
Size: When you replaceSize's copy constructor with= default;, the analyzer can easily track initialization flows through trivial types. The custom copy constructor seems to throw off the analyzer's data-flow analysis, leading it to incorrectly concludeA::idis uninitialized (even though it has an explicit in-class initializer).
How to Fix/Work Around It
Since you can't modify cv::Size (the real-world equivalent of your Size class), here are practical solutions:
Suppress the warning locally: Add a comment to tell clang-tidy to ignore this specific false positive. For example, mark the
Astruct definition:struct A { Size size; uint32_t id{0}; }; // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.Assign)Or use a file-level suppression if this pattern appears multiple times.
Upgrade your Clang/LLVM tools: Your versions are quite old (commits from several years ago). Newer releases of clang-tools-extra have fixed many analyzer false positives related to template-heavy libraries like Boost.
Explicitly define
A's constructors: Adding an explicit default constructor can help the analyzer recognize the initialization is intentional:struct A { A() = default; Size size; uint32_t id{0}; };
Full Error Log (For Reference)
test_variant.cc:15:8: warning: Value assigned to field 'id' in implicit constructor is garbage or undefined [clang-analyzer-core.uninitialized.Assign] struct A { ^ test_variant.cc:22:5: note: Calling move constructor for 'variant' T config = B(); ^ libraries/boost/include/boost/variant/variant.hpp:1880:9: note: Calling 'variant::internal_apply_visitor' operand.internal_apply_visitor(visitor); ^ libraries/boost/include/boost/variant/variant.hpp:2466:16: note: Calling 'variant::internal_apply_visitor_impl' return internal_apply_visitor_impl( ^ libraries/boost/include/boost/variant/variant.hpp:2452:16: note: Calling 'visitation_impl' return detail::variant::visitation_impl( ^ libraries/boost/include/boost/variant/detail/visitation_impl.hpp:225:5: note: Control jumps to 'case 0:' at line 238 switch (logical_which) ^ libraries/boost/include/boost/variant/detail/visitation_impl.hpp:240:11: note: Calling 'visitation_impl_invoke' , BOOST_VARIANT_AUX_APPLY_VISITOR_STEP_CASE ^ libraries/boost/include/boost/preprocessor/repetition/repeat.hpp:29:26: note: expanded from macro 'BOOST_PP_REPEAT' # define BOOST_PP_REPEAT BOOST_PP_CAT(BOOST_PP_REPEAT_, BOOST_PP_AUTO_REC(BOOST_PP_REPEAT_P, 4)) ^ libraries/boost/include/boost/preprocessor/cat.hpp:22:32: note: expanded from macro 'BOOST_PP_CAT' # define BOOST_PP_CAT(a, b) BOOST_PP_CAT_I(a, b) ^ libraries/boost/include/boost/preprocessor/cat.hpp:29:34: note: expanded from macro 'BOOST_PP_CAT_I' # define BOOST_PP_CAT_I(a, b) a ## b ^ note: (skipping 21 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all) libraries/boost/include/boost/preprocessor/repetition/repeat.hpp:53:56: note: expanded from macro 'BOOST_PP_REPEAT_1_2' # define BOOST_PP_REPEAT_1_2(m, d) BOOST_PP_REPEAT_1_1(m, d) m(2, 1, d) ^ libraries/boost/include/boost/preprocessor/repetition/repeat.hpp:52:36: note: expanded from macro 'BOOST_PP_REPEAT_1_1' # define BOOST_PP_REPEAT_1_1(m, d) m(2, 0, d) ^ libraries/boost/include/boost/variant/detail/visitation_impl.hpp:231:16: note: expanded from macro 'BOOST_VARIANT_AUX_APPLY_VISITOR_STEP_CASE' return (visitation_impl_invoke)( \ ^ libraries/boost/include/boost/variant/detail/visitation_impl.hpp:154:12: note: Calling 'visitation_impl_invoke_impl' return (visitation_impl_invoke_impl)( ^ libraries/boost/include/boost/variant/detail/visitation_impl.hpp:112:12: note: Calling 'move_into::internal_visit' return visitor.internal_visit( ^ libraries/boost/include/boost/variant/variant.hpp:507:23: note: Calling implicit move constructor for 'A' new(storage_) T(::boost::detail::variant::move(operand)); ^ test_variant.cc:15:8: note: Value assigned to field 'id' in implicit constructor is garbage or undefined struct A {
内容的提问来源于stack exchange,提问作者user823255

