https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/100355
>From 2b1255de05856e4c79f58d3e4071384ba80a881d Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Thu, 18 Jul 2024 16:26:16 -0500 Subject: [PATCH 1/3] [clang][Sema] Don't mark VarDecls of bindings in tuple-like decompositions as implicit --- clang/lib/AST/DeclCXX.cpp | 1 - clang/lib/Sema/SemaDeclCXX.cpp | 1 - .../debug-info-structured-binding.cpp | 36 ++++++++++-- .../ASTMatchers/ASTMatchersTraversalTest.cpp | 57 +++++++++++++++++++ 4 files changed, 88 insertions(+), 7 deletions(-) diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 72d68f39a97a5..2c22f42a5e0a8 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -3327,7 +3327,6 @@ VarDecl *BindingDecl::getHoldingVar() const { return nullptr; auto *VD = cast<VarDecl>(DRE->getDecl()); - assert(VD->isImplicit() && "holding var for binding decl not implicit"); return VD; } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index f24912cde275a..f4cc1fc4583aa 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1316,7 +1316,6 @@ static bool checkTupleLikeDecomposition(Sema &S, S.Context.getTrivialTypeSourceInfo(T, Loc), Src->getStorageClass()); RefVD->setLexicalDeclContext(Src->getLexicalDeclContext()); RefVD->setTSCSpec(Src->getTSCSpec()); - RefVD->setImplicit(); if (Src->isInlineSpecified()) RefVD->setInlineSpecified(); RefVD->getLexicalDeclContext()->addHiddenDecl(RefVD); diff --git a/clang/test/CodeGenCXX/debug-info-structured-binding.cpp b/clang/test/CodeGenCXX/debug-info-structured-binding.cpp index c88a5cdaa20e7..4a3126a36598d 100644 --- a/clang/test/CodeGenCXX/debug-info-structured-binding.cpp +++ b/clang/test/CodeGenCXX/debug-info-structured-binding.cpp @@ -5,20 +5,46 @@ // 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" -// CHECK: ![[VAR_2]] = !DILocalVariable(name: "y1" -// CHECK: ![[VAR_3]] = !DILocalVariable(name: "x2" -// CHECK: ![[VAR_4]] = !DILocalVariable(name: "y2" +// 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; } +}; + +namespace std { +template<typename T> struct tuple_size { +}; +template<> +struct tuple_size<B> { + static constexpr int value = 2; +}; + +template<int, typename T> struct tuple_element {}; +template<> struct tuple_element<0, B> { using type = int; }; +template<> struct tuple_element<1, B> { using type = int; }; +} + int f() { A a{10, 20}; auto [x1, y1] = a; auto &[x2, y2] = a; - return x1 + y1 + x2 + y2; + auto [z1, z2] = B{1, 2}; + return x1 + y1 + x2 + y2 + z1 + z2; } diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp index 47a71134d5027..06ac07cb12509 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -3163,6 +3163,63 @@ void foo() matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), true, {"-std=c++17"})); } + + Code = R"cpp( +struct Pair +{ + int x, y; +}; + +// Note: these utilities are required to force binding to tuple like structure +namespace std +{ + template <typename E> + struct tuple_size + { + }; + + template <> + struct tuple_size<Pair> + { + static constexpr unsigned value = 2; + }; + + template <unsigned I, class T> + struct tuple_element + { + using type = int; + }; + +}; + +template <unsigned I> +int &&get(Pair &&p); + +void decompTuple() +{ + Pair p{1, 2}; + auto [a, b] = p; + + a = 3; +} + )cpp"; + + { + auto M = bindingDecl(hasName("a")); + EXPECT_TRUE( + matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++17"})); + EXPECT_TRUE( + matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), + true, {"-std=c++17"})); + } + { + auto M = varDecl(hasName("a")); + EXPECT_TRUE( + matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++17"})); + EXPECT_TRUE( + matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), + true, {"-std=c++17"})); + } } TEST(Traversal, traverseNoImplicit) { >From 05e48902a3306eec6490c492a65fe75e34603972 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Wed, 24 Jul 2024 00:10:21 +0100 Subject: [PATCH 2/3] fixup! detect holding vars in CGDebugInfo; revert to setting isImplicit for bindings --- clang/lib/AST/DeclCXX.cpp | 1 + clang/lib/CodeGen/CGDebugInfo.cpp | 41 +++++++++++-- clang/lib/Sema/SemaDeclCXX.cpp | 1 + .../debug-info-structured-binding.cpp | 10 ++-- .../ASTMatchers/ASTMatchersTraversalTest.cpp | 57 ------------------- 5 files changed, 42 insertions(+), 68 deletions(-) diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 2c22f42a5e0a8..72d68f39a97a5 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -3327,6 +3327,7 @@ VarDecl *BindingDecl::getHoldingVar() const { return nullptr; auto *VD = cast<VarDecl>(DRE->getDecl()); + assert(VD->isImplicit() && "holding var for binding decl not implicit"); return VD; } diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 3d8a715b692de..8b261df1ea8b8 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -21,6 +21,7 @@ #include "TargetInfo.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" @@ -79,6 +80,35 @@ static uint32_t getDeclAlignIfRequired(const Decl *D, const ASTContext &Ctx) { return D->hasAttr<AlignedAttr>() ? D->getMaxAlignment() : 0; } +/// Returns true if \ref VD is a VarDecl that is a holding variable +/// (aka a VarDecl retrieved using \ref BindingDecl::getHoldingVar). +static bool IsDecomposedVarDecl(VarDecl const *VD) { + auto const *Init = VD->getInit(); + if (!Init) + return false; + + auto const *RefExpr = + llvm::dyn_cast_or_null<DeclRefExpr>(Init->IgnoreUnlessSpelledInSource()); + if (!RefExpr) + return false; + + return llvm::dyn_cast_or_null<DecompositionDecl>(RefExpr->getDecl()); +} + +/// Return true if \ref VD is a compiler-generated variable +/// and should be treated as artificial for the purposes +/// of debug-info generation. +static bool IsArtificial(VarDecl const *VD) { + // Tuple-like bindings are marked as implicit despite + // being spelled out in source. Don't treat them as artificial + // variables. + if (IsDecomposedVarDecl(VD)) + return false; + + return VD->isImplicit() || (isa<Decl>(VD->getDeclContext()) && + cast<Decl>(VD->getDeclContext())->isImplicit()); +} + CGDebugInfo::CGDebugInfo(CodeGenModule &CGM) : CGM(CGM), DebugKind(CGM.getCodeGenOpts().getDebugInfo()), DebugTypeExtRefs(CGM.getCodeGenOpts().DebugTypeExtRefs), @@ -4753,11 +4783,10 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD, if (VD->hasAttr<NoDebugAttr>()) return nullptr; - bool Unwritten = - VD->isImplicit() || (isa<Decl>(VD->getDeclContext()) && - cast<Decl>(VD->getDeclContext())->isImplicit()); + const bool VarIsArtificial = IsArtificial(VD); + llvm::DIFile *Unit = nullptr; - if (!Unwritten) + if (!VarIsArtificial) Unit = getOrCreateFile(VD->getLocation()); llvm::DIType *Ty; uint64_t XOffset = 0; @@ -4774,13 +4803,13 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD, // Get location information. unsigned Line = 0; unsigned Column = 0; - if (!Unwritten) { + if (!VarIsArtificial) { Line = getLineNumber(VD->getLocation()); Column = getColumnNumber(VD->getLocation()); } SmallVector<uint64_t, 13> Expr; llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; - if (VD->isImplicit()) + if (VarIsArtificial) Flags |= llvm::DINode::FlagArtificial; auto Align = getDeclAlignIfRequired(VD, CGM.getContext()); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index f4cc1fc4583aa..f24912cde275a 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1316,6 +1316,7 @@ static bool checkTupleLikeDecomposition(Sema &S, S.Context.getTrivialTypeSourceInfo(T, Loc), Src->getStorageClass()); RefVD->setLexicalDeclContext(Src->getLexicalDeclContext()); RefVD->setTSCSpec(Src->getTSCSpec()); + RefVD->setImplicit(); if (Src->isInlineSpecified()) RefVD->setInlineSpecified(); RefVD->getLexicalDeclContext()->addHiddenDecl(RefVD); diff --git a/clang/test/CodeGenCXX/debug-info-structured-binding.cpp b/clang/test/CodeGenCXX/debug-info-structured-binding.cpp index 4a3126a36598d..5fbd54c16382c 100644 --- a/clang/test/CodeGenCXX/debug-info-structured-binding.cpp +++ b/clang/test/CodeGenCXX/debug-info-structured-binding.cpp @@ -28,18 +28,18 @@ struct B { 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 int value = 2; + static constexpr unsigned value = 2; }; -template<int, typename T> struct tuple_element {}; -template<> struct tuple_element<0, B> { using type = int; }; -template<> struct tuple_element<1, B> { using type = int; }; -} +template<unsigned, typename T> struct tuple_element { using type = int; }; +} // namespace std int f() { A a{10, 20}; diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp index 06ac07cb12509..47a71134d5027 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -3163,63 +3163,6 @@ void foo() matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), true, {"-std=c++17"})); } - - Code = R"cpp( -struct Pair -{ - int x, y; -}; - -// Note: these utilities are required to force binding to tuple like structure -namespace std -{ - template <typename E> - struct tuple_size - { - }; - - template <> - struct tuple_size<Pair> - { - static constexpr unsigned value = 2; - }; - - template <unsigned I, class T> - struct tuple_element - { - using type = int; - }; - -}; - -template <unsigned I> -int &&get(Pair &&p); - -void decompTuple() -{ - Pair p{1, 2}; - auto [a, b] = p; - - a = 3; -} - )cpp"; - - { - auto M = bindingDecl(hasName("a")); - EXPECT_TRUE( - matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++17"})); - EXPECT_TRUE( - matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), - true, {"-std=c++17"})); - } - { - auto M = varDecl(hasName("a")); - EXPECT_TRUE( - matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++17"})); - EXPECT_TRUE( - matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), - true, {"-std=c++17"})); - } } TEST(Traversal, traverseNoImplicit) { >From 9a830ffca04eea63c3752c24377891addd9abb64 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Thu, 25 Jul 2024 00:18:14 +0100 Subject: [PATCH 3/3] fixup! fix comment --- clang/lib/CodeGen/CGDebugInfo.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 8b261df1ea8b8..4c59c7b65000b 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -80,8 +80,8 @@ static uint32_t getDeclAlignIfRequired(const Decl *D, const ASTContext &Ctx) { return D->hasAttr<AlignedAttr>() ? D->getMaxAlignment() : 0; } -/// Returns true if \ref VD is a VarDecl that is a holding variable -/// (aka a VarDecl retrieved using \ref BindingDecl::getHoldingVar). +/// Returns true if \ref VD is a a holding variable (aka a +/// VarDecl retrieved using \ref BindingDecl::getHoldingVar). static bool IsDecomposedVarDecl(VarDecl const *VD) { auto const *Init = VD->getInit(); if (!Init) @@ -95,7 +95,7 @@ static bool IsDecomposedVarDecl(VarDecl const *VD) { return llvm::dyn_cast_or_null<DecompositionDecl>(RefExpr->getDecl()); } -/// Return true if \ref VD is a compiler-generated variable +/// Returns true if \ref VD is a compiler-generated variable /// and should be treated as artificial for the purposes /// of debug-info generation. static bool IsArtificial(VarDecl const *VD) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits