-
Notifications
You must be signed in to change notification settings - Fork 0
[Clang][Sema] Use first instantiation pattern when comparing constrained functions #1
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
base: main
Are you sure you want to change the base?
Conversation
mizvekov
left a comment
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.
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