RobotLocomotion / drake

Model-based design and verification for robotics.
https://drake.mit.edu
Other
3.23k stars 1.25k forks source link

Comparison operators in TypeSafeIndex trigger GCC 9 sign-compare warning #13482

Closed jamiesnape closed 4 years ago

jamiesnape commented 4 years ago

For example, from https://drake-jenkins.csail.mit.edu/job/linux-focal-unprovisioned-gcc-bazel-experimental-debug/1/:

ERROR: manipulation/kuka_iiwa/BUILD.bazel:35:1: Couldn't build file manipulation/kuka_iiwa/_objs/iiwa_command_receiver/iiwa_command_receiver.pic.o: C++ compilation of rule '//manipulation/kuka_iiwa:iiwa_command_receiver' failed (Exit 1) gcc failed: error executing command /usr/bin/gcc -U_FORTIFY_SOURCE -fstack-protector -Wall -Wunused-but-set-parameter -Wno-free-nonheap-object -fno-omit-frame-pointer -g '-std=c++0x' -MD -MF ... (remaining 205 argument(s) skipped)
In file included from bazel-out/k8-dbg/bin/systems/framework/_virtual_includes/framework_common/drake/systems/framework/framework_common.h:13,
                 from bazel-out/k8-dbg/bin/systems/framework/_virtual_includes/continuous_state/drake/systems/framework/continuous_state.h:15,
                 from bazel-out/k8-dbg/bin/systems/framework/_virtual_includes/leaf_system/drake/systems/framework/leaf_system.h:22,
                 from bazel-out/k8-dbg/bin/manipulation/kuka_iiwa/_virtual_includes/iiwa_command_receiver/drake/manipulation/kuka_iiwa/iiwa_command_receiver.h:12,
                 from manipulation/kuka_iiwa/iiwa_command_receiver.cc:1:
bazel-out/k8-dbg/bin/common/_virtual_includes/type_safe_index/drake/common/type_safe_index.h: In instantiation of 'typename std::enable_if<(std::is_integral<U>::value && std::is_unsigned<U>::value), bool>::type drake::TypeSafeIndex<Tag>::operator==(const U&) const [with U = long unsigned int; Tag = drake::systems::DiscreteStateTag; typename std::enable_if<(std::is_integral<U>::value && std::is_unsigned<U>::value), bool>::type = bool]':
bazel-out/k8-dbg/bin/systems/framework/_virtual_includes/system_base/drake/systems/framework/system_base.h:905:5:   required from here
bazel-out/k8-dbg/bin/common/_virtual_includes/type_safe_index/drake/common/type_safe_index.h:351:18: error: comparison of integer expressions of different signedness: 'const long unsigned int' and 'int' [-Werror=sign-compare]
  351 |     return value <= std::numeric_limits<int>::max() &&
      |            ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bazel-out/k8-dbg/bin/common/_virtual_includes/type_safe_index/drake/common/type_safe_index.h: In instantiation of 'typename std::enable_if<(std::is_integral<U>::value && std::is_unsigned<U>::value), bool>::type drake::TypeSafeIndex<Tag>::operator==(const U&) const [with U = long unsigned int; Tag = drake::systems::AbstractStateTag; typename std::enable_if<(std::is_integral<U>::value && std::is_unsigned<U>::value), bool>::type = bool]':
bazel-out/k8-dbg/bin/systems/framework/_virtual_includes/system_base/drake/systems/framework/system_base.h:919:5:   required from here
bazel-out/k8-dbg/bin/common/_virtual_includes/type_safe_index/drake/common/type_safe_index.h:351:18: error: comparison of integer expressions of different signedness: 'const long unsigned int' and 'int' [-Werror=sign-compare]
bazel-out/k8-dbg/bin/common/_virtual_includes/type_safe_index/drake/common/type_safe_index.h: In instantiation of 'typename std::enable_if<(std::is_integral<U>::value && std::is_unsigned<U>::value), bool>::type drake::TypeSafeIndex<Tag>::operator==(const U&) const [with U = long unsigned int; Tag = drake::systems::NumericParameterTag; typename std::enable_if<(std::is_integral<U>::value && std::is_unsigned<U>::value), bool>::type = bool]':
bazel-out/k8-dbg/bin/systems/framework/_virtual_includes/system_base/drake/systems/framework/system_base.h:931:5:   required from here
bazel-out/k8-dbg/bin/common/_virtual_includes/type_safe_index/drake/common/type_safe_index.h:351:18: error: comparison of integer expressions of different signedness: 'const long unsigned int' and 'int' [-Werror=sign-compare]
bazel-out/k8-dbg/bin/common/_virtual_includes/type_safe_index/drake/common/type_safe_index.h: In instantiation of 'typename std::enable_if<(std::is_integral<U>::value && std::is_unsigned<U>::value), bool>::type drake::TypeSafeIndex<Tag>::operator==(const U&) const [with U = long unsigned int; Tag = drake::systems::AbstractParameterTag; typename std::enable_if<(std::is_integral<U>::value && std::is_unsigned<U>::value), bool>::type = bool]':
bazel-out/k8-dbg/bin/systems/framework/_virtual_includes/system_base/drake/systems/framework/system_base.h:945:5:   required from here
bazel-out/k8-dbg/bin/common/_virtual_includes/type_safe_index/drake/common/type_safe_index.h:351:18: error: comparison of integer expressions of different signedness: 'const long unsigned int' and 'int' [-Werror=sign-compare]
bazel-out/k8-dbg/bin/common/_virtual_includes/type_safe_index/drake/common/type_safe_index.h: In instantiation of 'typename std::enable_if<(std::is_integral<U>::value && std::is_unsigned<U>::value), bool>::type drake::TypeSafeIndex<Tag>::operator<(const U&) const [with U = long unsigned int; Tag = drake::systems::DiscreteStateTag; typename std::enable_if<(std::is_integral<U>::value && std::is_unsigned<U>::value), bool>::type = bool]':
bazel-out/k8-dbg/bin/systems/framework/_virtual_includes/system_base/drake/systems/framework/system_base.h:1166:5:   required from here
bazel-out/k8-dbg/bin/common/_virtual_includes/type_safe_index/drake/common/type_safe_index.h:395:18: error: comparison of integer expressions of different signedness: 'const long unsigned int' and 'int' [-Werror=sign-compare]
  395 |     return value > std::numeric_limits<int>::max() ||
      |            ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bazel-out/k8-dbg/bin/common/_virtual_includes/type_safe_index/drake/common/type_safe_index.h: In instantiation of 'typename std::enable_if<(std::is_integral<U>::value && std::is_unsigned<U>::value), bool>::type drake::TypeSafeIndex<Tag>::operator<(const U&) const [with U = long unsigned int; Tag = drake::systems::AbstractStateTag; typename std::enable_if<(std::is_integral<U>::value && std::is_unsigned<U>::value), bool>::type = bool]':
