
This patch is motivated by the debug-info issue in https://github.com/llvm/llvm-project/issues/48909. Clang is currently emitting the `DW_AT_artificial` attribute on debug-info entries for structured bindings whereas GCC does not. GCC's interpretation of the DWARF spec is more user-friendly in this regard, so we would like to do the same in Clang. [`CGDebugInfo` uses `isImplicit` to decide which variables to mark artificial](0c4023ae3b/clang/lib/CodeGen/CGDebugInfo.cpp (L4783-L4784)
) (e.g., `ImplicitParamDecls`, compiler-generated variables, etc.). But for the purposes of debug-info, when we say "artificial", what we really mean in many cases is: "not explicitly spelled out in source". `VarDecl`s that back tuple-like bindings are [technically compiler-generated](https://github.com/llvm/llvm-project/issues/48909#issuecomment-2238976579), but that is a confusing notion for debug-info, since these bindings *are* spelled out in source. The [documentation for `isImplicit`](68a0d0c762/clang/include/clang/AST/DeclBase.h (L596-L600)
) does to some extent imply that implicit variables aren't written in source. This patch adds another condition to deciding whether a `VarDecl` should be marked artificial. Specifically, don't treat structured bindings as artificial. **Main alternatives considered** 1. Don't use `isImplicit` in `CGDebugInfo` when determining whether to add `DW_AT_artificial`. Instead use some other property of the AST that would tell us whether a node was explicitly spelled out in source or not * Considered using `SourceRange` or `SourceLocation` to tell us this, but didn't find a good way to, e.g., correctly identify that the implicit `this` parameter wasn't spelled out in source (as opposed to an unnamed parameter in a function declaration) 2. We could've also added a bit to `VarDeclBitFields` that indicates that a `VarDecl` is a holding var, but the use-case didn't feel like good enough justification for this 3. Don't set the `VarDecl` introduced as part of a tuple-like decomposition as implicit. * This may affect AST matching/traversal and this specific use-case wasn't enough to justify such a change Fixes https://github.com/llvm/llvm-project/issues/48909
51 lines
2.2 KiB
C++
51 lines
2.2 KiB
C++
// RUN: %clang_cc1 -emit-llvm -debug-info-kind=standalone -triple %itanium_abi_triple %s -o - | FileCheck %s --implicit-check-not="call void @llvm.dbg.declare"
|
|
|
|
// CHECK: #dbg_declare(ptr %{{[a-z]+}}, ![[VAR_0:[0-9]+]], !DIExpression(),
|
|
// CHECK: #dbg_declare(ptr %{{[0-9]+}}, ![[VAR_1:[0-9]+]], !DIExpression(),
|
|
// CHECK: #dbg_declare(ptr %{{[0-9]+}}, ![[VAR_2:[0-9]+]], !DIExpression(DW_OP_plus_uconst, 4),
|
|
// CHECK: #dbg_declare(ptr %{{[0-9]+}}, ![[VAR_3:[0-9]+]], !DIExpression(DW_OP_deref),
|
|
// CHECK: #dbg_declare(ptr %{{[0-9]+}}, ![[VAR_4:[0-9]+]], !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 4),
|
|
// CHECK: #dbg_declare(ptr %z1, ![[VAR_5:[0-9]+]], !DIExpression()
|
|
// CHECK: #dbg_declare(ptr %z2, ![[VAR_6:[0-9]+]], !DIExpression()
|
|
// CHECK: ![[VAR_0]] = !DILocalVariable(name: "a"
|
|
// CHECK: ![[VAR_1]] = !DILocalVariable(name: "x1", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
|
|
// CHECK: ![[VAR_2]] = !DILocalVariable(name: "y1", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
|
|
// CHECK: ![[VAR_3]] = !DILocalVariable(name: "x2", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
|
|
// CHECK: ![[VAR_4]] = !DILocalVariable(name: "y2", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
|
|
// CHECK: ![[VAR_5]] = !DILocalVariable(name: "z1", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
|
|
// CHECK: ![[VAR_6]] = !DILocalVariable(name: "z2", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
|
|
|
|
struct A {
|
|
int x;
|
|
int y;
|
|
};
|
|
|
|
struct B {
|
|
int w;
|
|
int z;
|
|
template<int> int get();
|
|
template<> int get<0>() { return w; }
|
|
template<> int get<1>() { return z; }
|
|
};
|
|
|
|
// Note: the following declarations are necessary for decomposition of tuple-like
|
|
// structured bindings
|
|
namespace std {
|
|
template<typename T> struct tuple_size {
|
|
};
|
|
template<>
|
|
struct tuple_size<B> {
|
|
static constexpr unsigned value = 2;
|
|
};
|
|
|
|
template<unsigned, typename T> struct tuple_element { using type = int; };
|
|
} // namespace std
|
|
|
|
int f() {
|
|
A a{10, 20};
|
|
auto [x1, y1] = a;
|
|
auto &[x2, y2] = a;
|
|
auto [z1, z2] = B{1, 2};
|
|
return x1 + y1 + x2 + y2 + z1 + z2;
|
|
}
|