Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

[CodeView] Omitted class member function declaration for lambda. #45331

Open Quuxplusone opened 4 years ago

Quuxplusone commented 4 years ago
Bugzilla Link PR46361
Status NEW
Importance P enhancement
Reported by Carlos Alberto Enciso (international.phantom@gmail.com)
Reported on 2020-06-17 02:35:41 -0700
Last modified on 2020-06-18 22:36:59 -0700
Version trunk
Hardware PC All
CC dblaikie@gmail.com, greg.bedwell@sony.com, jdevlieghere@apple.com, jeremy.morse.llvm@gmail.com, keith.walker@arm.com, llvm-bugs@lists.llvm.org, orlando.hyams@sony.com, paul_robinson@playstation.sony.com, rnk@google.com
Fixed by commit(s)
Attachments
Blocks
Blocked by
See also
Given the following test case:

//------------------------------------------------------------
int test() {
  auto myLambdaFunction = [&](auto Param) {
    return Param;
  };

  return myLambdaFunction(1);
}
//------------------------------------------------------------

Using the command line to generate debug info CodeView:

clang -c -g -O0 lambda.cpp -o lambda-cv.o -gcodeview --target=x86_64-windows

The output generated by llvm-pdbutil, shows the definition for a member
function (operator ()), but it does not include its declaration in the class
associated with the lambda:

  0 | S_GPROC32_ID `test`
  0 | S_LOCAL `myLambdaFunction`
      type=0x1005 (test::<unnamed-tag>)
  0 | S_PROC_ID_END

** Class associated with lambda **
----------------------------------
0x1005 | LF_CLASS [size = 76] `test::<unnamed-tag>`
         unique name: `.?AV<lambda_0>@?0??test@@YAHXZ@`
         field list: 0x1004
0x1004 | LF_FIELDLIST      <--- Empty field list

** operator() definition **
---------------------------
  0 | S_LPROC32_ID `test::<unnamed-tag>::operator()<int>`
      type = `0x100C (operator())`
  0 | S_LOCAL `this`
      type=0x100D (const test::<unnamed-tag>*), flags = param
  0 | S_LOCAL [size = 16] `Param`
      type=0x0074 (int), flags = param
  0 | S_PROC_ID_END

0x100C | LF_MFUNC_ID
         name = operator(), type = 0x100B, class type = 0x1003
0x100B | LF_MFUNCTION
         return type = <no type>, # args = 1, param list = 0x100A
         class type = 0x1003, this type = 0x1009
0x100A | LF_ARGLIST
         0x0074 (int): `int`
0x1003 | LF_CLASS `test::<unnamed-tag>`
         options: forward ref

Using MSVC on the same test, the output looks like:

  0 | S_GPROC32_ID `test`
      type = `0x1015 (test)`
      original type = 0x100F
  0 | S_BPREL32 `myLambdaFunction`
      type = 0x100F
  0 | S_PROC_ID_END

