Skip to content

Commit c7eb520

Browse files
[clang][HeuristicResolver] Track the expression whose type is being simplified after each step in simplifyType() (#126689)
Fixes #126536
1 parent 0419db6 commit c7eb520

File tree

2 files changed

+43
-18
lines changed

2 files changed

+43
-18
lines changed

clang/lib/Sema/HeuristicResolver.cpp

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -210,37 +210,46 @@ QualType HeuristicResolverImpl::getPointeeType(QualType T) {
210210
QualType HeuristicResolverImpl::simplifyType(QualType Type, const Expr *E,
211211
bool UnwrapPointer) {
212212
bool DidUnwrapPointer = false;
213-
auto SimplifyOneStep = [&](QualType T) {
213+
// A type, together with an optional expression whose type it represents
214+
// which may have additional information about the expression's type
215+
// not stored in the QualType itself.
216+
struct TypeExprPair {
217+
QualType Type;
218+
const Expr *E = nullptr;
219+
};
220+
TypeExprPair Current{Type, E};
221+
auto SimplifyOneStep = [UnwrapPointer, &DidUnwrapPointer,
222+
this](TypeExprPair T) -> TypeExprPair {
214223
if (UnwrapPointer) {
215-
if (QualType Pointee = getPointeeType(T); !Pointee.isNull()) {
224+
if (QualType Pointee = getPointeeType(T.Type); !Pointee.isNull()) {
216225
DidUnwrapPointer = true;
217-
return Pointee;
226+
return {Pointee};
218227
}
219228
}
220-
if (const auto *RT = T->getAs<ReferenceType>()) {
229+
if (const auto *RT = T.Type->getAs<ReferenceType>()) {
221230
// Does not count as "unwrap pointer".
222-
return RT->getPointeeType();
231+
return {RT->getPointeeType()};
223232
}
224-
if (const auto *BT = T->getAs<BuiltinType>()) {
233+
if (const auto *BT = T.Type->getAs<BuiltinType>()) {
225234
// If BaseType is the type of a dependent expression, it's just
226235
// represented as BuiltinType::Dependent which gives us no information. We
227236
// can get further by analyzing the dependent expression.
228-
if (E && BT->getKind() == BuiltinType::Dependent) {
229-
return resolveExprToType(E);
237+
if (T.E && BT->getKind() == BuiltinType::Dependent) {
238+
return {resolveExprToType(T.E), T.E};
230239
}
231240
}
232-
if (const auto *AT = T->getContainedAutoType()) {
241+
if (const auto *AT = T.Type->getContainedAutoType()) {
233242
// If T contains a dependent `auto` type, deduction will not have
234243
// been performed on it yet. In simple cases (e.g. `auto` variable with
235244
// initializer), get the approximate type that would result from
236245
// deduction.
237246
// FIXME: A more accurate implementation would propagate things like the
238247
// `const` in `const auto`.
239-
if (E && AT->isUndeducedAutoType()) {
240-
if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
248+
if (T.E && AT->isUndeducedAutoType()) {
249+
if (const auto *DRE = dyn_cast<DeclRefExpr>(T.E)) {
241250
if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
242-
if (VD->hasInit())
243-
return resolveExprToType(VD->getInit());
251+
if (auto *Init = VD->getInit())
252+
return {resolveExprToType(Init), Init};
244253
}
245254
}
246255
}
@@ -251,15 +260,15 @@ QualType HeuristicResolverImpl::simplifyType(QualType Type, const Expr *E,
251260
// simplification steps.
252261
size_t StepCount = 0;
253262
const size_t MaxSteps = 64;
254-
while (!Type.isNull() && StepCount++ < MaxSteps) {
255-
QualType New = SimplifyOneStep(Type);
256-
if (New == Type)
263+
while (!Current.Type.isNull() && StepCount++ < MaxSteps) {
264+
TypeExprPair New = SimplifyOneStep(Current);
265+
if (New.Type == Current.Type)
257266
break;
258-
Type = New;
267+
Current = New;
259268
}
260269
if (UnwrapPointer && !DidUnwrapPointer)
261270
return QualType();
262-
return Type;
271+
return Current.Type;
263272
}
264273

265274
std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr(

clang/unittests/Sema/HeuristicResolverTest.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,22 @@ TEST(HeuristicResolver, MemberExpr_DeducedNonTypeTemplateParameter) {
394394
fieldDecl(hasName("found")).bind("output"));
395395
}
396396

397+
TEST(HeuristicResolver, MemberExpr_HangIssue126536) {
398+
std::string Code = R"cpp(
399+
template <class T>
400+
void foo() {
401+
T bar;
402+
auto baz = (bar, bar);
403+
baz.foo();
404+
}
405+
)cpp";
406+
// Test resolution of "foo" in "baz.foo()".
407+
// Here, we are testing that we do not get into an infinite loop.
408+
expectResolution(
409+
Code, &HeuristicResolver::resolveMemberExpr,
410+
cxxDependentScopeMemberExpr(hasMemberName("foo")).bind("input"));
411+
}
412+
397413
TEST(HeuristicResolver, DeclRefExpr_StaticMethod) {
398414
std::string Code = R"cpp(
399415
template <typename T>

0 commit comments

Comments
 (0)