| // RUN: %clang_cc1 -emit-llvm -triple x86_64-unknown_unknown -std=c++17 %s -o - -w -debug-info-kind=limited -gsimple-template-names=mangled \ |
| // RUN: | FileCheck %s |
| // RUN: %clang_cc1 -emit-llvm -triple x86_64-unknown_unknown -std=c++17 %s -o - -w -debug-info-kind=limited -gsimple-template-names=simple \ |
| // RUN: | FileCheck %s --implicit-check-not=_STN --check-prefix=SIMPLE |
| // RUN: %clang_cc1 -emit-llvm -triple x86_64-unknown_unknown -std=c++17 %s -o - -w -debug-info-kind=limited \ |
| // RUN: | FileCheck %s --implicit-check-not=_STN --check-prefix=FULL |
| // RUN: %clang_cc1 -emit-llvm -triple x86_64-unknown_unknown -std=c++17 %s -o - -w -debug-info-kind=line-tables-only -gsimple-template-names=mangled -fdebug-info-for-profiling \ |
| // RUN: | FileCheck %s --implicit-check-not=_STN --check-prefix=FULL |
| |
| template <typename... T> |
| void f1() {} |
| template <typename T, T V> |
| void f2() {} |
| template <typename... T> |
| struct t1 {}; |
| extern int x; |
| int x; |
| struct t2 { |
| template <typename T = float> |
| operator t1<int>() { __builtin_unreachable(); } |
| }; |
| template <template <typename...> class T> |
| void f3() {} |
| namespace { |
| enum LocalEnum { LocalEnum1 }; |
| } |
| template<typename T, T ... ts> |
| struct t3 { }; |
| struct t4 { |
| t3<LocalEnum, LocalEnum1> m1; |
| }; |
| |
| t4 v1; |
| enum { UnnamedEnum1 }; |
| template<decltype(UnnamedEnum1)> |
| void f4() { |
| } |
| // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "t3<(anonymous namespace)::LocalEnum, ((anonymous namespace)::LocalEnum)0>" |
| void f() { |
| // Basic examples of simplifiable/rebuildable names |
| f1<>(); |
| // CHECK: !DISubprogram(name: "_STN|f1|<>", |
| // SIMPLE: !DISubprogram(name: "f1", |
| // FULL: !DISubprogram(name: "f1<>", |
| f1<int>(); |
| // CHECK: !DISubprogram(name: "_STN|f1|<int>", |
| f1<void()>(); |
| // CHECK: !DISubprogram(name: "_STN|f1|<void ()>", |
| f2<int, 42>(); |
| // CHECK: !DISubprogram(name: "_STN|f2|<int, 42>", |
| |
| // Check that even though the nested name can't be rebuilt, it'll carry its |
| // full name and the outer name can be rebuilt from that. |
| f1<t1<void() noexcept>>(); |
| // CHECK: !DISubprogram(name: "_STN|f1|<t1<void () noexcept> >", |
| |
| // Vector array types are encoded in DWARF but the decoding in llvm-dwarfdump |
| // isn't implemented yet. |
| f1<__attribute__((__vector_size__((sizeof(int) * 2)))) int>(); |
| // CHECK: !DISubprogram(name: "f1<__attribute__((__vector_size__(2 * sizeof(int)))) int>", |
| |
| // noexcept is part of function types in C++17 onwards, but not encoded in |
| // DWARF |
| f1<void() noexcept>(); |
| // CHECK: !DISubprogram(name: "f1<void () noexcept>", |
| |
| // Unnamed entities (lambdas, structs/classes, enums) can't be fully rebuilt |
| // since we don't emit the column number. Also lambdas and unnamed classes are |
| // ambiguous with each other - there's no DWARF that designates a lambda as |
| // anything other than another unnamed class/struct. |
| auto Lambda = [] {}; |
| f1<decltype(Lambda)>(); |
| // CHECK: !DISubprogram(name: "f1<(lambda at {{.*}}debug-info-simple-template-names.cpp:[[# @LINE - 2]]:17)>", |
| f1<t1<t1<decltype(Lambda)>>>(); |
| // CHECK: !DISubprogram(name: "f1<t1<t1<(lambda at {{.*}}> > >", |
| struct { |
| } unnamed_struct; |
| f1<decltype(unnamed_struct)>(); |
| // CHECK: !DISubprogram(name: "f1<(unnamed struct at {{.*}}debug-info-simple-template-names.cpp:[[# @LINE - 3]]:3)>", |
| f1<void (decltype(unnamed_struct))>(); |
| // CHECK: !DISubprogram(name: "f1<void ((unnamed struct at {{.*}}debug-info-simple-template-names.cpp:[[# @LINE - 5]]:3))>", |
| enum {} unnamed_enum; |
| f1<decltype(unnamed_enum)>(); |
| // CHECK: !DISubprogram(name: "f1<(unnamed enum at {{.*}}debug-info-simple-template-names.cpp:[[# @LINE - 2]]:3)>", |
| |
| // Declarations can't readily be reversed as the value in the DWARF only |
| // contains the address of the value - we'd have to do symbol lookup to find |
| // the name of that value (& rely on it not having been stripped out, etc). |
| f2<int *, &x>(); |
| // CHECK: !DISubprogram(name: "f2<int *, &x>", |
| |
| // We could probably handle \/ this case, but since it's a small subset of |
| // pointer typed non-type-template parameters which can't be handled it |
| // doesn't seem high priority. |
| f2<decltype(nullptr), nullptr>(); |
| // CHECK: !DISubprogram(name: "f2<std::nullptr_t, nullptr>", |
| |
| // These larger constants are encoded as data blocks which makes them a bit |
| // harder to re-render. I think they might be missing sign information, or at |
| // maybe it's just a question of doing APInt things to render such large |
| // values. Punting on this for now. |
| f2<__int128, ((__int128)9223372036854775807) * 2>(); |
| // CHECK: !DISubprogram(name: "f2<__int128, (__int128)18446744073709551614>", |
| |
| t2().operator t1<int>(); |
| // FIXME: This should be something like "operator t1<int><float>" |
| // CHECK: !DISubprogram(name: "operator t1<float>", |
| |
| // Function pointer non-type-template parameters currently don't get any DWARF |
| // value (GCC doesn't provide one either) and even if there was a value, if |
| // it's like variable/pointer non-type template parameters, it couldn't be |
| // rebuilt anyway (see the note above for details on that) so we don't have to |
| // worry about seeing conversion operators as parameters to other templates. |
| |
| f3<t1>(); |
| // CHECK: !DISubprogram(name: "_STN|f3|<t1>", |
| |
| f1<_BitInt(3)>(); |
| // CHECK: !DISubprogram(name: "f1<_BitInt(3)>", |
| |
| f1<const unsigned _BitInt(5)>(); |
| // CHECK: !DISubprogram(name: "f1<const unsigned _BitInt(5)>", |
| |
| // Add a parameter just so this differs from other attributed function types |
| // that don't mangle differently. |
| int fnrt() __attribute__((noreturn)); |
| f1<decltype(fnrt)>(); |
| // CHECK: !DISubprogram(name: "f1<int () __attribute__((noreturn))>", |
| |
| f4<UnnamedEnum1>(); |
| // CHECK: !DISubprogram(name: "f4<((unnamed enum at {{.*}}))0>" |
| } |