Isolated TypedefDecl in CXXDeductionGuideDecl parameter?

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Isolated TypedefDecl in CXXDeductionGuideDecl parameter?

David Blaikie via cfe-dev
Hi,

Considering the below code:
01
02  struct A {};
03  typedef A AT;
04
05  template <typename T> struct ClassT {
06    ClassT(AT p0, T* p1) {}
07  };
08
09  A a;
10  int x;
11  auto y = ClassT(a, &x);

The deduction guide's first parameter refers to a TypedefDecl that is isolated
from the first TypedefDecl. First declaration:

|-TypedefDecl 0x5555561eaec0 <line:3:3, col:13> col:13 referenced AT 'A'
| `-RecordType 0x5555561ead80 'A'
|   `-CXXRecord 0x5555561eacf0 'A'

Vs the function prototype of the deduction guide refers to an isolated
(out-of-the-redecl-chain) TypedefDecl:

FunctionProtoType 0x55555621bc80 'auto (AT, T *) -> ClassT<T>' dependent trailing_return cdecl
|-InjectedClassNameType 0x5555561eb220 'ClassT<T>' dependent
| `-CXXRecord 0x5555561eafe0 'ClassT'
|-TypedefType 0x55555621bb20 'AT' sugar
| |-Typedef 0x55555621bac0 'AT'
| `-RecordType 0x5555561ead80 'struct A'
|   `-CXXRecord 0x5555561eacf0 'A'
`-PointerType 0x5555561eb410 'T *' dependent
  `-TemplateTypeParmType 0x5555561eafa0 'T' dependent depth 0 index 0
    `-TemplateTypeParm 0x5555561eaf18 'T'

So, in the translation unit, we have two distinct TypedefDecl AST nodes. The
first one's DeclContext is the TranslationUnidDecl, however, the second's is
the CXXDeductionGuideDecl.

This is strange, because when dealing with regular function template
instantiations, the two typedefs are the same and we have only one universal
TypedefDecl node in the AST.
01
02  struct A {};
03  typedef A AT;
04
05  template <typename T>
06  int fun(AT p0, T* p1) {}
07
08  A a;
09  int x;
10  int y = fun(a, &x);

TypedefDecl 0x5555561eaf70 <input.cc:3:3, col:13> col:13 referenced AT 'A'
`-RecordType 0x5555561eae30 'A'
  `-CXXRecord 0x5555561eada0 'A'

