Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing clang-tidy errors/warnings #158

Open
springmeyer opened this issue Aug 18, 2017 · 9 comments
Open

Fixing clang-tidy errors/warnings #158

springmeyer opened this issue Aug 18, 2017 · 9 comments
Assignees

Comments

@springmeyer
Copy link
Contributor

springmeyer commented Aug 18, 2017

I'm attempting to set up clang-tidy to run on codebases using variant. I am consistently seeing most warnings coming from variant. So these need to be addressed here, at the source, by either adding // NOLINT where appropriate or fixing.

@artemp can you please tackle this next week?

Here are the warnings:

``` ./include/mapbox/variant.hpp:344:16: warning: Function call argument is an uninitialized value [clang-analyzer-core.CallAndMessage] return f(unwrapper::apply(v.template get_unchecked())); ^ test/lambda_overload_test.cpp:122:5: note: Calling 'test_match_singleton' test_match_singleton(); ^ test/lambda_overload_test.cpp:87:5: note: Calling 'variant::match' singleton.match([](int) {}); ^ ./include/mapbox/variant.hpp:903:16: note: Calling 'variant::visit' return variant::visit(*this, ::mapbox::util::make_visitor(std::forward(fs)...)); ^ ./include/mapbox/variant.hpp:871:16: note: Calling 'dispatcher::apply' return detail::dispatcher::apply(v, std::forward(f)); ^ ./include/mapbox/variant.hpp:344:18: note: Calling 'unwrapper::apply' return f(unwrapper::apply(v.template get_unchecked())); ^ ./include/mapbox/variant.hpp:344:18: note: Returning from 'unwrapper::apply' return f(unwrapper::apply(v.template get_unchecked())); ^ ./include/mapbox/variant.hpp:344:16: note: Function call argument is an uninitialized value return f(unwrapper::apply(v.template get_unchecked())); ^ 2 warnings generated. ./include/mapbox/recursive_wrapper.hpp:106:36: warning: Undefined or garbage value returned to caller [clang-analyzer-core.uninitialized.UndefReturn] const T* get_pointer() const { return p_; } ^ test/hashable_test.cpp:157:5: note: Calling 'test_recursive_hashable' test_recursive_hashable(); ^ test/hashable_test.cpp:142:10: note: Calling move constructor for 'variant' Tree tree = Node{Node{Empty{}, Empty{}}, Empty{}}; ^ ./include/mapbox/variant.hpp:615:9: note: Calling 'variant_helper::move' helper_type::move(old.type_index, &old.data, &data); ^ ./include/mapbox/variant.hpp:235:9: note: Taking false branch if (old_type_index == sizeof...(Types)) ^ ./include/mapbox/variant.hpp:241:13: note: Calling 'variant_helper::move' variant_helper::move(old_type_index, old_value, new_value); ^ ./include/mapbox/variant.hpp:235:9: note: Taking false branch if (old_type_index == sizeof...(Types)) ^ ./include/mapbox/variant.hpp:241:13: note: Calling 'variant_helper::move' variant_helper::move(old_type_index, old_value, new_value); ^ ./include/mapbox/variant.hpp:241:13: note: Returning from 'variant_helper::move' variant_helper::move(old_type_index, old_value, new_value); ^ ./include/mapbox/variant.hpp:241:13: note: Returning from 'variant_helper::move' variant_helper::move(old_type_index, old_value, new_value); ^ ./include/mapbox/variant.hpp:615:9: note: Returning from 'variant_helper::move' helper_type::move(old.type_index, &old.data, &data); ^ test/hashable_test.cpp:142:10: note: Returning from move constructor for 'variant' Tree tree = Node{Node{Empty{}, Empty{}}, Empty{}}; ^ test/hashable_test.cpp:144:9: note: Calling 'hash::operator()' if (std::hash{}(tree) != ((5 + (5 + (3 + 3))) + 3)) ^ ./include/mapbox/variant.hpp:1022:16: note: Calling 'apply_visitor' return ::mapbox::util::apply_visitor(::mapbox::util::detail::hasher{}, v); ^ ./include/mapbox/variant.hpp:959:12: note: Calling 'variant::visit' return V::visit(v, std::forward(f)); ^ ./include/mapbox/variant.hpp:864:16: note: Calling 'dispatcher::apply_const' return detail::dispatcher::apply_const(v, std::forward(f)); ^ ./include/mapbox/variant.hpp:311:9: note: Taking false branch if (v.template is()) ^ ./include/mapbox/variant.hpp:317:20: note: Calling 'dispatcher::apply_const' return dispatcher::apply_const(v, std::forward(f)); ^ ./include/mapbox/variant.hpp:339:18: note: Calling 'unwrapper::apply_const' return f(unwrapper::apply_const(v.template get_unchecked())); ^ ./include/mapbox/variant.hpp:279:16: note: Calling 'recursive_wrapper::get' return obj.get(); ^ ./include/mapbox/recursive_wrapper.hpp:101:17: note: Calling 'recursive_wrapper::get_pointer' return *get_pointer(); ^ ./include/mapbox/recursive_wrapper.hpp:106:36: note: Undefined or garbage value returned to caller const T* get_pointer() const { return p_; } ^ ./include/mapbox/variant.hpp:555:16: warning: Function call argument is an uninitialized value [clang-analyzer-core.CallAndMessage] return std::hash{}(hashable); ^ test/hashable_test.cpp:153:5: note: Calling 'test_singleton' test_singleton(); ^ test/hashable_test.cpp:17:7: note: Calling move constructor for 'variant' V singleton = 5; ^ ./include/mapbox/variant.hpp:615:9: note: Calling 'variant_helper::move' helper_type::move(old.type_index, &old.data, &data); ^ ./include/mapbox/variant.hpp:235:9: note: Taking false branch if (old_type_index == sizeof...(Types)) ^ ./include/mapbox/variant.hpp:241:13: note: Calling 'variant_helper::move' variant_helper::move(old_type_index, old_value, new_value); ^ ./include/mapbox/variant.hpp:241:13: note: Returning from 'variant_helper::move' variant_helper::move(old_type_index, old_value, new_value); ^ ./include/mapbox/variant.hpp:615:9: note: Returning from 'variant_helper::move' helper_type::move(old.type_index, &old.data, &data); ^ test/hashable_test.cpp:17:7: note: Returning from move constructor for 'variant' V singleton = 5; ^ test/hashable_test.cpp:19:9: note: Calling 'hash::operator()' if (std::hash{}(singleton) != std::hash{}(5)) ^ ./include/mapbox/variant.hpp:1022:16: note: Calling 'apply_visitor' return ::mapbox::util::apply_visitor(::mapbox::util::detail::hasher{}, v); ^ ./include/mapbox/variant.hpp:959:12: note: Calling 'variant::visit' return V::visit(v, std::forward(f)); ^ ./include/mapbox/variant.hpp:864:16: note: Calling 'dispatcher::apply_const' return detail::dispatcher::apply_const(v, std::forward(f)); ^ ./include/mapbox/variant.hpp:339:18: note: Calling 'unwrapper::apply_const' return f(unwrapper::apply_const(v.template get_unchecked())); ^ ./include/mapbox/variant.hpp:339:18: note: Returning from 'unwrapper::apply_const' return f(unwrapper::apply_const(v.template get_unchecked())); ^ ./include/mapbox/variant.hpp:339:18: note: Passing value via 1st parameter 'hashable' return f(unwrapper::apply_const(v.template get_unchecked())); ^ ./include/mapbox/variant.hpp:339:16: note: Calling 'hasher::operator()' return f(unwrapper::apply_const(v.template get_unchecked())); ^ ./include/mapbox/variant.hpp:555:16: note: Function call argument is an uninitialized value return std::hash{}(hashable); ```

