[clang] [clang][HeuristicResolver] Track the expression whose type is being simplified after each step in simplifyType() (PR #126689)
Nathan Ridge via cfe-commits
cfe-commits at lists.llvm.org
Mon Feb 10 23:00:08 PST 2025
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 <zeratul976 at 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>
More information about the cfe-commits
mailing list