Skip to content

[clang] fix RecursiveASTVisitor traversal from type to decl #132551

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 22, 2025

Conversation

mizvekov
Copy link
Contributor

For that visitor, it is not expected that a type can traverse into a declaration. This makes the MemberPointer visitor conform to that rule.

This turns the base class visitor into a CXXRecordType visitor, and only performs that visit in case it points to something different than the qualifier does.

Fixes a regression reported here: #132401 (comment)
As this fixes a regression which has not been released, there are no release notes.

For that visitor, it is not expected that a type can traverse into
a declaration. This makes the MemberPointer visitor conform to
that rule.

This turns the base class visitor into a CXXRecordType visitor,
and only performs that visit in case it points to something different
than the qualifier does.

Fixes a regression reported here: #132401 (comment)
As this fixes a regression which has not been released, there are no release notes.
@mizvekov mizvekov requested review from mstorsjo and erichkeane March 22, 2025 14:33
@mizvekov mizvekov self-assigned this Mar 22, 2025
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Mar 22, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 22, 2025

@llvm/pr-subscribers-clang

Author: Matheus Izvekov (mizvekov)

Changes

For that visitor, it is not expected that a type can traverse into a declaration. This makes the MemberPointer visitor conform to that rule.

This turns the base class visitor into a CXXRecordType visitor, and only performs that visit in case it points to something different than the qualifier does.

Fixes a regression reported here: #132401 (comment)
As this fixes a regression which has not been released, there are no release notes.


Full diff: https://github.com/llvm/llvm-project/pull/132551.diff

2 Files Affected:

  • (modified) clang/include/clang/AST/RecursiveASTVisitor.h (+3-1)
  • (modified) clang/test/SemaCXX/member-pointer.cpp (+11)
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index e93d1d8eab56f..0d5d515c0e6f7 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -1005,7 +1005,9 @@ DEF_TRAVERSE_TYPE(RValueReferenceType,
 
 DEF_TRAVERSE_TYPE(MemberPointerType, {
   TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
-  TRY_TO(TraverseDecl(T->getMostRecentCXXRecordDecl()));
+  if (T->isSugared())
+    TRY_TO(TraverseType(
+        QualType(T->getMostRecentCXXRecordDecl()->getTypeForDecl(), 0)));
   TRY_TO(TraverseType(T->getPointeeType()));
 })
 
diff --git a/clang/test/SemaCXX/member-pointer.cpp b/clang/test/SemaCXX/member-pointer.cpp
index b6ab7d38610c8..3d9dd05755b8c 100644
--- a/clang/test/SemaCXX/member-pointer.cpp
+++ b/clang/test/SemaCXX/member-pointer.cpp
@@ -344,3 +344,14 @@ namespace GH132494 {
   };
   template struct A<E>; // expected-note {{requested here}}
 } // namespace GH132494
+
+namespace GH132401 {
+  template <typename Func> struct CallableHelper {
+    static auto Resolve() -> Func;
+  };
+  struct QIODevice {
+    void d_func() { (void)d_ptr; }
+    int d_ptr;
+  };
+  template struct CallableHelper<void (QIODevice::*)()>;
+} // namespace GH132401

Copy link
Contributor

@zyn0217 zyn0217 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better to have a release note as it looks like a potential behavior change of ASTVisitor.

Otherwise feel free to merge to put out the fire.

@mizvekov
Copy link
Contributor Author

It is a change but within the parameters of what the regressing commit already was. This is just changing what had already been changed there.

@mizvekov mizvekov merged commit 5999be0 into main Mar 22, 2025
14 checks passed
@mizvekov mizvekov deleted the users/mizvekov/GH132401_fix branch March 22, 2025 15:12
@bolshakov-a
Copy link
Contributor

@mizvekov, could you clarify please what is the point of traversing the host type twice? The tests pass if just remove the if statement.

@mizvekov
Copy link
Contributor Author

mizvekov commented Apr 6, 2025

Which host type twice?

In case the MemberPointerType represents a class adjustment, this visits the actual class type, instead of just the as-written qualifier.

example: https://gcc.godbolt.org/z/M5qfGPGMf

I didn't expect we would have in-tree users of the RecursiveVisitor for this, but it seems useful for external users to leave it in, no?

@bolshakov-a
Copy link
Contributor

Thanks, it becomes now clearer for me. However, I'm still not succeeded in making this code really working, because the default version of TraverseDecltypeType doesn't traverse the underlying desugared type:

DEF_TRAVERSE_TYPE(DecltypeType,
{ TRY_TO(TraverseStmt(T->getUnderlyingExpr())); })

But, maybe, if someone provides his own version of TraverseDecltypeType in his visitor, then this may become useful...

My primary concern is that one may think that NestedNameSpecifier node is now always inserted between MemberPointerType and its class type node, but it may be not the case, and under very specific conditions.

By the way, it looks strange for me that int Typedef::* is not considered as a sugar.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants