https://github.com/HighCommander4 created https://github.com/llvm/llvm-project/pull/126689
Fixes https://github.com/llvm/llvm-project/issues/126536 >From e5a3d7aa5362357acd30ef5d1bafaa814ac2c89f Mon Sep 17 00:00:00 2001 From: Nathan Ridge <zeratul...@hotmail.com> Date: Tue, 11 Feb 2025 01:56:50 -0500 Subject: [PATCH] [clang][HeuristicResolver] Track the expression whose type is being simplified after each step in simplifyType() --- clang/lib/Sema/HeuristicResolver.cpp | 47 ++++++++++++------- .../unittests/Sema/HeuristicResolverTest.cpp | 16 +++++++ 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/clang/lib/Sema/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp index 36e5b44b8b12cc1..3cbf33dcdced383 100644 --- a/clang/lib/Sema/HeuristicResolver.cpp +++ b/clang/lib/Sema/HeuristicResolver.cpp @@ -210,52 +210,63 @@ QualType HeuristicResolverImpl::getPointeeType(QualType T) { QualType HeuristicResolverImpl::simplifyType(QualType Type, const Expr *E, bool UnwrapPointer) { bool DidUnwrapPointer = false; - auto SimplifyOneStep = [&](QualType T) { + // A type, together with an optional expression whose type it represents + // which may have additional information about the expression's type + // not stored in the QualType itself. + struct TypeExprPair { + QualType Type; + const Expr *E = nullptr; + }; + TypeExprPair Current{Type, E}; + auto SimplifyOneStep = [UnwrapPointer, &DidUnwrapPointer, + this](TypeExprPair T) -> TypeExprPair { if (UnwrapPointer) { - if (QualType Pointee = getPointeeType(T); !Pointee.isNull()) { + if (QualType Pointee = getPointeeType(T.Type); !Pointee.isNull()) { DidUnwrapPointer = true; - return Pointee; + return {Pointee}; } } - if (const auto *RT = T->getAs<ReferenceType>()) { + if (const auto *RT = T.Type->getAs<ReferenceType>()) { // Does not count as "unwrap pointer". - return RT->getPointeeType(); + return {RT->getPointeeType()}; } - if (const auto *BT = T->getAs<BuiltinType>()) { + if (const auto *BT = T.Type->getAs<BuiltinType>()) { // If BaseType is the type of a dependent expression, it's just // represented as BuiltinType::Dependent which gives us no information. We // can get further by analyzing the dependent expression. - if (E && BT->getKind() == BuiltinType::Dependent) { - return resolveExprToType(E); + if (T.E && BT->getKind() == BuiltinType::Dependent) { + return {resolveExprToType(T.E), T.E}; } } - if (const auto *AT = T->getContainedAutoType()) { + if (const auto *AT = T.Type->getContainedAutoType()) { // If T contains a dependent `auto` type, deduction will not have // been performed on it yet. In simple cases (e.g. `auto` variable with // initializer), get the approximate type that would result from // deduction. // FIXME: A more accurate implementation would propagate things like the // `const` in `const auto`. - if (E && AT->isUndeducedAutoType()) { - if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) { + if (T.E && AT->isUndeducedAutoType()) { + if (const auto *DRE = dyn_cast<DeclRefExpr>(T.E)) { if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) { - if (VD->hasInit()) - return resolveExprToType(VD->getInit()); + if (VD->hasInit()) { + auto *Init = VD->getInit(); + return {resolveExprToType(Init), Init}; + } } } } } return T; }; - while (!Type.isNull()) { - QualType New = SimplifyOneStep(Type); - if (New == Type) + while (!Current.Type.isNull()) { + TypeExprPair New = SimplifyOneStep(Current); + if (New.Type == Current.Type) break; - Type = New; + Current = New; } if (UnwrapPointer && !DidUnwrapPointer) return QualType(); - return Type; + return Current.Type; } std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr( diff --git a/clang/unittests/Sema/HeuristicResolverTest.cpp b/clang/unittests/Sema/HeuristicResolverTest.cpp index 5c3459dbeb1018b..c7cfe7917c532e6 100644 --- a/clang/unittests/Sema/HeuristicResolverTest.cpp +++ b/clang/unittests/Sema/HeuristicResolverTest.cpp @@ -394,6 +394,22 @@ TEST(HeuristicResolver, MemberExpr_DeducedNonTypeTemplateParameter) { fieldDecl(hasName("found")).bind("output")); } +TEST(HeuristicResolver, MemberExpr_HangIssue126536) { + std::string Code = R"cpp( + template <class T> + void foo() { + T bar; + auto baz = (bar, bar); + baz.foo(); + } + )cpp"; + // Test resolution of "foo" in "baz.foo()". + // Here, we are testing that we do not get into an infinite loop. + expectResolution( + Code, &HeuristicResolver::resolveMemberExpr, + cxxDependentScopeMemberExpr(hasMemberName("foo")).bind("input")); +} + TEST(HeuristicResolver, DeclRefExpr_StaticMethod) { std::string Code = R"cpp( template <typename T> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits