Ilya Biryukov 85043c1c14
[Clang] Add a builtin that deduplicate types into a pack (#106730)
The new builtin `__builtin_dedup_pack` removes duplicates from list of
types.

The added builtin is special in that they produce an unexpanded pack
in the spirit of P3115R0 proposal.

Produced packs can be used directly in template argument lists and get
immediately expanded as soon as results of the computation are
available.

It allows to easily combine them, e.g.:

```cpp
template <class ...T>
struct Normalize {
  // Note: sort is not included in this PR, it illustrates the idea.
  using result = std::tuple<
    __builtin_sort_pack<
      __builtin_dedup_pack<int, double, T...>...
    >...>;
}
;
```

Limitations:
- only supported in template arguments and bases,
- can only be used inside the templates, even if non-dependent,
- the builtins cannot be assigned to template template parameters.

The actual implementation proceeds as follows:
- When the compiler encounters a `__builtin_dedup_pack` or other
type-producing
  builtin with dependent arguments, it creates a dependent
  `TemplateSpecializationType`.
- During substitution, if the template arguments are non-dependent, we
  will produce: a new type `SubstBuiltinTemplatePackType`, which stores
  an argument pack that needs to be substituted. This type is similar to
  the existing `SubstTemplateParmPack` in that it carries the argument
  pack that needs to be expanded further. The relevant code is shared.
- On top of that, Clang also wraps the resulting type into
  `TemplateSpecializationType`, but this time only as a sugar.
- To actually expand those packs, we collect the produced
  `SubstBuiltinTemplatePackType` inside `CollectUnexpandedPacks`.
  Because we know the size of the produces packs only after the initial
  substitution, places that do the actual expansion will need to have a
  second run over the substituted type to finalize the expansions (in
  this patch we only support this for template arguments, see
  `ExpandTemplateArgument`).

If the expansion are requested in the places we do not currently
support, we will produce an error.

More follow-up work will be needed to fully shape this:
- adding the builtin that sorts types,
- remove the restrictions for expansions,
- implementing P3115R0 (scheduled for C++29, see
  https://github.com/cplusplus/papers/issues/2300).
2025-08-20 18:11:36 +02:00

17 lines
498 B
C++

// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s
template <class> struct Pair;
template <class...> struct Tuple {
template <class _Up> Tuple(_Up);
};
template <typename> struct StatusOr;
template <int> using ElementType = int;
template <int... fields>
using Key = Tuple<ElementType<fields>...>;
template <int... fields>
StatusOr<Pair<Key<fields...>>> Parser();
struct Helper { Helper(Tuple<>, Tuple<>, int, int); };
struct D : Helper {
D(Key<> f, int n, int e) : Helper(f, Parser<>, n, e) {}
};