Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Circle compiles the MULTI library (almost) #118

Closed
correaa opened this issue May 5, 2022 · 29 comments
Closed

Circle compiles the MULTI library (almost) #118

correaa opened this issue May 5, 2022 · 29 comments

Comments

@correaa
Copy link

correaa commented May 5, 2022

Hi @seanbaxter , Alfredo here.

I wanted to let you know that I worked around all the errors in my code that circle complained about and other compilers didn't complain about.
So, circle b170 can compile the library (tests).

https://gitlab.com/correaa/boost-multi/-/jobs/2412971718

Thank you very much, I mention your compiler as one of the compatible compilers, https://gitlab.com/correaa/boost-multi#dependecies-and-compiler-requirements

I will keep your compiler in the CI so if something else arises, I will let you know.

Having said that, there are still about a dozen locations that I have to workaround by plainly commenting code.
Fortunately they are in tests only and not in the header file.

There are two types of problems, crashes and not recognizing constexpr that other compiler do recognize as constexpr (may be you are right and other compilers are wrong, I don't know).
These are all the places (file and line number and at the reason at the end of the line) I had to comment.

test/constructors.cpp:49:	#if defined(__cpp_deduction_guides) and not defined(__NVCC__) and not defined(__circle_build__)  // circle 170 crashes
test/constructors.cpp:74:#if defined(__cpp_deduction_guides) and not defined(__NVCC__) and not defined(__circle_build__)  // circle 170 crashes
test/layout.cpp:233:#if defined(__circle_build__)  // circle doesn't see dimensionality as a constexpr "cannot access value of A at compile time;"
test/layout.cpp:252:#if defined(__circle_build__)  // circle doesn't recognize this as a constexpr "cannot access value of A at compile time;"
test/initializer_list.cpp:73:	#if defined(__cpp_deduction_guides) and not defined(__NVCC__) and not defined(__circle_build__)  // circle 170 crashes
test/initializer_list.cpp:273:	#if defined(__cpp_deduction_guides) and not defined(__NVCC__) and not defined(__circle_build__)  // circle 170 crashes
test/iterator.cpp:48:	#if not defined(__circle_build__)  // circle 170 crashes
test/iterator.cpp:51:	#if not defined(__circle_build__)  // circle 170 crashes
test/iterator.cpp:54:	#if not defined(__circle_build__)  // circle 170 crashes
test/array_ref.cpp:299:	#if not defined(__circle_build__)  // circle 170 crashes https://github.com/seanbaxter/circle/issues/114

all these files are here: https://gitlab.com/correaa/boost-multi/-/tree/master/test

If it helps debugging, this is how I compile the library (tests):

$ git clone https://gitlab.com/correaa/boost-multi.git
$ cd boost-multi
$ mkdir build && cd build
$ CXX=/builds/correaa/boost-multi/build_latest/circle cmake .. -DBOOST_LIBRARYDIR=/usr/lib/x86_64-linux-gnu/ -DENABLE_CIRCLE=1
$ make VERBOSE=1
$ ctest --output-on-failure
@seanbaxter
Copy link
Owner

Thanks for the report. I'll get to work on it this week.

@correaa
Copy link
Author

correaa commented Dec 8, 2022

The library is added to godbolt Circle now. https://godbolt.org/z/fMxE5GhYr
Doesn't use any Circle feature yet, but I am considering to.

@correaa
Copy link
Author

correaa commented Jun 9, 2023

This code block used to crash with circle 170.
Now it works well with circle 198

test/constructors.cpp:49: #if defined(__cpp_deduction_guides) and not defined(__NVCC__) and not defined(__circle_build__) // circle 170 crashes

	#if defined(__cpp_deduction_guides) and not defined(__NVCC__) and not defined(__circle_build__)  // circle 170 crashes
	{
		multi::array arr(multi::extensions_t<1>{{0, 10}}, double{});
		BOOST_REQUIRE( size(arr)==10 );
		BOOST_REQUIRE( arr[5]== double{} );
	}
	{
		multi::array arr({{0, 10}}, double{});
		BOOST_REQUIRE( size(arr)==10 );
		BOOST_REQUIRE( arr[5]== double{} );
	}
	{
		multi::array arr({10}, double{});
		BOOST_REQUIRE( size(arr)==10 );
		BOOST_REQUIRE( arr[5]== double{} );
	}
	{
		multi::array arr(10, double{});
		BOOST_REQUIRE( size(arr)==10 );
		BOOST_REQUIRE( arr[5]== double{} );
	}
	#endif

@correaa
Copy link
Author

correaa commented Jun 9, 2023

circle 198 now correctly recognizes these as a constexpr in the static_assert, which didn't work before, as reported in the original post.

#if defined(__circle_build__)  // circle doesn't see dimensionality as a constexpr "cannot access value of A at compile time;"
        assert(multi::dimensionality(arr) == 3);
#else  // other compilers ok
		static_assert(multi::dimensionality(arr) == 3);
#endif
#if defined(__circle_build__)  // circle doesn't recognize this as a constexpr "cannot access value of `arr` at compile time;"
		assert(multi::stride(arr) == 20);
#else  // other compilers ok
		static_assert(multi::stride(arr) == 20);
#endif

@correaa
Copy link
Author

correaa commented Jun 10, 2023

Almost all problems have been solved at some point before version 198.
Either by fixes or by improving the code on my side.

Good job with the circle compiler!

The only remaining issues are regarding initializer_list.
Sometimes circle fails to deduce template parameters (opened another issue on that), sometimes circle just crashes.

This is a summary of the remaining cases that I was able to detect with my own library tests.

	{
		#if not defined(__circle_build__)  // crashes circle 198
		multi::static_array const arr = {1.2, 3.4, 5.6};
		BOOST_REQUIRE( size(arr) == 3 );
		BOOST_REQUIRE( arr[2] == 5.6 );
		BOOST_REQUIRE(( arr == multi::static_array{1.2, 3.4, 5.6} ));
		#else
		// multi::static_array const arr = {1.2, 3.4, 5.6};
		#endif
	}
	{
		#if not defined(__circle_build__)
		multi::static_array arr({1.0, 2.0, 3.0});
static_assert(std::is_same<decltype(arr)::element_type, double>{}, "!");
		BOOST_REQUIRE( size(arr) == 3 and num_elements(arr) == 3 );
		BOOST_REQUIRE( multi::rank<decltype(arr)>{}==1 and num_elements(arr)==3 and arr[1] == 2.0 );
		static_assert(typename decltype(arr)::rank{} == 1);
		#else
		// multi::static_array arr(                             {1.0, 2.0, 3.0});  // crashes circle
		// multi::static_array arr(std::initializer_list<double>{1.0, 2.0, 3.0});  // crashes circle
		#endif
	}
	{
		#if not defined(__circle_build__)
		multi::static_array const arr({
			{1.0, 2.0, 3.0},
			{4.0, 5.0, 6.0},
        });
		BOOST_TEST_REQUIRE( multi::rank<decltype(arr)>{} == 2 );
		BOOST_TEST_REQUIRE( num_elements(arr) == 6 );
		#else
		// // vvv--- gives segfault in circle
		// multi::static_array const arr({
		//  {1.0, 2.0, 3.0},
		//  {4.0, 5.0, 6.0},
        // });
		#endif
	}

	{
		#if not defined(__circle_build__)
		multi::array const arr({
			{1.0, 2.0, 3.0},
			{4.0, 5.0, 6.0},
        });
		BOOST_TEST_REQUIRE( multi::rank<decltype(arr)>{} == 2 );
		BOOST_TEST_REQUIRE( num_elements(arr) == 6 );
		#else
		// // vvv--- gives error in circle, not viable constructor
		// multi::array const arr({
		//  {1.0, 2.0, 3.0},
		//  {4.0, 5.0, 6.0},
        // });

		// vvv--- gives ODR violation in circle
		// multi::array const arr(std::initializer_list<std::initializer_list<double>>{
		//     {1.0, 2.0, 3.0},
		//     {4.0, 5.0, 6.0},
        // });
		// vvv--- gives ODR violation in circle
		// multi::array const arr(std::initializer_list<std::initializer_list<double>>{
		//  std::initializer_list<double>{1.0, 2.0, 3.0},
		//  std::initializer_list<double>{4.0, 5.0, 6.0},
        // });
		#endif
	}

@correaa
Copy link
Author

correaa commented Nov 1, 2023

Interestingly circle (v200) doesn't crash in godbolt and gives a meaningful error message:

https://godbolt.org/z/desaP6noa

declaration: example.cpp:6:31
during parsing of arr initializer
    multi::static_array const arr = {1.2, 3.4, 5.6}; 
                              ^
  error: /opt/compiler-explorer/libs/bmulti/trunk/include/multi/array.hpp:215:73
  ... included from example.cpp:1:9
  nullptr is not a type
    template<class Element, std::enable_if_t<std::is_convertible<Element, typename static_array::element>{} and (D == 0), int> = 0> 

The error is related to a constructor that shouldn't be invoked anyway, so it is SFINAE failing to fail.

I have figured out a workaround in my local computer, but it is still segfaults in a docker image.

The work around is to split the enable_if conditions into two enable_ifs, transform this code:

	template<class Element, std::enable_if_t<std::is_convertible_v<Element, typename static_array::element> && (D == 0), int> = 0>
	explicit static_array(Element const& elem, allocator_type const& alloc)
	: static_array(typename static_array::extensions_type{}, elem, alloc) {}

into this code

	template<class Element,
		std::enable_if_t<(D == 0) && sizeof(Element*), int> =0,  // separate reqs for circle
		std::enable_if_t<std::is_convertible_v<Element, typename static_array::element>, int> =0
	>
	explicit static_array(Element const& elem, allocator_type const& alloc)
	: static_array(typename static_array::extensions_type{}, elem, alloc) {}

but again, it still segfaults in some conditions.

@correaa
Copy link
Author

correaa commented May 29, 2024

The problems with initializer_list are solved now in version 201.

I found a new problem though regarding conversion operations, https://gitlab.com/correaa/boost-multi/-/jobs/6964145332#L714

I didn't find this problem in earlier versions (or with any other compiler https://gitlab.com/correaa/boost-multi/-/pipelines/1309447406), so I think it is a new problem.

@seanbaxter
Copy link
Owner

seanbaxter commented May 29, 2024 via email

@correaa
Copy link
Author

correaa commented May 29, 2024

You are right, it never compiled it.
Sorry for my confusion.

static_cast shouldn't be necessary, normal implicit conversion should work.
When implicit conversion didn't work for circle I changed it to a static_castwhich didn't work either.

(whether an implicit conversion is a good idea in the first place is a separate question, I think I made it implicit so it can work recursively out-of-the-box, so any D-dimensional array could be converted to any D-nested std::vector<std::vector<...>>, probably an overkill) (sorry, more confusion, the operator is explicit now)

I think it should be using a conversion operator of the RHS (multi::array), inherited from a base class (multi::subarray).
https://gitlab.com/correaa/boost-multi/-/blob/master/include/boost/multi/array_ref.hpp?ref_type=heads#L1516

@seanbaxter
Copy link
Owner

seanbaxter commented May 29, 2024 via email

@correaa
Copy link
Author

correaa commented May 29, 2024

Cool.

I now realize that expressions like A.operator std::vector<std::vector<double>>() do not work when the template conversion operator is inherited from the base class in many compilers (GCC and clang), so I have to define the conversion in the leaf class as well although it is a repetition of the base class.

I am testing it now, perhaps that works around the problem too. (I don't have a Linux to try with circle right now).

Thanks,
A

@seanbaxter
Copy link
Owner

seanbaxter commented May 29, 2024 via email

@seanbaxter
Copy link
Owner

seanbaxter commented May 29, 2024 via email

@correaa
Copy link
Author

correaa commented May 29, 2024

ok. i will try.

i am getting a segfault with 201.
actually, it happens often that circle crashes in docker but finishes (with an error) in the real machine.

https://gitlab.com/correaa/boost-multi/-/jobs/6971672356#L502 (see at the end)

@seanbaxter
Copy link
Owner

seanbaxter commented May 29, 2024 via email

@correaa
Copy link
Author

correaa commented May 29, 2024

I am getting this error with v202. Maybe it is a problem with my code:

https://gitlab.com/correaa/boost-multi/-/jobs/6972753629#L1065

cd /builds/correaa/boost-multi/build/test && /builds/correaa/boost-multi/build_latest/circle -DBOOST_ALL_NO_LIB -DBOOST_NO_CXX98_FUNCTION_BASE=1 -DBOOST_TEST_DYN_LINK=1 -DBOOST_TEST_MODULE="\"C++ Unit Tests for Multi member_array_cast.cpp.x\"" -DBOOST_UNIT_TEST_FRAMEWORK_DYN_LINK -I/builds/correaa/boost-multi/include -g -Werror -Wall -MD -MT test/CMakeFiles/member_array_cast.cpp.x.dir/member_array_cast.cpp.o -MF CMakeFiles/member_array_cast.cpp.x.dir/member_array_cast.cpp.o.d -o CMakeFiles/member_array_cast.cpp.x.dir/member_array_cast.cpp.o -c /builds/correaa/boost-multi/test/member_array_cast.cpp
ODR used by: element_transformed_from_member_invoker
/builds/correaa/boost-multi/test/member_array_cast.cpp:172:1
BOOST_AUTO_TEST_CASE(element_transformed_from_member) { 
^
ODR used by: element_transformed_from_member::test_method
/builds/correaa/boost-multi/test/member_array_cast.cpp:184:54
  multi::array<int, 2> ids = recs.element_transformed(&record::id); 
                                                     ^
ODR used by: boost::multi::array<int, 2l, std::allocator<int>>::array
/builds/correaa/boost-multi/include/boost/multi/array.hpp:352:25
  /*mplct*/ static_array(multi::subarray<TT, D, Args...>&& other)  // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)

It is possible that I am truly making ODR violations and circle is the only compiler to detect those.
I wouldn't know what to change in this particular case.

@seanbaxter
Copy link
Owner

seanbaxter commented May 29, 2024 via email

@correaa
Copy link
Author

correaa commented May 29, 2024

Yes, it is v202, in docker: https://gitlab.com/correaa/boost-multi/-/jobs/6972882032#L501

I am going to try in a real machine now. Maybe it is related to the fact that cmake is finding Clang as the compiler, which I didn't expect.

@seanbaxter
Copy link
Owner

seanbaxter commented May 29, 2024 via email

@correaa
Copy link
Author

correaa commented May 29, 2024

I get the ODR problem with v203 also, in a local machine Ubuntu 23.10. I am going to try a different version of Boost.Test or some docker image

correaa@proart:~/boost-multi/.build.circle203$ ~/bin/circle --version
circle version 1.0.0-203
  Circle public preview build 203
  Built May 29 2024 15:32:32 EDT
  (c) 2023 Sean Baxter
  https://www.circle-lang.org/
  Twitter: @seanbax
correaa@proart:~/boost-multi/.build.circle203$ CXX="$HOME/bin/circle" cmake .. -DCMAKE_BUILD_TYPE=Debug -DENABLE_CIRCLE=1
-- The CXX compiler identification is Clang 5.0.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /home/correaa/bin/circle - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Boost.Multi: standalone mode ON
current binary directory: /home/correaa/boost-multi/.build.circle203
current install prefix directory: /usr/local
-- Found Boost: /usr/lib/x86_64-linux-gnu/cmake/Boost-1.74.0/BoostConfig.cmake (found version "1.74.0") found components: unit_test_framework 
-- Found Boost: /usr/lib/x86_64-linux-gnu/cmake/Boost-1.74.0/BoostConfig.cmake (found suitable version "1.74.0", minimum required is "1.65") found components: unit_test_framework 
-- Looking for sgemm_
-- Looking for sgemm_ - not found
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE  
-- Looking for sgemm_
-- Looking for sgemm_ - found
-- Found BLAS: /usr/lib/x86_64-linux-gnu/libblas.so  
Some BLAS found: linker flags: , libs: /usr/lib/x86_64-linux-gnu/libblas.so, libs95: 
-- Found Boost: /usr/lib/x86_64-linux-gnu/cmake/Boost-1.74.0/BoostConfig.cmake (found version "1.74.0") found components: unit_test_framework 
-- Found PkgConfig: /usr/bin/pkg-config (found version "1.8.1") 
-- Checking for one of the modules 'fftw3'
-- Looking for cheev_
-- Looking for cheev_ - not found
-- Looking for cheev_
-- Looking for cheev_ - found
-- Found LAPACK: /usr/lib/x86_64-linux-gnu/liblapack.so;/usr/lib/x86_64-linux-gnu/libblas.so  
-- Configuring done (1.4s)
-- Generating done (0.1s)
CMake Warning:
  Manually-specified variables were not used by the project:

    ENABLE_CIRCLE


-- Build files have been written to: /home/correaa/boost-multi/.build.circle203
correaa@proart:~/boost-multi/.build.circle203$ make
[  0%] Building CXX object test/CMakeFiles/allocator.cpp.x.dir/allocator.cpp.o
[  1%] Linking CXX executable allocator.cpp.x
[  1%] Built target allocator.cpp.x
[  2%] Building CXX object test/CMakeFiles/array_cref.cpp.x.dir/array_cref.cpp.o
[  3%] Linking CXX executable array_cref.cpp.x
[  3%] Built target array_cref.cpp.x
[  4%] Building CXX object test/CMakeFiles/array_fancyref.cpp.x.dir/array_fancyref.cpp.o
[  5%] Linking CXX executable array_fancyref.cpp.x
[  5%] Built target array_fancyref.cpp.x
[  6%] Building CXX object test/CMakeFiles/array_legacy_c.cpp.x.dir/array_legacy_c.cpp.o
[  7%] Linking CXX executable array_legacy_c.cpp.x
[  7%] Built target array_legacy_c.cpp.x
[  8%] Building CXX object test/CMakeFiles/array_ptr.cpp.x.dir/array_ptr.cpp.o
[  9%] Linking CXX executable array_ptr.cpp.x
[  9%] Built target array_ptr.cpp.x
[ 10%] Building CXX object test/CMakeFiles/array_ref.cpp.x.dir/array_ref.cpp.o
[ 11%] Linking CXX executable array_ref.cpp.x
[ 11%] Built target array_ref.cpp.x
[ 12%] Building CXX object test/CMakeFiles/assignments.cpp.x.dir/assignments.cpp.o
[ 12%] Linking CXX executable assignments.cpp.x
[ 12%] Built target assignments.cpp.x
[ 13%] Building CXX object test/CMakeFiles/boost_array_concept.cpp.x.dir/boost_array_concept.cpp.o
[ 14%] Linking CXX executable boost_array_concept.cpp.x
[ 14%] Built target boost_array_concept.cpp.x
[ 15%] Building CXX object test/CMakeFiles/comparisons.cpp.x.dir/comparisons.cpp.o
[ 16%] Linking CXX executable comparisons.cpp.x
[ 16%] Built target comparisons.cpp.x
[ 17%] Building CXX object test/CMakeFiles/concepts.cpp.x.dir/concepts.cpp.o
[ 18%] Linking CXX executable concepts.cpp.x
[ 18%] Built target concepts.cpp.x
[ 19%] Building CXX object test/CMakeFiles/constructors.cpp.x.dir/constructors.cpp.o
[ 20%] Linking CXX executable constructors.cpp.x
[ 20%] Built target constructors.cpp.x
[ 21%] Building CXX object test/CMakeFiles/conversions.cpp.x.dir/conversions.cpp.o
[ 22%] Linking CXX executable conversions.cpp.x
[ 22%] Built target conversions.cpp.x
[ 23%] Building CXX object test/CMakeFiles/diagonal.cpp.x.dir/diagonal.cpp.o
[ 24%] Linking CXX executable diagonal.cpp.x
[ 24%] Built target diagonal.cpp.x
[ 25%] Building CXX object test/CMakeFiles/element_access.cpp.x.dir/element_access.cpp.o
[ 26%] Linking CXX executable element_access.cpp.x
[ 26%] Built target element_access.cpp.x
[ 27%] Building CXX object test/CMakeFiles/element_transformed.cpp.x.dir/element_transformed.cpp.o
[ 28%] Linking CXX executable element_transformed.cpp.x
[ 28%] Built target element_transformed.cpp.x
[ 29%] Building CXX object test/CMakeFiles/fill.cpp.x.dir/fill.cpp.o
[ 30%] Linking CXX executable fill.cpp.x
[ 30%] Built target fill.cpp.x
[ 31%] Building CXX object test/CMakeFiles/fix_complex.cpp.x.dir/fix_complex.cpp.o
[ 32%] Linking CXX executable fix_complex.cpp.x
[ 32%] Built target fix_complex.cpp.x
[ 33%] Building CXX object test/CMakeFiles/flatted.cpp.x.dir/flatted.cpp.o
[ 34%] Linking CXX executable flatted.cpp.x
[ 34%] Built target flatted.cpp.x
[ 34%] Building CXX object test/CMakeFiles/index_range.cpp.x.dir/index_range.cpp.o
[ 35%] Linking CXX executable index_range.cpp.x
[ 35%] Built target index_range.cpp.x
[ 36%] Building CXX object test/CMakeFiles/initializer_list.cpp.x.dir/initializer_list.cpp.o
[ 37%] Linking CXX executable initializer_list.cpp.x
[ 37%] Built target initializer_list.cpp.x
[ 38%] Building CXX object test/CMakeFiles/iterator.cpp.x.dir/iterator.cpp.o
[ 39%] Linking CXX executable iterator.cpp.x
[ 39%] Built target iterator.cpp.x
[ 40%] Building CXX object test/CMakeFiles/layout.cpp.x.dir/layout.cpp.o
[ 41%] Linking CXX executable layout.cpp.x
[ 41%] Built target layout.cpp.x
[ 42%] Building CXX object test/CMakeFiles/main.cpp.x.dir/main.cpp.o
[ 43%] Linking CXX executable main.cpp.x
[ 43%] Built target main.cpp.x
[ 44%] Building CXX object test/CMakeFiles/member_array_cast.cpp.x.dir/member_array_cast.cpp.o
ODR used by: element_transformed_from_member_invoker
/home/correaa/boost-multi/test/member_array_cast.cpp:172:1
BOOST_AUTO_TEST_CASE(element_transformed_from_member) { 
^

ODR used by: element_transformed_from_member::test_method
/home/correaa/boost-multi/test/member_array_cast.cpp:184:54
  multi::array<int, 2> ids = recs.element_transformed(&record::id); 
                                                     ^

ODR used by: boost::multi::array<int, 2l, std::allocator<int>>::array
/home/correaa/boost-multi/include/boost/multi/array.hpp:352:25
  /*mplct*/ static_array(multi::subarray<TT, D, Args...>&& other)  // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) 
                        ^

ODR used by: boost::multi::static_array<int, 2l, std::allocator<int>>::static_array<int, boost::multi::transform_ptr<int, int record::*, const record*, const int&>, boost::multi::layout_t<2l, long>, 0, boost::multi::array_iterator<int, 2l, int*>>
/home/correaa/boost-multi/include/boost/multi/array.hpp:353:5
  : static_array(std::move(other), allocator_type{}) {} 
    ^

  instantiation: during instantiation of function template boost::multi::static_array<int, 2l, std::allocator<int>>::static_array<int, boost::multi::transform_ptr<int, int record::*, const record*, const int&>, boost::multi::layout_t<2l, long>, void, boost::multi::array_iterator<int, 2l, int*>>(const boost::multi::subarray<int, 2l, boost::multi::transform_ptr<int, int record::*, const record*, const int&>, boost::multi::layout_t<2l, long>>&, const boost::multi::static_array<int, 2l, std::allocator<int>>::allocator_type&)
  template arguments: [
    0 = int
    1 = boost::multi::dimensionality_type 2l
    Alloc = std::allocator<int>
      class allocator declared at /usr/include/c++/13/bits/allocator.h:130:5
    TT = int
    Args#0 = boost::multi::transform_ptr<int, int record::*, const record*, const int&>
      class transform_ptr declared at /home/correaa/boost-multi/include/boost/multi/utility.hpp:67:1
    Args#1 = boost::multi::layout_t<2l, long>
      class layout_t declared at /home/correaa/boost-multi/include/boost/multi/detail/layout.hpp:570:1
    2 = void
    3 = boost::multi::array_iterator<int, 2l, int*>
      class array_iterator declared at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:368:1
  ]
    error: /home/correaa/boost-multi/include/boost/multi/array.hpp:318:27
        adl_uninitialized_copy(/*static_array::alloc()*/ other.begin(), other.end(), this->begin());  // TODO(correaa) implement via .elements() 
                              ^
    error during overload resolution for boost::multi::adl_uninitialized_copy_t::operator()
      instantiation: /home/correaa/boost-multi/include/boost/multi/array.hpp:318:27
          adl_uninitialized_copy(/*static_array::alloc()*/ other.begin(), other.end(), this->begin());  // TODO(correaa) implement via .elements() 
                                ^
      during substitution of return type of auto boost::multi::adl_uninitialized_copy_t::operator()(As&&...) const -> decltype(_(boost::multi::priority<6ul>{ boost::multi::priority<5ul>{ boost::multi::priority<4ul>{ boost::multi::priority<3ul>{ boost::multi::priority<2ul>{ boost::multi::priority<1ul>{ boost::multi::priority<0ul>{ std::integral_constant<bool, true>{ } } } } } } } }, forward<As>(args)...))
      
      template arguments: [
        As#0 = boost::multi::array_iterator<int, 2l, boost::multi::transform_ptr<int, int record::*, const record*, const int&>>
          class array_iterator declared at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:368:1
        As#1 = boost::multi::array_iterator<int, 2l, boost::multi::transform_ptr<int, int record::*, const record*, const int&>>
          class array_iterator declared at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:368:1
        As#2 = boost::multi::array_iterator<int, 2l, int*>
          class array_iterator declared at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:368:1
      ]
        error: /home/correaa/boost-multi/include/boost/multi/detail/adl.hpp:338:71
          template<class... As> constexpr auto operator()(As&&... args) const BOOST_MULTI_DECLRETURN(_(priority<6>{}, std::forward<As>(args)...)) 
                                                                              ^
        no viable candidates in call to _
          argument 0 is prvalue boost::multi::priority<6ul>
            boost::multi::priority<6ul> declared at /home/correaa/boost-multi/include/boost/multi/detail/adl.hpp:83:25
          argument 1 is xvalue boost::multi::array_iterator<int, 2l, boost::multi::transform_ptr<int, int record::*, const record*, const int&>>
            boost::multi::array_iterator<int, 2l, boost::multi::transform_ptr<int, int record::*, const record*, const int&>> declared at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:368:1
          argument 2 is xvalue boost::multi::array_iterator<int, 2l, boost::multi::transform_ptr<int, int record::*, const record*, const int&>>
            boost::multi::array_iterator<int, 2l, boost::multi::transform_ptr<int, int record::*, const record*, const int&>> declared at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:368:1
          argument 3 is xvalue boost::multi::array_iterator<int, 2l, int*>
            boost::multi::array_iterator<int, 2l, int*> declared at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:368:1
          candidate: /home/correaa/boost-multi/include/boost/multi/detail/adl.hpp:312:49
            [[nodiscard]]                  constexpr auto _(priority<1>/**/, InIt first, InIt last, FwdIt d_first) const 
                                                          ^
            error: /home/correaa/boost-multi/include/boost/multi/detail/adl.hpp:311:66
            ... included from /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:12:10
            ... included from /home/correaa/boost-multi/include/boost/multi/array.hpp:8:10
            ... included from /home/correaa/boost-multi/test/member_array_cast.cpp:6:10
              template<class InIt, class FwdIt, class=decltype(std::addressof(*FwdIt{}))>  // sfinae friendy std::uninitialized_copy 
                                                                             ^
            call to deleted function const boost::multi::subarray<int, 1l, int*, boost::multi::layout_t<1l, long>>* std::addressof<boost::multi::subarray<int, 1l, int*, boost::multi::layout_t<1l, long>>>(const boost::multi::subarray<int, 1l, int*, boost::multi::layout_t<1l, long>>&&)
            deleted function declared at /usr/include/c++/13/bits/move.h:144:16

          candidate: /home/correaa/boost-multi/include/boost/multi/detail/adl.hpp:332:57
            template<class TB, class... As       > constexpr auto _(priority<3>/**/, TB   first, As&&... args       ) const BOOST_MULTI_DECLRETURN(                        uninitialized_copy(                 first , std::forward<As>(args)...)) 
                                                                  ^
            instantiation: /home/correaa/boost-multi/include/boost/multi/detail/adl.hpp:338:71
              template<class... As> constexpr auto operator()(As&&... args) const BOOST_MULTI_DECLRETURN(_(priority<6>{}, std::forward<As>(args)...)) 
                                                                                  ^
            during substitution of return type of auto boost::multi::adl_uninitialized_copy_t::_(boost::multi::priority<3ul>, TB, As&&...) const -> decltype(uninitialized_copy(first, forward<As>(args)...))
            
            template arguments: [
              TB = boost::multi::array_iterator<int, 2l, boost::multi::transform_ptr<int, int record::*, const record*, const int&>>
                class array_iterator declared at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:368:1
              As#0 = boost::multi::array_iterator<int, 2l, boost::multi::transform_ptr<int, int record::*, const record*, const int&>>
                class array_iterator declared at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:368:1
              As#1 = boost::multi::array_iterator<int, 2l, int*>
                class array_iterator declared at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:368:1
            ]
              error: /home/correaa/boost-multi/include/boost/multi/detail/adl.hpp:332:115
                template<class TB, class... As       > constexpr auto _(priority<3>/**/, TB   first, As&&... args       ) const BOOST_MULTI_DECLRETURN(                        uninitialized_copy(                 first , std::forward<As>(args)...)) 
                                                                                                                                ^
              error during overload resolution for boost::multi::uninitialized_copy
                error: /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:3110:133
                ... included from /home/correaa/boost-multi/include/boost/multi/array.hpp:8:10
                ... included from /home/correaa/boost-multi/test/member_array_cast.cpp:6:10
                template<class In, class T, dimensionality_type N, class TP, class = std::enable_if_t<(N > 1)>, class = decltype((void)adl_begin(*In{}), adl_end(*In{}))> 
                                                                                                                                                    ^
                call to deleted default constructor boost::multi::array_types<int, 1l, boost::multi::transform_ptr<int, int record::*, const record*, const int&>, boost::multi::layout_t<1l, long>>::array_types()
                deleted constructor declared at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:214:3

          candidate: /home/correaa/boost-multi/include/boost/multi/detail/adl.hpp:333:57
            template<class TB, class TE, class DB> constexpr auto _(priority<4>/**/, TB   first, TE last, DB d_first) const BOOST_MULTI_DECLRETURN(std::decay_t<DB>      ::uninitialized_copy(                 first , last, d_first            )) 
                                                                  ^
            instantiation: /home/correaa/boost-multi/include/boost/multi/detail/adl.hpp:338:71
              template<class... As> constexpr auto operator()(As&&... args) const BOOST_MULTI_DECLRETURN(_(priority<6>{}, std::forward<As>(args)...)) 
                                                                                  ^
            during substitution of return type of auto boost::multi::adl_uninitialized_copy_t::_(boost::multi::priority<4ul>, TB, TE, DB) const -> decltype(std::decay_t<DB>::uninitialized_copy(first, last, d_first))
            
            template arguments: [
              TB = boost::multi::array_iterator<int, 2l, boost::multi::transform_ptr<int, int record::*, const record*, const int&>>
                class array_iterator declared at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:368:1
              TE = boost::multi::array_iterator<int, 2l, boost::multi::transform_ptr<int, int record::*, const record*, const int&>>
                class array_iterator declared at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:368:1
              DB = boost::multi::array_iterator<int, 2l, int*>
                class array_iterator declared at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:368:1
            ]
              error: /home/correaa/boost-multi/include/boost/multi/detail/adl.hpp:333:115
              ... included from /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:12:10
              ... included from /home/correaa/boost-multi/include/boost/multi/array.hpp:8:10
              ... included from /home/correaa/boost-multi/test/member_array_cast.cpp:6:10
                template<class TB, class TE, class DB> constexpr auto _(priority<4>/**/, TB   first, TE last, DB d_first) const BOOST_MULTI_DECLRETURN(std::decay_t<DB>      ::uninitialized_copy(                 first , last, d_first            )) 
                                                                                                                                ^
              uninitialized_copy is not a member of class boost::multi::array_iterator<int, 2l, int*>
                class definition at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:369:1

          candidate: /home/correaa/boost-multi/include/boost/multi/detail/adl.hpp:334:57
            template<class TB, class... As       > constexpr auto _(priority<5>/**/, TB&& first, As&&... args       ) const BOOST_MULTI_DECLRETURN(std::decay_t<TB>      ::uninitialized_copy(std::forward<TB>(first), std::forward<As>(args)...)) 
                                                                  ^
            instantiation: /home/correaa/boost-multi/include/boost/multi/detail/adl.hpp:338:71
              template<class... As> constexpr auto operator()(As&&... args) const BOOST_MULTI_DECLRETURN(_(priority<6>{}, std::forward<As>(args)...)) 
                                                                                  ^
            during substitution of return type of auto boost::multi::adl_uninitialized_copy_t::_(boost::multi::priority<5ul>, TB&&, As&&...) const -> decltype(std::decay_t<TB>::uninitialized_copy(forward<TB>(first), forward<As>(args)...))
            
            template arguments: [
              TB = boost::multi::array_iterator<int, 2l, boost::multi::transform_ptr<int, int record::*, const record*, const int&>>
                class array_iterator declared at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:368:1
              As#0 = boost::multi::array_iterator<int, 2l, boost::multi::transform_ptr<int, int record::*, const record*, const int&>>
                class array_iterator declared at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:368:1
              As#1 = boost::multi::array_iterator<int, 2l, int*>
                class array_iterator declared at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:368:1
            ]
              error: /home/correaa/boost-multi/include/boost/multi/detail/adl.hpp:334:115
              ... included from /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:12:10
              ... included from /home/correaa/boost-multi/include/boost/multi/array.hpp:8:10
              ... included from /home/correaa/boost-multi/test/member_array_cast.cpp:6:10
                template<class TB, class... As       > constexpr auto _(priority<5>/**/, TB&& first, As&&... args       ) const BOOST_MULTI_DECLRETURN(std::decay_t<TB>      ::uninitialized_copy(std::forward<TB>(first), std::forward<As>(args)...)) 
                                                                                                                                ^
              uninitialized_copy is not a member of class boost::multi::array_iterator<int, 2l, boost::multi::transform_ptr<int, int record::*, const record*, const int&>>
                class definition at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:369:1

          candidate: /home/correaa/boost-multi/include/boost/multi/detail/adl.hpp:335:57
            template<class TB, class... As       > constexpr auto _(priority<6>/**/, TB&& first, As&&... args       ) const BOOST_MULTI_DECLRETURN(std::forward<TB>(first).uninitialized_copy(                         std::forward<As>(args)...)) 
                                                                  ^
            instantiation: /home/correaa/boost-multi/include/boost/multi/detail/adl.hpp:338:71
              template<class... As> constexpr auto operator()(As&&... args) const BOOST_MULTI_DECLRETURN(_(priority<6>{}, std::forward<As>(args)...)) 
                                                                                  ^
            during substitution of return type of auto boost::multi::adl_uninitialized_copy_t::_(boost::multi::priority<6ul>, TB&&, As&&...) const -> decltype(forward<TB>(first).uninitialized_copy(forward<As>(args)...))
            
            template arguments: [
              TB = boost::multi::array_iterator<int, 2l, boost::multi::transform_ptr<int, int record::*, const record*, const int&>>
                class array_iterator declared at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:368:1
              As#0 = boost::multi::array_iterator<int, 2l, boost::multi::transform_ptr<int, int record::*, const record*, const int&>>
                class array_iterator declared at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:368:1
              As#1 = boost::multi::array_iterator<int, 2l, int*>
                class array_iterator declared at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:368:1
            ]
              error: /home/correaa/boost-multi/include/boost/multi/detail/adl.hpp:335:115
              ... included from /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:12:10
              ... included from /home/correaa/boost-multi/include/boost/multi/array.hpp:8:10
              ... included from /home/correaa/boost-multi/test/member_array_cast.cpp:6:10
                template<class TB, class... As       > constexpr auto _(priority<6>/**/, TB&& first, As&&... args       ) const BOOST_MULTI_DECLRETURN(std::forward<TB>(first).uninitialized_copy(                         std::forward<As>(args)...)) 
                                                                                                                                ^
              boost::multi::uninitialized_copy is not a member of type boost::multi::array_iterator<int, 2l, boost::multi::transform_ptr<int, int record::*, const record*, const int&>>
                declaration at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:3111:16
                class definition at /home/correaa/boost-multi/include/boost/multi/array_ref.hpp:369:1

make[2]: *** [test/CMakeFiles/member_array_cast.cpp.x.dir/build.make:76: test/CMakeFiles/member_array_cast.cpp.x.dir/member_array_cast.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:1674: test/CMakeFiles/member_array_cast.cpp.x.dir/all] Error 2
make: *** [Makefile:166: all] Error 2

@correaa
Copy link
Author

correaa commented May 29, 2024

I reproduced the ODR error in docker, with Ubuntu 20.04, Boost.Test 1.71

https://gitlab.com/correaa/boost-multi/-/jobs/6974545208#L659

@seanbaxter
Copy link
Owner

seanbaxter commented May 29, 2024 via email

@correaa
Copy link
Author

correaa commented May 30, 2024

Actually, I am sorry for the confusion with the #ifdef.

Also, to bother you, memory safety is probably more important.

Are you incorporating memory safety into Circle? In C++, I like the approach of LLVM/clang that tries to give memory safety through the standard library (e.g. span) and a bunch of really harsh warnings such as Wunsafe-buffer-usage that I am using myself to remind me that at some point I have to stop using pointer arithmetic and use std::span instead (which can be range checked). https://gitlab.com/correaa/boost-multi/-/blob/master/include/boost/multi/array_ref.hpp?ref_type=heads#L643-669

@seanbaxter
Copy link
Owner

seanbaxter commented May 30, 2024 via email

@seanbaxter
Copy link
Owner

seanbaxter commented May 30, 2024 via email

@correaa
Copy link
Author

correaa commented May 30, 2024

I see, so the problem is using decltype (expansion of DECLRETURN).

For context, decltype is used both to reduce the amount of typing, but also to discard bad candidates for the operation.

It is likely that the intention here is that the last candidate (priority<1>) is that one that should work, although it is possible that priority<3> is picked up due to "crappy" ADL.

I will deconstruct the operation into more basic functions.
First I am going to make the 1D case, and then rewrite element_transformed, which is quite high level into more basic operations.

Also, I am going to put this in terms of assignment and not initialization of a multi::array.

@correaa
Copy link
Author

correaa commented Jun 1, 2024

Okay, I think the problem is that Circle was the only compiler reaching the end of the priority list for adl_uninitialized_copy. This, in turn, is invalid code, and since it is an auto function, Circle was probably very confused.

I am not saying Circle got anything wrong, perhaps it is the only one that got the priority right.
It even picked up the option that makes more sense if one analizes the code.
I think other compilers got confused with priority 3:

	template<class TB, class... As       > constexpr auto _(priority<3>/**/, TB   first, As&&... args       ) const BOOST_MULTI_DECLRETURN(                        uninitialized_copy(                 first , std::forward<As>(args)...))

If I am not mistaken this is because compilers tend to look at ADL in internal template parameters which I think it is a terrible rule and perhaps Circle for whatever (good or bad) reason was not doing it.

I implemented the constructor differently so that unitialized_copy_* only acts on "terminal" elements, not in recursive lower dimensions. This seems to work (as it was the goal all along because it has better performance, can be better parallelized, and just plainly makes sense).

I am testing this code for all the other compilers to ensure it works.
But it looks good for now.

For reference, the changes are in the fix-constructor-for-circle branch.

@correaa
Copy link
Author

correaa commented Jun 2, 2024

Okay, I think it all works now. The library compiles with Circle from v202, v203, and v204.
https://gitlab.com/correaa/boost-multi/-/jobs/6997078025
https://gitlab.com/correaa/boost-multi/-/jobs/6997078026

In the end, the problem was solved by implementing a better-quality constructor that (uninitialized_)copies elements.
Now, the library doesn't need any ifdef for circle.
So, I will close this issue.

I don't know if the end circle is behaving differently than most (all?) other compilers.
It looks like circle was getting to the last candidate (probably passing priority<3>) on this list https://gitlab.com/correaa/boost-multi/-/blob/master/include/boost/multi/detail/adl.hpp?ref_type=heads#L311-335 . and perhaps failing to deduce the auto return.

In any case, I am glad that this behavior of the circle forced me to improve the implementation.
I also thank you for the fixes you made in the compiler to help with the compilation.

@correaa correaa closed this as completed Jun 2, 2024
@correaa
Copy link
Author

correaa commented Jun 2, 2024

By the way, I'd be interested to know if you have any ideas (I don't) on how the memory-safe that you are building into Circle could be exploited by this array library.

I guess the idea could be that subblocks of a bigger array can be passed (borrowed) to different functions (threads). Perhaps this is too much to ask for the compile-time system since the borrowing wouldn't happen for "whole objects" (a single big array) but for "part objects" (references to subblocks).

I don't know of any languages that can handle whole-part relations by constructor (Hylo / Val supposedly does so, but I failed to see how in real-world examples).
Perhaps this is a problem that a system alone cannot solve.

If you have any ideas let me know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants