blob: ca2a84de7698a4c41cb098ff4265485ace86c811 [file] [log] [blame]
// 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: env LLDB_USE_NATIVE_PDB_READER=1 %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<typename T>
struct MakeResult {
static T result() {
return T{};
}
};
template<typename T>
struct MakeResult<T&> {
static T& result() {
static T t;
return t;
}
};
template<typename T>
struct MakeResult<T&&> {
static T&& result() {
static T t;
return static_cast<T&&>(t);
}
};
template<typename R>
R nullary() { return MakeResult<R>::result(); }
template<typename R, typename A, typename B>
R three(A a, B b) { return MakeResult<R>::result(); }
template<typename R, typename A, typename B, typename C>
R four(A a, B b, C c) { return MakeResult<R>::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<typename T>
struct TC {};
// const and volatile modifiers
auto a = &four<S, C*, U&, E&&>;
// CHECK: (S (*)(C *, U &, E &&)) a = {{.*}}
auto b = &four<E, const S*, const C&, const U&&>;
// CHECK: (E (*)(const S *, const C &, const U &&)) b = {{.*}}
auto c = &four<U, volatile E*, volatile S&, volatile C&&>;
// CHECK: (U (*)(volatile E *, volatile S &, volatile C &&)) c = {{.*}}
auto d = &four<C, const volatile U*, const volatile E&, const volatile S&&>;
// CHECK: (C (*)(const volatile U *, const volatile E &, const volatile S &&)) d = {{.*}}
// classes nested in namespaces and inner classes
auto e = &three<A::B::S*, B::A::S*, A::C::S&>;
// CHECK: (A::B::S *(*)(B::A::S *, A::C::S &)) e = {{.*}}
auto f = &three<A::C::S&, A::B::S*, B::A::S*>;
// CHECK: (A::C::S &(*)(A::B::S *, B::A::S *)) f = {{.*}}
auto g = &three<B::A::S*, A::C::S&, A::B::S*>;
// CHECK: (B::A::S *(*)(A::C::S &, A::B::S *)) g = {{.*}}
// parameter types that are themselves template instantiations.
auto h = &four<TC<void>, TC<int>, TC<TC<int>>, TC<A::B::S>>;
// CHECK: (TC<void> (*)(TC<int>, TC<TC<int>>, TC<A::B::S>)) h = {{.*}}
auto i = &nullary<A::B::S>;
// CHECK: (A::B::S (*)()) i = {{.*}}
// Make sure we can handle types that don't have complete debug info.
struct Incomplete;
auto incomplete = &three<Incomplete*, Incomplete**, const Incomplete*>;
// 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<int>
// CHECK: |-CXXRecordDecl {{.*}} struct TC<TC<int>>
// CHECK: |-CXXRecordDecl {{.*}} struct TC<A::B::S>
// CHECK: |-CXXRecordDecl {{.*}} struct TC<void>
// CHECK: |-VarDecl {{.*}} h 'TC<void> (*)(TC<int>, TC<TC<int>>, TC<A::B::S>)'
// 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;
}