https://github.com/MythreyaK updated https://github.com/llvm/llvm-project/pull/155143
>From c1cdb3909c0bb55ce21d339f087c1e38616fec3f Mon Sep 17 00:00:00 2001 From: Mythreya Kuricheti <g...@mythreya.dev> Date: Sat, 23 Aug 2025 23:57:18 -0700 Subject: [PATCH 1/8] [clang] Heuristic resolution for explicit object parameter Assume `self` parameter is of the parent record type --- .../clangd/unittests/RenameTests.cpp | 43 ++++++++++++++++++- clang/lib/Sema/HeuristicResolver.cpp | 26 +++++++++++ .../unittests/Sema/HeuristicResolverTest.cpp | 19 +++++++- 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/clang-tools-extra/clangd/unittests/RenameTests.cpp b/clang-tools-extra/clangd/unittests/RenameTests.cpp index 2cb0722f7f285..4701ae07d0d12 100644 --- a/clang-tools-extra/clangd/unittests/RenameTests.cpp +++ b/clang-tools-extra/clangd/unittests/RenameTests.cpp @@ -17,10 +17,11 @@ #include "clang/Tooling/Core/Replacement.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/MemoryBuffer.h" -#include <algorithm> #include "gmock/gmock.h" #include "gtest/gtest.h" +#include <algorithm> + namespace clang { namespace clangd { namespace { @@ -2468,6 +2469,46 @@ TEST(CrossFileRenameTests, adjustmentCost) { } } +TEST(RenameTest, RenameWithExplicitObjectPararameter) { + Annotations Test = {R"cpp( + struct Foo { + int [[memb^er]] {}; + auto&& getter1(this auto&& self) { + auto local = [&] { + return self.[[memb^er]]; + }(); + return local + self.[[memb^er]]; + } + auto&& getter2(this Foo&& self) { + return self.[[memb^er]]; + } + int normal() { + return [[memb^er]]; + } + }; + )cpp"}; + + auto TU = TestTU::withCode(Test.code()); + TU.ExtraArgs.push_back("-std=c++23"); + auto AST = TU.build(); + + llvm::StringRef NewName = "m_member"; + auto Index = TU.index(); + + for (const auto &RenamePos : Test.points()) { + auto RenameResult = rename({RenamePos, NewName, AST, testPath(TU.Filename), + getVFSFromAST(AST), Index.get()}); + + ASSERT_TRUE(bool(RenameResult)) << RenameResult.takeError(); + auto Res = RenameResult.get(); + + ASSERT_TRUE(bool(RenameResult)) << RenameResult.takeError(); + ASSERT_EQ(1u, RenameResult->GlobalChanges.size()); + EXPECT_EQ(applyEdits(std::move(RenameResult->GlobalChanges)).front().second, + expectedResult(Test, NewName)); + } +} + } // namespace } // namespace clangd } // namespace clang diff --git a/clang/lib/Sema/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp index 933841beeac3d..20f7d0fca2066 100644 --- a/clang/lib/Sema/HeuristicResolver.cpp +++ b/clang/lib/Sema/HeuristicResolver.cpp @@ -14,6 +14,7 @@ #include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" #include "llvm/ADT/identity.h" +#include <optional> namespace clang { @@ -301,9 +302,34 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr( return {}; } + // check if member expr is in the context of an explicit object method + // If so, it's safe to assume the templated arg is of type of the record + const auto ExplicitMemberHeuristic = + [&](const Expr *Base) -> std::optional<QualType> { + if (auto *DeclRef = dyn_cast_if_present<DeclRefExpr>(Base)) { + auto *PrDecl = dyn_cast_if_present<ParmVarDecl>(DeclRef->getDecl()); + + if (PrDecl && PrDecl->isExplicitObjectParameter()) { + auto CxxRecord = dyn_cast_if_present<CXXRecordDecl>( + PrDecl->getDeclContext()->getParent()); + + if (CxxRecord) { + return Ctx.getTypeDeclType(dyn_cast<TypeDecl>(CxxRecord)); + } + } + } + + return std::nullopt; + }; + // Try resolving the member inside the expression's base type. Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase(); QualType BaseType = ME->getBaseType(); + + if (auto Type = ExplicitMemberHeuristic(Base)) { + BaseType = *Type; + } + BaseType = simplifyType(BaseType, Base, ME->isArrow()); return resolveDependentMember(BaseType, ME->getMember(), NoFilter); } diff --git a/clang/unittests/Sema/HeuristicResolverTest.cpp b/clang/unittests/Sema/HeuristicResolverTest.cpp index 7df25e01e66d4..21aca7a3489b8 100644 --- a/clang/unittests/Sema/HeuristicResolverTest.cpp +++ b/clang/unittests/Sema/HeuristicResolverTest.cpp @@ -41,7 +41,7 @@ template <typename InputNode, typename ParamT, typename InputMatcher, typename... OutputMatchers> void expectResolution(llvm::StringRef Code, ResolveFnT<ParamT> ResolveFn, const InputMatcher &IM, const OutputMatchers &...OMS) { - auto TU = tooling::buildASTFromCodeWithArgs(Code, {"-std=c++20"}); + auto TU = tooling::buildASTFromCodeWithArgs(Code, {"-std=c++23"}); auto &Ctx = TU->getASTContext(); auto InputMatches = match(IM, Ctx); ASSERT_EQ(1u, InputMatches.size()); @@ -449,6 +449,23 @@ TEST(HeuristicResolver, MemberExpr_DefaultTemplateArgument_Recursive) { cxxMethodDecl(hasName("foo")).bind("output")); } +TEST(HeuristicResolver, MemberExpr_ExplicitObjectParameter) { + std::string Code = R"cpp( + struct Foo { + int m_int; + + int bar(this auto&& self) { + return self.m_int; + } + }; + )cpp"; + // Test resolution of "m_int" in "self.m_int()". + expectResolution( + Code, &HeuristicResolver::resolveMemberExpr, + cxxDependentScopeMemberExpr(hasMemberName("m_int")).bind("input"), + fieldDecl(hasName("m_int")).bind("output")); +} + TEST(HeuristicResolver, DeclRefExpr_StaticMethod) { std::string Code = R"cpp( template <typename T> >From 0d482894a4e8bb045351e0c1724a6782caee87da Mon Sep 17 00:00:00 2001 From: Mythreya Kuricheti <g...@mythreya.dev> Date: Sun, 24 Aug 2025 00:46:19 -0700 Subject: [PATCH 2/8] code review --- clang/lib/Sema/HeuristicResolver.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/lib/Sema/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp index 20f7d0fca2066..ed817ac3691ad 100644 --- a/clang/lib/Sema/HeuristicResolver.cpp +++ b/clang/lib/Sema/HeuristicResolver.cpp @@ -305,7 +305,7 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr( // check if member expr is in the context of an explicit object method // If so, it's safe to assume the templated arg is of type of the record const auto ExplicitMemberHeuristic = - [&](const Expr *Base) -> std::optional<QualType> { + [&](const Expr *Base) -> QualType { if (auto *DeclRef = dyn_cast_if_present<DeclRefExpr>(Base)) { auto *PrDecl = dyn_cast_if_present<ParmVarDecl>(DeclRef->getDecl()); @@ -319,15 +319,15 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr( } } - return std::nullopt; + return {}; }; // Try resolving the member inside the expression's base type. Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase(); QualType BaseType = ME->getBaseType(); - if (auto Type = ExplicitMemberHeuristic(Base)) { - BaseType = *Type; + if (auto Type = ExplicitMemberHeuristic(Base); !Type.isNull()) { + BaseType = Type; } BaseType = simplifyType(BaseType, Base, ME->isArrow()); >From cd3601aaa400e4926058f3e33cf17c787ff47614 Mon Sep 17 00:00:00 2001 From: Mythreya Kuricheti <g...@mythreya.dev> Date: Sun, 24 Aug 2025 00:55:05 -0700 Subject: [PATCH 3/8] remove cxxdecl check --- clang/lib/Sema/HeuristicResolver.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/clang/lib/Sema/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp index ed817ac3691ad..4130e9b6686ec 100644 --- a/clang/lib/Sema/HeuristicResolver.cpp +++ b/clang/lib/Sema/HeuristicResolver.cpp @@ -304,18 +304,14 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr( // check if member expr is in the context of an explicit object method // If so, it's safe to assume the templated arg is of type of the record - const auto ExplicitMemberHeuristic = - [&](const Expr *Base) -> QualType { + const auto ExplicitMemberHeuristic = [&](const Expr *Base) -> QualType { if (auto *DeclRef = dyn_cast_if_present<DeclRefExpr>(Base)) { auto *PrDecl = dyn_cast_if_present<ParmVarDecl>(DeclRef->getDecl()); if (PrDecl && PrDecl->isExplicitObjectParameter()) { - auto CxxRecord = dyn_cast_if_present<CXXRecordDecl>( - PrDecl->getDeclContext()->getParent()); - - if (CxxRecord) { - return Ctx.getTypeDeclType(dyn_cast<TypeDecl>(CxxRecord)); - } + // get the parent, a cxxrecord + return Ctx.getTypeDeclType( + dyn_cast<TypeDecl>(PrDecl->getDeclContext()->getParent())); } } >From ea15161d0bd504ad5a67e22caedf122a589ef790 Mon Sep 17 00:00:00 2001 From: Mythreya Kuricheti <g...@mythreya.dev> Date: Sun, 24 Aug 2025 15:15:22 -0700 Subject: [PATCH 4/8] code review --- clang-tools-extra/clangd/unittests/RenameTests.cpp | 2 +- clang/lib/Sema/HeuristicResolver.cpp | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/clang-tools-extra/clangd/unittests/RenameTests.cpp b/clang-tools-extra/clangd/unittests/RenameTests.cpp index 4701ae07d0d12..1b930811108bf 100644 --- a/clang-tools-extra/clangd/unittests/RenameTests.cpp +++ b/clang-tools-extra/clangd/unittests/RenameTests.cpp @@ -2483,7 +2483,7 @@ TEST(RenameTest, RenameWithExplicitObjectPararameter) { return self.[[memb^er]]; } int normal() { - return [[memb^er]]; + return this->[[mem^ber]] + [[memb^er]]; } }; )cpp"}; diff --git a/clang/lib/Sema/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp index 4130e9b6686ec..210df82c9bb85 100644 --- a/clang/lib/Sema/HeuristicResolver.cpp +++ b/clang/lib/Sema/HeuristicResolver.cpp @@ -321,12 +321,14 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr( // Try resolving the member inside the expression's base type. Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase(); QualType BaseType = ME->getBaseType(); + BaseType = simplifyType(BaseType, Base, ME->isArrow()); - if (auto Type = ExplicitMemberHeuristic(Base); !Type.isNull()) { - BaseType = Type; + if (BaseType->isUndeducedAutoType() || BaseType->isTemplateTypeParmType()) { + if (auto Type = ExplicitMemberHeuristic(Base); !Type.isNull()) { + BaseType = Type; + } } - BaseType = simplifyType(BaseType, Base, ME->isArrow()); return resolveDependentMember(BaseType, ME->getMember(), NoFilter); } >From c2b8ac474f14bbc7a106de059a1786a3bb153ee9 Mon Sep 17 00:00:00 2001 From: Mythreya Kuricheti <g...@mythreya.dev> Date: Sun, 24 Aug 2025 15:45:57 -0700 Subject: [PATCH 5/8] add null-check --- clang/lib/Sema/HeuristicResolver.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp index 210df82c9bb85..c89ea61760a76 100644 --- a/clang/lib/Sema/HeuristicResolver.cpp +++ b/clang/lib/Sema/HeuristicResolver.cpp @@ -323,7 +323,8 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr( QualType BaseType = ME->getBaseType(); BaseType = simplifyType(BaseType, Base, ME->isArrow()); - if (BaseType->isUndeducedAutoType() || BaseType->isTemplateTypeParmType()) { + if (!BaseType.isNull() && + (BaseType->isUndeducedAutoType() || BaseType->isTemplateTypeParmType())) { if (auto Type = ExplicitMemberHeuristic(Base); !Type.isNull()) { BaseType = Type; } >From bf73e27667029b7f201919b71e7d83c55b5ac5b5 Mon Sep 17 00:00:00 2001 From: Mythreya Kuricheti <g...@mythreya.dev> Date: Tue, 26 Aug 2025 01:31:22 -0700 Subject: [PATCH 6/8] code review --- .../clangd/unittests/RenameTests.cpp | 61 ++++++------------- clang/lib/Sema/HeuristicResolver.cpp | 43 +++++++------ 2 files changed, 41 insertions(+), 63 deletions(-) diff --git a/clang-tools-extra/clangd/unittests/RenameTests.cpp b/clang-tools-extra/clangd/unittests/RenameTests.cpp index 1b930811108bf..e1183e6707683 100644 --- a/clang-tools-extra/clangd/unittests/RenameTests.cpp +++ b/clang-tools-extra/clangd/unittests/RenameTests.cpp @@ -862,6 +862,25 @@ TEST(RenameTest, WithinFileRename) { void func([[Fo^o]] *f) {} )cpp", + + // rename with explicit object parameter + R"cpp( + struct Foo { + int [[memb^er]] {}; + auto&& getter1(this auto&& self) { + auto local = [&] { + return self.[[memb^er]]; + }(); + return local + self.[[memb^er]]; + } + auto&& getter2(this Foo&& self) { + return self.[[memb^er]]; + } + int normal() { + return this->[[mem^ber]] + [[memb^er]]; + } + }; + )cpp", }; llvm::StringRef NewName = "NewName"; for (llvm::StringRef T : Tests) { @@ -869,6 +888,7 @@ TEST(RenameTest, WithinFileRename) { Annotations Code(T); auto TU = TestTU::withCode(Code.code()); TU.ExtraArgs.push_back("-xobjective-c++"); + TU.ExtraArgs.push_back("-std=c++23"); auto AST = TU.build(); auto Index = TU.index(); for (const auto &RenamePos : Code.points()) { @@ -2468,47 +2488,6 @@ TEST(CrossFileRenameTests, adjustmentCost) { T.ExpectedCost); } } - -TEST(RenameTest, RenameWithExplicitObjectPararameter) { - Annotations Test = {R"cpp( - struct Foo { - int [[memb^er]] {}; - auto&& getter1(this auto&& self) { - auto local = [&] { - return self.[[memb^er]]; - }(); - return local + self.[[memb^er]]; - } - auto&& getter2(this Foo&& self) { - return self.[[memb^er]]; - } - int normal() { - return this->[[mem^ber]] + [[memb^er]]; - } - }; - )cpp"}; - - auto TU = TestTU::withCode(Test.code()); - TU.ExtraArgs.push_back("-std=c++23"); - auto AST = TU.build(); - - llvm::StringRef NewName = "m_member"; - auto Index = TU.index(); - - for (const auto &RenamePos : Test.points()) { - auto RenameResult = rename({RenamePos, NewName, AST, testPath(TU.Filename), - getVFSFromAST(AST), Index.get()}); - - ASSERT_TRUE(bool(RenameResult)) << RenameResult.takeError(); - auto Res = RenameResult.get(); - - ASSERT_TRUE(bool(RenameResult)) << RenameResult.takeError(); - ASSERT_EQ(1u, RenameResult->GlobalChanges.size()); - EXPECT_EQ(applyEdits(std::move(RenameResult->GlobalChanges)).front().second, - expectedResult(Test, NewName)); - } -} - } // namespace } // namespace clangd } // namespace clang diff --git a/clang/lib/Sema/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp index c89ea61760a76..63b54923b0063 100644 --- a/clang/lib/Sema/HeuristicResolver.cpp +++ b/clang/lib/Sema/HeuristicResolver.cpp @@ -256,6 +256,21 @@ QualType HeuristicResolverImpl::simplifyType(QualType Type, const Expr *E, } } } + // check if member expr is in the context of an explicit object method + if (!T.Type.isNull() && + (T.Type->isUndeducedAutoType() || T.Type->isTemplateTypeParmType())) { + if (auto *DRE = dyn_cast_if_present<DeclRefExpr>(T.E)) { + auto *PrDecl = dyn_cast_if_present<ParmVarDecl>(DRE->getDecl()); + // Then the type of 'this' should be type of the record the method is + // defined in + if (PrDecl && PrDecl->isExplicitObjectParameter()) { + const auto *Parent = + dyn_cast<TypeDecl>(PrDecl->getDeclContext()->getParent()); + return {Ctx.getTypeDeclType(Parent)}; + } + } + } + return T; }; // As an additional protection against infinite loops, bound the number of @@ -302,33 +317,17 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr( return {}; } - // check if member expr is in the context of an explicit object method - // If so, it's safe to assume the templated arg is of type of the record - const auto ExplicitMemberHeuristic = [&](const Expr *Base) -> QualType { - if (auto *DeclRef = dyn_cast_if_present<DeclRefExpr>(Base)) { - auto *PrDecl = dyn_cast_if_present<ParmVarDecl>(DeclRef->getDecl()); - - if (PrDecl && PrDecl->isExplicitObjectParameter()) { - // get the parent, a cxxrecord - return Ctx.getTypeDeclType( - dyn_cast<TypeDecl>(PrDecl->getDeclContext()->getParent())); - } - } - - return {}; - }; - // Try resolving the member inside the expression's base type. Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase(); QualType BaseType = ME->getBaseType(); BaseType = simplifyType(BaseType, Base, ME->isArrow()); - if (!BaseType.isNull() && - (BaseType->isUndeducedAutoType() || BaseType->isTemplateTypeParmType())) { - if (auto Type = ExplicitMemberHeuristic(Base); !Type.isNull()) { - BaseType = Type; - } - } + // fflush(stdout); + // fflush(stderr); + // std::flush(std::cout); + // std::flush(std::cerr); + // using namespace std::chrono_literals; + // std::this_thread::sleep_for(10ms); return resolveDependentMember(BaseType, ME->getMember(), NoFilter); } >From b48fa0e4302794aa781ec8d4aa03489c4b642684 Mon Sep 17 00:00:00 2001 From: Mythreya Kuricheti <g...@mythreya.dev> Date: Tue, 26 Aug 2025 19:12:43 -0700 Subject: [PATCH 7/8] code review + misc cleanup --- .../clangd/unittests/RenameTests.cpp | 1 + clang/lib/Sema/HeuristicResolver.cpp | 21 ++++++------------- .../unittests/Sema/HeuristicResolverTest.cpp | 2 +- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/clang-tools-extra/clangd/unittests/RenameTests.cpp b/clang-tools-extra/clangd/unittests/RenameTests.cpp index e1183e6707683..5d2a77b62a219 100644 --- a/clang-tools-extra/clangd/unittests/RenameTests.cpp +++ b/clang-tools-extra/clangd/unittests/RenameTests.cpp @@ -2488,6 +2488,7 @@ TEST(CrossFileRenameTests, adjustmentCost) { T.ExpectedCost); } } + } // namespace } // namespace clangd } // namespace clang diff --git a/clang/lib/Sema/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp index 63b54923b0063..6d79f3feeaace 100644 --- a/clang/lib/Sema/HeuristicResolver.cpp +++ b/clang/lib/Sema/HeuristicResolver.cpp @@ -14,7 +14,6 @@ #include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" #include "llvm/ADT/identity.h" -#include <optional> namespace clang { @@ -256,17 +255,17 @@ QualType HeuristicResolverImpl::simplifyType(QualType Type, const Expr *E, } } } - // check if member expr is in the context of an explicit object method + // Check if the expression refers to an explicit object parameter of + // templated type. If so, heuristically treat it as having the type of the + // enclosing class. if (!T.Type.isNull() && (T.Type->isUndeducedAutoType() || T.Type->isTemplateTypeParmType())) { if (auto *DRE = dyn_cast_if_present<DeclRefExpr>(T.E)) { - auto *PrDecl = dyn_cast_if_present<ParmVarDecl>(DRE->getDecl()); - // Then the type of 'this' should be type of the record the method is - // defined in + auto *PrDecl = dyn_cast<ParmVarDecl>(DRE->getDecl()); if (PrDecl && PrDecl->isExplicitObjectParameter()) { const auto *Parent = - dyn_cast<TypeDecl>(PrDecl->getDeclContext()->getParent()); - return {Ctx.getTypeDeclType(Parent)}; + dyn_cast<TagDecl>(PrDecl->getDeclContext()->getParent()); + return {Ctx.getCanonicalTagType(Parent)}; } } } @@ -321,14 +320,6 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr( Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase(); QualType BaseType = ME->getBaseType(); BaseType = simplifyType(BaseType, Base, ME->isArrow()); - - // fflush(stdout); - // fflush(stderr); - // std::flush(std::cout); - // std::flush(std::cerr); - // using namespace std::chrono_literals; - // std::this_thread::sleep_for(10ms); - return resolveDependentMember(BaseType, ME->getMember(), NoFilter); } diff --git a/clang/unittests/Sema/HeuristicResolverTest.cpp b/clang/unittests/Sema/HeuristicResolverTest.cpp index 21aca7a3489b8..7cae57e150cef 100644 --- a/clang/unittests/Sema/HeuristicResolverTest.cpp +++ b/clang/unittests/Sema/HeuristicResolverTest.cpp @@ -41,7 +41,7 @@ template <typename InputNode, typename ParamT, typename InputMatcher, typename... OutputMatchers> void expectResolution(llvm::StringRef Code, ResolveFnT<ParamT> ResolveFn, const InputMatcher &IM, const OutputMatchers &...OMS) { - auto TU = tooling::buildASTFromCodeWithArgs(Code, {"-std=c++23"}); + auto TU = tooling::buildASTFromCodeWithArgs(Code, {"-std=c++20"}); auto &Ctx = TU->getASTContext(); auto InputMatches = match(IM, Ctx); ASSERT_EQ(1u, InputMatches.size()); >From 466efd8513755054b711f1a8bb36cbd2bbe9ebe8 Mon Sep 17 00:00:00 2001 From: Mythreya Kuricheti <g...@mythreya.dev> Date: Tue, 26 Aug 2025 20:22:25 -0700 Subject: [PATCH 8/8] fix error --- clang/unittests/Sema/HeuristicResolverTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/unittests/Sema/HeuristicResolverTest.cpp b/clang/unittests/Sema/HeuristicResolverTest.cpp index 7cae57e150cef..21aca7a3489b8 100644 --- a/clang/unittests/Sema/HeuristicResolverTest.cpp +++ b/clang/unittests/Sema/HeuristicResolverTest.cpp @@ -41,7 +41,7 @@ template <typename InputNode, typename ParamT, typename InputMatcher, typename... OutputMatchers> void expectResolution(llvm::StringRef Code, ResolveFnT<ParamT> ResolveFn, const InputMatcher &IM, const OutputMatchers &...OMS) { - auto TU = tooling::buildASTFromCodeWithArgs(Code, {"-std=c++20"}); + auto TU = tooling::buildASTFromCodeWithArgs(Code, {"-std=c++23"}); auto &Ctx = TU->getASTContext(); auto InputMatches = match(IM, Ctx); ASSERT_EQ(1u, InputMatches.size()); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits