diff --git a/src/lol/base/array.h b/src/lol/base/array.h
index 13a7d2c6..3c7a3ebb 100644
--- a/src/lol/base/array.h
+++ b/src/lol/base/array.h
@@ -50,7 +50,7 @@ enum class SortAlgorithm : uint8_t
  * m_count are allocated. The rest is uninitialised memory.
  */
 
-template<typename T, typename ARRAY> class array_base
+template<typename T, typename ARRAY> class LOL_ATTR_NODISCARD array_base
 {
 public:
     typedef T element_t;
diff --git a/src/lol/base/features.h b/src/lol/base/features.h
index bcb5e5bf..f16e6945 100644
--- a/src/lol/base/features.h
+++ b/src/lol/base/features.h
@@ -53,11 +53,17 @@
 
 #undef LOL_FEATURE_CXX17_ATTRIBUTE_NODISCARD
 
+/* Features detected through __has_cpp_attribute */
+#ifdef __has_cpp_attribute
+#   if __has_cpp_attribute(deprecated)
+#       define LOL_FEATURE_CXX17_ATTRIBUTE_NODISCARD 1
+#   endif
+#endif
+
 /* Features supported by GCC */
 #if defined __GNUC__
 #   define LOL_FEATURE_CXX11_UNRESTRICTED_UNIONS 1
 #   define LOL_FEATURE_CXX11_INHERIT_CONSTRUCTORS 1
-#   define LOL_FEATURE_CXX17_ATTRIBUTE_NODISCARD 1
 #   if defined(__GXX_EXPERIMENTAL_CXX0X) || __cplusplus >= 201103L
 #       define LOL_FEATURE_CXX11_CONSTEXPR 1
 #       define LOL_FEATURE_CXX11_ISNAN 1
@@ -75,7 +81,6 @@
 #   define LOL_FEATURE_CXX11_UNRESTRICTED_UNIONS 1
 #   define LOL_FEATURE_CXX11_INHERIT_CONSTRUCTORS 1
 #   define LOL_FEATURE_CXX11_ARRAY_INITIALIZERS 1
-#   define LOL_FEATURE_CXX17_ATTRIBUTE_NODISCARD 1
 #   if __has_feature(cxx_constexpr)
 #       define LOL_FEATURE_CXX11_CONSTEXPR 1
 #   endif
@@ -104,7 +109,6 @@
     /* Still unsupported as of VS 2015 (TODO: check VS2017) */
 #   undef LOL_FEATURE_CXX11_ARRAY_INITIALIZERS
 #   undef LOL_FEATURE_CXX11_CONSTEXPR
-#   undef LOL_FEATURE_CXX17_ATTRIBUTE_NODISCARD
 #endif
 
 
diff --git a/src/lol/base/string.h b/src/lol/base/string.h
index 828ff021..93145242 100644
--- a/src/lol/base/string.h
+++ b/src/lol/base/string.h
@@ -28,19 +28,19 @@
 namespace lol
 {
 
-class String : protected array<char>
+class LOL_ATTR_NODISCARD String : protected array<char>
 {
 private:
     typedef array<char> super;
 
 public:
-    inline LOL_ATTR_NODISCARD String()
+    inline String()
       : super()
     {
         push('\0');
     }
 
-    inline LOL_ATTR_NODISCARD String(char const *str)
+    inline String(char const *str)
       : super()
     {
         using namespace std;
@@ -49,7 +49,7 @@ public:
         memcpy(&(*this)[0], str, count() + 1);
     }
 
-    inline LOL_ATTR_NODISCARD String(char const *str, int item_count)
+    inline String(char const *str, int item_count)
       : super()
     {
         using namespace std;
@@ -59,7 +59,7 @@ public:
         ((super &)*this)[item_count] = '\0';
     }
 
-    inline LOL_ATTR_NODISCARD String(String const &s)
+    inline String(String const &s)
       : super((super const &)s)
     {
     }
@@ -268,13 +268,13 @@ public:
         return true;
     }
 
-    inline LOL_ATTR_NODISCARD String operator +(String const &s) const
+    inline String operator +(String const &s) const
     {
         String ret(*this);
         return ret += s;
     }
 
-    inline LOL_ATTR_NODISCARD String operator +(char c) const
+    inline String operator +(char c) const
     {
         String ret(*this);
         return ret += c;
@@ -338,12 +338,12 @@ public:
     static String vformat(char const *format, va_list ap);
 };
 
-inline LOL_ATTR_NODISCARD String operator +(char c, String const &s)
+inline String operator +(char c, String const &s)
 {
     return String() + c + s;
 }
 
-inline LOL_ATTR_NODISCARD String operator +(char const *sz, String const &s)
+inline String operator +(char const *sz, String const &s)
 {
     return String(sz) + s;
 }
diff --git a/src/lol/gpu/shader.h b/src/lol/gpu/shader.h
index 0274d22c..eee18ba0 100644
--- a/src/lol/gpu/shader.h
+++ b/src/lol/gpu/shader.h
@@ -36,7 +36,6 @@ namespace lol
 //VertexUsageBase -------------------------------------------------------------
 struct VertexUsageBase : public StructSafeEnum
 {
-
     enum Type
     {
         Position,
@@ -56,6 +55,7 @@ struct VertexUsageBase : public StructSafeEnum
         Sample,
         MAX,
     };
+
 protected:
     virtual bool BuildEnumMap(map<int64_t, String>& enum_map)
     {
diff --git a/src/lol/image/image.h b/src/lol/image/image.h
index 80391d76..c8276cf9 100644
--- a/src/lol/image/image.h
+++ b/src/lol/image/image.h
@@ -91,13 +91,13 @@ public:
     void SetWrap(WrapMode wrap_x, WrapMode wrap_y);
 
     /* Lock continuous arrays of pixels for writing */
-    template<PixelFormat T> typename PixelType<T>::type *lock();
-    void *lock();
+    template<PixelFormat T> LOL_ATTR_NODISCARD typename PixelType<T>::type *lock();
+    LOL_ATTR_NODISCARD void *lock();
     void unlock(void const *pixels);
 
     /* Lock 2D arrays of pixels for writing */
     template<PixelFormat T>
-    inline array2d<typename PixelType<T>::type> &lock2d()
+    LOL_ATTR_NODISCARD inline array2d<typename PixelType<T>::type> &lock2d()
     {
         /* Hack: this indirection is needed because of a Visual Studio ICE */
         return *(array2d<typename PixelType<T>::type> *)lock2d_helper(T);
diff --git a/src/lol/math/arraynd.h b/src/lol/math/arraynd.h
index edce84f9..95be1d1d 100644
--- a/src/lol/math/arraynd.h
+++ b/src/lol/math/arraynd.h
@@ -95,7 +95,7 @@ private:
 
 
 template<int N, typename... T>
-class arraynd : protected array<T...>
+class LOL_ATTR_NODISCARD arraynd : protected array<T...>
 {
 public:
     typedef array<T...> super;
diff --git a/src/lol/math/bigint.h b/src/lol/math/bigint.h
index 38c87ef4..624a9a18 100644
--- a/src/lol/math/bigint.h
+++ b/src/lol/math/bigint.h
@@ -40,7 +40,7 @@ namespace lol
  */
 
 template<unsigned int N = 16, typename T = uint32_t>
-class bigint
+class LOL_ATTR_NODISCARD bigint
 {
     static int const bits_per_digit = sizeof(T) * 8 - 1;
     static T const digit_mask = ~((T)1 << bits_per_digit);
diff --git a/src/lol/math/functions.h b/src/lol/math/functions.h
index 514ed011..a9116e99 100644
--- a/src/lol/math/functions.h
+++ b/src/lol/math/functions.h
@@ -34,45 +34,45 @@ namespace lol
 #undef max
 
 /* Standard cmath functions */
-static inline double sqrt(double const &x) { return std::sqrt(x); }
-static inline float sqrt(float const &x) { return std::sqrt(x); }
-
-static inline double cbrt(double const &x) { return std::cbrt(x); }
-static inline float cbrt(float const &x) { return std::cbrt(x); }
-
-static inline double exp(double const &x) { return std::exp(x); }
-static inline float exp(float const &x) { return std::exp(x); }
-
-static inline double sin(double const &x) { return std::sin(x); }
-static inline double cos(double const &x) { return std::cos(x); }
-static inline double tan(double const &x) { return std::tan(x); }
-static inline float sin(float const &x) { return std::sin(x); }
-static inline float cos(float const &x) { return std::cos(x); }
-static inline float tan(float const &x) { return std::tan(x); }
-
-static inline double asin(double const &x) { return std::asin(x); }
-static inline double acos(double const &x) { return std::acos(x); }
-static inline double atan(double const &x) { return std::atan(x); }
-static inline float asin(float const &x) { return std::asin(x); }
-static inline float acos(float const &x) { return std::acos(x); }
-static inline float atan(float const &x) { return std::atan(x); }
-
-static inline double atan2(double const &y, double const &x)
+LOL_ATTR_NODISCARD static inline double sqrt(double const &x) { return std::sqrt(x); }
+LOL_ATTR_NODISCARD static inline float sqrt(float const &x) { return std::sqrt(x); }
+
+LOL_ATTR_NODISCARD static inline double cbrt(double const &x) { return std::cbrt(x); }
+LOL_ATTR_NODISCARD static inline float cbrt(float const &x) { return std::cbrt(x); }
+
+LOL_ATTR_NODISCARD static inline double exp(double const &x) { return std::exp(x); }
+LOL_ATTR_NODISCARD static inline float exp(float const &x) { return std::exp(x); }
+
+LOL_ATTR_NODISCARD static inline double sin(double const &x) { return std::sin(x); }
+LOL_ATTR_NODISCARD static inline double cos(double const &x) { return std::cos(x); }
+LOL_ATTR_NODISCARD static inline double tan(double const &x) { return std::tan(x); }
+LOL_ATTR_NODISCARD static inline float sin(float const &x) { return std::sin(x); }
+LOL_ATTR_NODISCARD static inline float cos(float const &x) { return std::cos(x); }
+LOL_ATTR_NODISCARD static inline float tan(float const &x) { return std::tan(x); }
+
+LOL_ATTR_NODISCARD static inline double asin(double const &x) { return std::asin(x); }
+LOL_ATTR_NODISCARD static inline double acos(double const &x) { return std::acos(x); }
+LOL_ATTR_NODISCARD static inline double atan(double const &x) { return std::atan(x); }
+LOL_ATTR_NODISCARD static inline float asin(float const &x) { return std::asin(x); }
+LOL_ATTR_NODISCARD static inline float acos(float const &x) { return std::acos(x); }
+LOL_ATTR_NODISCARD static inline float atan(float const &x) { return std::atan(x); }
+
+LOL_ATTR_NODISCARD static inline double atan2(double const &y, double const &x)
 {
     return std::atan2(y, x);
 }
 
-static inline float atan2(float const &y, float const &x)
+LOL_ATTR_NODISCARD static inline float atan2(float const &y, float const &x)
 {
     return std::atan2(y, x);
 }
 
-static inline double pow(double const &x, double const &y)
+LOL_ATTR_NODISCARD static inline double pow(double const &x, double const &y)
 {
     return std::pow(x, y);
 }
 
-static inline float pow(float const &x, float const &y)
+LOL_ATTR_NODISCARD static inline float pow(float const &x, float const &y)
 {
     return std::pow(x, y);
 }
@@ -91,180 +91,180 @@ static inline void sincos(float const &x, float *s, float *c)
 }
 
 /* Inherited from GLSL */
-static inline float degrees(float radians)
+LOL_ATTR_NODISCARD static inline float degrees(float radians)
 {
     return radians * (180.0f / F_PI);
 }
 
-static inline double degrees(double radians)
+LOL_ATTR_NODISCARD static inline double degrees(double radians)
 {
     return radians * (180.0 / D_PI);
 }
 
-static inline ldouble degrees(ldouble radians)
+LOL_ATTR_NODISCARD static inline ldouble degrees(ldouble radians)
 {
     return radians * (180.0L / LD_PI);
 }
 
-static inline float radians(float degrees)
+LOL_ATTR_NODISCARD static inline float radians(float degrees)
 {
     return degrees * (F_PI / 180.0f);
 }
 
-static inline double radians(double degrees)
+LOL_ATTR_NODISCARD static inline double radians(double degrees)
 {
     return degrees * (D_PI / 180.0);
 }
 
-static inline ldouble radians(ldouble degrees)
+LOL_ATTR_NODISCARD static inline ldouble radians(ldouble degrees)
 {
     return degrees * (LD_PI / 180.0L);
 }
 
 /* The integer versions return floating point values. This avoids nasty
  * surprises when calling radians(180) instead of radians(180.0). */
-static inline float   degrees(int8_t x)   { return degrees(float(x)); }
-static inline float   degrees(uint8_t x)  { return degrees(float(x)); }
-static inline float   degrees(int16_t x)  { return degrees(float(x)); }
-static inline float   degrees(uint16_t x) { return degrees(float(x)); }
-static inline double  degrees(int32_t x)  { return degrees(double(x)); }
-static inline double  degrees(uint32_t x) { return degrees(double(x)); }
-static inline ldouble degrees(int64_t x)  { return degrees(ldouble(x)); }
-static inline ldouble degrees(uint64_t x) { return degrees(ldouble(x)); }
-
-static inline float   radians(int8_t x)   { return radians(float(x)); }
-static inline float   radians(uint8_t x)  { return radians(float(x)); }
-static inline float   radians(int16_t x)  { return radians(float(x)); }
-static inline float   radians(uint16_t x) { return radians(float(x)); }
-static inline double  radians(int32_t x)  { return radians(double(x)); }
-static inline double  radians(uint32_t x) { return radians(double(x)); }
-static inline ldouble radians(int64_t x)  { return radians(ldouble(x)); }
-static inline ldouble radians(uint64_t x) { return radians(ldouble(x)); }
-
-static inline float mix(float const &a, float const &b, float const &x)
+LOL_ATTR_NODISCARD static inline float   degrees(int8_t x)   { return degrees(float(x)); }
+LOL_ATTR_NODISCARD static inline float   degrees(uint8_t x)  { return degrees(float(x)); }
+LOL_ATTR_NODISCARD static inline float   degrees(int16_t x)  { return degrees(float(x)); }
+LOL_ATTR_NODISCARD static inline float   degrees(uint16_t x) { return degrees(float(x)); }
+LOL_ATTR_NODISCARD static inline double  degrees(int32_t x)  { return degrees(double(x)); }
+LOL_ATTR_NODISCARD static inline double  degrees(uint32_t x) { return degrees(double(x)); }
+LOL_ATTR_NODISCARD static inline ldouble degrees(int64_t x)  { return degrees(ldouble(x)); }
+LOL_ATTR_NODISCARD static inline ldouble degrees(uint64_t x) { return degrees(ldouble(x)); }
+
+LOL_ATTR_NODISCARD static inline float   radians(int8_t x)   { return radians(float(x)); }
+LOL_ATTR_NODISCARD static inline float   radians(uint8_t x)  { return radians(float(x)); }
+LOL_ATTR_NODISCARD static inline float   radians(int16_t x)  { return radians(float(x)); }
+LOL_ATTR_NODISCARD static inline float   radians(uint16_t x) { return radians(float(x)); }
+LOL_ATTR_NODISCARD static inline double  radians(int32_t x)  { return radians(double(x)); }
+LOL_ATTR_NODISCARD static inline double  radians(uint32_t x) { return radians(double(x)); }
+LOL_ATTR_NODISCARD static inline ldouble radians(int64_t x)  { return radians(ldouble(x)); }
+LOL_ATTR_NODISCARD static inline ldouble radians(uint64_t x) { return radians(ldouble(x)); }
+
+LOL_ATTR_NODISCARD static inline float mix(float const &a, float const &b, float const &x)
 {
     return a + (b - a) * x;
 }
 
-static inline double mix(double const &a, double const &b, double const &x)
+LOL_ATTR_NODISCARD static inline double mix(double const &a, double const &b, double const &x)
 {
     return a + (b - a) * x;
 }
 
-static inline ldouble mix(ldouble const &a, ldouble const &b, ldouble const &x)
+LOL_ATTR_NODISCARD static inline ldouble mix(ldouble const &a, ldouble const &b, ldouble const &x)
 {
     return a + (b - a) * x;
 }
 
 /* Inherited from HLSL */
-static inline float lerp(float const &a, float const &b, float const &x)
+LOL_ATTR_NODISCARD static inline float lerp(float const &a, float const &b, float const &x)
 {
     return mix(a, b, x);
 }
 
-static inline double lerp(double const &a, double const &b, double const &x)
+LOL_ATTR_NODISCARD static inline double lerp(double const &a, double const &b, double const &x)
 {
     return mix(a, b, x);
 }
 
-static inline ldouble lerp(ldouble const &a, ldouble const &b, ldouble const &x)
+LOL_ATTR_NODISCARD static inline ldouble lerp(ldouble const &a, ldouble const &b, ldouble const &x)
 {
     return mix(a, b, x);
 }
 
 /* These accelerated functions will be merged into the above, one day */
-double lol_sin(double);
-double lol_cos(double);
-double lol_tan(double);
+LOL_ATTR_NODISCARD double lol_sin(double);
+LOL_ATTR_NODISCARD double lol_cos(double);
+LOL_ATTR_NODISCARD double lol_tan(double);
 void lol_sincos(double, double*, double*);
 void lol_sincos(float, float*, float*);
-double lol_asin(double);
-double lol_acos(double);
-double lol_atan(double);
-double lol_atan2(double, double);
+LOL_ATTR_NODISCARD double lol_asin(double);
+LOL_ATTR_NODISCARD double lol_acos(double);
+LOL_ATTR_NODISCARD double lol_atan(double);
+LOL_ATTR_NODISCARD double lol_atan2(double, double);
 
 /* C++ doesn't define abs() and fmod() for all types; we add these for
  * convenience to avoid adding complexity to vector.h. */
-static inline int8_t abs(int8_t x) { return std::abs(x); }
-static inline uint8_t abs(uint8_t x) { return x; }
-static inline int16_t abs(int16_t x) { return std::abs(x); }
-static inline uint16_t abs(uint16_t x) { return x; }
-static inline int32_t abs(int32_t x) { return std::abs(x); }
-static inline uint32_t abs(uint32_t x) { return x; }
+LOL_ATTR_NODISCARD static inline int8_t abs(int8_t x) { return std::abs(x); }
+LOL_ATTR_NODISCARD static inline uint8_t abs(uint8_t x) { return x; }
+LOL_ATTR_NODISCARD static inline int16_t abs(int16_t x) { return std::abs(x); }
+LOL_ATTR_NODISCARD static inline uint16_t abs(uint16_t x) { return x; }
+LOL_ATTR_NODISCARD static inline int32_t abs(int32_t x) { return std::abs(x); }
+LOL_ATTR_NODISCARD static inline uint32_t abs(uint32_t x) { return x; }
 #if defined __native_client__ || defined __ANDROID__
 /* The pepper 19 toolchain doesn't provide abs() for long long int. */
-static inline int64_t abs(int64_t x) { return x > 0 ? x : -x; }
+LOL_ATTR_NODISCARD static inline int64_t abs(int64_t x) { return x > 0 ? x : -x; }
 #else
-static inline int64_t abs(int64_t x) { return std::abs(x); }
+LOL_ATTR_NODISCARD static inline int64_t abs(int64_t x) { return std::abs(x); }
 #endif
-static inline uint64_t abs(uint64_t x) { return x; }
-static inline float abs(float x) { return std::abs(x); }
-static inline double abs(double x) { return std::abs(x); }
-static inline ldouble abs(ldouble x) { return std::abs(x); }
-
-static inline uint8_t fmod(uint8_t x, uint8_t y) { return x % y; }
-static inline int8_t fmod(int8_t x, int8_t y) { return x % y; }
-static inline uint16_t fmod(uint16_t x, uint16_t y) { return x % y; }
-static inline int16_t fmod(int16_t x, int16_t y) { return x % y; }
-static inline uint32_t fmod(uint32_t x, uint32_t y) { return x % y; }
-static inline int32_t fmod(int32_t x, int32_t y) { return x % y; }
-static inline uint64_t fmod(uint64_t x, uint64_t y) { return x % y; }
-static inline int64_t fmod(int64_t x, int64_t y) { return x % y; }
-static inline float fmod(float x, float y) { return std::fmod(x, y); }
-static inline double fmod(double x, double y) { return std::fmod(x, y); }
-static inline ldouble fmod(ldouble x, ldouble y) { return std::fmod(x, y); }
-
-static inline uint8_t floor(uint8_t x) { return x; }
-static inline int8_t floor(int8_t x) { return x; }
-static inline uint16_t floor(uint16_t x) { return x; }
-static inline int16_t floor(int16_t x) { return x; }
-static inline uint32_t floor(uint32_t x) { return x; }
-static inline int32_t floor(int32_t x) { return x; }
-static inline uint64_t floor(uint64_t x) { return x; }
-static inline int64_t floor(int64_t x) { return x; }
-static inline float floor(float x) { return std::floor(x); }
-static inline double floor(double x) { return std::floor(x); }
-static inline ldouble floor(ldouble x) { return std::floor(x); }
-
-static inline uint8_t ceil(uint8_t x) { return x; }
-static inline int8_t ceil(int8_t x) { return x; }
-static inline uint16_t ceil(uint16_t x) { return x; }
-static inline int16_t ceil(int16_t x) { return x; }
-static inline uint32_t ceil(uint32_t x) { return x; }
-static inline int32_t ceil(int32_t x) { return x; }
-static inline uint64_t ceil(uint64_t x) { return x; }
-static inline int64_t ceil(int64_t x) { return x; }
-static inline float ceil(float x) { return std::ceil(x); }
-static inline double ceil(double x) { return std::ceil(x); }
-static inline ldouble ceil(ldouble x) { return std::ceil(x); }
-
-static inline uint8_t round(uint8_t x) { return x; }
-static inline int8_t round(int8_t x) { return x; }
-static inline uint16_t round(uint16_t x) { return x; }
-static inline int16_t round(int16_t x) { return x; }
-static inline uint32_t round(uint32_t x) { return x; }
-static inline int32_t round(int32_t x) { return x; }
-static inline uint64_t round(uint64_t x) { return x; }
-static inline int64_t round(int64_t x) { return x; }
-static inline float round(float x) { return std::round(x); }
-static inline double round(double x) { return std::round(x); }
-static inline ldouble round(ldouble x) { return std::round(x); }
+LOL_ATTR_NODISCARD static inline uint64_t abs(uint64_t x) { return x; }
+LOL_ATTR_NODISCARD static inline float abs(float x) { return std::abs(x); }
+LOL_ATTR_NODISCARD static inline double abs(double x) { return std::abs(x); }
+LOL_ATTR_NODISCARD static inline ldouble abs(ldouble x) { return std::abs(x); }
+
+LOL_ATTR_NODISCARD static inline uint8_t fmod(uint8_t x, uint8_t y) { return x % y; }
+LOL_ATTR_NODISCARD static inline int8_t fmod(int8_t x, int8_t y) { return x % y; }
+LOL_ATTR_NODISCARD static inline uint16_t fmod(uint16_t x, uint16_t y) { return x % y; }
+LOL_ATTR_NODISCARD static inline int16_t fmod(int16_t x, int16_t y) { return x % y; }
+LOL_ATTR_NODISCARD static inline uint32_t fmod(uint32_t x, uint32_t y) { return x % y; }
+LOL_ATTR_NODISCARD static inline int32_t fmod(int32_t x, int32_t y) { return x % y; }
+LOL_ATTR_NODISCARD static inline uint64_t fmod(uint64_t x, uint64_t y) { return x % y; }
+LOL_ATTR_NODISCARD static inline int64_t fmod(int64_t x, int64_t y) { return x % y; }
+LOL_ATTR_NODISCARD static inline float fmod(float x, float y) { return std::fmod(x, y); }
+LOL_ATTR_NODISCARD static inline double fmod(double x, double y) { return std::fmod(x, y); }
+LOL_ATTR_NODISCARD static inline ldouble fmod(ldouble x, ldouble y) { return std::fmod(x, y); }
+
+LOL_ATTR_NODISCARD static inline uint8_t floor(uint8_t x) { return x; }
+LOL_ATTR_NODISCARD static inline int8_t floor(int8_t x) { return x; }
+LOL_ATTR_NODISCARD static inline uint16_t floor(uint16_t x) { return x; }
+LOL_ATTR_NODISCARD static inline int16_t floor(int16_t x) { return x; }
+LOL_ATTR_NODISCARD static inline uint32_t floor(uint32_t x) { return x; }
+LOL_ATTR_NODISCARD static inline int32_t floor(int32_t x) { return x; }
+LOL_ATTR_NODISCARD static inline uint64_t floor(uint64_t x) { return x; }
+LOL_ATTR_NODISCARD static inline int64_t floor(int64_t x) { return x; }
+LOL_ATTR_NODISCARD static inline float floor(float x) { return std::floor(x); }
+LOL_ATTR_NODISCARD static inline double floor(double x) { return std::floor(x); }
+LOL_ATTR_NODISCARD static inline ldouble floor(ldouble x) { return std::floor(x); }
+
+LOL_ATTR_NODISCARD static inline uint8_t ceil(uint8_t x) { return x; }
+LOL_ATTR_NODISCARD static inline int8_t ceil(int8_t x) { return x; }
+LOL_ATTR_NODISCARD static inline uint16_t ceil(uint16_t x) { return x; }
+LOL_ATTR_NODISCARD static inline int16_t ceil(int16_t x) { return x; }
+LOL_ATTR_NODISCARD static inline uint32_t ceil(uint32_t x) { return x; }
+LOL_ATTR_NODISCARD static inline int32_t ceil(int32_t x) { return x; }
+LOL_ATTR_NODISCARD static inline uint64_t ceil(uint64_t x) { return x; }
+LOL_ATTR_NODISCARD static inline int64_t ceil(int64_t x) { return x; }
+LOL_ATTR_NODISCARD static inline float ceil(float x) { return std::ceil(x); }
+LOL_ATTR_NODISCARD static inline double ceil(double x) { return std::ceil(x); }
+LOL_ATTR_NODISCARD static inline ldouble ceil(ldouble x) { return std::ceil(x); }
+
+LOL_ATTR_NODISCARD static inline uint8_t round(uint8_t x) { return x; }
+LOL_ATTR_NODISCARD static inline int8_t round(int8_t x) { return x; }
+LOL_ATTR_NODISCARD static inline uint16_t round(uint16_t x) { return x; }
+LOL_ATTR_NODISCARD static inline int16_t round(int16_t x) { return x; }
+LOL_ATTR_NODISCARD static inline uint32_t round(uint32_t x) { return x; }
+LOL_ATTR_NODISCARD static inline int32_t round(int32_t x) { return x; }
+LOL_ATTR_NODISCARD static inline uint64_t round(uint64_t x) { return x; }
+LOL_ATTR_NODISCARD static inline int64_t round(int64_t x) { return x; }
+LOL_ATTR_NODISCARD static inline float round(float x) { return std::round(x); }
+LOL_ATTR_NODISCARD static inline double round(double x) { return std::round(x); }
+LOL_ATTR_NODISCARD static inline ldouble round(ldouble x) { return std::round(x); }
 
 #define LOL_GENERIC_FUNC(T) \
-    static inline T sq(T x) { return x * x; } \
-    static inline T fract(T x) { return x - lol::floor(x); } \
-    static inline T min(T x, T y) { return std::min(x, y); } \
-    static inline T max(T x, T y) { return std::max(x, y); } \
-    static inline T clamp(T x, T y, T z) { return min(max(x, y), z); } \
-    static inline T saturate(T x) { return min(max(x, (T)0), (T)1); }
+    LOL_ATTR_NODISCARD static inline T sq(T x) { return x * x; } \
+    LOL_ATTR_NODISCARD static inline T fract(T x) { return x - lol::floor(x); } \
+    LOL_ATTR_NODISCARD static inline T min(T x, T y) { return std::min(x, y); } \
+    LOL_ATTR_NODISCARD static inline T max(T x, T y) { return std::max(x, y); } \
+    LOL_ATTR_NODISCARD static inline T clamp(T x, T y, T z) { return min(max(x, y), z); } \
+    LOL_ATTR_NODISCARD static inline T saturate(T x) { return min(max(x, (T)0), (T)1); }
 
 #define LOL_GENERIC_FUNC_SIGNED(T) \
     LOL_GENERIC_FUNC(T) \
-    static inline T sign(T x) { return (T)(((T)0 < x) - (x < (T)0)); }
+    LOL_ATTR_NODISCARD static inline T sign(T x) { return (T)(((T)0 < x) - (x < (T)0)); }
 
 #define LOL_GENERIC_FUNC_UNSIGNED(T) \
     LOL_GENERIC_FUNC(T) \
-    static inline T sign(T x) { return (T)((T)0 < x); }
+    LOL_ATTR_NODISCARD static inline T sign(T x) { return (T)((T)0 < x); }
 
 LOL_GENERIC_FUNC_UNSIGNED(uint8_t)
 LOL_GENERIC_FUNC_SIGNED(int8_t)
diff --git a/src/lol/math/geometry.h b/src/lol/math/geometry.h
index ac01b3e7..ca78af48 100644
--- a/src/lol/math/geometry.h
+++ b/src/lol/math/geometry.h
@@ -29,7 +29,7 @@ namespace lol
 {
 
 //AxisBase --------------------------------------------------------------------
-    struct AxisBase : public StructSafeEnum
+struct AxisBase : public StructSafeEnum
 {
     enum Type
     {
@@ -90,7 +90,7 @@ T_(box_t<, C_ 4>, box4)
 #undef T_
 
 template<typename T, int N>
-struct box_t
+struct LOL_ATTR_NODISCARD box_t
 {
     inline box_t()
       : aa(vec_t<T, N>(T(0))),
@@ -153,12 +153,12 @@ struct box_t
         return *this = *this * s;
     }
 
-    bool operator ==(box_t<T,N> const &box) const
+    LOL_ATTR_NODISCARD bool operator ==(box_t<T,N> const &box) const
     {
         return aa == box.aa && bb == box.bb;
     }
 
-    bool operator !=(box_t<T,N> const &box) const
+    LOL_ATTR_NODISCARD bool operator !=(box_t<T,N> const &box) const
     {
         return aa != box.aa || bb != box.bb;
     }
@@ -192,19 +192,19 @@ private:
     float Minus() const;
     float Plus()  const;
 public:
-    bool operator==(float value) const;
-    bool operator!=(float value) const;
-    bool operator<(float value)  const;
-    bool operator<=(float value) const;
-    bool operator>(float value)  const;
-    bool operator>=(float value) const;
+    LOL_ATTR_NODISCARD bool operator==(float value) const;
+    LOL_ATTR_NODISCARD bool operator!=(float value) const;
+    LOL_ATTR_NODISCARD bool operator<(float value)  const;
+    LOL_ATTR_NODISCARD bool operator<=(float value) const;
+    LOL_ATTR_NODISCARD bool operator>(float value)  const;
+    LOL_ATTR_NODISCARD bool operator>=(float value) const;
 };
-bool operator==(float value, const TestEpsilon& epsilon);
-bool operator!=(float value, const TestEpsilon& epsilon);
-bool operator<(float value, const TestEpsilon& epsilon);
-bool operator<=(float value, const TestEpsilon& epsilon);
-bool operator>(float value, const TestEpsilon& epsilon);
-bool operator>=(float value, const TestEpsilon& epsilon);
+LOL_ATTR_NODISCARD bool operator==(float value, const TestEpsilon& epsilon);
+LOL_ATTR_NODISCARD bool operator!=(float value, const TestEpsilon& epsilon);
+LOL_ATTR_NODISCARD bool operator<(float value, const TestEpsilon& epsilon);
+LOL_ATTR_NODISCARD bool operator<=(float value, const TestEpsilon& epsilon);
+LOL_ATTR_NODISCARD bool operator>(float value, const TestEpsilon& epsilon);
+LOL_ATTR_NODISCARD bool operator>=(float value, const TestEpsilon& epsilon);
 
 //--
 static inline bool TestAABBVsAABB(box2 const &b1, box2 const &b2)
diff --git a/src/lol/math/half.h b/src/lol/math/half.h
index 9e538d23..dcf3dbfe 100644
--- a/src/lol/math/half.h
+++ b/src/lol/math/half.h
@@ -30,7 +30,7 @@ namespace lol
 
 namespace half_ops { struct base {}; }
 
-class half
+class LOL_ATTR_NODISCARD half
   : half_ops::base
 {
 public:
@@ -42,22 +42,22 @@ public:
     inline half(double f) { *this = makefast((float)f); }
     inline half(ldouble f) { *this = makefast((float)f); }
 
-    inline int is_nan() const
+    LOL_ATTR_NODISCARD inline int is_nan() const
     {
         return ((bits & 0x7c00u) == 0x7c00u) && (bits & 0x03ffu);
     }
 
-    inline int is_finite() const
+    LOL_ATTR_NODISCARD inline int is_finite() const
     {
         return (bits & 0x7c00u) != 0x7c00u;
     }
 
-    inline int is_inf() const
+    LOL_ATTR_NODISCARD inline int is_inf() const
     {
         return (uint16_t)(bits << 1) == (0x7c00u << 1);
     }
 
-    inline int is_normal() const
+    LOL_ATTR_NODISCARD inline int is_normal() const
     {
         return (is_finite() && (bits & 0x7c00u)) || ((bits & 0x7fffu) == 0);
     }
@@ -67,33 +67,33 @@ public:
     inline half &operator =(float f) { return *this = makefast(f); }
     inline half &operator =(double f) { return *this = makefast((float)f); }
     inline half &operator =(ldouble f) { return *this = makefast((float)f); }
-    inline operator int8_t() const { return (int8_t)(float)*this; }
-    inline operator uint8_t() const { return (uint8_t)(float)*this; }
-    inline operator int16_t() const { return (int16_t)(float)*this; }
-    inline operator uint16_t() const { return (uint16_t)(float)*this; }
-    inline operator int32_t() const { return (int32_t)(float)*this; }
-    inline operator uint32_t() const { return (uint32_t)(float)*this; }
-    inline operator int64_t() const { return (int64_t)(float)*this; }
-    inline operator uint64_t() const { return (uint64_t)(float)*this; }
-
-    operator float() const;
-    inline operator double() const { return (float)(*this); }
-    inline operator ldouble() const { return (float)(*this); }
+    LOL_ATTR_NODISCARD inline operator int8_t() const { return (int8_t)(float)*this; }
+    LOL_ATTR_NODISCARD inline operator uint8_t() const { return (uint8_t)(float)*this; }
+    LOL_ATTR_NODISCARD inline operator int16_t() const { return (int16_t)(float)*this; }
+    LOL_ATTR_NODISCARD inline operator uint16_t() const { return (uint16_t)(float)*this; }
+    LOL_ATTR_NODISCARD inline operator int32_t() const { return (int32_t)(float)*this; }
+    LOL_ATTR_NODISCARD inline operator uint32_t() const { return (uint32_t)(float)*this; }
+    LOL_ATTR_NODISCARD inline operator int64_t() const { return (int64_t)(float)*this; }
+    LOL_ATTR_NODISCARD inline operator uint64_t() const { return (uint64_t)(float)*this; }
+
+    LOL_ATTR_NODISCARD operator float() const;
+    LOL_ATTR_NODISCARD inline operator double() const { return (float)(*this); }
+    LOL_ATTR_NODISCARD inline operator ldouble() const { return (float)(*this); }
 
     /* Array conversions */
-    static size_t convert(half *dst, float const *src, size_t nelem);
-    static size_t convert(float *dst, half const *src, size_t nelem);
+    LOL_ATTR_NODISCARD static size_t convert(half *dst, float const *src, size_t nelem);
+    LOL_ATTR_NODISCARD static size_t convert(float *dst, half const *src, size_t nelem);
 
     /* Operations */
-    bool operator ==(half x) const { return (float)*this == (float)x; }
-    bool operator !=(half x) const { return (float)*this != (float)x; }
-    bool operator <(half x) const { return (float)*this < (float)x; }
-    bool operator >(half x) const { return (float)*this > (float)x; }
-    bool operator <=(half x) const { return (float)*this <= (float)x; }
-    bool operator >=(half x) const { return (float)*this >= (float)x; }
+    LOL_ATTR_NODISCARD bool operator ==(half x) const { return (float)*this == (float)x; }
+    LOL_ATTR_NODISCARD bool operator !=(half x) const { return (float)*this != (float)x; }
+    LOL_ATTR_NODISCARD bool operator <(half x) const { return (float)*this < (float)x; }
+    LOL_ATTR_NODISCARD bool operator >(half x) const { return (float)*this > (float)x; }
+    LOL_ATTR_NODISCARD bool operator <=(half x) const { return (float)*this <= (float)x; }
+    LOL_ATTR_NODISCARD bool operator >=(half x) const { return (float)*this >= (float)x; }
 
-    bool operator !() const { return !(bits & 0x7fffu); }
-    operator bool() const { return !!*this; }
+    LOL_ATTR_NODISCARD bool operator !() const { return !(bits & 0x7fffu); }
+    LOL_ATTR_NODISCARD operator bool() const { return !!*this; }
 
     inline half operator -() const { return makebits(bits ^ 0x8000u); }
     inline half operator +() const { return *this; }
@@ -102,10 +102,10 @@ public:
     inline half &operator *=(half h) { return (*this = (half)(*this * h)); }
     inline half &operator /=(half h) { return (*this = (half)(*this / h)); }
 
-    inline float operator +(half h) const { return (float)*this + (float)h; }
-    inline float operator -(half h) const { return (float)*this - (float)h; }
-    inline float operator *(half h) const { return (float)*this * (float)h; }
-    inline float operator /(half h) const { return (float)*this / (float)h; }
+    LOL_ATTR_NODISCARD inline float operator +(half h) const { return (float)*this + (float)h; }
+    LOL_ATTR_NODISCARD inline float operator -(half h) const { return (float)*this - (float)h; }
+    LOL_ATTR_NODISCARD inline float operator *(half h) const { return (float)*this * (float)h; }
+    LOL_ATTR_NODISCARD inline float operator /(half h) const { return (float)*this / (float)h; }
 
     /* Factories */
     static half makefast(float f);
diff --git a/src/lol/math/matrix.h b/src/lol/math/matrix.h
index 36c9baf1..b502aba7 100644
--- a/src/lol/math/matrix.h
+++ b/src/lol/math/matrix.h
@@ -34,7 +34,7 @@ namespace lol
  */
 
 template<typename T, int COLS, int ROWS>
-struct mat_t
+struct LOL_ATTR_NODISCARD mat_t
   : public linear_ops::base<vec_t<T,ROWS>>
 {
     static int const count = COLS;
@@ -72,7 +72,7 @@ private:
  */
 
 template <typename T>
-struct mat_t<T, 2, 2>
+struct LOL_ATTR_NODISCARD mat_t<T, 2, 2>
   : public linear_ops::base<vec_t<T,2>>
 {
     static int const count = 2;
@@ -157,7 +157,7 @@ static_assert(sizeof(dmat2) == 32, "sizeof(dmat2) == 32");
  */
 
 template <typename T>
-struct mat_t<T, 3, 3>
+struct LOL_ATTR_NODISCARD mat_t<T, 3, 3>
   : public linear_ops::base<vec_t<T,3>>
 {
     static int const count = 3;
@@ -288,7 +288,7 @@ static_assert(sizeof(dmat3) == 72, "sizeof(dmat3) == 72");
  */
 
 template <typename T>
-struct mat_t<T, 4, 4>
+struct LOL_ATTR_NODISCARD mat_t<T, 4, 4>
   : public linear_ops::base<vec_t<T,4>>
 {
     static int const count = 4;
@@ -498,7 +498,7 @@ mat_t<T, N - 1, N - 1> submatrix(mat_t<T, N, N> const &m, int i, int j)
  * Compute square matrix cofactor
  */
 
-template<typename T, int N>
+template<typename T, int N> LOL_ATTR_NODISCARD
 T cofactor(mat_t<T, N, N> const &m, int i, int j)
 {
     ASSERT(i >= 0); ASSERT(j >= 0); ASSERT(i < N); ASSERT(j < N);
@@ -506,7 +506,7 @@ T cofactor(mat_t<T, N, N> const &m, int i, int j)
     return ((i + j) & 1) ? -tmp : tmp;
 }
 
-template<typename T>
+template<typename T> LOL_ATTR_NODISCARD
 T cofactor(mat_t<T, 2, 2> const &m, int i, int j)
 {
     /* This specialisation shouldn't be needed, but Visual Studio. */
@@ -548,7 +548,7 @@ void lu_decomposition(mat_t<T, N, N> const &m, mat_t<T, N, N> & L, mat_t<T, N, N
  * Compute square matrix determinant, with a specialisation for 1×1 matrices
  */
 
-template<typename T, int N>
+template<typename T, int N> LOL_ATTR_NODISCARD
 T determinant(mat_t<T, N, N> const &m)
 {
     mat_t<T, N, N> L, U;
@@ -562,7 +562,7 @@ T determinant(mat_t<T, N, N> const &m)
     return permutation_det(P) * det;
 }
 
-template<typename T>
+template<typename T> LOL_ATTR_NODISCARD
 T const & determinant(mat_t<T, 1, 1> const &m)
 {
     return m[0][0];
@@ -655,7 +655,7 @@ vec_t<int, N> p_transpose(vec_t<int, N> P)
  * Compute the determinant of a permutation square matrix corresponding to the permutation vector
  */
 
-template<int N>
+template<int N> LOL_ATTR_NODISCARD
 int permutation_det(vec_t<int, N> const & permutation)
 {
     int result = 1;
diff --git a/src/lol/math/ops.h b/src/lol/math/ops.h
index 6e274248..11bc364d 100644
--- a/src/lol/math/ops.h
+++ b/src/lol/math/ops.h
@@ -70,14 +70,14 @@ namespace swizzle_ops
 namespace swizzle_ops
 {
 
-template<typename T, int N, int SWIZZLE1, int SWIZZLE2>
+template<typename T, int N, int SWIZZLE1, int SWIZZLE2> LOL_ATTR_NODISCARD
 static inline typename std::enable_if<SWIZZLE1 != FULL_SWIZZLE || SWIZZLE2 != FULL_SWIZZLE, bool>::type
 operator ==(vec_t<T,N,SWIZZLE1> const &a, vec_t<T,N,SWIZZLE2> const &b)
 {
     return vec_t<T,N>(a) == vec_t<T,N>(b);
 }
 
-template<typename T, int N, int SWIZZLE1, int SWIZZLE2>
+template<typename T, int N, int SWIZZLE1, int SWIZZLE2> LOL_ATTR_NODISCARD
 static inline typename std::enable_if<SWIZZLE1 != FULL_SWIZZLE || SWIZZLE2 != FULL_SWIZZLE, bool>::type
 operator !=(vec_t<T,N,SWIZZLE1> const &a, vec_t<T,N,SWIZZLE2> const &b)
 {
@@ -135,7 +135,7 @@ namespace linear_ops
  * Comparisons
  */
 
-template<typename V>
+template<typename V> LOL_ATTR_NODISCARD
 static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, bool>::type
 operator ==(V const &a, V const &b)
 {
@@ -145,7 +145,7 @@ operator ==(V const &a, V const &b)
     return true;
 }
 
-template<typename V>
+template<typename V> LOL_ATTR_NODISCARD
 static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, bool>::type
 operator !=(V const &a, V const &b)
 {
diff --git a/src/lol/math/polynomial.h b/src/lol/math/polynomial.h
index 385a8821..aeeac6c6 100644
--- a/src/lol/math/polynomial.h
+++ b/src/lol/math/polynomial.h
@@ -25,7 +25,7 @@ namespace lol
 {
 
 template<typename T>
-struct polynomial
+struct LOL_ATTR_NODISCARD polynomial
 {
     /* The zero polynomial */
     explicit inline polynomial() {}
@@ -90,7 +90,7 @@ struct polynomial
     /* Evaluate polynomial at a given value. This method can also
      * be used to compose polynomials, i.e. using another polynomial
      * as the value instead of a scalar. */
-    template<typename U> U eval(U x) const
+    template<typename U> LOL_ATTR_NODISCARD U eval(U x) const
     {
         U ret(leading());
         for (int i = degree() - 1; i >= 0; --i)
@@ -260,7 +260,7 @@ struct polynomial
      * copy because we cannot let the user mess with the integrity of
      * the structure (i.e. the guarantee that the leading coefficient
      * remains non-zero). */
-    inline T operator[](ptrdiff_t n) const
+    LOL_ATTR_NODISCARD inline T operator[](ptrdiff_t n) const
     {
         if (n < 0 || n > degree())
             return T(0);
@@ -269,7 +269,7 @@ struct polynomial
     }
 
     /* Return the leading coefficient */
-    inline T leading() const
+    LOL_ATTR_NODISCARD inline T leading() const
     {
         return (*this)[degree()];
     }
diff --git a/src/lol/math/rand.h b/src/lol/math/rand.h
index 5ad263cd..6256b90a 100644
--- a/src/lol/math/rand.h
+++ b/src/lol/math/rand.h
@@ -22,48 +22,48 @@ namespace lol
 {
 
 /* Random number generators */
-template<typename T> static inline T rand();
-template<typename T> static inline T rand(T a);
-template<typename T> static inline T rand(T a, T b);
+template<typename T> LOL_ATTR_NODISCARD static inline T rand();
+template<typename T> LOL_ATTR_NODISCARD static inline T rand(T a);
+template<typename T> LOL_ATTR_NODISCARD static inline T rand(T a, T b);
 
 /* One-value random number generators */
-template<typename T> static inline T rand(T a)
+template<typename T> LOL_ATTR_NODISCARD static inline T rand(T a)
 {
     return a ? rand<T>() % a : T(0);
 }
 
-template<> inline half rand<half>(half a)
+template<> LOL_ATTR_NODISCARD inline half rand<half>(half a)
 {
     float f = (float)std::rand() / (float)RAND_MAX;
     return (half)(a * f);
 }
 
-template<> inline float rand<float>(float a)
+template<> LOL_ATTR_NODISCARD inline float rand<float>(float a)
 {
     float f = (float)std::rand() / (float)RAND_MAX;
     return a * f;
 }
 
-template<> inline double rand<double>(double a)
+template<> LOL_ATTR_NODISCARD inline double rand<double>(double a)
 {
     double f = (double)std::rand() / (double)RAND_MAX;
     return a * f;
 }
 
-template<> inline ldouble rand<ldouble>(ldouble a)
+template<> LOL_ATTR_NODISCARD inline ldouble rand<ldouble>(ldouble a)
 {
     ldouble f = (ldouble)std::rand() / (ldouble)RAND_MAX;
     return a * f;
 }
 
 /* Two-value random number generator -- no need for specialisation */
-template<typename T> static inline T rand(T a, T b)
+template<typename T> LOL_ATTR_NODISCARD static inline T rand(T a, T b)
 {
     return a + rand<T>(b - a);
 }
 
 /* Default random number generator */
-template<typename T> static inline T rand()
+template<typename T> LOL_ATTR_NODISCARD static inline T rand()
 {
     switch (sizeof(T))
     {
@@ -117,10 +117,10 @@ template<typename T> static inline T rand()
     }
 }
 
-template<> inline half rand<half>() { return rand<half>(1.f); }
-template<> inline float rand<float>() { return rand<float>(1.f); }
-template<> inline double rand<double>() { return rand<double>(1.0); }
-template<> inline ldouble rand<ldouble>() { return rand<ldouble>(1.0); }
+template<> LOL_ATTR_NODISCARD inline half rand<half>() { return rand<half>(1.f); }
+template<> LOL_ATTR_NODISCARD inline float rand<float>() { return rand<float>(1.f); }
+template<> LOL_ATTR_NODISCARD inline double rand<double>() { return rand<double>(1.0); }
+template<> LOL_ATTR_NODISCARD inline ldouble rand<ldouble>() { return rand<ldouble>(1.0); }
 
 } /* namespace lol */
 
diff --git a/src/lol/math/real.h b/src/lol/math/real.h
index acba690b..9de383a8 100644
--- a/src/lol/math/real.h
+++ b/src/lol/math/real.h
@@ -35,7 +35,8 @@ namespace lol
  * avoid accidental implicit conversions ("int x = 1; sqrt(x)" will never
  * call real::sqrt).
  */
-template<int N> class Real
+template<int N>
+class LOL_ATTR_NODISCARD Real
 {
 public:
     Real();
@@ -53,11 +54,11 @@ public:
 
     Real(char const *str);
 
-    operator float() const;
-    operator double() const;
-    operator long double() const;
-    operator int() const;
-    operator unsigned int() const;
+    LOL_ATTR_NODISCARD operator float() const;
+    LOL_ATTR_NODISCARD operator double() const;
+    LOL_ATTR_NODISCARD operator long double() const;
+    LOL_ATTR_NODISCARD operator int() const;
+    LOL_ATTR_NODISCARD operator unsigned int() const;
 
     Real<N> operator +() const;
     Real<N> operator -() const;
@@ -70,15 +71,15 @@ public:
     Real<N> const &operator *=(Real<N> const &x);
     Real<N> const &operator /=(Real<N> const &x);
 
-    bool operator ==(Real<N> const &x) const;
-    bool operator !=(Real<N> const &x) const;
-    bool operator <(Real<N> const &x) const;
-    bool operator >(Real<N> const &x) const;
-    bool operator <=(Real<N> const &x) const;
-    bool operator >=(Real<N> const &x) const;
+    LOL_ATTR_NODISCARD bool operator ==(Real<N> const &x) const;
+    LOL_ATTR_NODISCARD bool operator !=(Real<N> const &x) const;
+    LOL_ATTR_NODISCARD bool operator <(Real<N> const &x) const;
+    LOL_ATTR_NODISCARD bool operator >(Real<N> const &x) const;
+    LOL_ATTR_NODISCARD bool operator <=(Real<N> const &x) const;
+    LOL_ATTR_NODISCARD bool operator >=(Real<N> const &x) const;
 
-    bool operator !() const;
-    operator bool() const;
+    LOL_ATTR_NODISCARD bool operator !() const;
+    LOL_ATTR_NODISCARD operator bool() const;
 
     /* Comparison functions */
     template<int K> friend Real<K> min(Real<K> const &a, Real<K> const &b);
@@ -238,11 +239,11 @@ template<> real::Real(int64_t i);
 template<> real::Real(uint64_t i);
 template<> real::Real(char const *str);
 
-template<> real::operator float() const;
-template<> real::operator double() const;
-template<> real::operator long double() const;
-template<> real::operator int() const;
-template<> real::operator unsigned int() const;
+template<> LOL_ATTR_NODISCARD real::operator float() const;
+template<> LOL_ATTR_NODISCARD real::operator double() const;
+template<> LOL_ATTR_NODISCARD real::operator long double() const;
+template<> LOL_ATTR_NODISCARD real::operator int() const;
+template<> LOL_ATTR_NODISCARD real::operator unsigned int() const;
 template<> real real::operator +() const;
 template<> real real::operator -() const;
 template<> real real::operator +(real const &x) const;
@@ -253,14 +254,14 @@ template<> real const &real::operator +=(real const &x);
 template<> real const &real::operator -=(real const &x);
 template<> real const &real::operator *=(real const &x);
 template<> real const &real::operator /=(real const &x);
-template<> bool real::operator ==(real const &x) const;
-template<> bool real::operator !=(real const &x) const;
-template<> bool real::operator <(real const &x) const;
-template<> bool real::operator >(real const &x) const;
-template<> bool real::operator <=(real const &x) const;
-template<> bool real::operator >=(real const &x) const;
-template<> bool real::operator !() const;
-template<> real::operator bool() const;
+template<> LOL_ATTR_NODISCARD bool real::operator ==(real const &x) const;
+template<> LOL_ATTR_NODISCARD bool real::operator !=(real const &x) const;
+template<> LOL_ATTR_NODISCARD bool real::operator <(real const &x) const;
+template<> LOL_ATTR_NODISCARD bool real::operator >(real const &x) const;
+template<> LOL_ATTR_NODISCARD bool real::operator <=(real const &x) const;
+template<> LOL_ATTR_NODISCARD bool real::operator >=(real const &x) const;
+template<> LOL_ATTR_NODISCARD bool real::operator !() const;
+template<> LOL_ATTR_NODISCARD real::operator bool() const;
 
 template<int K> Real<K> min(Real<K> const &a, Real<K> const &b);
 template<int K> Real<K> max(Real<K> const &a, Real<K> const &b);
diff --git a/src/lol/math/transform.h b/src/lol/math/transform.h
index 159656c3..6f153f77 100644
--- a/src/lol/math/transform.h
+++ b/src/lol/math/transform.h
@@ -31,7 +31,7 @@ namespace lol
  */
 
 template<typename T>
-struct cmplx_t : public linear_ops::base<T>
+struct LOL_ATTR_NODISCARD cmplx_t : public linear_ops::base<T>
 {
     static int const count = 2;
     typedef T scalar_element;
@@ -78,7 +78,7 @@ static_assert(sizeof(dcmplx) == 16, "sizeof(dcmplx) == 16");
  */
 
 template<typename T>
-struct quat_t : public linear_ops::base<T>
+struct LOL_ATTR_NODISCARD quat_t : public linear_ops::base<T>
 {
     static int const count = 4;
     typedef T scalar_element;
@@ -233,7 +233,7 @@ struct quat_t : public linear_ops::base<T>
         return normalize(v);
     }
 
-    inline T angle()
+    LOL_ATTR_NODISCARD inline T angle()
     {
         vec_t<T,3> v(x, y, z);
         T n2 = sqlength(v);
@@ -258,7 +258,7 @@ static_assert(sizeof(dquat) == 32, "sizeof(dquat) == 32");
  */
 
 template<typename T>
-struct sqt_t
+struct LOL_ATTR_NODISCARD sqt_t
 {
     /* Default constructor and copy constructor */
     inline constexpr sqt_t() : s(), q(), t() {}
@@ -325,7 +325,7 @@ struct sqt_t
  * Common operations on transforms
  */
 
-template<typename T>
+template<typename T> LOL_ATTR_NODISCARD
 static inline T dot(cmplx_t<T> const &t1, cmplx_t<T> const &t2)
 {
     T ret(0);
@@ -334,20 +334,20 @@ static inline T dot(cmplx_t<T> const &t1, cmplx_t<T> const &t2)
     return ret;
 }
 
-template<typename T>
+template<typename T> LOL_ATTR_NODISCARD
 static inline T sqlength(cmplx_t<T> const &t)
 {
     return dot(t, t);
 }
 
-template<typename T>
+template<typename T> LOL_ATTR_NODISCARD
 static inline T length(cmplx_t<T> const &t)
 {
     /* FIXME: this is not very nice */
     return (T)sqrt((double)sqlength(t));
 }
 
-template<typename T>
+template<typename T> LOL_ATTR_NODISCARD
 static inline T norm(cmplx_t<T> const &t)
 {
     return length(t);
@@ -362,7 +362,7 @@ static inline cmplx_t<T> normalize(cmplx_t<T> const &z)
 
 /* XXX: duplicate */
 
-template<typename T>
+template<typename T> LOL_ATTR_NODISCARD
 static inline T dot(quat_t<T> const &t1, quat_t<T> const &t2)
 {
     T ret(0);
@@ -371,20 +371,20 @@ static inline T dot(quat_t<T> const &t1, quat_t<T> const &t2)
     return ret;
 }
 
-template<typename T>
+template<typename T> LOL_ATTR_NODISCARD
 static inline T sqlength(quat_t<T> const &t)
 {
     return dot(t, t);
 }
 
-template<typename T>
+template<typename T> LOL_ATTR_NODISCARD
 static inline T length(quat_t<T> const &t)
 {
     /* FIXME: this is not very nice */
     return (T)sqrt((double)sqlength(t));
 }
 
-template<typename T>
+template<typename T> LOL_ATTR_NODISCARD
 static inline T norm(quat_t<T> const &t)
 {
     return length(t);
@@ -419,22 +419,22 @@ static inline cmplx_t<T> operator /(cmplx_t<T> a, cmplx_t<T> const &b)
     return a * inverse(b);
 }
 
-template<typename T>
+template<typename T> LOL_ATTR_NODISCARD
 static inline bool operator ==(cmplx_t<T> const &a, T b)
 {
     return (a.x == b) && !a.y;
 }
 
-template<typename T>
+template<typename T> LOL_ATTR_NODISCARD
 static inline bool operator !=(cmplx_t<T> const &a, T b)
 {
     return (a.x != b) || a.y;
 }
 
-template<typename T>
+template<typename T> LOL_ATTR_NODISCARD
 static inline bool operator ==(T a, cmplx_t<T> const &b) { return b == a; }
 
-template<typename T>
+template<typename T> LOL_ATTR_NODISCARD
 static inline bool operator !=(T a, cmplx_t<T> const &b) { return b != a; }
 
 /*
diff --git a/src/lol/math/vector.h b/src/lol/math/vector.h
index 507a96f7..7e75221a 100644
--- a/src/lol/math/vector.h
+++ b/src/lol/math/vector.h
@@ -57,7 +57,7 @@ namespace lol
  */
 
 template<typename T, int N, int SWIZZLE>
-struct vec_t
+struct LOL_ATTR_NODISCARD vec_t
     /* MUST have a different base than e.g. vec_t<T,2> otherwise the unions
      * in vec_t<T,2> with the same base will cause empty base optimisation
      * failures. */
@@ -108,7 +108,7 @@ struct vec_t
 /* The generic “vec_t” type, which is a fixed-size vector with no
  * swizzling. There's an override for N=2, N=3, N=4 that has swizzling. */
 template<typename T, int N>
-struct vec_t<T, N, FULL_SWIZZLE>
+struct LOL_ATTR_NODISCARD vec_t<T, N, FULL_SWIZZLE>
   : public componentwise_ops::base<T>
 {
     static int const count = N;
@@ -221,7 +221,7 @@ private:
  */
 
 template <typename T>
-struct vec_t<T,2>
+struct LOL_ATTR_NODISCARD vec_t<T,2>
   : public swizzle_ops::base<T>
 {
     static int const count = 2;
@@ -337,7 +337,7 @@ static_assert(sizeof(dvec2) == 16, "sizeof(dvec2) == 16");
  */
 
 template <typename T>
-struct vec_t<T,3>
+struct LOL_ATTR_NODISCARD vec_t<T,3>
   : public swizzle_ops::base<T>
 {
     static int const count = 3;
@@ -583,7 +583,7 @@ static_assert(sizeof(dvec3) == 24, "sizeof(dvec3) == 24");
  */
 
 template <typename T>
-struct vec_t<T,4>
+struct LOL_ATTR_NODISCARD vec_t<T,4>
   : public swizzle_ops::base<T>
 {
     static int const count = 4;
@@ -1138,7 +1138,7 @@ static inline vec_t<T,N> mix(vec_t<T,N,SWIZZLE1> const &x,
  * Some GLSL-like functions.
  */
 
-template<typename T, int N, int SWIZZLE1, int SWIZZLE2>
+template<typename T, int N, int SWIZZLE1, int SWIZZLE2> LOL_ATTR_NODISCARD
 static inline T dot(vec_t<T,N,SWIZZLE1> const &a,
                     vec_t<T,N,SWIZZLE2> const &b)
 {
@@ -1148,13 +1148,13 @@ static inline T dot(vec_t<T,N,SWIZZLE1> const &a,
     return ret;
 }
 
-template<typename T, int N, int SWIZZLE>
+template<typename T, int N, int SWIZZLE> LOL_ATTR_NODISCARD
 static inline T sqlength(vec_t<T,N,SWIZZLE> const &a)
 {
     return dot(a, a);
 }
 
-template<typename T, int N, int SWIZZLE>
+template<typename T, int N, int SWIZZLE> LOL_ATTR_NODISCARD
 static inline T length(vec_t<T,N,SWIZZLE> const &a)
 {
     /* FIXME: this is not very nice */
@@ -1172,7 +1172,7 @@ static inline vec_t<T,N> lerp(vec_t<T,N,SWIZZLE1> const &a,
     return ret;
 }
 
-template<typename T, int N, int SWIZZLE1, int SWIZZLE2>
+template<typename T, int N, int SWIZZLE1, int SWIZZLE2> LOL_ATTR_NODISCARD
 static inline T distance(vec_t<T,N,SWIZZLE1> const &a,
                          vec_t<T,N,SWIZZLE2> const &b)
 {