Here is how I'm testing:

/cc @daniel-j-h

@artemp artemp self-assigned this Aug 21, 2017
@artemp
Copy link
Contributor

artemp commented Aug 21, 2017

@springmeyer - is your analyser buggy ^ ?? I'm not getting warnings, maybe I'm missing something.

  LLVM (http://llvm.org/):
  LLVM version 5.0.0svn
  Optimized build.
  Default target: x86_64-apple-darwin16.7.0
  Host CPU: ivybridge
./scripts/clang-tidy.sh
* Already installed at /Users/artem/Projects/mapbox/variant/mason_packages/osx-x86_64/clang-tidy/4.0.1
* Linking /Users/artem/Projects/mapbox/variant/mason_packages/osx-x86_64/clang-tidy/4.0.1
* Links will be inside /Users/artem/Projects/mapbox/variant/mason_packages/.link/
* Using bash fallback for symlinking (install lndir for faster symlinking)
* Done linking /Users/artem/Projects/mapbox/variant/mason_packages/osx-x86_64/clang-tidy/4.0.1
Enabled checks:
    boost-use-to-string
    cert-dcl03-c
    cert-dcl50-cpp
    cert-dcl54-cpp
    cert-dcl59-cpp
    cert-env33-c
    cert-err09-cpp
    cert-err34-c
    cert-err52-cpp
    cert-err58-cpp
    cert-err60-cpp
    cert-err61-cpp
    cert-fio38-c
    cert-flp30-c
    cert-msc30-c
    cert-msc50-cpp
    cert-oop11-cpp
    clang-analyzer-apiModeling.google.GTest
    clang-analyzer-core.CallAndMessage
    clang-analyzer-core.DivideZero
    clang-analyzer-core.DynamicTypePropagation
    clang-analyzer-core.NonNullParamChecker
    clang-analyzer-core.NullDereference
    clang-analyzer-core.StackAddressEscape
    clang-analyzer-core.UndefinedBinaryOperatorResult
    clang-analyzer-core.VLASize
    clang-analyzer-core.builtin.BuiltinFunctions
    clang-analyzer-core.builtin.NoReturnFunctions
    clang-analyzer-core.uninitialized.ArraySubscript
    clang-analyzer-core.uninitialized.Assign
    clang-analyzer-core.uninitialized.Branch
    clang-analyzer-core.uninitialized.CapturedBlockVariable
    clang-analyzer-core.uninitialized.UndefReturn
    clang-analyzer-cplusplus.NewDelete
    clang-analyzer-cplusplus.NewDeleteLeaks
    clang-analyzer-cplusplus.SelfAssignment
    clang-analyzer-deadcode.DeadStores
    clang-analyzer-llvm.Conventions
    clang-analyzer-nullability.NullPassedToNonnull
    clang-analyzer-nullability.NullReturnedFromNonnull
    clang-analyzer-nullability.NullableDereferenced
    clang-analyzer-nullability.NullablePassedToNonnull
    clang-analyzer-nullability.NullableReturnedFromNonnull
    clang-analyzer-optin.cplusplus.VirtualCall
    clang-analyzer-optin.mpi.MPI-Checker
    clang-analyzer-optin.osx.cocoa.localizability.EmptyLocalizationContextChecker
    clang-analyzer-optin.osx.cocoa.localizability.NonLocalizedStringChecker
    clang-analyzer-optin.performance.Padding
    clang-analyzer-osx.API
    clang-analyzer-osx.NumberObjectConversion
    clang-analyzer-osx.ObjCProperty
    clang-analyzer-osx.SecKeychainAPI
    clang-analyzer-osx.cocoa.AtSync
    clang-analyzer-osx.cocoa.ClassRelease
    clang-analyzer-osx.cocoa.Dealloc
    clang-analyzer-osx.cocoa.IncompatibleMethodTypes
    clang-analyzer-osx.cocoa.Loops
    clang-analyzer-osx.cocoa.MissingSuperCall
    clang-analyzer-osx.cocoa.NSAutoreleasePool
    clang-analyzer-osx.cocoa.NSError
    clang-analyzer-osx.cocoa.NilArg
    clang-analyzer-osx.cocoa.NonNilReturnValue
    clang-analyzer-osx.cocoa.ObjCGenerics
    clang-analyzer-osx.cocoa.RetainCount
    clang-analyzer-osx.cocoa.SelfInit
    clang-analyzer-osx.cocoa.SuperDealloc
    clang-analyzer-osx.cocoa.UnusedIvars
    clang-analyzer-osx.cocoa.VariadicMethodTypes
    clang-analyzer-osx.coreFoundation.CFError
    clang-analyzer-osx.coreFoundation.CFNumber
    clang-analyzer-osx.coreFoundation.CFRetainRelease
    clang-analyzer-osx.coreFoundation.containers.OutOfBounds
    clang-analyzer-osx.coreFoundation.containers.PointerSizedValues
    clang-analyzer-security.FloatLoopCounter
    clang-analyzer-security.insecureAPI.UncheckedReturn
    clang-analyzer-security.insecureAPI.getpw
    clang-analyzer-security.insecureAPI.gets
    clang-analyzer-security.insecureAPI.mkstemp
    clang-analyzer-security.insecureAPI.mktemp
    clang-analyzer-security.insecureAPI.rand
    clang-analyzer-security.insecureAPI.strcpy
    clang-analyzer-security.insecureAPI.vfork
    clang-analyzer-unix.API
    clang-analyzer-unix.Malloc
    clang-analyzer-unix.MallocSizeof
    clang-analyzer-unix.MismatchedDeallocator
    clang-analyzer-unix.StdCLibraryFunctions
    clang-analyzer-unix.Vfork
    clang-analyzer-unix.cstring.BadSizeArg
    clang-analyzer-unix.cstring.NullArg
    cppcoreguidelines-c-copy-assignment-signature
    cppcoreguidelines-interfaces-global-init
    cppcoreguidelines-no-malloc
    cppcoreguidelines-pro-bounds-array-to-pointer-decay
    cppcoreguidelines-pro-bounds-constant-array-index
    cppcoreguidelines-pro-bounds-pointer-arithmetic
    cppcoreguidelines-pro-type-const-cast
    cppcoreguidelines-pro-type-cstyle-cast
    cppcoreguidelines-pro-type-member-init
    cppcoreguidelines-pro-type-reinterpret-cast
    cppcoreguidelines-pro-type-static-cast-downcast
    cppcoreguidelines-pro-type-union-access
    cppcoreguidelines-pro-type-vararg
    cppcoreguidelines-slicing
    cppcoreguidelines-special-member-functions
    google-build-explicit-make-pair
    google-build-namespaces
    google-build-using-namespace
    google-default-arguments
    google-explicit-constructor
    google-global-names-in-headers
    google-readability-braces-around-statements
    google-readability-casting
    google-readability-function-size
    google-readability-namespace-comments
    google-readability-redundant-smartptr-get
    google-readability-todo
    google-runtime-int
    google-runtime-member-string-references
    google-runtime-memset
    google-runtime-operator
    google-runtime-references
    llvm-header-guard
    llvm-include-order
    llvm-namespace-comment
    llvm-twine-local
    misc-argument-comment
    misc-assert-side-effect
    misc-bool-pointer-implicit-conversion
    misc-dangling-handle
    misc-definitions-in-headers
    misc-fold-init-type
    misc-forward-declaration-namespace
    misc-inaccurate-erase
    misc-incorrect-roundings
    misc-inefficient-algorithm
    misc-macro-parentheses
    misc-macro-repeated-side-effects
    misc-misplaced-const
    misc-misplaced-widening-cast
    misc-move-const-arg
    misc-move-constructor-init
    misc-move-forwarding-reference
    misc-multiple-statement-macro
    misc-new-delete-overloads
    misc-noexcept-move-constructor
    misc-non-copyable-objects
    misc-redundant-expression
    misc-sizeof-container
    misc-sizeof-expression
    misc-static-assert
    misc-string-compare
    misc-string-constructor
    misc-string-integer-assignment
    misc-string-literal-with-embedded-nul
    misc-suspicious-enum-usage
    misc-suspicious-missing-comma
    misc-suspicious-semicolon
    misc-suspicious-string-compare
    misc-swapped-arguments
    misc-throw-by-value-catch-by-reference
    misc-unconventional-assign-operator
    misc-undelegated-constructor
    misc-uniqueptr-reset-release
    misc-unused-alias-decls
    misc-unused-parameters
    misc-unused-raii
    misc-unused-using-decls
    misc-use-after-move
    misc-virtual-near-miss
    modernize-avoid-bind
    modernize-deprecated-headers
    modernize-loop-convert
    modernize-make-shared
    modernize-make-unique
    modernize-pass-by-value
    modernize-raw-string-literal
    modernize-redundant-void-arg
    modernize-replace-auto-ptr
    modernize-shrink-to-fit
    modernize-use-auto
    modernize-use-bool-literals
    modernize-use-default-member-init
    modernize-use-emplace
    modernize-use-equals-default
    modernize-use-equals-delete
    modernize-use-nullptr
    modernize-use-override
    modernize-use-transparent-functors
    modernize-use-using
    mpi-buffer-deref
    mpi-type-mismatch
    performance-faster-string-find
    performance-for-range-copy
    performance-implicit-cast-in-loop
    performance-inefficient-string-concatenation
    performance-type-promotion-in-math-fn
    performance-unnecessary-copy-initialization
    performance-unnecessary-value-param
    readability-avoid-const-params-in-decls
    readability-braces-around-statements
    readability-container-size-empty
    readability-delete-null-pointer
    readability-deleted-default
    readability-else-after-return
    readability-function-size
    readability-identifier-naming
    readability-implicit-bool-cast
    readability-inconsistent-declaration-parameter-name
    readability-misplaced-array-index
    readability-named-parameter
    readability-non-const-parameter
    readability-redundant-control-flow
    readability-redundant-declaration
    readability-redundant-function-ptr-dereference
    readability-redundant-member-init
    readability-redundant-smartptr-get
    readability-redundant-string-cstr
    readability-redundant-string-init
    readability-simplify-boolean-expr
    readability-static-definition-in-anonymous-namespace
    readability-uniqueptr-delete-release


clang-tidy -header-filter=^/Users/artem/Projects/mapbox/variant/build/.* -export-fixes /var/folders/83/rt7rty5j1v3gj5kpymxsq_0w0000gn/T/tmpk73w1f/tmpw0Mi8S.yaml -p=/Users/artem/Projects/mapbox/variant/build /Users/artem/Projects/mapbox/variant/test/bench_variant.cpp
Applying fixes ...

@springmeyer
Copy link
Contributor Author

@artemp your output indicates that only bench_variant.cpp is being checked. Not sure why that is. Mine is checking more .cpp files locally. Can you share the build/compile_commands.json that is on your machine in a gist? Also, for reference, here is my output https://gist.github.com/springmeyer/86c27ec500c81286bd124128b06f6bd8

@springmeyer
Copy link
Contributor Author

@artemp Thinking more. The problem is likely that my script to produce compile_commands.json is brittle. It has some minimal regex to try to detect which lines (coming from make) are compile commands:

TOKEN_DENOTING_COMPILED_FILE='c++'

@artemp
Copy link
Contributor

artemp commented Aug 21, 2017

    {
        "directory": "/Users/artem/Projects/mapbox/variant",
        "command": "/Users/artem/Projects/mapbox/variant/.toolchain/bin/clang++ -o out/bench-variant test/bench_variant.cpp -I./include -isystem test/include -s\
td=c++11 -Werror -Wall -Wextra -pedantic -Wformat=2 -Wsign-conversion -Wshadow -Wunused-parameter -O3 -DNDEBUG -march=native -DSINGLE_THREADED -fvisibility-inli\
nes-hidden -fvisibility=hidden  -stdlib=libc++ -mmacosx-version-min=10.7  -isystem /Users/artem/Projects/mapbox/variant/mason_packages/headers/boost/1.62.0/incl\
ude/",
        "file": "/Users/artem/Projects/mapbox/variant/test/bench_variant.cpp"
    }
]

