[Clang][Sema] Use first instantiation pattern when comparing constrained functions#1
[Clang][Sema] Use first instantiation pattern when comparing constrained functions#1sdkrystian wants to merge 1 commit intocppalliance:mainfrom
Conversation
mizvekov
left a comment
There was a problem hiding this comment.
getTemplateInstantiationPattern should dig down until it finds the pattern as written by the user, it would be pretty inconvenient if we relied on this for some cases but not others.
Can we just fix getTemplateInstantiationPattern instead?
|
name: Fix GH175426 Crash
Fix GH175426: Assertion Failure in Constraint Partial OrderingProblem AnalysisThe crash occurs when:
The failing assertion in Root CauseIn SemaTemplateDeduction.cpp FunctionDecl *F1 = FD1;
if (FunctionDecl *P = FD1->getTemplateInstantiationPattern(false))
F1 = P;This only goes one level back. For a local class inside a generic lambda, the instantiation chain may have multiple levels:
The pattern retrieved may still be Compare to SemaLambda.cpp if (FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization) {
while (FD->getInstantiatedFromMemberFunction())
FD = FD->getInstantiatedFromMemberFunction();
return FD;
}SolutionModify FunctionDecl *F1 = FD1;
while (FunctionDecl *P = F1->getTemplateInstantiationPattern(false))
F1 = P;
FunctionDecl *F2 = FD2;
while (FunctionDecl *P = F2->getTemplateInstantiationPattern(false))
F2 = P;Files to Modify
Test CaseThe test should verify no crash occurs and the expected error (missing // RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
template <typename T1> auto fwd2(const T1 &t1) {
return [](auto &&...ts1) {
struct LocalType {
int data;
auto operator<=>(const LocalType &other) const = default; // expected-error {{cannot default}}
};
LocalType x{42}, y{42};
static_assert(noexcept(x < y), "Noexcept check failed");
}();
}
int main() { return fwd2(1); } |
|
That's a good point. Let me examine [2 tools called] You're right. Looking at the two implementations: VarDecl::getTemplateInstantiationPattern iterates through the chain: if (MemberSpecializationInfo *MSInfo = VD->getMemberSpecializationInfo()) {
if (isTemplateInstantiation(MSInfo->getTemplateSpecializationKind())) {
VD = VD->getInstantiatedFromStaticDataMember();
while (auto *NewVD = VD->getInstantiatedFromStaticDataMember())
VD = NewVD;
}
}FunctionDecl::getTemplateInstantiationPattern only goes one level: if (MemberSpecializationInfo *Info = FD->getMemberSpecializationInfo()) {
if (ForDefinition &&
!clang::isTemplateInstantiation(Info->getTemplateSpecializationKind()))
return nullptr;
return getDefinitionOrSelf(cast<FunctionDecl>(Info->getInstantiatedFrom()));
}This inconsistency does seem like an oversight. The fix in if (MemberSpecializationInfo *Info = FD->getMemberSpecializationInfo()) {
if (ForDefinition &&
!clang::isTemplateInstantiation(Info->getTemplateSpecializationKind()))
return nullptr;
FunctionDecl *Result = FD->getInstantiatedFromMemberFunction();
while (FunctionDecl *Next = Result->getInstantiatedFromMemberFunction())
Result = Next;
return getDefinitionOrSelf(Result);
}This would be a more principled fix because:
Would you like to switch to Agent mode so I can implement this fix in |
Fixes llvm#175426