Core: Fix C++14 linkage of metadata constants

libeigen/eigen!3357

diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h
index df347cc..0a80402 100644
--- a/Eigen/src/Core/util/IntegralConstant.h
+++ b/Eigen/src/Core/util/IntegralConstant.h
@@ -109,6 +109,11 @@
   constexpr VariableAndFixedInt<N> operator()(int val) const { return VariableAndFixedInt<N>(val); }
 };
 
+#if EIGEN_COMP_CXXVER < 17
+template <int N>
+constexpr int FixedInt<N>::value;
+#endif
+
 /** \internal
  * \class VariableAndFixedInt
  *
diff --git a/contrib/Eigen/src/EulerAngles/EulerSystem.h b/contrib/Eigen/src/EulerAngles/EulerSystem.h
index ca369f3..2c213b6 100644
--- a/contrib/Eigen/src/EulerAngles/EulerSystem.h
+++ b/contrib/Eigen/src/EulerAngles/EulerSystem.h
@@ -176,6 +176,15 @@
   friend struct internal::eulerangles_assign_impl;
 };
 
+#if EIGEN_COMP_CXXVER < 17
+template <int Alpha, int Beta, int Gamma>
+constexpr int EulerSystem<Alpha, Beta, Gamma>::AlphaAxis;
+template <int Alpha, int Beta, int Gamma>
+constexpr int EulerSystem<Alpha, Beta, Gamma>::BetaAxis;
+template <int Alpha, int Beta, int Gamma>
+constexpr int EulerSystem<Alpha, Beta, Gamma>::GammaAxis;
+#endif
+
 #define EIGEN_EULER_SYSTEM_TYPEDEF(A, B, C) typedef EulerSystem<EULER_##A, EULER_##B, EULER_##C> EulerSystem##A##B##C;
 
 /** Default XYZ Euler coordinate system.
diff --git a/contrib/Eigen/src/StructuredMatrices/Bccb.h b/contrib/Eigen/src/StructuredMatrices/Bccb.h
index e950f57..655c036 100644
--- a/contrib/Eigen/src/StructuredMatrices/Bccb.h
+++ b/contrib/Eigen/src/StructuredMatrices/Bccb.h
@@ -651,6 +651,23 @@
 
 }  // namespace internal
 
+#if EIGEN_COMP_CXXVER < 17
+template <typename Scalar_, int BlockSize_, int NumBlocks_>
+constexpr int Bccb<Scalar_, BlockSize_, NumBlocks_>::RowsAtCompileTime;
+template <typename Scalar_, int BlockSize_, int NumBlocks_>
+constexpr int Bccb<Scalar_, BlockSize_, NumBlocks_>::ColsAtCompileTime;
+template <typename Scalar_, int BlockSize_, int NumBlocks_>
+constexpr int Bccb<Scalar_, BlockSize_, NumBlocks_>::MaxRowsAtCompileTime;
+template <typename Scalar_, int BlockSize_, int NumBlocks_>
+constexpr int Bccb<Scalar_, BlockSize_, NumBlocks_>::MaxColsAtCompileTime;
+template <typename Scalar_, int BlockSize_, int NumBlocks_>
+constexpr int Bccb<Scalar_, BlockSize_, NumBlocks_>::SizeAtCompileTime;
+template <typename Scalar_, int BlockSize_, int NumBlocks_>
+constexpr int Bccb<Scalar_, BlockSize_, NumBlocks_>::MaxSizeAtCompileTime;
+template <typename Scalar_, int BlockSize_, int NumBlocks_>
+constexpr bool Bccb<Scalar_, BlockSize_, NumBlocks_>::IsRowMajor;
+#endif
+
 }  // namespace Eigen
 
 #endif  // EIGEN_STRUCTURED_BCCB_H
diff --git a/contrib/Eigen/src/StructuredMatrices/Cauchy.h b/contrib/Eigen/src/StructuredMatrices/Cauchy.h
index 9d10bb1..99e52b2 100644
--- a/contrib/Eigen/src/StructuredMatrices/Cauchy.h
+++ b/contrib/Eigen/src/StructuredMatrices/Cauchy.h
@@ -462,6 +462,23 @@
 
 }  // namespace internal
 
+#if EIGEN_COMP_CXXVER < 17
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Cauchy<Scalar_, Rows_, Cols_>::RowsAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Cauchy<Scalar_, Rows_, Cols_>::ColsAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Cauchy<Scalar_, Rows_, Cols_>::MaxRowsAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Cauchy<Scalar_, Rows_, Cols_>::MaxColsAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Cauchy<Scalar_, Rows_, Cols_>::SizeAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Cauchy<Scalar_, Rows_, Cols_>::MaxSizeAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr bool Cauchy<Scalar_, Rows_, Cols_>::IsRowMajor;
+#endif
+
 }  // namespace Eigen
 
 #endif  // EIGEN_STRUCTURED_CAUCHY_H
diff --git a/contrib/Eigen/src/StructuredMatrices/Circulant.h b/contrib/Eigen/src/StructuredMatrices/Circulant.h
index 159d892..bb1ebc5 100644
--- a/contrib/Eigen/src/StructuredMatrices/Circulant.h
+++ b/contrib/Eigen/src/StructuredMatrices/Circulant.h
@@ -558,6 +558,23 @@
 
 }  // namespace internal
 
+#if EIGEN_COMP_CXXVER < 17
+template <typename Scalar_, int Size_>
+constexpr int Circulant<Scalar_, Size_>::RowsAtCompileTime;
+template <typename Scalar_, int Size_>
+constexpr int Circulant<Scalar_, Size_>::ColsAtCompileTime;
+template <typename Scalar_, int Size_>
+constexpr int Circulant<Scalar_, Size_>::MaxRowsAtCompileTime;
+template <typename Scalar_, int Size_>
+constexpr int Circulant<Scalar_, Size_>::MaxColsAtCompileTime;
+template <typename Scalar_, int Size_>
+constexpr int Circulant<Scalar_, Size_>::SizeAtCompileTime;
+template <typename Scalar_, int Size_>
+constexpr int Circulant<Scalar_, Size_>::MaxSizeAtCompileTime;
+template <typename Scalar_, int Size_>
+constexpr bool Circulant<Scalar_, Size_>::IsRowMajor;
+#endif
+
 }  // namespace Eigen
 
 #endif  // EIGEN_STRUCTURED_CIRCULANT_H
diff --git a/contrib/Eigen/src/StructuredMatrices/DiagonalPlusLowRank.h b/contrib/Eigen/src/StructuredMatrices/DiagonalPlusLowRank.h
index ed8c6dd..9dd76f7 100644
--- a/contrib/Eigen/src/StructuredMatrices/DiagonalPlusLowRank.h
+++ b/contrib/Eigen/src/StructuredMatrices/DiagonalPlusLowRank.h
@@ -366,6 +366,23 @@
 
 }  // namespace internal
 
+#if EIGEN_COMP_CXXVER < 17
+template <typename Scalar_, int Size_, int Rank_>
+constexpr int DiagonalPlusLowRank<Scalar_, Size_, Rank_>::RowsAtCompileTime;
+template <typename Scalar_, int Size_, int Rank_>
+constexpr int DiagonalPlusLowRank<Scalar_, Size_, Rank_>::ColsAtCompileTime;
+template <typename Scalar_, int Size_, int Rank_>
+constexpr int DiagonalPlusLowRank<Scalar_, Size_, Rank_>::MaxRowsAtCompileTime;
+template <typename Scalar_, int Size_, int Rank_>
+constexpr int DiagonalPlusLowRank<Scalar_, Size_, Rank_>::MaxColsAtCompileTime;
+template <typename Scalar_, int Size_, int Rank_>
+constexpr int DiagonalPlusLowRank<Scalar_, Size_, Rank_>::SizeAtCompileTime;
+template <typename Scalar_, int Size_, int Rank_>
+constexpr int DiagonalPlusLowRank<Scalar_, Size_, Rank_>::MaxSizeAtCompileTime;
+template <typename Scalar_, int Size_, int Rank_>
+constexpr bool DiagonalPlusLowRank<Scalar_, Size_, Rank_>::IsRowMajor;
+#endif
+
 }  // namespace Eigen
 
 #endif  // EIGEN_STRUCTURED_DIAGONAL_PLUS_LOW_RANK_H
diff --git a/contrib/Eigen/src/StructuredMatrices/Hankel.h b/contrib/Eigen/src/StructuredMatrices/Hankel.h
index 7bbf12e..65efd15 100644
--- a/contrib/Eigen/src/StructuredMatrices/Hankel.h
+++ b/contrib/Eigen/src/StructuredMatrices/Hankel.h
@@ -426,6 +426,27 @@
 
 }  // namespace internal
 
+#if EIGEN_COMP_CXXVER < 17
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Hankel<Scalar_, Rows_, Cols_>::RowsAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Hankel<Scalar_, Rows_, Cols_>::ColsAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Hankel<Scalar_, Rows_, Cols_>::MaxRowsAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Hankel<Scalar_, Rows_, Cols_>::MaxColsAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Hankel<Scalar_, Rows_, Cols_>::SizeAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Hankel<Scalar_, Rows_, Cols_>::MaxSizeAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr bool Hankel<Scalar_, Rows_, Cols_>::IsRowMajor;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Hankel<Scalar_, Rows_, Cols_>::GenSizeAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Hankel<Scalar_, Rows_, Cols_>::SolveRowsAtCompileTime;
+#endif
+
 }  // namespace Eigen
 
 #endif  // EIGEN_STRUCTURED_HANKEL_H
diff --git a/contrib/Eigen/src/StructuredMatrices/KroneckerOperator.h b/contrib/Eigen/src/StructuredMatrices/KroneckerOperator.h
index e796b97..4e83bda 100644
--- a/contrib/Eigen/src/StructuredMatrices/KroneckerOperator.h
+++ b/contrib/Eigen/src/StructuredMatrices/KroneckerOperator.h
@@ -1524,6 +1524,23 @@
 
 }  // namespace internal
 
+#if EIGEN_COMP_CXXVER < 17
+template <typename LhsMatrix, typename RhsMatrix>
+constexpr int KroneckerOperator<LhsMatrix, RhsMatrix>::RowsAtCompileTime;
+template <typename LhsMatrix, typename RhsMatrix>
+constexpr int KroneckerOperator<LhsMatrix, RhsMatrix>::ColsAtCompileTime;
+template <typename LhsMatrix, typename RhsMatrix>
+constexpr int KroneckerOperator<LhsMatrix, RhsMatrix>::MaxRowsAtCompileTime;
+template <typename LhsMatrix, typename RhsMatrix>
+constexpr int KroneckerOperator<LhsMatrix, RhsMatrix>::MaxColsAtCompileTime;
+template <typename LhsMatrix, typename RhsMatrix>
+constexpr int KroneckerOperator<LhsMatrix, RhsMatrix>::SizeAtCompileTime;
+template <typename LhsMatrix, typename RhsMatrix>
+constexpr int KroneckerOperator<LhsMatrix, RhsMatrix>::MaxSizeAtCompileTime;
+template <typename LhsMatrix, typename RhsMatrix>
+constexpr bool KroneckerOperator<LhsMatrix, RhsMatrix>::IsRowMajor;
+#endif
+
 }  // namespace Eigen
 
 #endif  // EIGEN_STRUCTURED_KRONECKER_OPERATOR_H
diff --git a/contrib/Eigen/src/StructuredMatrices/KroneckerSum.h b/contrib/Eigen/src/StructuredMatrices/KroneckerSum.h
index 0ecab69..9302981 100644
--- a/contrib/Eigen/src/StructuredMatrices/KroneckerSum.h
+++ b/contrib/Eigen/src/StructuredMatrices/KroneckerSum.h
@@ -955,6 +955,23 @@
 
 }  // namespace internal
 
+#if EIGEN_COMP_CXXVER < 17
+template <typename LhsMatrix, typename RhsMatrix>
+constexpr int KroneckerSum<LhsMatrix, RhsMatrix>::RowsAtCompileTime;
+template <typename LhsMatrix, typename RhsMatrix>
+constexpr int KroneckerSum<LhsMatrix, RhsMatrix>::ColsAtCompileTime;
+template <typename LhsMatrix, typename RhsMatrix>
+constexpr int KroneckerSum<LhsMatrix, RhsMatrix>::MaxRowsAtCompileTime;
+template <typename LhsMatrix, typename RhsMatrix>
+constexpr int KroneckerSum<LhsMatrix, RhsMatrix>::MaxColsAtCompileTime;
+template <typename LhsMatrix, typename RhsMatrix>
+constexpr int KroneckerSum<LhsMatrix, RhsMatrix>::SizeAtCompileTime;
+template <typename LhsMatrix, typename RhsMatrix>
+constexpr int KroneckerSum<LhsMatrix, RhsMatrix>::MaxSizeAtCompileTime;
+template <typename LhsMatrix, typename RhsMatrix>
+constexpr bool KroneckerSum<LhsMatrix, RhsMatrix>::IsRowMajor;
+#endif
+
 }  // namespace Eigen
 
 #endif  // EIGEN_STRUCTURED_KRONECKER_SUM_H
diff --git a/contrib/Eigen/src/StructuredMatrices/Toeplitz.h b/contrib/Eigen/src/StructuredMatrices/Toeplitz.h
index 01456c8..bea571d 100644
--- a/contrib/Eigen/src/StructuredMatrices/Toeplitz.h
+++ b/contrib/Eigen/src/StructuredMatrices/Toeplitz.h
@@ -346,6 +346,23 @@
 
 }  // namespace internal
 
+#if EIGEN_COMP_CXXVER < 17
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Toeplitz<Scalar_, Rows_, Cols_>::RowsAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Toeplitz<Scalar_, Rows_, Cols_>::ColsAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Toeplitz<Scalar_, Rows_, Cols_>::MaxRowsAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Toeplitz<Scalar_, Rows_, Cols_>::MaxColsAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Toeplitz<Scalar_, Rows_, Cols_>::SizeAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Toeplitz<Scalar_, Rows_, Cols_>::MaxSizeAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr bool Toeplitz<Scalar_, Rows_, Cols_>::IsRowMajor;
+#endif
+
 }  // namespace Eigen
 
 #endif  // EIGEN_STRUCTURED_TOEPLITZ_H
diff --git a/contrib/Eigen/src/StructuredMatrices/Vandermonde.h b/contrib/Eigen/src/StructuredMatrices/Vandermonde.h
index b84f1cd..6a56aa0 100644
--- a/contrib/Eigen/src/StructuredMatrices/Vandermonde.h
+++ b/contrib/Eigen/src/StructuredMatrices/Vandermonde.h
@@ -640,6 +640,27 @@
 
 }  // namespace internal
 
+#if EIGEN_COMP_CXXVER < 17
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Vandermonde<Scalar_, Rows_, Cols_>::RowsAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Vandermonde<Scalar_, Rows_, Cols_>::ColsAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Vandermonde<Scalar_, Rows_, Cols_>::MaxRowsAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Vandermonde<Scalar_, Rows_, Cols_>::MaxColsAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Vandermonde<Scalar_, Rows_, Cols_>::SizeAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Vandermonde<Scalar_, Rows_, Cols_>::MaxSizeAtCompileTime;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr bool Vandermonde<Scalar_, Rows_, Cols_>::IsRowMajor;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Vandermonde<Scalar_, Rows_, Cols_>::NodeOptions;
+template <typename Scalar_, int Rows_, int Cols_>
+constexpr int Vandermonde<Scalar_, Rows_, Cols_>::Flags;
+#endif
+
 }  // namespace Eigen
 
 #endif  // EIGEN_STRUCTURED_VANDERMONDE_H
diff --git a/contrib/Eigen/src/Tensor/Tensor.h b/contrib/Eigen/src/Tensor/Tensor.h
index 95014f8..f3c7d29 100644
--- a/contrib/Eigen/src/Tensor/Tensor.h
+++ b/contrib/Eigen/src/Tensor/Tensor.h
@@ -376,6 +376,15 @@
   }
 };
 
+#if EIGEN_COMP_CXXVER < 17
+template <typename Scalar_, int NumIndices_, int Options_, typename IndexType_>
+constexpr int Tensor<Scalar_, NumIndices_, Options_, IndexType_>::NumIndices;
+template <typename Scalar_, int NumIndices_, int Options_, typename IndexType_>
+constexpr int Tensor<Scalar_, NumIndices_, Options_, IndexType_>::Layout;
+template <typename Scalar_, int NumIndices_, int Options_, typename IndexType_>
+constexpr int Tensor<Scalar_, NumIndices_, Options_, IndexType_>::Options;
+#endif
+
 }  // end namespace Eigen
 
 #endif  // EIGEN_TENSOR_TENSOR_H
diff --git a/contrib/Eigen/src/Tensor/TensorCostModel.h b/contrib/Eigen/src/Tensor/TensorCostModel.h
index 5cb986a..8b8a7ea 100644
--- a/contrib/Eigen/src/Tensor/TensorCostModel.h
+++ b/contrib/Eigen/src/Tensor/TensorCostModel.h
@@ -246,6 +246,25 @@
   }
 };
 
+#if EIGEN_COMP_CXXVER < 17
+template <typename Device>
+constexpr int TensorCostModel<Device>::kDeviceCyclesPerComputeCycle;
+template <typename Device>
+constexpr int TensorCostModel<Device>::kStartupCycles;
+template <typename Device>
+constexpr int TensorCostModel<Device>::kPerThreadCycles;
+template <typename Device>
+constexpr int TensorCostModel<Device>::kTaskSize;
+template <typename Device>
+constexpr int TensorCostModel<Device>::kMemBandwidthSaturationThreads;
+template <typename Device>
+constexpr double TensorCostModel<Device>::kMemBoundThreshold;
+template <typename Device>
+constexpr double TensorCostModel<Device>::kDramThresholdBytes;
+template <typename Device>
+constexpr double TensorCostModel<Device>::kByteCost;
+#endif
+
 }  // namespace Eigen
 
 #endif  // EIGEN_TENSOR_TENSOR_COST_MODEL_H
diff --git a/contrib/Eigen/src/Tensor/TensorDimensions.h b/contrib/Eigen/src/Tensor/TensorDimensions.h
index 9de06e7..2ea34f9 100644
--- a/contrib/Eigen/src/Tensor/TensorDimensions.h
+++ b/contrib/Eigen/src/Tensor/TensorDimensions.h
@@ -129,6 +129,13 @@
   }
 };
 
+#if EIGEN_COMP_CXXVER < 17
+template <std::ptrdiff_t... Indices>
+constexpr std::ptrdiff_t Sizes<Indices...>::total_size;
+template <std::ptrdiff_t... Indices>
+constexpr std::ptrdiff_t Sizes<Indices...>::count;
+#endif
+
 namespace internal {
 template <std::ptrdiff_t... Indices>
 constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::ptrdiff_t array_prod(const Sizes<Indices...>&) {
@@ -258,6 +265,11 @@
   }
 };
 
+#if EIGEN_COMP_CXXVER < 17
+template <typename DenseIndex, int NumDims>
+constexpr int DSizes<DenseIndex, NumDims>::count;
+#endif
+
 template <typename IndexType, int NumDims>
 std::ostream& operator<<(std::ostream& os, const DSizes<IndexType, NumDims>& dims) {
   os << "[";
diff --git a/contrib/Eigen/src/Tensor/TensorFixedSize.h b/contrib/Eigen/src/Tensor/TensorFixedSize.h
index ccf9d17..03af104 100644
--- a/contrib/Eigen/src/Tensor/TensorFixedSize.h
+++ b/contrib/Eigen/src/Tensor/TensorFixedSize.h
@@ -213,6 +213,15 @@
   }
 };
 
+#if EIGEN_COMP_CXXVER < 17
+template <typename Scalar_, typename Dimensions_, int Options_, typename IndexType>
+constexpr std::size_t TensorFixedSize<Scalar_, Dimensions_, Options_, IndexType>::NumIndices;
+template <typename Scalar_, typename Dimensions_, int Options_, typename IndexType>
+constexpr int TensorFixedSize<Scalar_, Dimensions_, Options_, IndexType>::Layout;
+template <typename Scalar_, typename Dimensions_, int Options_, typename IndexType>
+constexpr int TensorFixedSize<Scalar_, Dimensions_, Options_, IndexType>::Options;
+#endif
+
 }  // end namespace Eigen
 
 #endif  // EIGEN_TENSOR_TENSOR_FIXED_SIZE_H
diff --git a/contrib/Eigen/src/Tensor/TensorIndexList.h b/contrib/Eigen/src/Tensor/TensorIndexList.h
index a236117..1d55f55 100644
--- a/contrib/Eigen/src/Tensor/TensorIndexList.h
+++ b/contrib/Eigen/src/Tensor/TensorIndexList.h
@@ -42,6 +42,15 @@
   }
 };
 
+#if EIGEN_COMP_CXXVER < 17
+template <Index n>
+constexpr Index type2index<n>::value;
+template <Index f, Index s>
+constexpr Index type2indexpair<f, s>::first;
+template <Index f, Index s>
+constexpr Index type2indexpair<f, s>::second;
+#endif
+
 template <Index n>
 struct NumTraits<type2index<n>> {
   typedef Index Real;
diff --git a/contrib/Eigen/src/Tensor/TensorMap.h b/contrib/Eigen/src/Tensor/TensorMap.h
index 7c35633..edaed0d 100644
--- a/contrib/Eigen/src/Tensor/TensorMap.h
+++ b/contrib/Eigen/src/Tensor/TensorMap.h
@@ -185,6 +185,16 @@
   Dimensions m_dimensions;
 };
 
+#if EIGEN_COMP_CXXVER < 17
+template <typename PlainObjectType, int Options_, template <class> class MakePointer_>
+constexpr typename TensorMap<PlainObjectType, Options_, MakePointer_>::Index
+    TensorMap<PlainObjectType, Options_, MakePointer_>::NumIndices;
+template <typename PlainObjectType, int Options_, template <class> class MakePointer_>
+constexpr int TensorMap<PlainObjectType, Options_, MakePointer_>::Layout;
+template <typename PlainObjectType, int Options_, template <class> class MakePointer_>
+constexpr int TensorMap<PlainObjectType, Options_, MakePointer_>::Options;
+#endif
+
 }  // end namespace Eigen
 
 #endif  // EIGEN_TENSOR_TENSOR_MAP_H
diff --git a/contrib/Eigen/src/Tensor/TensorRef.h b/contrib/Eigen/src/Tensor/TensorRef.h
index 3a36128..052af5f 100644
--- a/contrib/Eigen/src/Tensor/TensorRef.h
+++ b/contrib/Eigen/src/Tensor/TensorRef.h
@@ -237,6 +237,13 @@
   TensorLazyBaseEvaluator<Dimensions, Scalar>* m_evaluator = nullptr;
 };
 
+#if EIGEN_COMP_CXXVER < 17
+template <typename Derived>
+constexpr typename TensorRefBase<Derived>::Index TensorRefBase<Derived>::NumIndices;
+template <typename Derived>
+constexpr int TensorRefBase<Derived>::Layout;
+#endif
+
 }  // namespace internal
 
 /**
diff --git a/contrib/test/EulerAngles.cpp b/contrib/test/EulerAngles.cpp
index 20062ce..b5115b9 100644
--- a/contrib/test/EulerAngles.cpp
+++ b/contrib/test/EulerAngles.cpp
@@ -302,6 +302,20 @@
   VERIFY_IS_APPROX(e.gamma(), gamma);
 }
 
+// A volatile pointer forces odr-use even when optimization could fold the value.
+template <typename T>
+T read_through_address(const T& value) {
+  const T* volatile address = &value;
+  return *address;
+}
+
+template <typename System>
+void eulerangles_axes_odr_use(int alpha, int beta, int gamma) {
+  VERIFY_IS_EQUAL(read_through_address(System::AlphaAxis), alpha);
+  VERIFY_IS_EQUAL(read_through_address(System::BetaAxis), beta);
+  VERIFY_IS_EQUAL(read_through_address(System::GammaAxis), gamma);
+}
+
 EIGEN_DECLARE_TEST(EulerAngles) {
   // Simple cast test
   EulerAnglesXYZd onesEd(1, 1, 1);
@@ -325,6 +339,8 @@
 
   CALL_SUBTEST_6(eulerangles_data_constructor<float>());
   CALL_SUBTEST_6(eulerangles_data_constructor<double>());
+  CALL_SUBTEST_6((eulerangles_axes_odr_use<EulerSystemXYZ>(1, 2, 3)));
+  CALL_SUBTEST_6((eulerangles_axes_odr_use<EulerSystem<1, -2, 3>>(1, -2, 3)));
 
   // TODO: Add tests for auto diff
   // TODO: Add tests for complex numbers
diff --git a/contrib/test/structured_matrices.cpp b/contrib/test/structured_matrices.cpp
index 313521a..00ff71f 100644
--- a/contrib/test/structured_matrices.cpp
+++ b/contrib/test/structured_matrices.cpp
@@ -1542,7 +1542,58 @@
   forEachFlushToZeroMode([&](FlushToZeroMode) { check(); });
 }
 
+// A volatile pointer forces odr-use even when optimization could fold the value.
+template <typename T>
+T read_through_address(const T& value) {
+  const T* volatile address = &value;
+  return *address;
+}
+
+template <typename Operator>
+void structured_metadata_odr_use(int rows, int cols, bool row_major = false) {
+  const int size = rows == Dynamic || cols == Dynamic ? Dynamic : rows * cols;
+  VERIFY_IS_EQUAL(read_through_address(Operator::RowsAtCompileTime), rows);
+  VERIFY_IS_EQUAL(read_through_address(Operator::ColsAtCompileTime), cols);
+  VERIFY_IS_EQUAL(read_through_address(Operator::MaxRowsAtCompileTime), rows);
+  VERIFY_IS_EQUAL(read_through_address(Operator::MaxColsAtCompileTime), cols);
+  VERIFY_IS_EQUAL(read_through_address(Operator::SizeAtCompileTime), size);
+  VERIFY_IS_EQUAL(read_through_address(Operator::MaxSizeAtCompileTime), size);
+  VERIFY_IS_EQUAL(read_through_address(Operator::IsRowMajor), row_major);
+}
+
+static void test_structured_metadata_odr_use() {
+  structured_metadata_odr_use<Bccb<double, 2, 3>>(6, 6);
+  structured_metadata_odr_use<Bccb<double>>(Dynamic, Dynamic);
+  structured_metadata_odr_use<Cauchy<double, 4, 3>>(4, 3);
+  structured_metadata_odr_use<Cauchy<double>>(Dynamic, Dynamic);
+  structured_metadata_odr_use<Circulant<double, 4>>(4, 4);
+  structured_metadata_odr_use<Circulant<double>>(Dynamic, Dynamic);
+  structured_metadata_odr_use<DiagonalPlusLowRank<double, 4, 2>>(4, 4);
+  structured_metadata_odr_use<DiagonalPlusLowRank<double>>(Dynamic, Dynamic);
+  structured_metadata_odr_use<Hankel<double, 4, 3>>(4, 3);
+  structured_metadata_odr_use<Hankel<double>>(Dynamic, Dynamic);
+  structured_metadata_odr_use<KroneckerOperator<Matrix<double, 2, 3>, Matrix<double, 3, 4>>>(6, 12);
+  structured_metadata_odr_use<KroneckerOperator<MatrixXd, MatrixXd>>(Dynamic, Dynamic);
+  structured_metadata_odr_use<KroneckerSum<Matrix2d, Matrix3d>>(6, 6);
+  structured_metadata_odr_use<KroneckerSum<MatrixXd, MatrixXd>>(Dynamic, Dynamic);
+  structured_metadata_odr_use<Toeplitz<double, 4, 3>>(4, 3);
+  structured_metadata_odr_use<Toeplitz<double>>(Dynamic, Dynamic);
+  structured_metadata_odr_use<Vandermonde<double, 4, 3>>(4, 3);
+  structured_metadata_odr_use<Vandermonde<double>>(Dynamic, Dynamic);
+  structured_metadata_odr_use<Vandermonde<double, 1, 3>>(1, 3, true);
+  VERIFY_IS_EQUAL((read_through_address(Hankel<double, 4, 3>::GenSizeAtCompileTime)), 6);
+  VERIFY_IS_EQUAL((read_through_address(Hankel<double, 4, 3>::SolveRowsAtCompileTime)), 3);
+  VERIFY_IS_EQUAL(read_through_address(Hankel<double>::GenSizeAtCompileTime), Dynamic);
+  VERIFY_IS_EQUAL(read_through_address(Hankel<double>::SolveRowsAtCompileTime), Dynamic);
+  VERIFY_IS_EQUAL((read_through_address(Vandermonde<double, 4, 3>::NodeOptions)), int(DontAlign));
+  VERIFY_IS_EQUAL((read_through_address(Vandermonde<double, 4, 3>::Flags)), 0);
+  VERIFY_IS_EQUAL(read_through_address(Vandermonde<double>::NodeOptions), int(AutoAlign));
+  VERIFY_IS_EQUAL(read_through_address(Vandermonde<double>::Flags), 0);
+  VERIFY_IS_EQUAL((read_through_address(Vandermonde<double, 1, 3>::Flags)), int(RowMajorBit));
+}
+
 EIGEN_DECLARE_TEST(structured_matrices) {
+  CALL_SUBTEST_16(test_structured_metadata_odr_use());
   for (int i = 0; i < g_repeat; ++i) {
     // Circulant: direct path (small), FFT path (composite and prime sizes), edge cases.
     CALL_SUBTEST_1((test_circulant_product<double>(1)));
diff --git a/contrib/test/tensor_cost_model.cpp b/contrib/test/tensor_cost_model.cpp
index 58eb996..e54f822 100644
--- a/contrib/test/tensor_cost_model.cpp
+++ b/contrib/test/tensor_cost_model.cpp
@@ -47,7 +47,26 @@
   }
 }
 
+// A volatile pointer forces odr-use even when optimization could fold the value.
+template <typename T>
+T read_through_address(const T& value) {
+  const T* volatile address = &value;
+  return *address;
+}
+
+static void test_cost_model_constants_odr_use() {
+  using Cost = Eigen::TensorCostModel<DefaultDevice>;
+  VERIFY_IS_EQUAL(read_through_address(Cost::kDeviceCyclesPerComputeCycle), 1);
+  VERIFY_IS_EQUAL(read_through_address(Cost::kStartupCycles), 25000);
+  VERIFY_IS_EQUAL(read_through_address(Cost::kPerThreadCycles), 25000);
+  VERIFY_IS_EQUAL(read_through_address(Cost::kTaskSize), 40000);
+  VERIFY_IS_EQUAL(read_through_address(Cost::kMemBandwidthSaturationThreads), 4);
+  VERIFY_IS_EQUAL(read_through_address(Cost::kMemBoundThreshold), 2.0);
+  VERIFY_IS_EQUAL(read_through_address(Cost::kDramThresholdBytes), 1024.0 * 1024.0);
+}
+
 EIGEN_DECLARE_TEST(tensor_cost_model) {
+  CALL_SUBTEST(test_cost_model_constants_odr_use());
   CALL_SUBTEST(test_nullary_zero_bytes_loaded<float>());
   CALL_SUBTEST(test_nullary_zero_bytes_loaded<double>());
   CALL_SUBTEST(test_nullary_zero_bytes_loaded<int>());
diff --git a/contrib/test/tensor_dimension.cpp b/contrib/test/tensor_dimension.cpp
index 4c064e2..60f58f3 100644
--- a/contrib/test/tensor_dimension.cpp
+++ b/contrib/test/tensor_dimension.cpp
@@ -91,7 +91,52 @@
   VERIFY_RAISES_ASSERT((Eigen::DSizes<std::ptrdiff_t, 3>(2, 3, std::size_t(-1))));
 }
 
+// A volatile pointer forces odr-use even when optimization could fold the value.
+template <typename T>
+T read_through_address(const T& value) {
+  const T* volatile address = &value;
+  return *address;
+}
+
+static void test_dimension_constants_odr_use() {
+  VERIFY_IS_EQUAL((read_through_address(Eigen::Sizes<2, 3>::total_size)), std::ptrdiff_t(6));
+  VERIFY_IS_EQUAL((read_through_address(Eigen::Sizes<2, 3>::count)), std::ptrdiff_t(2));
+  VERIFY_IS_EQUAL(read_through_address(Eigen::Sizes<>::total_size), std::ptrdiff_t(1));
+  VERIFY_IS_EQUAL(read_through_address(Eigen::Sizes<>::count), std::ptrdiff_t(0));
+  VERIFY_IS_EQUAL((read_through_address(Eigen::DSizes<Index, 3>::count)), 3);
+  VERIFY_IS_EQUAL((read_through_address(Eigen::DSizes<int, 0>::count)), 0);
+}
+
+template <typename TensorType>
+void tensor_rank_layout_odr_use(int rank, int layout) {
+  VERIFY_IS_EQUAL(read_through_address(TensorType::NumIndices), rank);
+  VERIFY_IS_EQUAL(read_through_address(TensorType::Layout), layout);
+}
+
+template <typename TensorType>
+void tensor_metadata_odr_use(int rank, int layout, int options) {
+  tensor_rank_layout_odr_use<TensorType>(rank, layout);
+  VERIFY_IS_EQUAL(read_through_address(TensorType::Options), options);
+}
+
+static void test_tensor_metadata_odr_use() {
+  tensor_metadata_odr_use<Tensor<float, 3>>(3, ColMajor, 0);
+  tensor_metadata_odr_use<Tensor<float, 3, RowMajor, int>>(3, RowMajor, RowMajor);
+  tensor_metadata_odr_use<Tensor<float, 0>>(0, ColMajor, 0);
+  tensor_metadata_odr_use<TensorFixedSize<float, Sizes<2, 3>>>(2, ColMajor, 0);
+  tensor_metadata_odr_use<TensorFixedSize<float, Sizes<2, 3>, RowMajor, int>>(2, RowMajor, RowMajor);
+  tensor_metadata_odr_use<TensorFixedSize<float, Sizes<>>>(0, ColMajor, 0);
+  tensor_metadata_odr_use<TensorMap<Tensor<float, 3>>>(3, ColMajor, 0);
+  tensor_metadata_odr_use<TensorMap<const Tensor<float, 3, RowMajor>, Aligned>>(3, RowMajor, Aligned);
+  tensor_metadata_odr_use<TensorMap<TensorFixedSize<float, Sizes<2, 3>>>>(2, ColMajor, 0);
+  tensor_rank_layout_odr_use<TensorRef<Tensor<float, 3>>>(3, ColMajor);
+  tensor_rank_layout_odr_use<TensorRef<const Tensor<float, 3, RowMajor>>>(3, RowMajor);
+  tensor_rank_layout_odr_use<TensorRef<TensorFixedSize<float, Sizes<>>>>(0, ColMajor);
+}
+
 EIGEN_DECLARE_TEST(tensor_dimension) {
+  CALL_SUBTEST(test_dimension_constants_odr_use());
+  CALL_SUBTEST(test_tensor_metadata_odr_use());
   CALL_SUBTEST(test_dynamic_size());
   CALL_SUBTEST(test_fixed_size());
   CALL_SUBTEST(test_match());
diff --git a/contrib/test/tensor_index_list.cpp b/contrib/test/tensor_index_list.cpp
index 4d8156b..12a74b8 100644
--- a/contrib/test/tensor_index_list.cpp
+++ b/contrib/test/tensor_index_list.cpp
@@ -452,7 +452,22 @@
   VERIFY(dimensions_match(dim1, dim2));
 }
 
+// A volatile pointer forces odr-use even when optimization could fold the value.
+template <typename T>
+T read_through_address(const T& value) {
+  const T* volatile address = &value;
+  return *address;
+}
+
+static void test_static_index_odr_use() {
+  VERIFY_IS_EQUAL(read_through_address(Eigen::type2index<3>::value), Index(3));
+  VERIFY_IS_EQUAL(read_through_address(Eigen::type2index<-3>::value), Index(-3));
+  VERIFY_IS_EQUAL((read_through_address(Eigen::type2indexpair<1, -2>::first)), Index(1));
+  VERIFY_IS_EQUAL((read_through_address(Eigen::type2indexpair<1, -2>::second)), Index(-2));
+}
+
 EIGEN_DECLARE_TEST(tensor_index_list) {
+  CALL_SUBTEST(test_static_index_odr_use());
   CALL_SUBTEST(test_static_index_list());
   CALL_SUBTEST(test_type2index_list());
   CALL_SUBTEST(test_type2indexpair_list());
diff --git a/test/symbolic_index.cpp b/test/symbolic_index.cpp
index 7dbcafe..1981c11 100644
--- a/test/symbolic_index.cpp
+++ b/test/symbolic_index.cpp
@@ -71,4 +71,19 @@
   }
 }
 
-EIGEN_DECLARE_TEST(symbolic_index) { CALL_SUBTEST_1(check_symbolic_index()); }
+// A volatile pointer forces odr-use even when optimization could fold the value.
+template <typename T>
+T read_through_address(const T& value) {
+  const T* volatile address = &value;
+  return *address;
+}
+
+void check_fixed_int_odr_use() {
+  VERIFY_IS_EQUAL(read_through_address(internal::FixedInt<3>::value), 3);
+  VERIFY_IS_EQUAL(read_through_address(internal::FixedInt<-3>::value), -3);
+}
+
+EIGEN_DECLARE_TEST(symbolic_index) {
+  CALL_SUBTEST_1(check_symbolic_index());
+  CALL_SUBTEST_1(check_fixed_int_odr_use());
+}