[PATCH] Make ex::operator[] const dispatch to basic::operator[] const.
authorRichard Kreckel <kreckel@ginac.de>
Mon, 5 Apr 2021 18:46:55 +0000 (20:46 +0200)
committerRichard Kreckel <kreckel@ginac.de>
Mon, 5 Apr 2021 19:06:41 +0000 (21:06 +0200)
It turned out that ex::operator[] const dispatched to non-const
basic::operator[] because
* member variable ex::bp is non-const and
* ptr<T>::operator*() returns a non-const T &.

As a result, indexing failed for multiply referenced objects.

Thanks to Vitaly Magerya <vmagerya@gmail.com> for reporting this.

check/exam_paranoia.cpp
ginac/ex.h

index 7a89f9de19e90943dc916a6922f01226690b4af7..af36238bbe9889688772901704cf80c68178a0d0 100644 (file)
@@ -638,6 +638,27 @@ unsigned exam_paranoia26()
        return result;
 }
 
+// Bug in collect()
+// cf. https://www.ginac.de/pipermail/ginac-list/2021-March/002337.html
+static unsigned exam_collect_multiply_referenced_lst()
+{
+        unsigned result = 0;
+        symbol x("x"), y("y");
+        ex a = x + y;
+        ex l = lst{x, y};
+        ex l2 = l;  // make l a multiply referenced object
+
+        try {
+                ex b = collect(a, l);
+        } catch (const std::runtime_error & e) {
+                clog << "collect(" << ", " << l << ") threw a runtime_error("
+                     << e.what() << ")" << endl;
+                ++result;
+        }
+
+        return result;
+}
+
 unsigned exam_paranoia()
 {
        unsigned result = 0;
@@ -672,6 +693,7 @@ unsigned exam_paranoia()
        result += exam_paranoia24();  cout << '.' << flush;
        result += exam_paranoia25();  cout << '.' << flush;
        result += exam_paranoia26();  cout << '.' << flush;
+       result += exam_collect_multiply_referenced_lst();  cout << '.' << flush;
        
        return result;
 }
index dccf37af2edeb93eefffb2d6a1f1e61145d70880..6c9d429c7a6403e0b620a73c7ea31da0b5a9c433 100644 (file)
@@ -134,8 +134,8 @@ public:
        // operand access
        size_t nops() const { return bp->nops(); }
        ex op(size_t i) const { return bp->op(i); }
-       ex operator[](const ex & index) const { return (*bp)[index]; }
-       ex operator[](size_t i) const { return (*bp)[i]; }
+       ex operator[](const ex & index) const { return (const_cast<const basic&>(*bp))[index]; }
+       ex operator[](size_t i) const { return (const_cast<const basic&>(*bp))[i]; }
        ex & let_op(size_t i);
        ex & operator[](const ex & index);
        ex & operator[](size_t i);