^ yep, looks rather minimal

@kkaefer
Copy link
Member

kkaefer commented Apr 3, 2019

This is still an issue that prevents us from running clang-tidy on a full codebase. Here's the clang-tidy 7.0.0 message that I'm getting:

``` /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:504:20: error: The right operand of '==' is a garbage value [clang-analyzer-core.UndefinedBinaryOperatorResult,-warnings-as-errors] return lhs == rhs; ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:323:9: note: Assuming the condition is false if (it == properties.end()) { ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:323:5: note: Taking false branch if (it == properties.end()) { ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:330:9: note: Assuming 'property' is not equal to FillExtrusionOpacity if (property == Property::FillExtrusionOpacity) { ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:330:5: note: Taking false branch if (property == Property::FillExtrusionOpacity) { ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:342:9: note: Assuming 'property' is not equal to FillExtrusionColor if (property == Property::FillExtrusionColor) { ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:342:5: note: Taking false branch if (property == Property::FillExtrusionColor) { ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:354:9: note: Assuming 'property' is not equal to FillExtrusionTranslate if (property == Property::FillExtrusionTranslate) { ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:354:5: note: Taking false branch if (property == Property::FillExtrusionTranslate) { ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:366:9: note: Assuming 'property' is not equal to FillExtrusionTranslateAnchor if (property == Property::FillExtrusionTranslateAnchor) { ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:366:5: note: Taking false branch if (property == Property::FillExtrusionTranslateAnchor) { ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:378:9: note: Assuming 'property' is not equal to FillExtrusionPattern if (property == Property::FillExtrusionPattern) { ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:378:5: note: Taking false branch if (property == Property::FillExtrusionPattern) { ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:390:9: note: Assuming 'property' is equal to FillExtrusionHeight if (property == Property::FillExtrusionHeight || property == Property::FillExtrusionBase) { ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:390:51: note: Left side of '||' is true if (property == Property::FillExtrusionHeight || property == Property::FillExtrusionBase) { ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:393:13: note: Assuming the condition is false if (!typedValue) { ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:393:9: note: Taking false branch if (!typedValue) { ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:397:9: note: Taking true branch if (property == Property::FillExtrusionHeight) { ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:398:13: note: Calling 'FillExtrusionLayer::setFillExtrusionHeight' setFillExtrusionHeight(*typedValue); ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:209:18: note: Calling 'FillExtrusionLayer::getFillExtrusionHeight' if (value == getFillExtrusionHeight()) ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:205:12: note: Calling implicit copy constructor for 'PropertyValue' return impl().paint.template get().value; ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:205:12: note: Calling copy constructor for 'variant>' /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:595:9: note: Calling 'variant_helper::copy' helper_type::copy(old.type_index, &old.data, &data); ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:234:9: note: Taking false branch if (old_type_index == sizeof...(Types)) ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:240:13: note: Calling 'variant_helper::copy' variant_helper::copy(old_type_index, old_value, new_value); ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:234:9: note: Taking false branch if (old_type_index == sizeof...(Types)) ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:240:13: note: Calling 'variant_helper::copy' variant_helper::copy(old_type_index, old_value, new_value); ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:234:9: note: Taking false branch if (old_type_index == sizeof...(Types)) ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:240:13: note: Calling 'variant_helper::copy' variant_helper::copy(old_type_index, old_value, new_value); ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:250:77: note: Returning without writing to '' VARIANT_INLINE static void copy(const std::size_t, const void*, void*) {} ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:240:13: note: Returning from 'variant_helper::copy' variant_helper::copy(old_type_index, old_value, new_value); ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:242:5: note: Returning without writing to 'new_value' } ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:240:13: note: Returning from 'variant_helper::copy' variant_helper::copy(old_type_index, old_value, new_value); ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:242:5: note: Returning without writing to 'new_value' } ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:240:13: note: Returning from 'variant_helper::copy' variant_helper::copy(old_type_index, old_value, new_value); ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:242:5: note: Returning without writing to 'new_value' } ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:595:9: note: Returning from 'variant_helper::copy' helper_type::copy(old.type_index, &old.data, &data); ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:205:12: note: Returning from copy constructor for 'variant>' return impl().paint.template get().value; ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:205:12: note: Returning from copy constructor for 'PropertyValue' /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:209:18: note: Returning from 'FillExtrusionLayer::getFillExtrusionHeight' if (value == getFillExtrusionHeight()) ^ /Users/kkaefer/Code/gl/native/src/mbgl/style/layers/fill_extrusion_layer.cpp:209:9: note: Calling 'operator==' if (value == getFillExtrusionHeight()) ^ /Users/kkaefer/Code/gl/native/include/mbgl/style/property_value.hpp:22:16: note: Calling 'variant::operator==' return lhs.value == rhs.value; ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:902:9: note: Taking false branch if (this->which() != rhs.which()) ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:907:16: note: Calling 'variant::visit' return visit(rhs, visitor); ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:850:16: note: Calling 'dispatcher::apply_const' return detail::dispatcher::apply_const(v, std::forward(f)); ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:298:9: note: Taking false branch if (v.template is()) ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:304:20: note: Calling 'dispatcher::apply_const' return dispatcher::apply_const(v, std::forward(f)); ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:298:9: note: Taking true branch if (v.template is()) ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:300:20: note: Calling 'comparer::operator()' return f(unwrapper::apply_const(v.template get_unchecked())); ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:529:36: note: Passing value via 2nd parameter 'rhs' return Comp()(lhs_content, rhs_content); ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:529:16: note: Calling 'equal_comp::operator()' return Comp()(lhs_content, rhs_content); ^ /Users/kkaefer/Code/gl/native/vendor/variant/include/mapbox/variant.hpp:504:20: note: The right operand of '==' is a garbage value return lhs == rhs; ^ ```

