Skip to content

[Clang] Fix an assertion in the resolution of perfect matches #140073

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 2 commits into from
May 15, 2025

Conversation

cor3ntin
Copy link
Contributor

Function pointers can have an identity conversion to a pointer to member function if they are resolved to a member function.

Fix a regression introduced by #136203

Function pointers can have an identity conversion to
a pointer to member function if they are resolved to
a member function.

Fix a regression introduced by llvm#136203
@cor3ntin cor3ntin requested review from alexfh and erichkeane May 15, 2025 14:59
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels May 15, 2025
@llvmbot
Copy link
Member

llvmbot commented May 15, 2025

@llvm/pr-subscribers-clang

Author: cor3ntin (cor3ntin)

Changes

Function pointers can have an identity conversion to a pointer to member function if they are resolved to a member function.

Fix a regression introduced by #136203


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

2 Files Affected:

  • (modified) clang/include/clang/Sema/Overload.h (+8-2)
  • (modified) clang/test/SemaCXX/overload-resolution-deferred-templates.cpp (+19)
diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h
index 58452e159821a..f980c9d4a85df 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -430,8 +430,14 @@ class Sema;
       if (!ReferenceBinding) {
 #ifndef NDEBUG
         auto Decay = [&](QualType T) {
-          return (T->isArrayType() || T->isFunctionType()) ? C.getDecayedType(T)
-                                                           : T;
+          T = (T->isArrayType() || T->isFunctionType()) ? C.getDecayedType(T)
+                                                        : T;
+
+          // A function pointer type can be resolved to a member function type,
+          // which is still an identity conversion.
+          if (auto *N = T->getAs<MemberPointerType>())
+            T = C.getDecayedType(N->getPointeeType());
+          return T;
         };
         // The types might differ if there is an array-to-pointer conversion
         // an function-to-pointer conversion, or lvalue-to-rvalue conversion.
diff --git a/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp b/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
index 277c5df3bb62b..d559fb23ca043 100644
--- a/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
+++ b/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
@@ -232,3 +232,22 @@ struct InitListAreNotPerfectCpy {
 };
 
 InitListAreNotPerfectCpy InitListAreNotPerfectCpy_test({InitListAreNotPerfectCpy{}});
+
+namespace PointerToMemFunc {
+template <typename>
+class A;
+struct N {
+  template <typename T>
+  void f(T);
+};
+template <typename T>
+struct E {
+  template <class = A<int>>
+  void g() = delete;
+  void g(void (T::*)(char));
+};
+void f() {
+  E<N> e;
+  e.g(&N::f);
+}
+}

Copy link
Contributor

@alexfh alexfh left a comment

Choose a reason for hiding this comment

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

Thank you for the prompt fix! Looks good with one suggestion.

@@ -430,8 +430,14 @@ class Sema;
if (!ReferenceBinding) {
#ifndef NDEBUG
auto Decay = [&](QualType T) {
return (T->isArrayType() || T->isFunctionType()) ? C.getDecayedType(T)
: T;
T = (T->isArrayType() || T->isFunctionType()) ? C.getDecayedType(T)
Copy link
Contributor

Choose a reason for hiding this comment

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

Since it's not a single expression any more, a simple if would be a bit nicer here, IMO.

@cor3ntin cor3ntin merged commit 090f46d into llvm:main May 15, 2025
11 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented May 15, 2025

LLVM Buildbot has detected a new failure on builder openmp-s390x-linux running on systemz-1 while building clang at step 6 "test-openmp".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/88/builds/11663

Here is the relevant piece of the build log for the reference
Step 6 (test-openmp) failure: 1200 seconds without output running [b'ninja', b'-j 4', b'check-openmp'], attempting to kill
...
PASS: ompd-test :: openmp_examples/example_3.c (443 of 453)
PASS: ompd-test :: openmp_examples/example_4.c (444 of 453)
PASS: ompd-test :: openmp_examples/example_5.c (445 of 453)
PASS: ompd-test :: openmp_examples/example_task.c (446 of 453)
UNSUPPORTED: ompd-test :: openmp_examples/ompd_bt.c (447 of 453)
PASS: ompd-test :: openmp_examples/fibonacci.c (448 of 453)
UNSUPPORTED: ompd-test :: openmp_examples/ompd_parallel.c (449 of 453)
PASS: ompd-test :: openmp_examples/parallel.c (450 of 453)
PASS: ompd-test :: openmp_examples/nested.c (451 of 453)
PASS: ompd-test :: openmp_examples/ompd_icvs.c (452 of 453)
command timed out: 1200 seconds without output running [b'ninja', b'-j 4', b'check-openmp'], attempting to kill
process killed by signal 9
program finished with exit code -1
elapsedTime=1353.024454

@alexfh
Copy link
Contributor

alexfh commented May 16, 2025

@cor3ntin unfortunately, this fix causes assertion failures elsewhere:

assertion failed at clang/lib/AST/ASTContext.cpp:3913 in QualType clang::ASTContext::getDecayedType(QualType) const: (T->isArrayType() || T->isFunctionTy
pe()) && "T does not decay"
    @     0x55637f01d274  __assert_fail
    @     0x55637acbde6d  clang::ASTContext::getDecayedType()
    @     0x55637a77c6e4  clang::StandardConversionSequence::isPerfect()
    @     0x55637a75a692  clang::OverloadCandidateSet::PerfectViableFunction()
    @     0x55637a7473bf  clang::OverloadCandidateSet::BestViableFunction()
    @     0x55637a58b7d6  ResolveConstructorOverload()
    @     0x55637a5878c0  TryConstructorInitialization()
    @     0x55637a56b042  TryConstructorOrParenListInitialization()
    @     0x55637a5651dc  clang::InitializationSequence::InitializeFrom()
    @     0x55637a4562e8  clang::Sema::BuildCXXTypeConstructExpr()
    @     0x55637aa0401c  clang::TreeTransform<>::TransformCXXUnresolvedConstructExpr()
    @     0x55637aa27c6d  clang::TreeTransform<>::TransformReturnStmt()
    @     0x55637aa0aa33  clang::TreeTransform<>::TransformCompoundStmt()
    @     0x55637a9ee50b  clang::Sema::SubstStmt()
    @     0x55637aa6c377  clang::Sema::InstantiateFunctionDefinition()
    @     0x55637b59d77f  clang::StackExhaustionHandler::runWithSufficientStackSpace()
    @     0x55637a928f4f  clang::Sema::DeduceReturnType()
    @     0x55637a2ffe56  clang::Sema::DiagnoseUseOfDecl()
    @     0x55637a76c667  clang::Sema::BuildCallToMemberFunction()
    @     0x55637a307c71  clang::Sema::BuildCallExpr()
    @     0x55637a3227c7  clang::Sema::ActOnCallExpr()
    @     0x55637aa030f9  clang::TreeTransform<>::TransformCallExpr()
    @     0x55637aa18f38  clang::TreeTransform<>::TransformDecltypeType()
    @     0x55637a9e6179  clang::TreeTransform<>::TransformType()
    @     0x55637a9e5b2b  clang::TreeTransform<>::TransformType()
    @     0x55637a9e567d  clang::Sema::SubstType()
    @     0x55637aa54455  clang::TemplateDeclInstantiator::InstantiateTypedefNameDecl()
    @     0x55637aa56093  clang::TemplateDeclInstantiator::VisitTypeAliasDecl()
    @     0x55637a9eac80  clang::Sema::InstantiateClass()
    @     0x55637a9ed604  clang::Sema::InstantiateClassTemplateSpecialization()
    @     0x55637aaf357d  llvm::function_ref<>::callback_fn<>()
    @     0x55637b59d77f  clang::StackExhaustionHandler::runWithSufficientStackSpace()
    @     0x55637aad6405  clang::Sema::RequireCompleteTypeImpl()
    @     0x55637aad5a55  clang::Sema::RequireCompleteType()
    @     0x55637a45629c  clang::Sema::BuildCXXTypeConstructExpr()
    @     0x55637aa0401c  clang::TreeTransform<>::TransformCXXUnresolvedConstructExpr()
    @     0x55637aa27c6d  clang::TreeTransform<>::TransformReturnStmt()
    @     0x55637aa0aa33  clang::TreeTransform<>::TransformCompoundStmt()
    @     0x55637a9ee50b  clang::Sema::SubstStmt()
    @     0x55637aa6c377  clang::Sema::InstantiateFunctionDefinition()
    @     0x55637b59d77f  clang::StackExhaustionHandler::runWithSufficientStackSpace()
    @     0x55637a928f4f  clang::Sema::DeduceReturnType()
    @     0x55637a2ffe56  clang::Sema::DiagnoseUseOfDecl()
    @     0x55637a763c49  FinishOverloadedCallExpr()
    @     0x55637a763955  clang::Sema::BuildOverloadedCallExpr()
    @     0x55637a307a25  clang::Sema::BuildCallExpr()
    @     0x55637a3227c7  clang::Sema::ActOnCallExpr()
    @     0x556379d1766d  clang::Parser::ParsePostfixExpressionSuffix()
    @     0x556379d198f8  clang::Parser::ParseCastExpression()
    @     0x556379d1b06f  clang::Parser::ParseCastExpression()
    @     0x556379d14aed  clang::Parser::ParseAssignmentExpression()
    @     0x556379d2346a  clang::Parser::ParseExpressionList()
    @     0x556379d1741d  clang::Parser::ParsePostfixExpressionSuffix()
    @     0x556379d198f8  clang::Parser::ParseCastExpression()
    @     0x556379d14aed  clang::Parser::ParseAssignmentExpression()
    @     0x556379d1e191  clang::Parser::ParseParenExpression()
    @     0x556379d1bb17  clang::Parser::ParseCastExpression()
    @     0x556379d14aed  clang::Parser::ParseAssignmentExpression()
    @     0x556379d2346a  clang::Parser::ParseExpressionList()
    @     0x556379d1741d  clang::Parser::ParsePostfixExpressionSuffix()
    @     0x556379d198f8  clang::Parser::ParseCastExpression()
    @     0x556379d163c8  clang::Parser::ParseCastExpression()
    @     0x556379d14aed  clang::Parser::ParseAssignmentExpression()
    @     0x556379d2346a  clang::Parser::ParseExpressionList()
    @     0x556379d1741d  clang::Parser::ParsePostfixExpressionSuffix()
    @     0x556379d198f8  clang::Parser::ParseCastExpression()
    @     0x556379d163c8  clang::Parser::ParseCastExpression()
    @     0x556379d14aed  clang::Parser::ParseAssignmentExpression()
    @     0x556379d35ef7  clang::Parser::ParseCXXCondition()
    @     0x556379dbd931  clang::Parser::ParseParenExprOrCondition()
    @     0x556379db711a  clang::Parser::ParseWhileStatement()
    @     0x556379db27b3  clang::Parser::ParseStatementOrDeclarationAfterAttributes()
    @     0x556379db16b1  clang::Parser::ParseStatementOrDeclaration()
    @     0x556379dbd4f5  clang::Parser::ParseCompoundStatementBody()
    @     0x556379dbfd3d  llvm::function_ref<>::callback_fn<>()
    @     0x55637b59d77f  clang::StackExhaustionHandler::runWithSufficientStackSpace()
    @     0x556379db230c  clang::Parser::ParseStatementOrDeclarationAfterAttributes()
    @     0x556379db16b1  clang::Parser::ParseStatementOrDeclaration()
    @     0x556379db6120  clang::Parser::ParseIfStatement()
    @     0x556379db2348  clang::Parser::ParseStatementOrDeclarationAfterAttributes()
    @     0x556379db16b1  clang::Parser::ParseStatementOrDeclaration()
    @     0x556379dbd4f5  clang::Parser::ParseCompoundStatementBody()
    @     0x556379dbe303  clang::Parser::ParseFunctionStatementBody()
    @     0x556379cf49c3  clang::Parser::ParseFunctionDefinition()
    @     0x556379d6be5e  clang::Parser::ParseDeclGroup()
    @     0x556379cf3393  clang::Parser::ParseDeclOrFunctionDefInternal()
    @     0x556379cf28eb  clang::Parser::ParseDeclarationOrFunctionDefinition()
    @     0x556379cf1676  clang::Parser::ParseExternalDeclaration()
    @     0x556379d3e877  clang::Parser::ParseInnerNamespace()
    @     0x556379d3d812  clang::Parser::ParseNamespace()
    @     0x556379d6934b  clang::Parser::ParseDeclaration()
    @     0x556379cf117e  clang::Parser::ParseExternalDeclaration()
    @     0x556379d3e877  clang::Parser::ParseInnerNamespace()
    @     0x556379d3d812  clang::Parser::ParseNamespace()
    @     0x556379d6934b  clang::Parser::ParseDeclaration()
    @     0x556379cf117e  clang::Parser::ParseExternalDeclaration()
    @     0x556379cef798  clang::Parser::ParseTopLevelDecl()
    @     0x556379cea9be  clang::ParseAST()
    @     0x5563799cc6da  clang::FrontendAction::Execute()
    @     0x55637993bf64  clang::CompilerInstance::ExecuteAction()
    @     0x556378c67c49  clang::ExecuteCompilerInvocation()
    @     0x556378c64715  cc1_main()
...

The test is being reduced.

@alexfh
Copy link
Contributor

alexfh commented May 16, 2025

@cor3ntin the reduced test case for the assertion failure above is: https://gcc.godbolt.org/z/zveexjqW3

struct N {
  int field;
};
template <typename It, typename T>
struct B {
  B(It, T);
  template <typename It2>
  B(B<It2, T>);
};
template <typename T>
struct C {
  auto g() { return B<int, T>(0, T{}); }
};
void f() {
  using T = decltype(C<decltype(&N::field)>{}.g());
}
$ clang -fsyntax-only test.cc
assertion failed at clang/lib/AST/ASTContext.cpp:3892 in QualType clang::ASTContext::getDecayedType(QualType) const: (T->isArrayType() || T->isFunctionType()) && "T does not decay"
    @     0x55c3a1ba66c4  __assert_fail
    @     0x55c39d98e0a0  clang::ASTContext::getDecayedType()
    @     0x55c39d5576e9  clang::StandardConversionSequence::isPerfect()
    @     0x55c39d5397d9  clang::OverloadCandidateSet::PerfectViableFunction()
    @     0x55c39d5277fb  clang::OverloadCandidateSet::BestViableFunction()
    @     0x55c39d3a6ea7  ResolveConstructorOverload()
    @     0x55c39d3a3538  TryConstructorInitialization()
    @     0x55c39d3889d9  TryConstructorOrParenListInitialization()
    @     0x55c39d38431a  clang::InitializationSequence::InitializeFrom()
    @     0x55c39d2aa14e  clang::Sema::BuildCXXTypeConstructExpr()
    @     0x55c39d72596b  clang::TreeTransform<>::TransformCXXUnresolvedConstructExpr()
    @     0x55c39d741e78  clang::TreeTransform<>::TransformReturnStmt()
    @     0x55c39d72b688  clang::TreeTransform<>::TransformCompoundStmt()
    @     0x55c39d714d28  clang::Sema::SubstStmt()
    @     0x55c39d771f4c  clang::Sema::InstantiateFunctionDefinition()
    @     0x55c39e1cddcf  clang::StackExhaustionHandler::runWithSufficientStackSpace()
    @     0x55c39d67ac56  clang::Sema::DeduceReturnType()
    @     0x55c39d1a6b93  clang::Sema::DiagnoseUseOfDecl()
    @     0x55c39d344cc4  clang::Sema::BuildMemberReferenceExpr()
    @     0x55c39d3421ef  clang::Sema::BuildMemberReferenceExpr()
    @     0x55c39d346123  clang::Sema::ActOnMemberAccessExpr()
    @     0x55c39cc1e3bf  clang::Parser::ParsePostfixExpressionSuffix()
    @     0x55c39cc1f72e  clang::Parser::ParseCastExpression()
    @     0x55c39cc1ffe3  clang::Parser::ParseCastExpression()
    @     0x55c39cc1b38e  clang::Parser::ParseAssignmentExpression()
    @     0x55c39cc1b26e  clang::Parser::ParseExpression()
    @     0x55c39cc44b10  clang::Parser::ParseDecltypeSpecifier()
    @     0x55c39cc2c5da  clang::Parser::ParseOptionalCXXScopeSpecifier()
    @     0x55c39cc03af0  clang::Parser::TryAnnotateCXXScopeToken()
    @     0x55c39cc6a889  clang::Parser::ParseDeclarationSpecifiers()
    @     0x55c39cc6a100  clang::Parser::ParseSpecifierQualifierList()
    @     0x55c39cc591c4  clang::Parser::ParseTypeName()
    @     0x55c39cc43cd1  clang::Parser::ParseAliasDeclarationAfterDeclarator()
    @     0x55c39cc42b59  clang::Parser::ParseUsingDeclaration()
    @     0x55c39cc41d1f  clang::Parser::ParseUsingDirectiveOrDeclaration()
    @     0x55c39cc65b3d  clang::Parser::ParseDeclaration()
    @     0x55c39cca40ec  clang::Parser::ParseStatementOrDeclarationAfterAttributes()
    @     0x55c39cca3993  clang::Parser::ParseStatementOrDeclaration()
    @     0x55c39ccad3ed  clang::Parser::ParseCompoundStatementBody()
    @     0x55c39ccae030  clang::Parser::ParseFunctionStatementBody()
    @     0x55c39cbffa9c  clang::Parser::ParseFunctionDefinition()
    @     0x55c39cc68324  clang::Parser::ParseDeclGroup()
    @     0x55c39cbfea66  clang::Parser::ParseDeclOrFunctionDefInternal()
    @     0x55c39cbfe25d  clang::Parser::ParseDeclarationOrFunctionDefinition()
    @     0x55c39cbfd0f9  clang::Parser::ParseExternalDeclaration()
    @     0x55c39cbfb774  clang::Parser::ParseTopLevelDecl()
    @     0x55c39cbf73be  clang::ParseAST()

@Caslyn
Copy link
Contributor

Caslyn commented May 16, 2025

Hi @cor3ntin,

Would you please revert this change while resolving this failure case? I've attached a reproducer for this assert scenario to help with debugging.

command_line_options-df343c.zip

@cor3ntin
Copy link
Contributor Author

@Caslyn Expect a fix shortly. Thanks for the repro

@cor3ntin
Copy link
Contributor Author

@alexfh Thanks a lot. I have a fix, a PR will be made once I run the tests

cor3ntin added a commit to cor3ntin/llvm-project that referenced this pull request May 16, 2025
Pointer to data member don't decay, assuming they do caused
an assertion failure.
cor3ntin added a commit that referenced this pull request May 16, 2025
Pointer to data member don't decay, assuming they do caused an assertion
failure.
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.

6 participants