[Gmp-commit] /var/hg/gmp: Do not use mp directly in mpz_class

mercurial at gmplib.org mercurial at gmplib.org
Mon Apr 18 16:21:48 CEST 2022


details:   /var/hg/gmp/rev/88e4445a72d1
changeset: 18347:88e4445a72d1
user:      Marc Glisse <marc.glisse at inria.fr>
date:      Mon Apr 18 16:19:20 2022 +0200
description:
Do not use mp directly in mpz_class

This is the difference between f and g in the following,
where gcc generates "return 1;" for f and not for g.
The aliasing is caused by the functions get_num and get_den
in mpq_class.

struct mpz_struct { int i; };
typedef mpz_struct mpz_t[1];
struct mpq_struct { mpz_struct num, den; };
typedef mpq_struct mpq_t[1];
struct mpz_class { mpz_t mp; };
struct mpq_class { mpq_t mp; };

int f(mpq_class*q, mpz_class*z){
  q->mp->num.i = 1;
  z->mp->i = 2;
  return q->mp->num.i;
}
int g(mpq_class*q, mpz_class*z){
  q->mp->num.i = 1;
  int*p=&z->mp->i;
  *p = 2;
  return q->mp->num.i;
}

diffstat:

 ChangeLog |   4 ++++
 gmpxx.h   |  17 ++++++++++-------
 2 files changed, 14 insertions(+), 7 deletions(-)

diffs (66 lines):

diff -r 541600d84118 -r 88e4445a72d1 ChangeLog
--- a/ChangeLog	Mon Apr 18 09:09:50 2022 +0200
+++ b/ChangeLog	Mon Apr 18 16:19:20 2022 +0200
@@ -1,3 +1,7 @@
+2022-04-18  Marc Glisse  <marc.glisse at inria.fr>
+
+	* gmpxx.h (mpz_class): Do not use mp directly.
+
 2022-03-18 Marco Bodrato <bodrato at mail.dm.unipi.it>
 
 	* tests/mpz/t-lucm.c: Remove an unused var.
diff -r 541600d84118 -r 88e4445a72d1 gmpxx.h
--- a/gmpxx.h	Mon Apr 18 09:09:50 2022 +0200
+++ b/gmpxx.h	Mon Apr 18 16:19:20 2022 +0200
@@ -1580,7 +1580,7 @@
   void assign_ui(unsigned long l)
   {
     if (__GMPXX_CONSTANT_TRUE(l == 0))
-      mp->_mp_size = 0;
+      __get_mp()->_mp_size = 0;
     else
       mpz_set_ui(mp, l);
   }
@@ -1634,7 +1634,7 @@
   __gmp_expr(const __gmp_expr &z) { mpz_init_set(mp, z.mp); }
 #if __GMPXX_USE_CXX11
   __gmp_expr(__gmp_expr &&z) noexcept
-  { *mp = *z.mp; mpz_init(z.mp); }
+  { *__get_mp() = *z.__get_mp(); mpz_init(z.mp); }
 #endif
   template <class T>
   __gmp_expr(const __gmp_expr<mpz_t, T> &expr)
@@ -1666,7 +1666,8 @@
 
   ~__gmp_expr() { mpz_clear(mp); }
 
-  void swap(__gmp_expr& z) __GMPXX_NOEXCEPT { std::swap(*mp, *z.mp); }
+  void swap(__gmp_expr& z) __GMPXX_NOEXCEPT
+  { std::swap(*__get_mp(), *z.__get_mp()); }
 
   // assignment operators
   __gmp_expr & operator=(const __gmp_expr &z)
@@ -1728,7 +1729,7 @@
   // bool fits_ldouble_p() const { return mpz_fits_ldouble_p(mp); }
 
 #if __GMPXX_USE_CXX11
-  explicit operator bool() const { return mp->_mp_size != 0; }
+  explicit operator bool() const { return __get_mp()->_mp_size != 0; }
 #endif
 
   // member operators
@@ -1896,9 +1897,11 @@
 
   // conversion functions
 
-  // casting a reference to an mpz_t to mpz_class & is a dirty hack,
-  // but works because the internal representation of mpz_class is
-  // exactly an mpz_t
+  // casting a reference to an mpz_t to mpz_class & is a dirty hack.
+  // It kind of works because the internal representation of mpz_class is
+  // exactly an mpz_t, but compilers are allowed to assume that mpq_class
+  // and mpz_class do not alias... In mpz_class, we avoid using mp directly,
+  // to reduce the risks of such problematic optimizations.
   const mpz_class & get_num() const
   { return reinterpret_cast<const mpz_class &>(*mpq_numref(mp)); }
   mpz_class & get_num()


More information about the gmp-commit mailing list