FunctionProtoType 0x5555561eb240 'int (AT, T *)' dependent cdecl
|-BuiltinType 0x5555561ab0a0 'int'
|-TypedefType 0x5555561eb090 'AT' sugar
| |-Typedef 0x5555561eaf70 'AT'
| `-RecordType 0x5555561eae30 'struct A'
|   `-CXXRecord 0x5555561eada0 'A'
`-PointerType 0x5555561eb160 'T *' dependent
  `-TemplateTypeParmType 0x5555561eb050 'T' dependent depth 0 index 0
    `-TemplateTypeParm 0x5555561eafc8 'T'

I was wondering whether this discrepancy is deliberate. IMO, the deduction
guide should refer to the TypedefDecl in the TranslationUnidDecl and it should
not create a new TypedefDecl. Can someone confirm if this is a bug or not?

Context: I am trying to fix an infinite loop in the ASTImporter that is related
to importing deduction guidelines.

Any insight would be really appreciated.

Thanks,
Gabor


_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Isolated TypedefDecl in CXXDeductionGuideDecl parameter?

David Blaikie via cfe-dev
On Fri, Nov 20, 2020 at 11:30 AM Gábor Márton <[hidden email]> wrote:

>
> Hi,
>
> Considering the below code:
> 01
> 02  struct A {};
> 03  typedef A AT;
> 04
> 05  template <typename T> struct ClassT {
> 06    ClassT(AT p0, T* p1) {}
> 07  };
> 08
> 09  A a;
> 10  int x;
> 11  auto y = ClassT(a, &x);
>
> The deduction guide's first parameter refers to a TypedefDecl that is isolated
> from the first TypedefDecl. First declaration:
>
> |-TypedefDecl 0x5555561eaec0 <line:3:3, col:13> col:13 referenced AT 'A'
> | `-RecordType 0x5555561ead80 'A'
> |   `-CXXRecord 0x5555561eacf0 'A'
>
> Vs the function prototype of the deduction guide refers to an isolated
> (out-of-the-redecl-chain) TypedefDecl:
>
> FunctionProtoType 0x55555621bc80 'auto (AT, T *) -> ClassT<T>' dependent trailing_return cdecl
> |-InjectedClassNameType 0x5555561eb220 'ClassT<T>' dependent
> | `-CXXRecord 0x5555561eafe0 'ClassT'
> |-TypedefType 0x55555621bb20 'AT' sugar
> | |-Typedef 0x55555621bac0 'AT'
> | `-RecordType 0x5555561ead80 'struct A'
> |   `-CXXRecord 0x5555561eacf0 'A'
> `-PointerType 0x5555561eb410 'T *' dependent
>   `-TemplateTypeParmType 0x5555561eafa0 'T' dependent depth 0 index 0
>     `-TemplateTypeParm 0x5555561eaf18 'T'
>
> So, in the translation unit, we have two distinct TypedefDecl AST nodes. The
> first one's DeclContext is the TranslationUnidDecl, however, the second's is
> the CXXDeductionGuideDecl.
>
> This is strange, because when dealing with regular function template
> instantiations, the two typedefs are the same and we have only one universal
> TypedefDecl node in the AST.
> 01
> 02  struct A {};
> 03  typedef A AT;
> 04
> 05  template <typename T>
> 06  int fun(AT p0, T* p1) {}
> 07
> 08  A a;
> 09  int x;
> 10  int y = fun(a, &x);
>
> TypedefDecl 0x5555561eaf70 <input.cc:3:3, col:13> col:13 referenced AT 'A'
> `-RecordType 0x5555561eae30 'A'
>   `-CXXRecord 0x5555561eada0 'A'
>
> FunctionProtoType 0x5555561eb240 'int (AT, T *)' dependent cdecl
> |-BuiltinType 0x5555561ab0a0 'int'
> |-TypedefType 0x5555561eb090 'AT' sugar
> | |-Typedef 0x5555561eaf70 'AT'
> | `-RecordType 0x5555561eae30 'struct A'
> |   `-CXXRecord 0x5555561eada0 'A'
> `-PointerType 0x5555561eb160 'T *' dependent
>   `-TemplateTypeParmType 0x5555561eb050 'T' dependent depth 0 index 0
>     `-TemplateTypeParm 0x5555561eafc8 'T'
>
> I was wondering whether this discrepancy is deliberate. IMO, the deduction
> guide should refer to the TypedefDecl in the TranslationUnidDecl and it should
> not create a new TypedefDecl. Can someone confirm if this is a bug or not?

I can't confirm that this behavior is a bug, but it certainly smells
like one to me. We use pointer comparisons to establish declaration
identity and that would fail with this (and this also gets used in
things like the JSON AST dumper). That said, I'm not certain why the
behavior is the way it is, so it's possible there's something deeper
going on here (but I'd argue it's still likely a bug).

~Aaron

>
> Context: I am trying to fix an infinite loop in the ASTImporter that is related
> to importing deduction guidelines.
>
> Any insight would be really appreciated.
>
> Thanks,
> Gabor
>
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Isolated TypedefDecl in CXXDeductionGuideDecl parameter?

David Blaikie via cfe-dev
This looks like a bug. We intentionally clone typedef declarations into deduction guide declarations in some cases:

template<typename T> struct A {
  typedef T U;
  A(U);
};

... should generate a deduction guide

template<typename T> [typedef T U;]
A(U) -> A<T>;

that has a local clone of the typedef declaration. That's important because we want the typedef declaration to be part of the current instantiation when deducing / instantiating with the deduction guide, in order to allow us to properly "look through" U to T. (We tried other approaches here and this is the one that worked best.)

But this should only be happening for typedefs that are declared within the enclosing class template.