0x100F | LF_CLASS `test::__l2::<lambda_5684e4bda96652f15ead82ba8f8a98f2>`
         unique name: `.?AV<lambda_5684e4bda96652f15ead82ba8f8a98f2>@@`28ae9b9a`
         field list: 0x100E
0x100E | LF_FIELDLIST
         - LF_METHOD .....
         - LF_ONEMETHOD ....
Quuxplusone commented 4 years ago
This is the output from llvm-diva (Sony's tool under development).

llvm-diva --print=scopes,symbols,types lambda_dw.o lambda_cv.o lambda_ms.o --
attribute=level,format

DWARF Logical View: (Clang)
---------------------------
[000]       {File} 'lambda_dw.o' -> elf64-x86-64
[001]         {CompileUnit} 'lambda.cpp'
[002]           {Producer} 'clang version 11.0.0'
[002] 2         {Function} extern not_inlined 'operator()<int>' -> 'int'
[003] 2           {Parameter} 'Param' -> 'int'
[003]             {Parameter} 'this' -> '* const test::2'
[003]             {TemplateType} 'Param:auto' -> 'int'
[002] 1         {Function} extern not_inlined 'test' -> 'int'
[003] 2           {Class} 'test::2'
[004] 2             {Function} public not_inlined 'operator()<int>' -> 'auto'
[005]                 {Parameter} '' -> '* const test::2'
[005]                 {Parameter} '' -> 'int'
[005]                 {TemplateType} 'Param:auto' -> 'int'
[003] 2           {Variable} 'myLambdaFunction' -> 'test::2'

CodeView Logical View: (Clang)
------------------------------
[000]       {File} 'lambda_cv.o' -> COFF-x86-64
[001]         {CompileUnit} 'lambda.cpp'
[002]           {Producer} 'clang version 11.0.0'
[002]           {Function} not_inlined 'operator()<int>' -> '<no type>'
[003]             {Parameter} 'Param' -> 'int'
[003]             {Parameter} 'this' -> '* const <unnamed-tag>'
[002]           {Function} extern not_inlined 'test' -> 'int'
[003] 2           {Class} '<unnamed-tag>'
[003]             {Variable} 'myLambdaFunction' -> '<unnamed-tag>'

CodeView Logical View: (MSVC)
-----------------------------
[000]       {File} 'lambda_ms.o' -> COFF-i386
[001]         {CompileUnit} 'lambda.cpp'
[002]           {Producer} 'Microsoft (R) Optimizing Compiler'
[002]           {Function} not_inlined 'operator()<int>' -> 'int'
[003]             {Parameter} 'Param' -> 'int'
[003]             {Variable} 'this' -> '* const <lambda_56..f2>'
[002]           {Function} extern not_inlined 'test' -> 'int'
[003] 4           {Class} '<lambda_56..f2>'
[004]               {Function} public not_inlined '<lambda_56..f2>' -> 'void'
[005]                 {Parameter} '' -> '* <lambda_56..f2>'
[005]                 {Parameter} '' -> '&& <lambda_56..f2>'
[004]               {Function} public not_inlined '<lambda_56..f2>' -> 'void'
[005]                 {Parameter} '' -> '* <lambda_56..f2>'
[004]               {Function} public not_inlined 'operator=' -> '&
<lambda_56..f2>'
[005]                 {Parameter} '' -> '* <lambda_56..f2>'
[005]                 {Parameter} '' -> '& const <lambda_56..f2>'
[003]             {Variable} 'myLambdaFunction' -> '<lambda_56..f2>'
Quuxplusone commented 4 years ago
Guessing this might be not lambda specific, maybe try the non-lambda equivalent:

struct t1 {
  template<typename T>
  void f1(T) { }
};

int main() {
  t1().f1(1);
}

May be a requirement for CodeView type descriptions to be consistent in every
use - in which case putting declarations of member function template
specializations wouldn't be compatible - because you don't know how many/which
specializations exist. (what does MSVC do?)
Quuxplusone commented 4 years ago
(In reply to David Blaikie from comment #2)
> Guessing this might be not lambda specific, maybe try the non-lambda
> equivalent:
>
> struct t1 {
>   template<typename T>
>   void f1(T) { }
> };
>
> int main() {
>   t1().f1(1);
> }
>
> May be a requirement for CodeView type descriptions to be consistent in
> every use - in which case putting declarations of member function template
> specializations wouldn't be compatible - because you don't know how
> many/which specializations exist. (what does MSVC do?)

Thanks for your comments and test case.

I have included the logical views generated by llvm-diva for your case:

DWARF Logical View: (Clang)
---------------------------
Logical View:
[000]           {File} 'template_dw.o' -> elf64-x86-64
[001]             {CompileUnit} 'template.cpp'
[002]               {Producer} 'clang version 11.0.0'
[002]     3         {Function} extern not_inlined 'f1<int>' -> 'void'
[003]     3           {Parameter} '' -> 'int'
[003]                 {Parameter} 'this' -> '* t1'
[003]                 {TemplateType} 'T' -> 'int'
[002]     6         {Function} extern not_inlined 'main' -> 'int'
[002]     1         {Struct} 't1'
[003]     3           {Function} public not_inlined 'f1<int>' -> 'void'
[004]                   {Parameter} '' -> '* t1'
[004]                   {Parameter} '' -> 'int'
[004]                   {TemplateType} 'T' -> 'int'

CodeView Logical View: (Clang)
------------------------------
Logical View:
[000]           {File} 'template_cv.o' -> COFF-x86-64
[001]             {CompileUnit} 'template.cpp'
[002]               {Producer} 'clang version 11.0.0'
[002]               {Function} extern not_inlined 'f1<int>' -> 'void'
[003]                 {Parameter} '' -> 'int'
[003]                 {Parameter} 'this' -> '* t1'
[002]               {Function} extern not_inlined 'main' -> 'int'
[002]     1         {Struct} 't1'

CodeView Logical View: (MSVC)
-----------------------------
Logical View:
[000]           {File} 'template_ms.o' -> COFF-i386
[001]             {CompileUnit} 'template.cpp'
[002]               {Producer} 'Microsoft (R) Optimizing Compiler'
[002]               {Function} extern not_inlined 'f1<int>' -> 'void'
[003]                 {Parameter} '__formal' -> 'int'
[003]                 {Variable} 'this' -> '* t1'
[002]               {Function} extern not_inlined 'main' -> 'int'
[002]     1         {Struct} 't1'

MSVC and Clang on CodeView produces basically the same view. Except for
parameter information in the MSVC (flags to indicate parameter or variable).