Skip to content

Commit

Permalink
Attempt porting to clang
Browse files Browse the repository at this point in the history
 * clang refuses constexpr initializer_list, I think it might be correct
 * some template type deduction in auto deduced types is failing, I helped it along
 * Cannot get regular template user defined literal compiling, revert to gnu extension

This still doesn't compile however:

value_parser returns something dependent on array_parser
array_parser returns something dependent on value_parser

I'm not sure how gcc is able to compile this with auto return deduction, but
clang really doesn't like it

@elbeno
  • Loading branch information
lefticus committed May 13, 2017
1 parent 64d0af3 commit 92b120c
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 22 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ else()
-ftemplate-backtrace-limit=0
-ffunction-sections
-Wall -Wextra -Werror -pedantic-errors
-Wno-gnu-string-literal-operator-template
-Wcast-align
-Wcast-qual
-Wctor-dtor-privacy
Expand Down
26 changes: 16 additions & 10 deletions src/include/cx_json_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -597,40 +597,43 @@ namespace JSON
return value_proxy{0, object_storage, string_storage};
}

using Value_Proxy = value_proxy<NumObjects, cx::vector<value, NumObjects>,
cx::basic_string<char, StringSize>>;

template <typename K,
std::enable_if_t<!std::is_integral<K>::value, int> = 0>
constexpr auto operator[](const K& s) const {
return value_proxy{0, object_storage, string_storage}[s];
return Value_Proxy{0, object_storage, string_storage}[s];
}
template <typename K,
std::enable_if_t<!std::is_integral<K>::value, int> = 0>
constexpr auto operator[](const K& s) {
return value_proxy{0, object_storage, string_storage}[s];
return Value_Proxy{0, object_storage, string_storage}[s];
}
constexpr auto object_Size() const {
return value_proxy{0, object_storage, string_storage}.object_Size();
return Value_Proxy{0, object_storage, string_storage}.object_Size();
}

constexpr auto operator[](std::size_t idx) const {
return value_proxy{0, object_storage, string_storage}[idx];
return Value_Proxy{0, object_storage, string_storage}[idx];
}
constexpr auto operator[](std::size_t idx) {
return value_proxy{0, object_storage, string_storage}[idx];
return Value_Proxy{0, object_storage, string_storage}[idx];
}
constexpr auto array_Size() const {
return value_proxy{0, object_storage, string_storage}.array_Size();
return Value_Proxy{0, object_storage, string_storage}.array_Size();
}

constexpr auto is_Null() const { return object_storage[0].is_Null(); }

constexpr decltype(auto) to_String() const {
return value_proxy{0, object_storage, string_storage}.to_String();
return Value_Proxy{0, object_storage, string_storage}.to_String();
}
constexpr decltype(auto) to_String() {
return value_proxy{0, object_storage, string_storage}.to_String();
return Value_Proxy{0, object_storage, string_storage}.to_String();
}
constexpr auto string_Size() const {
return value_proxy{0, object_storage, string_storage}.string_Size();
return Value_Proxy{0, object_storage, string_storage}.string_Size();
}

constexpr decltype(auto) to_Number() const { return object_storage[0].to_Number(); }
Expand All @@ -650,16 +653,19 @@ namespace JSON

namespace literals
{

// why cannot we get regular literal operator template here?

This comment has been minimized.

Copy link
@elbeno

elbeno May 13, 2017

Collaborator

Why indeed. I remember wondering that when writing this, of course I tried "regular" first...

This comment has been minimized.

Copy link
@elbeno

elbeno May 15, 2017

Collaborator

Aha, this is N3599 - a paper by Richard Smith from 2013 proposing exactly this - which is not yet in the standard but is currently a gnu extension. Perhaps based on this use case we can add more weight to the standardization argument.

template <typename T, T... Ts>
constexpr auto operator "" _json()
{
constexpr std::initializer_list<T> il{Ts...};
std::initializer_list<T> il{Ts...};

This comment has been minimized.

Copy link
@elbeno

elbeno May 13, 2017

Collaborator

Yes, unclear whether initializer_list should be constexpr value/aggregate constructible? Well, I think it should be but not clear what the standard currently says :)

// I tried using structured bindings here, but g++ says:
// "error: decomposition declaration cannot be declared 'constexpr'"
constexpr auto S = sizes<Ts...>();
return value_wrapper<S.num_objects, S.string_size>(
std::string_view(il.begin(), il.size()));
}

}

}
27 changes: 15 additions & 12 deletions src/test/algorithm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,62 +128,65 @@ void algo_tests_nonmod()

