Skip to content

Commit c4724f6

Browse files
authored
Fix assertion failure during conversion function overload resolution. (#98671)
When clang is built with assertions, an otherwise silent (and seemingly innocuous) assertion failure from `SemaConcept.cpp` is triggered by the following program: ```cpp struct S { operator int(); template <typename T> operator T(); }; constexpr auto r = &S::operator int; ``` The function in question compares the "constrained-ness" of `S::operator int` and `S::operator T<int>`; the template kind of the former is `TK_NonTemplate`, whereas the template kind of the later is `TK_FunctionTemplateSpecialization`. The later kind is not "expected" by the function, thus the assertion-failure.
1 parent 1cbd25f commit c4724f6

File tree

3 files changed

+41
-4
lines changed

3 files changed

+41
-4
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,8 @@ Bug Fixes to C++ Support
217217
- Clang now preserves the unexpanded flag in a lambda transform used for pack expansion. (#GH56852), (#GH85667),
218218
(#GH99877).
219219
- Fixed a bug when diagnosing ambiguous explicit specializations of constrained member functions.
220+
- Fixed an assertion failure when selecting a function from an overload set that includes a
221+
specialization of a conversion function template.
220222

221223
Bug Fixes to AST Handling
222224
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaTemplateDeduction.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5805,12 +5805,19 @@ FunctionDecl *Sema::getMoreConstrainedFunction(FunctionDecl *FD1,
58055805
FunctionDecl *FD2) {
58065806
assert(!FD1->getDescribedTemplate() && !FD2->getDescribedTemplate() &&
58075807
"not for function templates");
5808+
assert(!FD1->isFunctionTemplateSpecialization() ||
5809+
isa<CXXConversionDecl>(FD1));
5810+
assert(!FD2->isFunctionTemplateSpecialization() ||
5811+
isa<CXXConversionDecl>(FD2));
5812+
58085813
FunctionDecl *F1 = FD1;
5809-
if (FunctionDecl *MF = FD1->getInstantiatedFromMemberFunction())
5810-
F1 = MF;
5814+
if (FunctionDecl *P = FD1->getTemplateInstantiationPattern(false))
5815+
F1 = P;
5816+
58115817
FunctionDecl *F2 = FD2;
5812-
if (FunctionDecl *MF = FD2->getInstantiatedFromMemberFunction())
5813-
F2 = MF;
5818+
if (FunctionDecl *P = FD2->getTemplateInstantiationPattern(false))
5819+
F2 = P;
5820+
58145821
llvm::SmallVector<const Expr *, 1> AC1, AC2;
58155822
F1->getAssociatedConstraints(AC1);
58165823
F2->getAssociatedConstraints(AC2);

clang/test/SemaCXX/PR98671.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %clang_cc1 -std=c++20 -fsyntax-only %s -verify
2+
3+
struct S1 {
4+
operator int();
5+
6+
template <typename T>
7+
operator T();
8+
};
9+
10+
11+
// Ensure that no assertion is raised when overload resolution fails while
12+
// choosing between an operator function template and an operator function.
13+
constexpr auto r = &S1::operator int;
14+
// expected-error@-1 {{initializer of type '<overloaded function type>'}}
15+
16+
17+
template <typename T>
18+
struct S2 {
19+
template <typename U=T>
20+
S2(U={}) requires (sizeof(T) > 0) {}
21+
// expected-note@-1 {{candidate constructor}}
22+
23+
template <typename U=T>
24+
S2(U={}) requires (true) {}
25+
// expected-note@-1 {{candidate constructor}}
26+
};
27+
28+
S2<int> s; // expected-error {{call to constructor of 'S2<int>' is ambiguous}}

0 commit comments

Comments
 (0)