// clang-format off // REQUIRES: lld, x86 // Test that we can display function signatures with class types. // RUN: %clang_cl --target=x86_64-windows-msvc -Od -Z7 -c /Fo%t.obj -- %s // RUN: lld-link -debug:full -nodefaultlib -entry:main %t.obj -out:%t.exe -pdb:%t.pdb // RUN: %lldb -f %t.exe -s \ // RUN: %p/Inputs/function-types-classes.lldbinit | FileCheck %s // This is just some unimportant helpers needed so that we can get reference and // rvalue-reference types into return values. template struct MakeResult { static T result() { return T{}; } }; template struct MakeResult { static T& result() { static T t; return t; } }; template struct MakeResult { static T&& result() { static T t; return static_cast(t); } }; template R nullary() { return MakeResult::result(); } template R three(A a, B b) { return MakeResult::result(); } template R four(A a, B b, C c) { return MakeResult::result(); } struct S {}; class C {}; union U {}; enum E {}; namespace A { namespace B { // NS::NS struct S { }; } struct C { // NS::Struct struct S {}; }; } struct B { struct A { // Struct::Struct struct S {}; }; }; // clang (incorrectly) doesn't emit debug information for outer classes // unless they are instantiated. They should also be emitted if there // is an inner class which is instantiated. A::C ForceInstantiateAC; B ForceInstantiateB; B::A ForceInstantiateBA; template struct TC {}; // const and volatile modifiers auto a = &four; // CHECK: (S (*)(C *, U &, E &&)) a = {{.*}} auto b = &four; // CHECK: (E (*)(const S *, const C &, const U &&)) b = {{.*}} auto c = &four; // CHECK: (U (*)(volatile E *, volatile S &, volatile C &&)) c = {{.*}} auto d = &four; // CHECK: (C (*)(const volatile U *, const volatile E &, const volatile S &&)) d = {{.*}} // classes nested in namespaces and inner classes auto e = &three; // CHECK: (A::B::S *(*)(B::A::S *, A::C::S &)) e = {{.*}} auto f = &three; // CHECK: (A::C::S &(*)(A::B::S *, B::A::S *)) f = {{.*}} auto g = &three; // CHECK: (B::A::S *(*)(A::C::S &, A::B::S *)) g = {{.*}} // parameter types that are themselves template instantiations. auto h = &four, TC, TC>, TC>; // CHECK: (TC (*)(TC, TC>, TC)) h = {{.*}} auto i = &nullary; // CHECK: (A::B::S (*)()) i = {{.*}} // Make sure we can handle types that don't have complete debug info. struct Incomplete; auto incomplete = &three; // CHECK: (Incomplete *(*)(Incomplete **, const Incomplete *)) incomplete = {{.*}} // CHECK: TranslationUnitDecl {{.*}} // CHECK: |-CXXRecordDecl {{.*}} class C // CHECK: |-CXXRecordDecl {{.*}} union U // CHECK: |-EnumDecl {{.*}} E // CHECK: |-CXXRecordDecl {{.*}} struct S // CHECK: |-VarDecl {{.*}} a 'S (*)(C *, U &, E &&)' // CHECK: |-VarDecl {{.*}} b 'E (*)(const S *, const C &, const U &&)' // CHECK: |-VarDecl {{.*}} c 'U (*)(volatile E *, volatile S &, volatile C &&)' // CHECK: |-VarDecl {{.*}} d 'C (*)(const volatile U *, const volatile E &, const volatile S &&)' // CHECK: |-CXXRecordDecl {{.*}} struct B // CHECK: | `-CXXRecordDecl {{.*}} struct A // CHECK: | `-CXXRecordDecl {{.*}} struct S // CHECK: |-NamespaceDecl {{.*}} A // CHECK: | |-CXXRecordDecl {{.*}} struct C // CHECK: | | `-CXXRecordDecl {{.*}} struct S // CHECK: | `-NamespaceDecl {{.*}} B // CHECK: | `-CXXRecordDecl {{.*}} struct S // CHECK: |-VarDecl {{.*}} e 'A::B::S *(*)(B::A::S *, A::C::S &)' // CHECK: |-VarDecl {{.*}} f 'A::C::S &(*)(A::B::S *, B::A::S *)' // CHECK: |-VarDecl {{.*}} g 'B::A::S *(*)(A::C::S &, A::B::S *)' // CHECK: |-CXXRecordDecl {{.*}} struct TC // CHECK: |-CXXRecordDecl {{.*}} struct TC> // CHECK: |-CXXRecordDecl {{.*}} struct TC // CHECK: |-CXXRecordDecl {{.*}} struct TC // CHECK: |-VarDecl {{.*}} h 'TC (*)(TC, TC>, TC)' // CHECK: |-VarDecl {{.*}} i 'A::B::S (*)()' // CHECK: |-CXXRecordDecl {{.*}} struct Incomplete // CHECK: `-VarDecl {{.*}} incomplete 'Incomplete *(*)(Incomplete **, const Incomplete *)' int main(int argc, char **argv) { return 0; }