void algo_tests_mod()
{
using std::begin;
using std::end;

{
constexpr auto il = {1, 3, 5, 7, 9};
constexpr int il[] = {1, 3, 5, 7, 9};
constexpr auto vec = [&] () {
cx::vector<int, 5> v;
cx::copy(il.begin(), il.end(), cx::back_insert_iterator(v));
cx::copy(begin(il), end(il), cx::back_insert_iterator(v));
return v;
}();
static_assert(vec.size() == 5, "copy fail");
}

{
constexpr auto il = {1, 2, 5, 7, 4};
constexpr int il[] = {1, 2, 5, 7, 4};
constexpr auto vec = [&] () {
cx::vector<int, 5> v;
cx::copy_if(il.begin(), il.end(), cx::back_insert_iterator(v),
cx::copy_if(begin(il), end(il), cx::back_insert_iterator(v),
[] (auto i) { return i % 2 == 0; });
return v;
}();
static_assert(vec.size() == 2, "copy_if fail");
}

{
constexpr auto il = {1, 3, 5, 7, 9};
constexpr int il[] = {1, 3, 5, 7, 9};
constexpr auto vec = [&] () {
cx::vector<int, 5> v;
cx::copy_n(il.begin(), 3, cx::back_insert_iterator(v));
cx::copy_n(begin(il), 3, cx::back_insert_iterator(v));
return v;
}();
static_assert(vec.size() == 3, "copy_n fail");
}

{
constexpr auto il = {1, 3, 5, 7, 9};
constexpr int il[] = {1, 3, 5, 7, 9};
constexpr auto vec = [&] () {
cx::vector<int, 5> v = {0,0,0,0,0};
cx::copy_backward(il.begin(), il.end(), v.end());
cx::copy_backward(begin(il), end(il), v.end());
return v;
}();
static_assert(vec.size() == 5 && vec[0] == 1 && vec[4] == 9, "copy_backward fail");
}

{
constexpr auto il = {1, 3, 5, 7, 9};
constexpr int il[] = {1, 3, 5, 7, 9};
constexpr auto vec = [&] () {
cx::vector<int, 5> v;
cx::move(il.begin(), il.end(), cx::back_insert_iterator(v));
cx::move(begin(il), end(il), cx::back_insert_iterator(v));
return v;
}();
static_assert(vec.size() == 5, "move fail");
}

{
constexpr auto il = {1, 3, 5, 7, 9};
constexpr int il[] = {1, 3, 5, 7, 9};
constexpr auto vec = [&] () {
cx::vector<int, 5> v = {0,0,0,0,0};
cx::move_backward(il.begin(), il.end(), v.end());
cx::move_backward(begin(il), end(il), v.end());
return v;
}();
static_assert(vec.size() == 5 && vec[0] == 1 && vec[4] == 9, "move_backward fail");
Expand Down

1 comment on commit 92b120c

@elbeno
Copy link
Collaborator

@elbeno elbeno commented on 92b120c May 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re type deduction problems (mutual recursion of value_parser & array_parser): is this a problem with clang's template instantiation? All the foo_recur structs are templates and then inside any of the member functions, the entire class should be visible, right?
In an earlier incarnation I had the early unevaluated call to fail() to try to help the compiler deduce a lambda return type (

if (false) return fail(std::size_t{})(sv);
) - not sure if that would help clang here...

Please sign in to comment.