#include #include // This code demonstrates the error that causes the unit test TeuchosParameterList_StringIndexedOrderedValueObjectContainer to fail // This code fails for optimization level 0 but succeeds for other optimization levels. // Tested for clang: Apple LLVM version 7.3.0 (clang-703.0.31) // The bug can be reproduced using a simple command line build with optimization level set to 0 // build: clang++ -o test test.cpp -O0 Bad! begin() = end() but should be different. // build: clang++ -o test test.cpp -O1 OK // build: clang++ -o test test.cpp -O2 OK // build: clang++ -o test test.cpp -O3 OK // // Notable Things // Change deque to vector clears all problems // Direct read of deque begin() and end() seems ok but reading through templated functions is not ok // Checking deque size() always seems ok // There are several lines of code which can be added after the 'problem' which then clear the problem. Commented out at the end. // // Some spurious things we can remove from this code which also remove the bug // The template declaration on the Item class // Change the 'itr1.current()' to be 'itr1.current_' // Change the container1 object to have the same template type as container2 // Remove the container1 object or remove the check on it's begin() and end() which are fine // Remove the dummy1 or dummy2 input parameters below // Change the inputs to those dummy variables from the current begin() and end() settings template class Filter { public: // remove the spurious dummy1 or dummy2 and in the call below and then OK Filter( Type current, Type dummy1, Type dummy2 ) : current_(current) {} Type current() const { return current_; } Type current_; }; template bool operator==(const Filter& itr1, const Filter& itr2) { return itr1.current() == itr2.current(); // change first current() to current_ then ok } template class Item // remove the spurious template parameter and then OK { public: Item(std::string name) : name_(name) {} std::string name_; }; template class Container { public: typedef Item item_t; typedef std::deque deque_t; // change deque to vector and then OK typedef Filter const_itr; Container() {} void addElement(std::string key) { deque_.push_back(item_t(key)); } // note the second two parameters are spurious but removing them or changing and then OK const_itr begin() const { return const_itr( deque_.begin(), deque_.begin(), deque_.end() ); } const_itr end() const { return const_itr( deque_.end(), deque_.begin(), deque_.end() ); } deque_t deque_; }; int main( int argc, char* argv[] ) { Container container1; // change template to match other type (double) and then OK container1.addElement("AAA"); if( container1.begin() == container1.end() ) { std::cout << "This never happens and it shouldn't happen..." << std::endl; } // remove this line and then OK Container container2; // or change this template to match first (int) and then OK container2.addElement("BBB"); if( container2.begin() == container2.end() ) { std::cout << "Bad! begin() = end() but should be different." << std::endl; return 1; } // This will verify direct read is ok // if( container2.deque_.begin() != container2.deque_.end() ) { std::cout << "Direct read of container2 begin() and end() is ok - not equal." << std::endl; } // This will verify deque size is 1 as it should be // std::cout << "deque size is " << container1.deque_.size() << std::endl; // Adding any of these lines 'fixes' the above error so it won't happen... // if( container2.deque_.begin() != container2.begin().current() ) { std::cout << "begin() direct does not match begin() through Filter." << std::endl; } // if( container2.deque_.end() != container2.end().current() ) { std::cout << "begin() direct does not match begin() through Filter." << std::endl; } // container2.end().current(); // container2.begin().current(); // Adding any of these lines does not 'fix' the above error // container1.begin(); // container1.end(); // container2.begin(); // container2.end(); // container1.end().current(); // container1.begin().current(); std::cout << "OK" << std::endl; return 0; }