On Fri, 20 Nov 2020 at 08:49, Aaron Ballman <[hidden email]> wrote:
On Fri, Nov 20, 2020 at 11:30 AM Gábor Márton <[hidden email]> wrote:
>
> Hi,
>
> Considering the below code:
> 01
> 02  struct A {};
> 03  typedef A AT;
> 04
> 05  template <typename T> struct ClassT {
> 06    ClassT(AT p0, T* p1) {}
> 07  };
> 08
> 09  A a;
> 10  int x;
> 11  auto y = ClassT(a, &x);
>
> The deduction guide's first parameter refers to a TypedefDecl that is isolated
> from the first TypedefDecl. First declaration:
>
> |-TypedefDecl 0x5555561eaec0 <line:3:3, col:13> col:13 referenced AT 'A'
> | `-RecordType 0x5555561ead80 'A'
> |   `-CXXRecord 0x5555561eacf0 'A'
>
> Vs the function prototype of the deduction guide refers to an isolated
> (out-of-the-redecl-chain) TypedefDecl:
>
> FunctionProtoType 0x55555621bc80 'auto (AT, T *) -> ClassT<T>' dependent trailing_return cdecl
> |-InjectedClassNameType 0x5555561eb220 'ClassT<T>' dependent
> | `-CXXRecord 0x5555561eafe0 'ClassT'
> |-TypedefType 0x55555621bb20 'AT' sugar
> | |-Typedef 0x55555621bac0 'AT'
> | `-RecordType 0x5555561ead80 'struct A'
> |   `-CXXRecord 0x5555561eacf0 'A'
> `-PointerType 0x5555561eb410 'T *' dependent
>   `-TemplateTypeParmType 0x5555561eafa0 'T' dependent depth 0 index 0
>     `-TemplateTypeParm 0x5555561eaf18 'T'
>
> So, in the translation unit, we have two distinct TypedefDecl AST nodes. The
> first one's DeclContext is the TranslationUnidDecl, however, the second's is
> the CXXDeductionGuideDecl.
>
> This is strange, because when dealing with regular function template
> instantiations, the two typedefs are the same and we have only one universal
> TypedefDecl node in the AST.
> 01
> 02  struct A {};
> 03  typedef A AT;
> 04
> 05  template <typename T>
> 06  int fun(AT p0, T* p1) {}
> 07
> 08  A a;
> 09  int x;
> 10  int y = fun(a, &x);
>
> TypedefDecl 0x5555561eaf70 <input.cc:3:3, col:13> col:13 referenced AT 'A'
> `-RecordType 0x5555561eae30 'A'
>   `-CXXRecord 0x5555561eada0 'A'
>
> FunctionProtoType 0x5555561eb240 'int (AT, T *)' dependent cdecl
> |-BuiltinType 0x5555561ab0a0 'int'
> |-TypedefType 0x5555561eb090 'AT' sugar
> | |-Typedef 0x5555561eaf70 'AT'
> | `-RecordType 0x5555561eae30 'struct A'
> |   `-CXXRecord 0x5555561eada0 'A'
> `-PointerType 0x5555561eb160 'T *' dependent
>   `-TemplateTypeParmType 0x5555561eb050 'T' dependent depth 0 index 0
>     `-TemplateTypeParm 0x5555561eafc8 'T'
>
> I was wondering whether this discrepancy is deliberate. IMO, the deduction
> guide should refer to the TypedefDecl in the TranslationUnidDecl and it should
> not create a new TypedefDecl. Can someone confirm if this is a bug or not?

I can't confirm that this behavior is a bug, but it certainly smells
like one to me. We use pointer comparisons to establish declaration
identity and that would fail with this (and this also gets used in
things like the JSON AST dumper). That said, I'm not certain why the
behavior is the way it is, so it's possible there's something deeper
going on here (but I'd argue it's still likely a bug).

~Aaron

>
> Context: I am trying to fix an infinite loop in the ASTImporter that is related
> to importing deduction guidelines.
>
> Any insight would be really appreciated.
>
> Thanks,
> Gabor
>

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Isolated TypedefDecl in CXXDeductionGuideDecl parameter?

David Blaikie via cfe-dev
Richard, Aaron, thanks for your input!
I've came up with a quick (draft) patch to solve the issue. I might not cover all cases, and perhaps the change should have a better place in another function, please take a look if you have some time.
Besides, I ended up using the test infrastructure of the ASTImporter. We could do a refactor to make that infra usable in other AST related tests, if you find that direction okay.

Gabor

On Tue, Nov 24, 2020 at 7:43 PM Richard Smith <[hidden email]> wrote:
This looks like a bug. We intentionally clone typedef declarations into deduction guide declarations in some cases:

template<typename T> struct A {
  typedef T U;
  A(U);
};

... should generate a deduction guide

template<typename T> [typedef T U;]
A(U) -> A<T>;

that has a local clone of the typedef declaration. That's important because we want the typedef declaration to be part of the current instantiation when deducing / instantiating with the deduction guide, in order to allow us to properly "look through" U to T. (We tried other approaches here and this is the one that worked best.)

But this should only be happening for typedefs that are declared within the enclosing class template.

On Fri, 20 Nov 2020 at 08:49, Aaron Ballman <[hidden email]> wrote:
On Fri, Nov 20, 2020 at 11:30 AM Gábor Márton <[hidden email]> wrote:
>
> Hi,
>
> Considering the below code:
> 01
> 02  struct A {};
> 03  typedef A AT;
> 04
> 05  template <typename T> struct ClassT {
> 06    ClassT(AT p0, T* p1) {}
> 07  };
> 08
> 09  A a;
> 10  int x;
> 11  auto y = ClassT(a, &x);
>
> The deduction guide's first parameter refers to a TypedefDecl that is isolated
> from the first TypedefDecl. First declaration:
>
> |-TypedefDecl 0x5555561eaec0 <line:3:3, col:13> col:13 referenced AT 'A'
> | `-RecordType 0x5555561ead80 'A'
> |   `-CXXRecord 0x5555561eacf0 'A'
>
> Vs the function prototype of the deduction guide refers to an isolated
> (out-of-the-redecl-chain) TypedefDecl:
>
> FunctionProtoType 0x55555621bc80 'auto (AT, T *) -> ClassT<T>' dependent trailing_return cdecl
> |-InjectedClassNameType 0x5555561eb220 'ClassT<T>' dependent
> | `-CXXRecord 0x5555561eafe0 'ClassT'
> |-TypedefType 0x55555621bb20 'AT' sugar
> | |-Typedef 0x55555621bac0 'AT'
> | `-RecordType 0x5555561ead80 'struct A'
> |   `-CXXRecord 0x5555561eacf0 'A'
> `-PointerType 0x5555561eb410 'T *' dependent
>   `-TemplateTypeParmType 0x5555561eafa0 'T' dependent depth 0 index 0
>     `-TemplateTypeParm 0x5555561eaf18 'T'
>
> So, in the translation unit, we have two distinct TypedefDecl AST nodes. The
> first one's DeclContext is the TranslationUnidDecl, however, the second's is
> the CXXDeductionGuideDecl.
>
> This is strange, because when dealing with regular function template
> instantiations, the two typedefs are the same and we have only one universal
> TypedefDecl node in the AST.
> 01
> 02  struct A {};
> 03  typedef A AT;
> 04
> 05  template <typename T>
> 06  int fun(AT p0, T* p1) {}
> 07
> 08  A a;
> 09  int x;
> 10  int y = fun(a, &x);
>
> TypedefDecl 0x5555561eaf70 <input.cc:3:3, col:13> col:13 referenced AT 'A'
> `-RecordType 0x5555561eae30 'A'
>   `-CXXRecord 0x5555561eada0 'A'
>
> FunctionProtoType 0x5555561eb240 'int (AT, T *)' dependent cdecl
> |-BuiltinType 0x5555561ab0a0 'int'
> |-TypedefType 0x5555561eb090 'AT' sugar
> | |-Typedef 0x5555561eaf70 'AT'
> | `-RecordType 0x5555561eae30 'struct A'
> |   `-CXXRecord 0x5555561eada0 'A'
> `-PointerType 0x5555561eb160 'T *' dependent
>   `-TemplateTypeParmType 0x5555561eb050 'T' dependent depth 0 index 0
>     `-TemplateTypeParm 0x5555561eafc8 'T'
>
> I was wondering whether this discrepancy is deliberate. IMO, the deduction
> guide should refer to the TypedefDecl in the TranslationUnidDecl and it should
> not create a new TypedefDecl. Can someone confirm if this is a bug or not?

I can't confirm that this behavior is a bug, but it certainly smells
like one to me. We use pointer comparisons to establish declaration
identity and that would fail with this (and this also gets used in
things like the JSON AST dumper). That said, I'm not certain why the
behavior is the way it is, so it's possible there's something deeper
going on here (but I'd argue it's still likely a bug).

~Aaron

>
> Context: I am trying to fix an infinite loop in the ASTImporter that is related
> to importing deduction guidelines.
>
> Any insight would be really appreciated.
>
> Thanks,
> Gabor
>

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev