llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.42k stars 12.16k forks source link

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

Open CarlosAlbertoEnciso opened 4 years ago

CarlosAlbertoEnciso commented 4 years ago
Bugzilla Link 46361
Version trunk
OS All
CC @dwblaikie,@gregbedwell,@JDevlieghere,@jmorse,@walkerkd,@OCHyams,@pogo59,@rnk

Extended Description

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 ....
CarlosAlbertoEnciso commented 4 years ago

Guessing this might be not lambda specific, maybe try the non-lambda equivalent:

struct t1 { template 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' -> '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' -> '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' -> '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' -> '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).

dwblaikie commented 4 years ago

Guessing this might be not lambda specific, maybe try the non-lambda equivalent:

struct t1 { template 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?)

CarlosAlbertoEnciso 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' [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()' -> '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()' -> '' [003] {Parameter} 'Param' -> 'int' [003] {Parameter} 'this' -> '* const ' [002] {Function} extern not_inlined 'test' -> 'int' [003] 2 {Class} '' [003] {Variable} 'myLambdaFunction' -> ''

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' [003] {Parameter} 'Param' -> 'int' [003] {Variable} 'this' -> ' const ' [002] {Function} extern not_inlined 'test' -> 'int' [003] 4 {Class} '' [004] {Function} public not_inlined '' -> 'void' [005] {Parameter} '' -> ' ' [005] {Parameter} '' -> '&& ' [004] {Function} public not_inlined '' -> 'void' [005] {Parameter} '' -> ' ' [004] {Function} public not_inlined 'operator=' -> '& ' [005] {Parameter} '' -> ' ' [005] {Parameter} '' -> '& const ' [003] {Variable} 'myLambdaFunction' -> ''