[PATCH] D128113: Clang: fix AST representation of expanded template arguments.

Matheus Izvekov via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Sat Aug 27 08:50:13 PDT 2022


mizvekov added a comment.

In D128113#3753565 <https://reviews.llvm.org/D128113#3753565>, @davrec wrote:

> 2: After thinking about it further I don't think the pack index provides sufficiently useful info in any case, since packs will always be expanded in full, in order: when you find the first `SubstTemplateTypeParmType` expanded from a pack, the rest are sure to be right behind.  IIUC I see how including the pack index makes resugaring more straightforward: the substitution of the sugared info for the non-sugared info occurs via a TreeTransform (see clang/lib/Sema/SemaTemplate.cpp in https://reviews.llvm.org/D127695), and by storing the pack index Matheus can simply override `TransformSubstTemplateTypeParmType` to make use of the pack index to easily fetch the corresponding sugared info.  But since the pack indices are predictable given a bird's eye view of the AST, maybe state info can be stored in the TreeTransform to allow the pack index to be inferred in each call to `TransformSubstTemplateTypeParmType`?

Packs are expanded from patterns, which is an arbitrary type that will reference one or more parameter pack anywhere within. So going back from an expanded pack back to a pattern + number of expansions will take more effort and we may need to add new markings to the AST to help with that.

Check this example out: https://godbolt.org/z/rsGsM6GrM

  template <class ...Ts> struct A {
    template <class ...Us> struct B {
        using type1 = void ((void (*...fps)(Ts, Us)));
    };
  };
  using type2 = A<int, char>::B<short, bool>::type1;

  TypeAliasDecl 0x55ffe8b45368 <line:8:1, col:45> col:7 type2 'A<int, char>::B<short, bool>::type1':'void ((void (*)(int, short), void (*)(char, bool)))'
    `-ElaboratedType 0x55ffe8b452f0 'A<int, char>::B<short, bool>::type1' sugar
      `-TypedefType 0x55ffe8b452d0 'A<int, char>::B<short, bool>::type1' sugar
        |-TypeAlias 0x55ffe8b45258 'type1'
        `-FunctionProtoType 0x55ffe8b451e0 'void ((void (*)(int, short), void (*)(char, bool)))' cdecl
          |-ParenType 0x55ffe8b12150 'void' sugar
          | `-BuiltinType 0x55ffe8ac6370 'void'
          |-PointerType 0x55ffe8b44550 'void (*)(int, short)'
          | `-ParenType 0x55ffe8b444f0 'void (int, short)' sugar
          |   `-FunctionProtoType 0x55ffe8b444b0 'void (int, short)' cdecl
          |     |-BuiltinType 0x55ffe8ac6370 'void'
          |     |-SubstTemplateTypeParmType 0x55ffe8b44310 'int' sugar
          |     | |-TemplateTypeParmType 0x55ffe8b11440 'Ts' dependent contains_unexpanded_pack depth 0 index 0 pack
          |     | | `-TemplateTypeParm 0x55ffe8b113c0 'Ts'
          |     | `-BuiltinType 0x55ffe8ac6410 'int'
          |     `-SubstTemplateTypeParmType 0x55ffe8b443c0 'short' sugar
          |       |-TemplateTypeParmType 0x55ffe8b11960 'Us' dependent contains_unexpanded_pack depth 1 index 0 pack
          |       | `-TemplateTypeParm 0x55ffe8b118d8 'Us'
          |       `-BuiltinType 0x55ffe8ac63f0 'short'
          `-PointerType 0x55ffe8b450c0 'void (*)(char, bool)'
            `-ParenType 0x55ffe8b45060 'void (char, bool)' sugar
              `-FunctionProtoType 0x55ffe8b447d0 'void (char, bool)' cdecl
                |-BuiltinType 0x55ffe8ac6370 'void'
                |-SubstTemplateTypeParmType 0x55ffe8b44630 'char' sugar
                | |-TemplateTypeParmType 0x55ffe8b11440 'Ts' dependent contains_unexpanded_pack depth 0 index 0 pack
                | | `-TemplateTypeParm 0x55ffe8b113c0 'Ts'
                | `-BuiltinType 0x55ffe8ac63b0 'char'
                `-SubstTemplateTypeParmType 0x55ffe8b446e0 'bool' sugar
                  |-TemplateTypeParmType 0x55ffe8b11960 'Us' dependent contains_unexpanded_pack depth 1 index 0 pack
                  | `-TemplateTypeParm 0x55ffe8b118d8 'Us'
                  `-BuiltinType 0x55ffe8ac6390 'bool'

And in fact, a given parameter pack might be referenced more than one time in a given pack expansion pattern:

  template <class ...Ts> struct A {
    template <class ...Us> struct B {
        using type1 = void ((void (*...fps)(Ts, Ts, Us)));
    };
  };

Ie those two Ts are referencing the same argument within the pack, we can't confuse that with an expansion.

So think also about a case like the above, but where you are performing the expansion just one time. It doesn't look like to me you can figure that out from what Clang leaves behind in the AST at the moment.
We may need to create a new AST node, which is like a Subst variant of a PackExpansionType, at the expansion loci.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D128113/new/

https://reviews.llvm.org/D128113



More information about the cfe-commits mailing list