MSVC: Fix the MSVC 14.29 build of nine tests libeigen/eigen!3369 Co-authored-by: Rasmus Munk Larsen <rmlarsen@gmail.com>
diff --git a/Eigen/src/Core/products/GeneralMatrixMatrix.h b/Eigen/src/Core/products/GeneralMatrixMatrix.h index 842c37e..529f7d0 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrix.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrix.h
@@ -408,7 +408,10 @@ }; using LhsScalar = std::conditional_t<Transpose, RhsScalar_, LhsScalar_>; using RhsScalar = std::conditional_t<Transpose, LhsScalar_, RhsScalar_>; - enum { SizeA = ActualRows * MaxDepth, SizeB = ActualCols * MaxDepth }; + // A zero-sized fixed dimension must not declare a zero-length array, which MSVC rejects (C2229); every caller + // returns before it touches the blocks of an empty product. + static constexpr int SizeA = plain_enum_max(int(ActualRows) * MaxDepth, 1); + static constexpr int SizeB = plain_enum_max(int(ActualCols) * MaxDepth, 1); #if EIGEN_MAX_STATIC_ALIGN_BYTES >= EIGEN_DEFAULT_ALIGN_BYTES EIGEN_ALIGN_MAX LhsScalar m_staticA[SizeA];
diff --git a/contrib/Eigen/src/Tensor/TensorEvaluator.h b/contrib/Eigen/src/Tensor/TensorEvaluator.h index 84decf9..fc3687e 100644 --- a/contrib/Eigen/src/Tensor/TensorEvaluator.h +++ b/contrib/Eigen/src/Tensor/TensorEvaluator.h
@@ -989,6 +989,13 @@ static constexpr bool VectorizedCondCast = std::is_same<CondScalar, bool>::value && TensorEvaluator<IfArgType, Device>::PacketAccess && internal::type_casting_traits<CondScalar, std::remove_const_t<Scalar>>::VectorizedCast; + // How condPacket() builds the mask: 0 = coefficient by coefficient, 1 = from one condition packet, 2 = from two, + // 3 = from one wider condition packet while it stays inside the condition. + static constexpr int CondPacketMode = !VectorizedCondCast ? 0 + : CondPacketSize == PacketSize ? 1 + : PacketSize == 2 * CondPacketSize ? 2 + : CondPacketSize > PacketSize ? 3 + : 0; typedef typename TensorEvaluator<IfArgType, Device>::Dimensions Dimensions; typedef StorageMemory<CoeffReturnType, Device> Storage; typedef typename Storage::Type EvaluatorPointerType; @@ -1054,36 +1061,36 @@ return m_condImpl.coeff(index) ? m_thenImpl.coeff(index) : m_elseImpl.coeff(index); } - template <bool UseVecCast = VectorizedCondCast> - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::enable_if_t<UseVecCast && (CondPacketSize == PacketSize), PacketReturnType> - condPacket(Index index) const { + // Tag dispatch rather than enable_if overloads: MSVC 19.29 folds the non-dependent part of each enable_if + // condition and then rejects the overloads whose conditions fold alike as redeclarations (C2535). Modes 1-3 are + // member templates so that explicitly instantiating the evaluator does not instantiate pcasts its packet types lack. + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType condPacket(Index index) const { + return condPacket(index, std::integral_constant<int, CondPacketMode>()); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType condPacket(Index index, std::integral_constant<int, 0>) const { + return scalarCondPacket(index); + } + + template <typename Unused = void> + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType condPacket(Index index, std::integral_constant<int, 1>) const { return internal::pcast<CondPacket, PacketReturnType>(m_condImpl.template packet<Unaligned>(index)); } - template <bool UseVecCast = VectorizedCondCast> - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE - std::enable_if_t<UseVecCast && (PacketSize == 2 * CondPacketSize), PacketReturnType> - condPacket(Index index) const { + template <typename Unused = void> + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType condPacket(Index index, std::integral_constant<int, 2>) const { return internal::pcast<CondPacket, PacketReturnType>(m_condImpl.template packet<Unaligned>(index), m_condImpl.template packet<Unaligned>(index + CondPacketSize)); } - template <bool UseVecCast = VectorizedCondCast> - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::enable_if_t<UseVecCast && (CondPacketSize > PacketSize), PacketReturnType> - condPacket(Index index) const { + template <typename Unused = void> + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType condPacket(Index index, std::integral_constant<int, 3>) const { if (index + CondPacketSize <= m_condSize) { return internal::pcast<CondPacket, PacketReturnType>(m_condImpl.template packet<Unaligned>(index)); } return scalarCondPacket(index); } - template <bool UseVecCast = VectorizedCondCast> - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::enable_if_t< - !UseVecCast || (CondPacketSize < PacketSize && PacketSize != 2 * CondPacketSize), PacketReturnType> - condPacket(Index index) const { - return scalarCondPacket(index); - } - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType scalarCondPacket(Index index) const { EIGEN_ALIGN_TO_BOUNDARY(internal::unpacket_traits<PacketReturnType>::alignment) std::remove_const_t<Scalar> arr[PacketSize]; @@ -1108,9 +1115,7 @@ } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const { - const bool cond_vectorized = - vectorized && (TernaryPacketAccess || - (VectorizedCondCast && (CondPacketSize >= PacketSize || PacketSize == 2 * CondPacketSize))); + const bool cond_vectorized = vectorized && (TernaryPacketAccess || CondPacketMode != 0); return m_condImpl.costPerCoeff(cond_vectorized) + (vectorized ? (m_thenImpl.costPerCoeff(vectorized) + m_elseImpl.costPerCoeff(vectorized) + TensorOpCost(0, 0, internal::functor_traits<TernarySelectOp>::Cost, vectorized, PacketSize))
diff --git a/contrib/test/tensor_expr.cpp b/contrib/test/tensor_expr.cpp index 0eb39e1..9b3fe19 100644 --- a/contrib/test/tensor_expr.cpp +++ b/contrib/test/tensor_expr.cpp
@@ -278,6 +278,18 @@ } } +// An explicit instantiation instantiates every non-template member, so the condPacket() paths that a bool condition +// over these branch types cannot take must be member templates. +template struct Eigen::TensorEvaluator< + const Eigen::TensorSelectOp<const Tensor<bool, 1>, const Tensor<float, 1>, const Tensor<float, 1>>, + Eigen::DefaultDevice>; +template struct Eigen::TensorEvaluator< + const Eigen::TensorSelectOp<const Tensor<bool, 1>, const Tensor<double, 1>, const Tensor<double, 1>>, + Eigen::DefaultDevice>; +template struct Eigen::TensorEvaluator< + const Eigen::TensorSelectOp<const Tensor<bool, 1>, const Tensor<int, 1>, const Tensor<int, 1>>, + Eigen::DefaultDevice>; + static void test_select() { using TypedGTOp = internal::scalar_cmp_op<float, float, internal::cmp_GT, true>;
diff --git a/test/numext.cpp b/test/numext.cpp index 0373d13..fc88c58 100644 --- a/test/numext.cpp +++ b/test/numext.cpp
@@ -465,7 +465,9 @@ volatile T parts[4] = {a.real(), a.imag(), b.real(), b.imag()}; std::fenv_t environment; if (std::feholdexcept(&environment) != 0) return -1; - const std::complex<T> q = numext::divide(std::complex<T>(parts[0], parts[1]), std::complex<T>(parts[2], parts[3])); + // MSVC's std::complex<T>(const T&, const T&) cannot bind a volatile T, so read each part into a temporary. + const std::complex<T> q = + numext::divide(std::complex<T>(T(parts[0]), T(parts[1])), std::complex<T>(T(parts[2]), T(parts[3]))); volatile T result[2] = {q.real(), q.imag()}; EIGEN_UNUSED_VARIABLE(result); const int exceptions = std::fetestexcept(FE_OVERFLOW | FE_UNDERFLOW | FE_INVALID | FE_DIVBYZERO);
diff --git a/test/serializer.cpp b/test/serializer.cpp index 6009017..4361fca 100644 --- a/test/serializer.cpp +++ b/test/serializer.cpp
@@ -228,7 +228,8 @@ void test_malformed_sparse_matrix() { using T = SparseMatrix<float, Options, int>; using Header = typename Serializer<T>::Header; - constexpr bool kRowMajor = T::IsRowMajor; + // static: MSVC 19.29 wants a captureless lambda to capture even a constexpr local. + static constexpr bool kRowMajor = T::IsRowMajor; // 3 x 2 with entries (0, 0), (2, 0), (1, 1): compressed, the payload is outer[3], inner[3], values[3] in column-major // order, and outer[4], inner[3], values[3] in row-major order. T m(3, 2);
diff --git a/test/shape_checks_compatibility.cpp b/test/shape_checks_compatibility.cpp index 4f3ff4e..b2fefbd 100644 --- a/test/shape_checks_compatibility.cpp +++ b/test/shape_checks_compatibility.cpp
@@ -48,7 +48,7 @@ EIGEN_DECLARE_TEST(shape_checks_compatibility) { VERIFY_IS_EQUAL(guarded_tail_max<1>(Matrix<double, 1, 1>::Ones()), 0.0); VERIFY_IS_EQUAL(guarded_tail_max<2>(Vector2d::Constant(7)), 7.0); - VERIFY_IS_EQUAL(guarded_column_max_size(Matrix<double, 0, 0>()), Index(0)); + VERIFY_IS_EQUAL(guarded_column_max_size<0>(Matrix<double, 0, 0>()), Index(0)); VERIFY_IS_EQUAL(guarded_column_max_size<2>(Matrix2d::Ones()), Index(2)); VERIFY_IS_EQUAL((guarded_determinants<3, 4>(Matrix<double, 3, 4>::Zero())), 0.0); VERIFY_IS_EQUAL((guarded_determinants<2, 2>(Matrix2d::Identity())), 6.0);