-
Notifications
You must be signed in to change notification settings - Fork 15.2k
Open
Labels
clang:frontendLanguage frontend issues, e.g. anything involving "Sema"Language frontend issues, e.g. anything involving "Sema"conceptsC++20 conceptsC++20 conceptsneeds-reductionLarge reproducer that should be reduced into a simpler formLarge reproducer that should be reduced into a simpler form
Description
The following code worked in previous versions of clang, and works in MSVC, and GCC, but fails in Clang 21.1.0, this code attempts to specialize the function "set_data
" via SFINAE with requires
for scalars, std::span
using a special "ns_is_specialization_of" macro with links to where this was taken from, and explicit specialization for std::string_view
and std::string
#include <type_traits>
#include <string_view>
#include <span>
#include <iostream>
#include <cstdint>
namespace ns{
//From https://stackoverflow.com/a/55398444/, only source where I could find that handles non type templates
namespace detail {
template<auto f>
struct is_specialization_of_impl {
private:
template<class T>
static auto value_impl(int) -> std::is_same<T, decltype(f.template operator()<T>())>;
template<class T>
static auto value_impl(...) -> std::false_type;
public:
template<class T>
static constexpr bool value = decltype(value_impl<T>(0))::value;
};
// To replace std::declval which yields T&&
template<class T>
T declrval();
}
}
#define ns_is_specialization_of(...) \
ns::detail::is_specialization_of_impl<[]<class NsImplTemplate_T>() -> decltype(__VA_ARGS__(ns::detail::declrval<NsImplTemplate_T>())) { }>::template value
template <typename T>
void set_data(std::string_view key, T values) = delete;
void set_data(std::string_view key, const void* value, std::size_t value_count){
std::cout << key << (uintptr_t)(value) << value_count;
}
//attempting to specialize set_data for scalars, std::span, string_view, and string all separatley
template <typename T>
requires(ns_is_specialization_of(std::span)<T>)
void set_data(std::string_view key, T values) {
set_data(key, values.data(), values.size());
}
template <typename T>
requires std::integral<T>
|| std::floating_point<T>
|| std::same_as<std::remove_cvref<T>(), bool>
void set_data(std::string_view key, T values) {
set_data(key, &values, 1);
}
template <>
inline void set_data(std::string_view key, std::string_view value) {
set_data(key, value.data(), value.size());
}
template <>
inline void set_data(std::string_view key, std::string value) {
// verify_data_type<std::string>(key, value.size());
set_data(key, value.data(), value.size());
}
int test_function(int num) {
std::span<char> test;
set_data("hello", test);
return num * num;
}
This results in the rather confusing error:
<source>:40:38: error: no matching conversion for functional-style cast from 'std::basic_string<char>' to 'std::span<remove_reference_t<ranges::range_reference_t<std::basic_string<char, std::char_traits<char>, std::allocator<char>> &>>>' (aka 'span<char>')
40 | requires(ns_is_specialization_of(std::span)<T>)
| ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
<source>:30:85: note: expanded from macro 'ns_is_specialization_of'
30 | ns::detail::is_specialization_of_impl<[]<class NsImplTemplate_T>() -> decltype(__VA_ARGS__(ns::detail::declrval<NsImplTemplate_T>())) { }>::template value
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:40:14: note: in instantiation of member class '(unnamed class at <source>:40:14)' requested here
40 | requires(ns_is_specialization_of(std::span)<T>)
| ^
<source>:30:44: note: expanded from macro 'ns_is_specialization_of'
30 | ns::detail::is_specialization_of_impl<[]<class NsImplTemplate_T>() -> decltype(__VA_ARGS__(ns::detail::declrval<NsImplTemplate_T>())) { }>::template value
| ^
<source>:21:52: note: while substituting explicitly-specified template arguments into function template 'value_impl'
21 | static constexpr bool value = decltype(value_impl<T>(0))::value;
| ^
<source>:40:14: note: in instantiation of static data member 'ns::detail::is_specialization_of_impl<(lambda at <source>:40:14){}>::value<std::basic_string<char>>' requested here
40 | requires(ns_is_specialization_of(std::span)<T>)
| ^
<source>:30:155: note: expanded from macro 'ns_is_specialization_of'
30 | ns::detail::is_specialization_of_impl<[]<class NsImplTemplate_T>() -> decltype(__VA_ARGS__(ns::detail::declrval<NsImplTemplate_T>())) { }>::template value
| ^
<source>:40:14: note: while substituting template arguments into constraint expression here
40 | requires(ns_is_specialization_of(std::span)<T>)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:30:6: note: expanded from macro 'ns_is_specialization_of'
30 | ns::detail::is_specialization_of_impl<[]<class NsImplTemplate_T>() -> decltype(__VA_ARGS__(ns::detail::declrval<NsImplTemplate_T>())) { }>::template value
| ^
<source>:60:13: note: while checking constraint satisfaction for template 'set_data<std::basic_string<char>>' required here
60 | inline void set_data(std::string_view key, std::string value) {
| ^~~~~~~~
<source>:60:13: note: while substituting deduced template arguments into function template 'set_data' [with T = std::string]
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:248:7: note: candidate constructor not viable: no known conversion from 'std::basic_string<char>' to 'const span<char>' for 1st argument
248 | span(const span&) noexcept = default;
| ^ ~~~~~~~~~~~
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:203:2: note: candidate template ignored: could not match 'type_identity_t<element_type>[_ArrayExtent]' (aka 'char[_ArrayExtent]') against 'std::basic_string<char>'
203 | span(type_identity_t<element_type> (&__arr)[_ArrayExtent]) noexcept
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:210:2: note: candidate template ignored: could not match 'array' against 'std::basic_string'
210 | span(array<_Tp, _ArrayExtent>& __arr) noexcept
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:217:2: note: candidate template ignored: could not match 'array' against 'std::basic_string'
217 | span(const array<_Tp, _ArrayExtent>& __arr) noexcept
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:229:2: note: candidate template ignored: constraints not satisfied [with _Range = std::basic_string<char>]
229 | span(_Range&& __range)
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:226:8: note: because 'std::basic_string<char>' does not satisfy 'borrowed_range'
226 | && (ranges::borrowed_range<_Range> || is_const_v<element_type>)
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/bits/ranges_base.h:523:23: note: because 'std::basic_string<char>' does not satisfy '__maybe_borrowed_range'
523 | = range<_Tp> && __detail::__maybe_borrowed_range<_Tp>;
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/bits/ranges_base.h:101:4: note: because 'is_lvalue_reference_v<std::basic_string<char>>' evaluated to false
101 | = is_lvalue_reference_v<_Tp>
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/bits/ranges_base.h:102:7: note: and 'enable_borrowed_range<remove_cvref_t<std::basic_string<char, std::char_traits<char>, std::allocator<char>>>>' evaluated to false
102 | || enable_borrowed_range<remove_cvref_t<_Tp>>;
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:226:42: note: and 'is_const_v<element_type>' evaluated to false
226 | && (ranges::borrowed_range<_Range> || is_const_v<element_type>)
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:256:2: note: candidate template ignored: could not match 'span' against 'std::basic_string'
256 | span(const span<_OType, _OExtent>& __s) noexcept
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:470:7: note: candidate constructor not viable: constraints not satisfied
470 | span(_SizedPtr __ptr) noexcept
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:471:17: note: because 'extent != dynamic_extent' (18446744073709551615 != 18446744073709551615) evaluated to false
471 | requires (extent != dynamic_extent)
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:177:7: note: candidate constructor not viable: requires 0 arguments, but 1 was provided
177 | span() noexcept
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:185:2: note: candidate constructor template not viable: requires 2 arguments, but 1 was provided
185 | span(_It __first, size_type __count)
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:194:2: note: candidate constructor template not viable: requires 2 arguments, but 1 was provided
194 | span(_It __first, _End __last)
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~
<source>:40:38: error: no matching conversion for functional-style cast from 'std::basic_string<char>' to 'std::span<remove_reference_t<ranges::range_reference_t<std::basic_string<char, std::char_traits<char>, std::allocator<char>> &>>>' (aka 'span<char>')
40 | requires(ns_is_specialization_of(std::span)<T>)
| ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
<source>:30:85: note: expanded from macro 'ns_is_specialization_of'
30 | ns::detail::is_specialization_of_impl<[]<class NsImplTemplate_T>() -> decltype(__VA_ARGS__(ns::detail::declrval<NsImplTemplate_T>())) { }>::template value
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:248:7: note: candidate constructor not viable: no known conversion from 'std::basic_string<char>' to 'const span<char>' for 1st argument
248 | span(const span&) noexcept = default;
| ^ ~~~~~~~~~~~
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:203:2: note: candidate template ignored: could not match 'type_identity_t<element_type>[_ArrayExtent]' (aka 'char[_ArrayExtent]') against 'std::basic_string<char>'
203 | span(type_identity_t<element_type> (&__arr)[_ArrayExtent]) noexcept
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:210:2: note: candidate template ignored: could not match 'array' against 'std::basic_string'
210 | span(array<_Tp, _ArrayExtent>& __arr) noexcept
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:217:2: note: candidate template ignored: could not match 'array' against 'std::basic_string'
217 | span(const array<_Tp, _ArrayExtent>& __arr) noexcept
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:229:2: note: candidate template ignored: constraints not satisfied [with _Range = std::basic_string<char>]
229 | span(_Range&& __range)
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:226:8: note: because 'std::basic_string<char>' does not satisfy 'borrowed_range'
226 | && (ranges::borrowed_range<_Range> || is_const_v<element_type>)
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/bits/ranges_base.h:523:23: note: because 'std::basic_string<char>' does not satisfy '__maybe_borrowed_range'
523 | = range<_Tp> && __detail::__maybe_borrowed_range<_Tp>;
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/bits/ranges_base.h:101:4: note: because 'is_lvalue_reference_v<std::basic_string<char>>' evaluated to false
101 | = is_lvalue_reference_v<_Tp>
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/bits/ranges_base.h:102:7: note: and 'enable_borrowed_range<remove_cvref_t<std::basic_string<char, std::char_traits<char>, std::allocator<char>>>>' evaluated to false
102 | || enable_borrowed_range<remove_cvref_t<_Tp>>;
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:226:42: note: and 'is_const_v<element_type>' evaluated to false
226 | && (ranges::borrowed_range<_Range> || is_const_v<element_type>)
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:256:2: note: candidate template ignored: could not match 'span' against 'std::basic_string'
256 | span(const span<_OType, _OExtent>& __s) noexcept
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:470:7: note: candidate constructor not viable: constraints not satisfied
470 | span(_SizedPtr __ptr) noexcept
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:471:17: note: because 'extent != dynamic_extent' (18446744073709551615 != 18446744073709551615) evaluated to false
471 | requires (extent != dynamic_extent)
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:177:7: note: candidate constructor not viable: requires 0 arguments, but 1 was provided
177 | span() noexcept
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:185:2: note: candidate constructor template not viable: requires 2 arguments, but 1 was provided
185 | span(_It __first, size_type __count)
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:194:2: note: candidate constructor template not viable: requires 2 arguments, but 1 was provided
194 | span(_It __first, _End __last)
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~
<source>:40:38: error: no matching conversion for functional-style cast from 'std::basic_string<char>' to 'std::span<remove_reference_t<ranges::range_reference_t<std::basic_string<char, std::char_traits<char>, std::allocator<char>> &>>>' (aka 'span<char>')
40 | requires(ns_is_specialization_of(std::span)<T>)
| ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
<source>:30:85: note: expanded from macro 'ns_is_specialization_of'
30 | ns::detail::is_specialization_of_impl<[]<class NsImplTemplate_T>() -> decltype(__VA_ARGS__(ns::detail::declrval<NsImplTemplate_T>())) { }>::template value
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:248:7: note: candidate constructor not viable: no known conversion from 'std::basic_string<char>' to 'const span<char>' for 1st argument
248 | span(const span&) noexcept = default;
| ^ ~~~~~~~~~~~
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:203:2: note: candidate template ignored: could not match 'type_identity_t<element_type>[_ArrayExtent]' (aka 'char[_ArrayExtent]') against 'std::basic_string<char>'
203 | span(type_identity_t<element_type> (&__arr)[_ArrayExtent]) noexcept
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:210:2: note: candidate template ignored: could not match 'array' against 'std::basic_string'
210 | span(array<_Tp, _ArrayExtent>& __arr) noexcept
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:217:2: note: candidate template ignored: could not match 'array' against 'std::basic_string'
217 | span(const array<_Tp, _ArrayExtent>& __arr) noexcept
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:229:2: note: candidate template ignored: constraints not satisfied [with _Range = std::basic_string<char>]
229 | span(_Range&& __range)
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:226:8: note: because 'std::basic_string<char>' does not satisfy 'borrowed_range'
226 | && (ranges::borrowed_range<_Range> || is_const_v<element_type>)
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/bits/ranges_base.h:523:23: note: because 'std::basic_string<char>' does not satisfy '__maybe_borrowed_range'
523 | = range<_Tp> && __detail::__maybe_borrowed_range<_Tp>;
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/bits/ranges_base.h:101:4: note: because 'is_lvalue_reference_v<std::basic_string<char>>' evaluated to false
101 | = is_lvalue_reference_v<_Tp>
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/bits/ranges_base.h:102:7: note: and 'enable_borrowed_range<remove_cvref_t<std::basic_string<char, std::char_traits<char>, std::allocator<char>>>>' evaluated to false
102 | || enable_borrowed_range<remove_cvref_t<_Tp>>;
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:226:42: note: and 'is_const_v<element_type>' evaluated to false
226 | && (ranges::borrowed_range<_Range> || is_const_v<element_type>)
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:256:2: note: candidate template ignored: could not match 'span' against 'std::basic_string'
256 | span(const span<_OType, _OExtent>& __s) noexcept
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:470:7: note: candidate constructor not viable: constraints not satisfied
470 | span(_SizedPtr __ptr) noexcept
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:471:17: note: because 'extent != dynamic_extent' (18446744073709551615 != 18446744073709551615) evaluated to false
471 | requires (extent != dynamic_extent)
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:177:7: note: candidate constructor not viable: requires 0 arguments, but 1 was provided
177 | span() noexcept
| ^
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:185:2: note: candidate constructor template not viable: requires 2 arguments, but 1 was provided
185 | span(_It __first, size_type __count)
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-15.2.0/lib/gcc/x86_64-linux-gnu/15.2.0/../../../../include/c++/15.2.0/span:194:2: note: candidate constructor template not viable: requires 2 arguments, but 1 was provided
194 | span(_It __first, _End __last)
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~
3 errors generated.
Compiler returned: 1
Godbolt Links:
Fails Clang21.1.0
Succeeds: Clang20.1.0
Succeeds: msvc v19.43 VS17.13
Succeeds: GCC 15.2
Metadata
Metadata
Assignees
Labels
clang:frontendLanguage frontend issues, e.g. anything involving "Sema"Language frontend issues, e.g. anything involving "Sema"conceptsC++20 conceptsC++20 conceptsneeds-reductionLarge reproducer that should be reduced into a simpler formLarge reproducer that should be reduced into a simpler form