[clang] [clang-tools-extra] [clang] Compute accurate begin location for CallExpr with explicit object parameter (PR #117841)
HighCommander4 wrote: > I didn't check if any tests fail but here's a version where `CallExpr` saves > its `BeginLoc` explicitly: > http://llvm-compile-time-tracker.com/compare.php?from=416e4cd332c7421b187844ac9aaf6fe28b575a7d&to=0b6e36fe460409aa59958b79766b4f64a31c97e6&stat=instructions:u Yeah, this is another alternative, though I wonder if the memory tradeoff it makes (increasing the size of `CallExpr` by 4 bytes) is worth it. https://github.com/llvm/llvm-project/pull/117841 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang] Compute accurate begin location for CallExpr with explicit object parameter (PR #117841)
tbaederr wrote: I didn't check if any tests fail but here's a version where `CallExpr` saves its `BeginLoc` explicitly: http://llvm-compile-time-tracker.com/compare.php?from=416e4cd332c7421b187844ac9aaf6fe28b575a7d&to=0b6e36fe460409aa59958b79766b4f64a31c97e6&stat=instructions:u https://github.com/llvm/llvm-project/pull/117841 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang] Compute accurate begin location for CallExpr with explicit object parameter (PR #117841)
HighCommander4 wrote: > The branch is **not** taken most of the time (it's only taken for calls to > functions with an explicit object argument, which is a C++23 feature), so > perhaps annotating the branch as "unlikely" is sufficient to avoid the > performance regression? Ah, no, that's not sufficient because it takes some work (a call to `getCalleeDecl()`) to compute the branch condition. We could consider revising the implementation approach to optimize this better; for example, add a "uses explicit object argument" bit to `CallExprBits`? https://github.com/llvm/llvm-project/pull/117841 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang] Compute accurate begin location for CallExpr with explicit object parameter (PR #117841)
HighCommander4 wrote: > It looks like this causes a significant compile-time regression: > https://llvm-compile-time-tracker.com/compare.php?from=2b855dd97092e2178ac5c470a804a17ec440d7e5&to=9ccde12f5eeb91152900082a2ae839e2a9702b31&stat=instructions:u > (Maybe most clearly seen during clang bootstrap, where this adds 0.5% to > many compilations: > https://llvm-compile-time-tracker.com/compare_clang.php?from=2b855dd97092e2178ac5c470a804a17ec440d7e5&to=9ccde12f5eeb91152900082a2ae839e2a9702b31&stat=instructions%3Au&sortBy=interestingness) > > Is that expected? I think it's at least conceivable, as the patch adds an extra branch to `CallExpr::getBeginLoc()`, which is likely to be called pretty frequently. The branch is **not** taken most of the time (it's only taken for calls to functions with an explicit object argument, which is a C++23 feature), so perhaps annotating the branch as "unlikely" is sufficient to avoid the performance regression? https://github.com/llvm/llvm-project/pull/117841 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang] Compute accurate begin location for CallExpr with explicit object parameter (PR #117841)
nikic wrote: It looks like this causes a significant compile-time regression: https://llvm-compile-time-tracker.com/compare.php?from=2b855dd97092e2178ac5c470a804a17ec440d7e5&to=9ccde12f5eeb91152900082a2ae839e2a9702b31&stat=instructions:u (Maybe most clearly seen during clang bootstrap, where this adds 0.5% to many compilations: https://llvm-compile-time-tracker.com/compare_clang.php?from=2b855dd97092e2178ac5c470a804a17ec440d7e5&to=9ccde12f5eeb91152900082a2ae839e2a9702b31&stat=instructions%3Au&sortBy=interestingness) Is that expected? https://github.com/llvm/llvm-project/pull/117841 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang] Compute accurate begin location for CallExpr with explicit object parameter (PR #117841)
https://github.com/HighCommander4 closed https://github.com/llvm/llvm-project/pull/117841 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang] Compute accurate begin location for CallExpr with explicit object parameter (PR #117841)
@@ -1639,11 +1639,19 @@ SourceLocation CallExpr::getBeginLoc() const { if (const auto *OCE = dyn_cast(this)) return OCE->getBeginLoc(); + if (const auto *Method = + dyn_cast_if_present(getCalleeDecl()); HighCommander4 wrote: > heh I think there is some opportunities to merge the slightly different if > statements (for the explicit and not explicit cases) but it would be a minor > improvement so I'll will approve that Ah, I see. I considered doing something like this: ```c++ bool UseFirstArgLoc = false; if (/* is explicit object */) UseFirstArgLoc = true; SourceLocation begin = getCallee()->getBeginLoc(); if ((begin.isInvalid() || UseFirstArgLoc) && getNumArgs() > 0 && getArg(0)) begin = getArg(0)->getBeginLoc(); return begin; ``` But this needlessly evaluates `getCallee()->getBeginLoc()` in the explicit case, so I opted not to do this. https://github.com/llvm/llvm-project/pull/117841 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang] Compute accurate begin location for CallExpr with explicit object parameter (PR #117841)
@@ -1639,11 +1639,19 @@ SourceLocation CallExpr::getBeginLoc() const { if (const auto *OCE = dyn_cast(this)) return OCE->getBeginLoc(); + if (const auto *Method = + dyn_cast_if_present(getCalleeDecl()); HighCommander4 wrote: Sorry, I'm not quite following this suggestion. What am I supposed to do with `Offset`? https://github.com/llvm/llvm-project/pull/117841 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang] Compute accurate begin location for CallExpr with explicit object parameter (PR #117841)
@@ -1639,11 +1639,19 @@ SourceLocation CallExpr::getBeginLoc() const { if (const auto *OCE = dyn_cast(this)) return OCE->getBeginLoc(); + if (const auto *Method = + dyn_cast_if_present(getCalleeDecl()); cor3ntin wrote: Maybe you could do something like ``` unsigned Offset = 0; if(isExplicitObjectMemberFunction()) Offset = 1; ``` To avoid some duplication https://github.com/llvm/llvm-project/pull/117841 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang] Compute accurate begin location for CallExpr with explicit object parameter (PR #117841)
https://github.com/zyn0217 approved this pull request. Thanks, while I haven’t come up with a better solution to model this situation, I think this looks good for now. Please give @cor3ntin some time before merging, in case there are some better approaches that I might have overlooked. https://github.com/llvm/llvm-project/pull/117841 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang] Compute accurate begin location for CallExpr with explicit object parameter (PR #117841)
https://github.com/zyn0217 edited https://github.com/llvm/llvm-project/pull/117841 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang] Compute accurate begin location for CallExpr with explicit object parameter (PR #117841)
@@ -1639,11 +1639,19 @@ SourceLocation CallExpr::getBeginLoc() const { if (const auto *OCE = dyn_cast(this)) return OCE->getBeginLoc(); + if (const auto *Method = + dyn_cast_if_present(getCalleeDecl()); zyn0217 wrote: nit: I presume the `const` in `` isn't necessary, right? https://github.com/llvm/llvm-project/pull/117841 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang] Compute accurate begin location for CallExpr with explicit object parameter (PR #117841)
HighCommander4 wrote: (Removed extraneous formatting changes) https://github.com/llvm/llvm-project/pull/117841 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang] Compute accurate begin location for CallExpr with explicit object parameter (PR #117841)
https://github.com/HighCommander4 updated https://github.com/llvm/llvm-project/pull/117841 >From 3e5e55fa72c04996dfde1304662e9def6a1ef726 Mon Sep 17 00:00:00 2001 From: Nathan Ridge Date: Fri, 29 Nov 2024 00:08:40 -0500 Subject: [PATCH] [clang] Compute accurate begin location for CallExpr with explicit object parameter The explicit object parameter is written before the callee expression, so the begin location should come from the explicit object parameter. --- clang-tools-extra/clangd/unittests/XRefsTests.cpp | 10 ++ clang/lib/AST/Expr.cpp| 8 clang/lib/Sema/SemaOverload.cpp | 2 +- clang/test/AST/ast-dump-cxx2b-deducing-this.cpp | 4 ++-- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp index d393c72974d447..7d824d659ad2ce 100644 --- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -1019,6 +1019,15 @@ TEST(LocateSymbol, All) { void *Value; void *getPointer() const { return Info::get^Pointer(Value); } }; + )cpp", + R"cpp(// Deducing this +struct S { + int bar(this S&); +}; +void foo() { + S [[waldo]]; + int x = wa^ldo.bar(); +} )cpp"}; for (const char *Test : Tests) { Annotations T(Test); @@ -1035,6 +1044,7 @@ TEST(LocateSymbol, All) { TU.Code = std::string(T.code()); TU.ExtraArgs.push_back("-xobjective-c++"); +TU.ExtraArgs.push_back("-std=c++23"); auto AST = TU.build(); auto Results = locateSymbolAt(AST, T.point()); diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index a4fb4d5a1f2ec4..5a6738196d2890 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1639,11 +1639,19 @@ SourceLocation CallExpr::getBeginLoc() const { if (const auto *OCE = dyn_cast(this)) return OCE->getBeginLoc(); + if (const auto *Method = + dyn_cast_if_present(getCalleeDecl()); + Method && Method->isExplicitObjectMemberFunction()) { +assert(getNumArgs() > 0 && getArg(0)); +return getArg(0)->getBeginLoc(); + } + SourceLocation begin = getCallee()->getBeginLoc(); if (begin.isInvalid() && getNumArgs() > 0 && getArg(0)) begin = getArg(0)->getBeginLoc(); return begin; } + SourceLocation CallExpr::getEndLoc() const { if (const auto *OCE = dyn_cast(this)) return OCE->getEndLoc(); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 4c9e37bd286dee..e4bf9aa521224b 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -15565,7 +15565,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, // Build the actual expression node. ExprResult FnExpr = CreateFunctionRefExpr(*this, Method, FoundDecl, MemExpr, - HadMultipleCandidates, MemExpr->getBeginLoc()); + HadMultipleCandidates, MemExpr->getExprLoc()); if (FnExpr.isInvalid()) return ExprError(); diff --git a/clang/test/AST/ast-dump-cxx2b-deducing-this.cpp b/clang/test/AST/ast-dump-cxx2b-deducing-this.cpp index 04cff07376885a..1b385e0fc33319 100644 --- a/clang/test/AST/ast-dump-cxx2b-deducing-this.cpp +++ b/clang/test/AST/ast-dump-cxx2b-deducing-this.cpp @@ -9,7 +9,7 @@ int main() { S s; int x = s.f(); // CHECK: CallExpr 0x{{[^ ]*}} 'int - // CHECK-NEXT: |-ImplicitCastExpr 0x{{[^ ]*}} 'int (*)(S &)' - // CHECK-NEXT: | `-DeclRefExpr 0x{{[^ ]*}} 'int (S &)' lvalue CXXMethod 0x{{[^ ]*}} 'f' 'int (S &)' + // CHECK-NEXT: |-ImplicitCastExpr 0x{{[^ ]*}} 'int (*)(S &)' + // CHECK-NEXT: | `-DeclRefExpr 0x{{[^ ]*}} 'int (S &)' lvalue CXXMethod 0x{{[^ ]*}} 'f' 'int (S &)' } } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang] Compute accurate begin location for CallExpr with explicit object parameter (PR #117841)
github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning: You can test this locally with the following command: ``bash git-clang-format --diff 9fde1a498f2dc97a737a3564cb427c6f2a7bfe6c 367a0cc6b3e1e1f67d023c96e06ae438f8f37f37 --extensions cpp -- clang-tools-extra/clangd/unittests/XRefsTests.cpp clang/lib/AST/Expr.cpp clang/lib/Sema/SemaOverload.cpp clang/test/AST/ast-dump-cxx2b-deducing-this.cpp `` View the diff from clang-format here. ``diff diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp index 87efb42be4..7d824d659a 100644 --- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -450,7 +450,7 @@ TEST(LocateSymbol, All) { // $def is the definition location (if absent, symbol has no definition) // unnamed range becomes both $decl and $def. const char *Tests[] = { -R"cpp( + R"cpp( struct X { union { int [[a]]; @@ -462,7 +462,7 @@ TEST(LocateSymbol, All) { } )cpp", -R"cpp(// Local variable + R"cpp(// Local variable int main() { int [[bonjour]]; ^bonjour = 2; @@ -470,7 +470,7 @@ TEST(LocateSymbol, All) { } )cpp", -R"cpp(// Struct + R"cpp(// Struct namespace ns1 { struct [[MyClass]] {}; } // namespace ns1 @@ -479,21 +479,21 @@ TEST(LocateSymbol, All) { } )cpp", -R"cpp(// Function definition via pointer + R"cpp(// Function definition via pointer void [[foo]](int) {} int main() { auto *X = &^foo; } )cpp", -R"cpp(// Function declaration via call + R"cpp(// Function declaration via call int $decl[[foo]](int); int main() { return ^foo(42); } )cpp", -R"cpp(// Field + R"cpp(// Field struct Foo { int [[x]]; }; int main() { Foo bar; @@ -501,21 +501,21 @@ TEST(LocateSymbol, All) { } )cpp", -R"cpp(// Field, member initializer + R"cpp(// Field, member initializer struct Foo { int [[x]]; Foo() : ^x(0) {} }; )cpp", -R"cpp(// Field, field designator + R"cpp(// Field, field designator struct Foo { int [[x]]; }; int main() { Foo bar = { .^x = 2 }; } )cpp", -R"cpp(// Method call + R"cpp(// Method call struct Foo { int $decl[[x]](); }; int main() { Foo bar; @@ -523,31 +523,31 @@ TEST(LocateSymbol, All) { } )cpp", -R"cpp(// Typedef + R"cpp(// Typedef typedef int $decl[[Foo]]; int main() { ^Foo bar; } )cpp", -R"cpp(// Template type parameter + R"cpp(// Template type parameter template void foo() { ^T t; } )cpp", -R"cpp(// Template template type parameter + R"cpp(// Template template type parameter template class [[T]]> void foo() { ^T t; } )cpp", -R"cpp(// Namespace + R"cpp(// Namespace namespace $decl[[ns]] { struct Foo { static void bar(); }; } // namespace ns int main() { ^ns::Foo::bar(); } )cpp", -R"cpp(// Macro + R"cpp(// Macro class TTT { public: int a; }; #define [[FF]](S) if (int b = S.a) {} void f() { @@ -556,12 +556,12 @@ TEST(LocateSymbol, All) { } )cpp", -R"cpp(// Macro argument + R"cpp(// Macro argument int [[i]]; #define ADDRESSOF(X) &X; int *j = ADDRESSOF(^i); )cpp", -R"cpp(// Macro argument appearing multiple times in expansion + R"cpp(// Macro argument appearing multiple times in expansion #define VALIDATE_TYPE(x) (void)x; #define ASSERT(expr) \ do { \ @@ -573,37 +573,37 @@ TEST(LocateSymbol, All) { ASSERT(wa^ldo()); } )cpp", -R"cpp(// Symbol concatenated inside macro (not supported) + R"cpp(// Symbol concatenated inside macro (not supported) int *pi; #define POINTER(X) p ## X; int x = *POINTER(^i); )cpp", -R"cpp(// Forward class declaration + R"cpp(// Forward class declaration class $decl[[Foo]]; class $def[[Foo]] {}; F^oo* foo(); )cpp", -R"cpp(// Function declaration + R"cpp(// Function declaration void $decl[[foo]](); void g() { f^oo(); } void $def[[foo]]() {} )cpp", -R"cpp( + R"cpp( #define FF(name) class name##_Test {}; [[FF]](my); void f() { my^_Test a; } )cpp", -R"cpp( + R"cpp( #define FF() class [[Test]] {}; FF();
[clang] [clang-tools-extra] [clang] Compute accurate begin location for CallExpr with explicit object parameter (PR #117841)
HighCommander4 wrote: Updated to add a clangd test that fails with the previous fix approach. > A more general implementation of `CallExpr::getBeginLoc` that occurs to me > is: return the earlier of the callee's begin loc and the first argument's (if > present) begin loc. I did not do this because accurately determining which of two `SourceLocation`s is earlier requires calling `SourceManager::isBeforeInTranslationUnit()`, and a `SourceManager` does not seem to be available in `CallExpr::getBeginLoc()`. https://github.com/llvm/llvm-project/pull/117841 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang] Compute accurate begin location for CallExpr with explicit object parameter (PR #117841)
https://github.com/HighCommander4 updated https://github.com/llvm/llvm-project/pull/117841 >From 367a0cc6b3e1e1f67d023c96e06ae438f8f37f37 Mon Sep 17 00:00:00 2001 From: Nathan Ridge Date: Tue, 26 Nov 2024 22:41:43 -0500 Subject: [PATCH] [clang] Compute accurate begin location for CallExpr with explicit object parameter The explicit object parameter is written before the callee expression, so the begin location should come from the explicit object parameter. --- .../clangd/unittests/XRefsTests.cpp | 148 ++ clang/lib/AST/Expr.cpp| 8 + clang/lib/Sema/SemaOverload.cpp | 2 +- .../test/AST/ast-dump-cxx2b-deducing-this.cpp | 4 +- 4 files changed, 90 insertions(+), 72 deletions(-) diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp index d393c72974d447..87efb42be47121 100644 --- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -450,7 +450,7 @@ TEST(LocateSymbol, All) { // $def is the definition location (if absent, symbol has no definition) // unnamed range becomes both $decl and $def. const char *Tests[] = { - R"cpp( +R"cpp( struct X { union { int [[a]]; @@ -462,7 +462,7 @@ TEST(LocateSymbol, All) { } )cpp", - R"cpp(// Local variable +R"cpp(// Local variable int main() { int [[bonjour]]; ^bonjour = 2; @@ -470,7 +470,7 @@ TEST(LocateSymbol, All) { } )cpp", - R"cpp(// Struct +R"cpp(// Struct namespace ns1 { struct [[MyClass]] {}; } // namespace ns1 @@ -479,21 +479,21 @@ TEST(LocateSymbol, All) { } )cpp", - R"cpp(// Function definition via pointer +R"cpp(// Function definition via pointer void [[foo]](int) {} int main() { auto *X = &^foo; } )cpp", - R"cpp(// Function declaration via call +R"cpp(// Function declaration via call int $decl[[foo]](int); int main() { return ^foo(42); } )cpp", - R"cpp(// Field +R"cpp(// Field struct Foo { int [[x]]; }; int main() { Foo bar; @@ -501,21 +501,21 @@ TEST(LocateSymbol, All) { } )cpp", - R"cpp(// Field, member initializer +R"cpp(// Field, member initializer struct Foo { int [[x]]; Foo() : ^x(0) {} }; )cpp", - R"cpp(// Field, field designator +R"cpp(// Field, field designator struct Foo { int [[x]]; }; int main() { Foo bar = { .^x = 2 }; } )cpp", - R"cpp(// Method call +R"cpp(// Method call struct Foo { int $decl[[x]](); }; int main() { Foo bar; @@ -523,31 +523,31 @@ TEST(LocateSymbol, All) { } )cpp", - R"cpp(// Typedef +R"cpp(// Typedef typedef int $decl[[Foo]]; int main() { ^Foo bar; } )cpp", - R"cpp(// Template type parameter +R"cpp(// Template type parameter template void foo() { ^T t; } )cpp", - R"cpp(// Template template type parameter +R"cpp(// Template template type parameter template class [[T]]> void foo() { ^T t; } )cpp", - R"cpp(// Namespace +R"cpp(// Namespace namespace $decl[[ns]] { struct Foo { static void bar(); }; } // namespace ns int main() { ^ns::Foo::bar(); } )cpp", - R"cpp(// Macro +R"cpp(// Macro class TTT { public: int a; }; #define [[FF]](S) if (int b = S.a) {} void f() { @@ -556,12 +556,12 @@ TEST(LocateSymbol, All) { } )cpp", - R"cpp(// Macro argument +R"cpp(// Macro argument int [[i]]; #define ADDRESSOF(X) &X; int *j = ADDRESSOF(^i); )cpp", - R"cpp(// Macro argument appearing multiple times in expansion +R"cpp(// Macro argument appearing multiple times in expansion #define VALIDATE_TYPE(x) (void)x; #define ASSERT(expr) \ do { \ @@ -573,37 +573,37 @@ TEST(LocateSymbol, All) { ASSERT(wa^ldo()); } )cpp", - R"cpp(// Symbol concatenated inside macro (not supported) +R"cpp(// Symbol concatenated inside macro (not supported) int *pi; #define POINTER(X) p ## X; int x = *POINTER(^i); )cpp", - R"cpp(// Forward class declaration +R"cpp(// Forward class declaration class $decl[[Foo]]; class $def[[Foo]] {}; F^oo* foo(); )cpp", - R"cpp(// Function declaration +R"cpp(// Function declaration void $decl[[foo]](); void g() { f^oo(); } void $def[[foo]]() {} )cpp", -