-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Fix assertion failure during conversion function overload resolution. #98671
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
Conversation
@llvm/pr-subscribers-clang Author: Daniel M. Katz (katzdm) ChangesWhen clang is built with assertions, an otherwise silent (and seemingly innocuous) assertion failure from struct S {
operator int();
template <typename T> operator T();
};
constexpr auto r = &S::operator int; The function in question compares the "constrained-ness" of Full diff: https://github.com/llvm/llvm-project/pull/98671.diff 2 Files Affected:
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 202dd86c67f62..f94fb8be20e07 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1519,7 +1519,8 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
auto IsExpectedEntity = [](const FunctionDecl *FD) {
FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
return Kind == FunctionDecl::TK_NonTemplate ||
- Kind == FunctionDecl::TK_FunctionTemplate;
+ Kind == FunctionDecl::TK_FunctionTemplate ||
+ Kind == FunctionDecl::TK_FunctionTemplateSpecialization;
};
const auto *FD2 = dyn_cast<FunctionDecl>(D2);
(void)IsExpectedEntity;
diff --git a/clang/test/SemaCXX/PR98671.cpp b/clang/test/SemaCXX/PR98671.cpp
new file mode 100644
index 0000000000000..696b750759854
--- /dev/null
+++ b/clang/test/SemaCXX/PR98671.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only %s -verify
+
+struct S {
+ operator int();
+
+ template <typename T>
+ operator T();
+};
+
+
+// Ensure that no assertion is raised when overload resolution fails while
+// choosing between an operator function template and an operator function.
+constexpr auto r = &S::operator int;
+// expected-error@-1 {{initializer of type '<overloaded function type>'}}
|
I think this looks good, thanks Adding @AaronBallman @mizvekov for additional pairs of eyes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM as well
Looking further into this, I think this is a narrow problem that arises when selecting a function from an overload set which includes a specialization of a conversion function template. Consider a class: struct S {
template <typename> void fn();
template <typename T> operator T();
}; When looking up Looking up From here, deducing the placeholder type for The implementation of template <typename>
struct S {
void fn();
}; but not our conversion-function-template. Since I believe that specializations of conversion-function-templates are the only specializations that can appear in the |
CC @zygoloid for a potential additional set of eyes |
Hmm. See https://lists.isocpp.org/core/2024/06/15952.php -- I think we should never be comparing constraints between functions whose signatures aren't otherwise the same, and in particular we should never compare the constraints of a conversion function template against the constraints of a conversion function. Conversion functions do add another wrinkle here, because we can find them in different scopes too. For example: template<typename T> concept C = true;
template<typename T> concept D = C<T> && true;
template<typename T>
struct A {
operator T() requires C<T>;
};
template<typename U>
struct B {
operator U() requires D<U>;
};
struct X : A<int>, B<int> {};
int n = X();
auto p = &X::operator int; It doesn't make sense to compare the constraints of the conversion functions of the two templates here, because That said... an example like the following sidesteps all these issues and still crashes clang, so I think the above comments are somewhat orthogonal to this patch (except that I think we should have something like this as a test case instead of the current test case): template<typename T> concept C = true;
template<typename T> concept D = C<T> && true;
struct X {
template<C T> operator T();
template<D T> operator T();
};
auto p = &X::operator int; |
FYI that code should be affected by #18291 |
@zygoloid Friendly ping here, if you have a chance to take another look. |
@AaronBallman @cor3ntin Would you mind taking another look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but please add a release note so users know about the fix.
@AaronBallman Appreciate the reminder! Done. |
Thanks! Do you need someone to land the changes? |
Yep, I don't have commit privilege - would appreciate the help :) |
When clang is built with assertions, an otherwise silent (and seemingly innocuous) assertion failure from
SemaConcept.cpp
is triggered by the following program:The function in question compares the "constrained-ness" of
S::operator int
andS::operator T<int>
; the template kind of the former isTK_NonTemplate
, whereas the template kind of the later isTK_FunctionTemplateSpecialization
. The later kind is not "expected" by the function, thus the assertion-failure.