@kkaefer
Copy link
Member

kkaefer commented Apr 3, 2019

Here's a minimal reproduction:

#include <mapbox/variant.hpp>

class Empty {};
inline bool operator==(const Empty&, const Empty&) { return true; }

int main() {
    using type = mapbox::util::variant<Empty, int>;
    type a;
    type b = a;
    (void)(a == b);
}

I'm invoking clang-tidy like this:

clang-tidy -checks=clang-analyzer-core.UndefinedBinaryOperatorResult variant.cpp -- -std=c++14 -I<path-to-variant>

and get this output:

``` vendor/variant/include/mapbox/variant.hpp:504:20: error: The right operand of '==' is a garbage value [clang-analyzer-core.UndefinedBinaryOperatorResult,-warnings-as-errors] return lhs == rhs; ^ /Users/kkaefer/Code/gl/native/variant.cpp:9:14: note: Calling copy constructor for 'variant' type b = a; ^ vendor/variant/include/mapbox/variant.hpp:595:9: note: Calling 'variant_helper::copy' helper_type::copy(old.type_index, &old.data, &data); ^ vendor/variant/include/mapbox/variant.hpp:234:9: note: Taking false branch if (old_type_index == sizeof...(Types)) ^ vendor/variant/include/mapbox/variant.hpp:240:13: note: Calling 'variant_helper::copy' variant_helper::copy(old_type_index, old_value, new_value); ^ vendor/variant/include/mapbox/variant.hpp:234:9: note: Taking false branch if (old_type_index == sizeof...(Types)) ^ vendor/variant/include/mapbox/variant.hpp:240:13: note: Calling 'variant_helper::copy' variant_helper::copy(old_type_index, old_value, new_value); ^ vendor/variant/include/mapbox/variant.hpp:250:77: note: Returning without writing to '' VARIANT_INLINE static void copy(const std::size_t, const void*, void*) {} ^ vendor/variant/include/mapbox/variant.hpp:240:13: note: Returning from 'variant_helper::copy' variant_helper::copy(old_type_index, old_value, new_value); ^ vendor/variant/include/mapbox/variant.hpp:242:5: note: Returning without writing to 'new_value' } ^ vendor/variant/include/mapbox/variant.hpp:240:13: note: Returning from 'variant_helper::copy' variant_helper::copy(old_type_index, old_value, new_value); ^ vendor/variant/include/mapbox/variant.hpp:242:5: note: Returning without writing to 'new_value' } ^ vendor/variant/include/mapbox/variant.hpp:595:9: note: Returning from 'variant_helper::copy' helper_type::copy(old.type_index, &old.data, &data); ^ /Users/kkaefer/Code/gl/native/variant.cpp:9:14: note: Returning from copy constructor for 'variant' type b = a; ^ /Users/kkaefer/Code/gl/native/variant.cpp:10:12: note: Calling 'variant::operator==' (void)(a == b); ^ vendor/variant/include/mapbox/variant.hpp:902:9: note: Taking false branch if (this->which() != rhs.which()) ^ vendor/variant/include/mapbox/variant.hpp:907:16: note: Calling 'variant::visit' return visit(rhs, visitor); ^ vendor/variant/include/mapbox/variant.hpp:850:16: note: Calling 'dispatcher::apply_const' return detail::dispatcher::apply_const(v, std::forward(f)); ^ vendor/variant/include/mapbox/variant.hpp:298:9: note: Taking false branch if (v.template is()) ^ vendor/variant/include/mapbox/variant.hpp:304:20: note: Calling 'dispatcher::apply_const' return dispatcher::apply_const(v, std::forward(f)); ^ vendor/variant/include/mapbox/variant.hpp:326:16: note: Calling 'comparer::operator()' return f(unwrapper::apply_const(v.template get_unchecked())); ^ vendor/variant/include/mapbox/variant.hpp:529:36: note: Passing value via 2nd parameter 'rhs' return Comp()(lhs_content, rhs_content); ^ vendor/variant/include/mapbox/variant.hpp:529:16: note: Calling 'equal_comp::operator()' return Comp()(lhs_content, rhs_content); ^ vendor/variant/include/mapbox/variant.hpp:504:20: note: The right operand of '==' is a garbage value return lhs == rhs; ^ ```

Some observations:

  • Invoking the copy constructor (type b = a) is vital, it doesn't reproduce without it
  • It only works with non-scalar types (class Empty)

@artemp
Copy link
Contributor

artemp commented Apr 3, 2019

@kkaefer I'll take a look, thanks.

@kkaefer
Copy link
Member

kkaefer commented Apr 3, 2019

More observations:

  • adding non-defaulted constructor (Empty() {}) makes the UB go away, but adding a defaulted constructor (Empty() = default) doesn't

@artemp
Copy link
Contributor

artemp commented Apr 3, 2019

quick workaround :

struct alignas(1) Empty
{
    std::uint8_t val = 1u;
    Empty() {};
};

I'll see if is_empty<T> can be used to add overloads for empty types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants