| 
 | 1 | +// RUN: %clang_cc1 -std=c++20 -verify %s  | 
 | 2 | +// expected-no-diagnostics  | 
 | 3 | + | 
 | 4 | +template <int __v> struct integral_constant {  | 
 | 5 | +  static constexpr int value = __v;  | 
 | 6 | +};  | 
 | 7 | +template <bool _Val> using _BoolConstant = integral_constant<_Val>;  | 
 | 8 | +template <int, class> struct tuple_element;  | 
 | 9 | +template <class...> class tuple;  | 
 | 10 | +template <int _Ip, class... _Tp> struct tuple_element<_Ip, tuple<_Tp...>> {  | 
 | 11 | +  using type = __type_pack_element<_Ip, _Tp...>;  | 
 | 12 | +};  | 
 | 13 | +template <class> struct tuple_size;  | 
 | 14 | +template <bool> using __enable_if_t = int;  | 
 | 15 | +template <template <class> class _BaseType, class _Tp, _Tp _SequenceSize>  | 
 | 16 | +using __make_integer_sequence_impl =  | 
 | 17 | +    __make_integer_seq<_BaseType, _Tp, _SequenceSize>;  | 
 | 18 | +template <class _Tp, _Tp...> struct __integer_sequence;  | 
 | 19 | +template <int... _Indices>  | 
 | 20 | +using __index_sequence = __integer_sequence<int, _Indices...>;  | 
 | 21 | +template <int _SequenceSize>  | 
 | 22 | +using __make_index_sequence =  | 
 | 23 | +    __make_integer_sequence_impl<__integer_sequence, int, _SequenceSize>;  | 
 | 24 | +template <class _Tp, _Tp...> struct integer_sequence {};  | 
 | 25 | +template <int... _Ip> using index_sequence = integer_sequence<int, _Ip...>;  | 
 | 26 | +template <class _Tp, _Tp _Ep>  | 
 | 27 | +using make_integer_sequence =  | 
 | 28 | +    __make_integer_sequence_impl<integer_sequence, _Tp, _Ep>;  | 
 | 29 | +template <int _Np> using make_index_sequence = make_integer_sequence<int, _Np>;  | 
 | 30 | +enum __element_count : int;  | 
 | 31 | +constexpr void __constexpr_memmove(char *__dest, const char *__src,  | 
 | 32 | +                                   __element_count __n) {  | 
 | 33 | +  __builtin_memmove(__dest, __src, __n);  | 
 | 34 | +}  | 
 | 35 | +template <class _Tp> using __underlying_type_t = __underlying_type(_Tp);  | 
 | 36 | +template <class _Tp> using underlying_type_t = __underlying_type_t<_Tp>;  | 
 | 37 | +template <class _Tp, class> using __enable_if_tuple_size_imp = _Tp;  | 
 | 38 | +template <class _Tp>  | 
 | 39 | +struct tuple_size<__enable_if_tuple_size_imp<  | 
 | 40 | +    const _Tp, __enable_if_t<_BoolConstant<__is_volatile(int)>::value>>>  | 
 | 41 | +    : integral_constant<tuple_size<_Tp>::value> {};  | 
 | 42 | +template <class... _Tp>  | 
 | 43 | +struct tuple_size<tuple<_Tp...>> : integral_constant<sizeof...(_Tp)> {};  | 
 | 44 | +template <class _Tp> constexpr int tuple_size_v = tuple_size<_Tp>::value;  | 
 | 45 | +template <class _T1, class _T2> struct pair {  | 
 | 46 | +  _T1 first;  | 
 | 47 | +  _T2 second;  | 
 | 48 | +};  | 
 | 49 | +template <class _T1> constexpr pair<_T1, char *> make_pair(_T1, char *__t2) {  | 
 | 50 | +  return pair(_T1(), __t2);  | 
 | 51 | +}  | 
 | 52 | +template <int, class _Hp> struct __tuple_leaf {  | 
 | 53 | +  _Hp __value_;  | 
 | 54 | +  constexpr const _Hp &get() const { return __value_; }  | 
 | 55 | +};  | 
 | 56 | +template <class...> struct __tuple_impl;  | 
 | 57 | +template <int... _Indx, class... _Tp>  | 
 | 58 | +struct __tuple_impl<__index_sequence<_Indx...>, _Tp...>  | 
 | 59 | +    : __tuple_leaf<_Indx, _Tp>... {  | 
 | 60 | +  template <class... _Args>  | 
 | 61 | +  constexpr __tuple_impl(int, _Args... __args)  | 
 | 62 | +      : __tuple_leaf<_Indx, _Tp>(__args)... {}  | 
 | 63 | +};  | 
 | 64 | +template <class... _Tp> struct tuple {  | 
 | 65 | +  __tuple_impl<__make_index_sequence<sizeof...(_Tp)>, _Tp...> __base_;  | 
 | 66 | +  template <class... _Up> constexpr tuple(_Up... __u) : __base_({}, __u...) {}  | 
 | 67 | +};  | 
 | 68 | +template <int _Ip, class... _Tp>  | 
 | 69 | +constexpr const tuple_element<_Ip, tuple<_Tp...>>::type &  | 
 | 70 | +get(const tuple<_Tp...> &__t) noexcept {  | 
 | 71 | +  return static_cast<const __tuple_leaf<  | 
 | 72 | +      _Ip, typename tuple_element<_Ip, tuple<_Tp...>>::type> &>(__t.__base_)  | 
 | 73 | +      .get();  | 
 | 74 | +}  | 
 | 75 | +template <class... _Tp> constexpr tuple<_Tp...> make_tuple(_Tp... __t) {  | 
 | 76 | +  return tuple<_Tp...>(__t...);  | 
 | 77 | +}  | 
 | 78 | +constexpr int __char_traits_length_checked(const char *__s) {  | 
 | 79 | +  return __builtin_strlen(__s);  | 
 | 80 | +}  | 
 | 81 | +struct basic_string_view {  | 
 | 82 | +  constexpr basic_string_view() {}  | 
 | 83 | +  constexpr basic_string_view(const char *__s)  | 
 | 84 | +      : __data_(__s), __size_(__char_traits_length_checked(__s)) {}  | 
 | 85 | +  constexpr const char *begin() { return __data_; }  | 
 | 86 | +  constexpr const char *end() {  | 
 | 87 | +    return __data_ + __size_;  | 
 | 88 | +  }  | 
 | 89 | +  const char *__data_;  | 
 | 90 | +  int __size_;  | 
 | 91 | +};  | 
 | 92 | +template <class _Algorithm>  | 
 | 93 | +constexpr pair<const char *, char *>  | 
 | 94 | +__copy_move_unwrap_iters(const char *__first, const char *__last,  | 
 | 95 | +                         char *__out_first) {  | 
 | 96 | +  pair<const char *, const char *> __range = {__first, __last};  | 
 | 97 | +  auto __result = _Algorithm()(__range.first, __range.second, __out_first);  | 
 | 98 | +  return make_pair(__result.first, __result.second);  | 
 | 99 | +}  | 
 | 100 | +struct __copy_impl {  | 
 | 101 | +  constexpr pair<const char *, char *>  | 
 | 102 | +  operator()(const char *__first, const char *__last, char *__result) {  | 
 | 103 | +    const int __n(__last - __first);  | 
 | 104 | +    __constexpr_memmove(__result, __first, __element_count(__n));  | 
 | 105 | +    return make_pair(__last, __result);  | 
 | 106 | +  }  | 
 | 107 | +};  | 
 | 108 | +constexpr char *copy(const char *__first, const char *__last, char *__result) {  | 
 | 109 | +  return __copy_move_unwrap_iters<__copy_impl>(__first, __last, __result).second;  | 
 | 110 | +}  | 
 | 111 | +constexpr char *copy_n(const char *__first, int __orig_n, char *__result) {  | 
 | 112 | +  return copy(__first, __first + __orig_n, __result);  | 
 | 113 | +}  | 
 | 114 | +template <int _Size> struct array {  | 
 | 115 | +  basic_string_view __elems_[_Size];  | 
 | 116 | +  constexpr basic_string_view &operator[](int __n) { return __elems_[__n]; }  | 
 | 117 | +  constexpr basic_string_view operator[](int __n) const {  | 
 | 118 | +    return __elems_[__n];  | 
 | 119 | +  }  | 
 | 120 | +};  | 
 | 121 | + | 
 | 122 | +template <typename> struct FieldId;  | 
 | 123 | + | 
 | 124 | +template <FieldId field> constexpr auto FieldIdToInnerValue() {  | 
 | 125 | +  return field.template ToInnerValue<field>();  | 
 | 126 | +}  | 
 | 127 | +struct FieldNameEnum {  | 
 | 128 | +  enum class type;  | 
 | 129 | +};  | 
 | 130 | +template <int N> using FieldName = FieldNameEnum::type;  | 
 | 131 | +template <typename, auto> struct GetParentMessageAtIndexImpl;  | 
 | 132 | +template <typename, auto> struct FieldInfoHelper;  | 
 | 133 | +template <FieldId...> struct PathImpl;  | 
 | 134 | +template <int N> struct LongPathLiteral {  | 
 | 135 | +  consteval LongPathLiteral(const char (&s)[N]) {  | 
 | 136 | +    copy_n(s, N, long_path)[N] = field_count = long_path_size = 1;  | 
 | 137 | +  }  | 
 | 138 | +  consteval basic_string_view to_string_view() const { return long_path; }  | 
 | 139 | +  char long_path[N + 1];  | 
 | 140 | +  int long_path_size;  | 
 | 141 | +  int field_count;  | 
 | 142 | +};  | 
 | 143 | +template <LongPathLiteral kLongPath> consteval auto get_field_components() {  | 
 | 144 | +  basic_string_view long_path(kLongPath.to_string_view());  | 
 | 145 | +  array<kLongPath.field_count> ret;  | 
 | 146 | +  for (int i = 0; i < kLongPath.field_count; ++i)  | 
 | 147 | +    ret[i] = long_path;  | 
 | 148 | +  return ret;  | 
 | 149 | +}  | 
 | 150 | +template <LongPathLiteral kLongPath>  | 
 | 151 | +constexpr auto kFieldComponents = get_field_components<kLongPath>();  | 
 | 152 | +template <LongPathLiteral kLongPath> struct LongPathHelper {  | 
 | 153 | +  template <int... I>  | 
 | 154 | +  static PathImpl<kFieldComponents<kLongPath>[I]...>  | 
 | 155 | +      PathForLongPath(index_sequence<I...>);  | 
 | 156 | +  using type =  | 
 | 157 | +      decltype(PathForLongPath(make_index_sequence<kLongPath.field_count>{}));  | 
 | 158 | +};  | 
 | 159 | +template <typename T> struct PathFieldId {  | 
 | 160 | +  template <typename Arg> constexpr PathFieldId(Arg &arg) : value(arg) {}  | 
 | 161 | +  T value;  | 
 | 162 | +};  | 
 | 163 | +template <PathFieldId...> constexpr auto PathImplHelper();  | 
 | 164 | + | 
 | 165 | +template <int N> using FieldName = FieldName<N>;  | 
 | 166 | +enum class FieldNumber;  | 
 | 167 | +template <PathFieldId... fields>  | 
 | 168 | +constexpr auto Path = PathImplHelper<fields...>();  | 
 | 169 | +template <typename Proto, FieldId field>  | 
 | 170 | +using FieldInfo =  | 
 | 171 | +    FieldInfoHelper<Proto, FieldIdToInnerValue<field>()>::type;  | 
 | 172 | +template <> struct FieldId<FieldNameEnum::type> {  | 
 | 173 | +  constexpr FieldId(basic_string_view);  | 
 | 174 | +  int size;  | 
 | 175 | +  long hash;  | 
 | 176 | +  template <auto field> static constexpr auto ToInnerValue() {  | 
 | 177 | +    return static_cast<FieldNameEnum::type>(field.hash);  | 
 | 178 | +  }  | 
 | 179 | +};  | 
 | 180 | +FieldId(basic_string_view) -> FieldId<FieldNameEnum::type>;  | 
 | 181 | +template <typename Proto, FieldId field, int index>  | 
 | 182 | +using GetParentMessageAtIndex = GetParentMessageAtIndexImpl<  | 
 | 183 | +    Proto, FieldIdToInnerValue<field>()>::type;  | 
 | 184 | + | 
 | 185 | +template <typename T>  | 
 | 186 | +PathFieldId(T &t) -> PathFieldId<decltype(LongPathLiteral(t))>;  | 
 | 187 | +template <FieldId... fields1, FieldId... fields2>  | 
 | 188 | +constexpr PathImpl<fields1..., fields2...> *ConcatPath(PathImpl<fields1...> *,  | 
 | 189 | +                                                       PathImpl<fields2...> *) {  | 
 | 190 | +  return nullptr;  | 
 | 191 | +}  | 
 | 192 | +template <LongPathLiteral long_path_literal>  | 
 | 193 | +constexpr LongPathHelper<long_path_literal>::type *SinglePath() {  | 
 | 194 | +  return nullptr;  | 
 | 195 | +}  | 
 | 196 | +template <PathFieldId... fields> constexpr auto PathImplHelper() {  | 
 | 197 | +  return ConcatPath(SinglePath<fields.value>()...);  | 
 | 198 | +}  | 
 | 199 | +template <auto hash_prime, auto offset_bias>  | 
 | 200 | +constexpr auto Fnv1a(basic_string_view str) {  | 
 | 201 | +  auto hash = offset_bias;  | 
 | 202 | +  for (char c : str) {  | 
 | 203 | +    hash ^= c;  | 
 | 204 | +    hash *= hash_prime;  | 
 | 205 | +  }  | 
 | 206 | +  return hash;  | 
 | 207 | +}  | 
 | 208 | +constexpr auto HashField(basic_string_view str) {  | 
 | 209 | +  return Fnv1a<1099511628211u, 1039346656037>(str);  | 
 | 210 | +}  | 
 | 211 | +template <typename FI> struct FieldInfoValueTypeAlias : FI {};  | 
 | 212 | +template <typename Proto, auto field> struct FieldInfoHelperBase {  | 
 | 213 | +  static constexpr auto MaskFieldNameHash() {  | 
 | 214 | +    using FieldEnum = decltype(field);  | 
 | 215 | +    return FieldEnum{static_cast<underlying_type_t<FieldEnum>>(field) & 31};  | 
 | 216 | +  }  | 
 | 217 | +  using internal_type =  | 
 | 218 | +      Proto::template FieldInfoImpl<decltype(field), MaskFieldNameHash()>;  | 
 | 219 | +};  | 
 | 220 | +template <typename Proto, auto field> struct FieldInfoHelper {  | 
 | 221 | +  using type = FieldInfoValueTypeAlias<  | 
 | 222 | +      typename FieldInfoHelperBase<Proto, field>::internal_type>;  | 
 | 223 | +};  | 
 | 224 | + | 
 | 225 | +template <auto... fields>  | 
 | 226 | +struct FieldId<const PathImpl<fields...> *> {  | 
 | 227 | +  constexpr FieldId(PathImpl<fields...> *) : path() {}  | 
 | 228 | +  template <auto field> static constexpr auto ToInnerValue() {  | 
 | 229 | +    return field.path;  | 
 | 230 | +  }  | 
 | 231 | +  const PathImpl<fields...> *path;  | 
 | 232 | +};  | 
 | 233 | +template <auto... fields>  | 
 | 234 | +FieldId(PathImpl<fields...> *)  | 
 | 235 | +    -> FieldId<const PathImpl<fields...> *>;  | 
 | 236 | + | 
 | 237 | +template <auto> struct UnpackedField {  | 
 | 238 | +  static constexpr bool is_path = false;  | 
 | 239 | +};  | 
 | 240 | +template <auto... fields, const PathImpl<fields...> *path>  | 
 | 241 | +struct UnpackedField<path> {  | 
 | 242 | +  static constexpr auto value = make_tuple(fields...);  | 
 | 243 | +  static constexpr bool is_path = true;  | 
 | 244 | +};  | 
 | 245 | +template <typename Proto, FieldId... fields, const PathImpl<fields...> *path>  | 
 | 246 | +struct GetParentMessageAtIndexImpl<Proto, path> {  | 
 | 247 | +  using type = Proto;  | 
 | 248 | +};  | 
 | 249 | + | 
 | 250 | +constexpr FieldId<FieldNameEnum::type>::FieldId(basic_string_view str)  | 
 | 251 | +    : size(), hash(HashField(str)) {}  | 
 | 252 | +template <FieldId field> constexpr bool IsPath() {  | 
 | 253 | +  return UnpackedField<  | 
 | 254 | +      FieldIdToInnerValue<field>()>::is_path;  | 
 | 255 | +}  | 
 | 256 | +template <FieldId field> constexpr auto UnpackFieldToTuple() {  | 
 | 257 | +  return UnpackedField<FieldIdToInnerValue<field>()>::value;  | 
 | 258 | +}  | 
 | 259 | +template <int> struct CompileTimeString {  | 
 | 260 | +  consteval CompileTimeString(basic_string_view &v) : internal_view_(v) {}  | 
 | 261 | +  basic_string_view &internal_view_;  | 
 | 262 | +};  | 
 | 263 | +CompileTimeString(basic_string_view) -> CompileTimeString<0>;  | 
 | 264 | + | 
 | 265 | +template <CompileTimeString... parts> struct NameJoiner {  | 
 | 266 | +  template <CompileTimeString... after>  | 
 | 267 | +  NameJoiner<parts...> operator+(NameJoiner<after...>);  | 
 | 268 | +};  | 
 | 269 | +template <FieldId> struct FieldNameBuilder;  | 
 | 270 | +template <FieldId field>  | 
 | 271 | +  requires(!IsPath<field>())  | 
 | 272 | +struct FieldNameBuilder<field> {  | 
 | 273 | +  template <typename Proto> static auto Get() {  | 
 | 274 | +    return NameJoiner<FieldInfo<Proto, field>::name>();  | 
 | 275 | +  }  | 
 | 276 | +};  | 
 | 277 | +template <FieldId field>  | 
 | 278 | +  requires(IsPath<field>())  | 
 | 279 | +struct FieldNameBuilder<field> {  | 
 | 280 | +  static constexpr auto kTuple = UnpackFieldToTuple<field>();  | 
 | 281 | +  static constexpr int kTupleSize = tuple_size_v<decltype(kTuple)>;  | 
 | 282 | +  template <typename Proto, int... Is> static void Get(index_sequence<Is...>) {  | 
 | 283 | +    (FieldNameBuilder<get<Is>(  | 
 | 284 | +         kTuple)>::template Get<GetParentMessageAtIndex<Proto, field, Is>>() +  | 
 | 285 | +     ...);  | 
 | 286 | +  }  | 
 | 287 | +  template <typename Proto> static void Get() {  | 
 | 288 | +    Get<Proto>(make_index_sequence<kTupleSize>());  | 
 | 289 | +  }  | 
 | 290 | +};  | 
 | 291 | + | 
 | 292 | +struct T {  | 
 | 293 | +  template <typename FieldType, FieldType> struct FieldInfoImpl;  | 
 | 294 | +};  | 
 | 295 | +void AddPathsToFieldMask() {  | 
 | 296 | +  FieldNameBuilder<Path<"message_field", "int32_field">>::Get<T>();  | 
 | 297 | +}  | 
 | 298 | +template <> struct T::FieldInfoImpl<FieldNumber, FieldNumber{1}> {  | 
 | 299 | +  static basic_string_view name;  | 
 | 300 | +};  | 
 | 301 | +template <>  | 
 | 302 | +struct T::FieldInfoImpl<FieldName<1>, FieldName<1>{12}>  | 
 | 303 | +    : FieldInfoImpl<FieldNumber, FieldNumber{1}> {};  | 
 | 304 | +template <> struct T::FieldInfoImpl<FieldNumber, FieldNumber{10}> {  | 
 | 305 | +  static basic_string_view name;  | 
 | 306 | +};  | 
 | 307 | +template <>  | 
 | 308 | +struct T::FieldInfoImpl<FieldName<3>, FieldName<3>{11}>  | 
 | 309 | +    : FieldInfoImpl<FieldNumber, FieldNumber{10}> {};  | 
0 commit comments