bazel-out/k8-dbg/bin/systems/framework/_virtual_includes/system_base/drake/systems/framework/system_base.h:1172:5:   required from here
bazel-out/k8-dbg/bin/common/_virtual_includes/type_safe_index/drake/common/type_safe_index.h:395:18: error: comparison of integer expressions of different signedness: 'const long unsigned int' and 'int' [-Werror=sign-compare]
bazel-out/k8-dbg/bin/common/_virtual_includes/type_safe_index/drake/common/type_safe_index.h: In instantiation of 'typename std::enable_if<(std::is_integral<U>::value && std::is_unsigned<U>::value), bool>::type drake::TypeSafeIndex<Tag>::operator<(const U&) const [with U = long unsigned int; Tag = drake::systems::NumericParameterTag; typename std::enable_if<(std::is_integral<U>::value && std::is_unsigned<U>::value), bool>::type = bool]':
bazel-out/k8-dbg/bin/systems/framework/_virtual_includes/system_base/drake/systems/framework/system_base.h:1178:5:   required from here
bazel-out/k8-dbg/bin/common/_virtual_includes/type_safe_index/drake/common/type_safe_index.h:395:18: error: comparison of integer expressions of different signedness: 'const long unsigned int' and 'int' [-Werror=sign-compare]
bazel-out/k8-dbg/bin/common/_virtual_includes/type_safe_index/drake/common/type_safe_index.h: In instantiation of 'typename std::enable_if<(std::is_integral<U>::value && std::is_unsigned<U>::value), bool>::type drake::TypeSafeIndex<Tag>::operator<(const U&) const [with U = long unsigned int; Tag = drake::systems::AbstractParameterTag; typename std::enable_if<(std::is_integral<U>::value && std::is_unsigned<U>::value), bool>::type = bool]':
bazel-out/k8-dbg/bin/systems/framework/_virtual_includes/system_base/drake/systems/framework/system_base.h:1184:5:   required from here
bazel-out/k8-dbg/bin/common/_virtual_includes/type_safe_index/drake/common/type_safe_index.h:395:18: error: comparison of integer expressions of different signedness: 'const long unsigned int' and 'int' [-Werror=sign-compare]

Relates #13102. FYI @jwnimmer-tri @SeanCurtis-TRI.

jwnimmer-tri commented 4 years ago

Most look like size_t coming from std collection .size(). I suggest that the unsigned => int conversion be abstracted into a private helper method within the class, and that all of ==, !=, < etc. invoke the helper to convert the U-typed unsigned value into something to compare with this.

SeanCurtis-TRI commented 4 years ago

I don't think the solution is casting U to "this", but to convert the maximum value of this to U. For example:


  template <typename U>
  typename std::enable_if<
      std::is_integral<U>::value && std::is_unsigned<U>::value, bool>::type
  operator!=(const U& value) const {
    DRAKE_ASSERT_VOID(AssertValid(index_, "Testing != with invalid index."));
    return value > static_cast<U>(kMaxIndex) ||
        index_ != static_cast<int>(value);
  }

static constexpr int kMaxIndex = std::numeric_limits<int>::max();

If sizeof(U) is bigger than sizeof(int), then things get nicely promoted there and we can detect size_t values that would otherwise truncate into a lie if we cast the other way.

If sizeof(U) is smaller, then we end up truncating 01111.1111 to the maximum unsigned value of that smaller type (16 1s, 8 1s, etc.) and, by definition the value stored in that smaller unsigned type cannot be larger than that type consisting of all 1s.

I'll go ahead and quickly PR this. I'll exercise the focal CI indicated above.