-
Notifications
You must be signed in to change notification settings - Fork 11.8k
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
[Clang] Implement CWG2369 "Ordering between constraints and substitution" #102857
base: main
Are you sure you want to change the base?
Conversation
You can test this locally with the following command:git-clang-format --diff 4336f00f2156970cc0af2816331387a0a4039317 6fc2f7de9235499320514a70ee8d3a95f57deccb --extensions cpp,h -- clang/include/clang/Sema/Sema.h clang/include/clang/Sema/Template.h clang/lib/Sema/SemaConcept.cpp clang/lib/Sema/SemaTemplateDeduction.cpp clang/lib/Sema/SemaTemplateDeductionGuide.cpp clang/lib/Sema/SemaTemplateInstantiate.cpp clang/lib/Sema/TreeTransform.h clang/test/CXX/drs/cwg23xx.cpp clang/test/CXX/drs/cwg26xx.cpp clang/test/CXX/drs/cwg27xx.cpp clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp clang/test/SemaCXX/concept-crash-on-diagnostic.cpp clang/test/SemaCXX/cxx20-ctad-type-alias.cpp clang/test/SemaCXX/cxx23-assume.cpp clang/test/SemaCXX/cxx2c-fold-exprs.cpp clang/test/SemaCXX/lambda-unevaluated.cpp clang/test/SemaTemplate/concepts-recursive-inst.cpp clang/test/SemaTemplate/cxx2a-constraint-exprs.cpp clang/test/SemaTemplate/deduction-guide.cpp clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp View the diff from clang-format here.diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 20a8b5c369..fab460dbd8 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13008,7 +13008,8 @@ public:
///
/// \param DC In the event we don't HAVE a declaration yet, we instead provide
/// the decl context where it will be created. In this case, the \p
- /// Innermost should likely be provided. If \p ND is non-null, this is ignored.
+ /// Innermost should likely be provided. If \p ND is non-null, this is
+ /// ignored.
///
/// \param Innermost if non-NULL, specifies a template argument list for the
/// template declaration passed as \p ND.
|
The function template<class Duration> requires three_way_comparable_with<sys_seconds, sys_time<Duration>> constexpr auto operator<=>(const leap_second& x, const sys_time<Duration>& y) noexcept; Has a recursive constrained. This caused an infinite loop in GCC and is now hit by llvm#102857. A fix would be to make this function a hidden friend, this solution is propsed in LWG4139. For consistency all comparisons are made hidden friends. Since the issue causes compilation failures no additional test are needed. Fixes: llvm#104700
The function template<class Duration> requires three_way_comparable_with<sys_seconds, sys_time<Duration>> constexpr auto operator<=>(const leap_second& x, const sys_time<Duration>& y) noexcept; Has a recursive constrained. This caused an infinite loop in GCC and is now hit by llvm#102857. A fix would be to make this function a hidden friend, this solution is propsed in LWG4139. For consistency all comparisons are made hidden friends. Since the issue causes compilation failures no additional test are needed.
@mordante |
The function template<class Duration> requires three_way_comparable_with<sys_seconds, sys_time<Duration>> constexpr auto operator<=>(const leap_second& x, const sys_time<Duration>& y) noexcept; Has a recursive constrained. This caused an infinite loop in GCC and is now hit by #102857. A fix would be to make this function a hidden friend, this solution is propsed in LWG4139. For consistency all comparisons are made hidden friends. Since the issue causes compilation failures no additional test are needed. Fixes: #104700
(Unassigning myself because I’m not familiar enough w/ the details of substitution to review this in a meaningful way). That said, I think this is still missing a release note isn’t it? :) |
No problem :)
Yeah, I realized it the moment after I pushed the last commit, and I decided to leave that in the next push so I don't make commits piecemeal. |
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.
Thanks!
I did a first pass on the review, I have a few questions
clang/include/clang/Sema/Sema.h
Outdated
/// template declaration passed as \p ND. The next declaration context would | ||
/// be switched to \p DC if present; otherwise, it would be the semantic |
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.
I am not sure what "Next Declaration Context" refers too here
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.
It means the visitation order. In order to collect the instantiation arguments, we start with a declaration and walk up toward its template parents. This function could use a refactor and be smarter in figuring out how to walk up from ND alone, so that the DC parameter becomes unnecessary and could be removed.
clang/lib/Sema/SemaTemplate.cpp
Outdated
MultiLevelTemplateArgumentList MLTAL = | ||
getTemplateInstantiationArgs(Template, Template->getDeclContext(), | ||
/*Final=*/false, CanonicalConverted, | ||
/*RelativeToPrimary=*/true, | ||
/*Pattern=*/nullptr, | ||
/*ForConceptInstantiation=*/true); |
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.
Can you explain why we do not use NewContext
anymore?
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.
The NewContext
argument didn't actually make any difference to getTemplateInstantiationArgs()
previously, as it would always move to Template->getDeclContext()
for the next traversal if the Innermost parameter (which is CanonicalConverted
) was present. So I changed it to Template->getDeclContext()
to clarify the behavior.
However, I can revert the changes on getTemplateInstantiationArgs()
after @sdkrystian's refactoring patch, so this is left only for the time being.
…104713) The function template<class Duration> requires three_way_comparable_with<sys_seconds, sys_time<Duration>> constexpr auto operator<=>(const leap_second& x, const sys_time<Duration>& y) noexcept; Has a recursive constrained. This caused an infinite loop in GCC and is now hit by llvm#102857. A fix would be to make this function a hidden friend, this solution is propsed in LWG4139. For consistency all comparisons are made hidden friends. Since the issue causes compilation failures no additional test are needed. Fixes: llvm#104700
(Sorry for picking up this late, and this is ready for the second round of review - apart from the |
if (SemaRef.CurrentInstantiationScope->findInstantiationUnsafe(OldParm)) | ||
return false; | ||
// The current context might have been changed in the process of transforming | ||
// lambda expression. So resume it before we substitute into the parameter. |
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.
// lambda expression. So resume it before we substitute into the parameter. | |
// lambda expression. So restore it before we substitute into the parameter. |
@@ -4042,8 +4062,8 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( | |||
// ([temp.constr.decl]), those constraints are checked for satisfaction | |||
// ([temp.constr.constr]). If the constraints are not satisfied, type | |||
// deduction fails. | |||
if (!IsIncomplete) { | |||
if (CheckInstantiatedFunctionTemplateConstraints( | |||
if (IsLambda && !IsIncomplete) { |
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.
can you add a fixme comment here?
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.
There's one on line 4003, maybe that just suffices?
return TemplateDeductionResult::ConstraintsNotSatisfied; | ||
} | ||
} | ||
// C++ [temp.deduct.call]p10: [DR1391] |
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.
// C++ [temp.deduct.call]p10: [DR1391] | |
// CWG1391 |
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.
Oops, I thought I have fixed it everywhere...
Info.reset(Info.takeSugared(), | ||
TemplateArgumentList::CreateCopy(Context, CanonicalBuilder)); |
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.
Why is that necessary?
@@ -1517,7 +1555,7 @@ substituteParameterMappings(Sema &S, NormalizedConstraint &N, | |||
static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N, | |||
const ConceptSpecializationExpr *CSE) { | |||
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs( | |||
CSE->getNamedConcept(), CSE->getNamedConcept()->getLexicalDeclContext(), | |||
CSE->getNamedConcept(), CSE->getNamedConcept()->getDeclContext(), |
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.
Do you have tests with friend functions?
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.
This is another leftover of my previous changes on getTemplateInstantiationArgs()
... Will revert it
if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) | ||
ThisScope.emplace(SemaRef, /*Record=*/Method->getParent(), | ||
/*ThisQuals=*/Method->getMethodQualifiers()); |
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.
When is that useful?
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.
Honestly, I don't know. :(
I copied that from the previous implementation, and I was expecting it to make a difference in situations where member function calls are involved in a constraint evaluation. But I ran the regression tests with that removed and everything seemed fine.
I will have another try on a build without this patch. It could also be the case we're missing some tests, but I don't know...
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.
Huh, I removed these CXXThisScopeRAII
lines in CheckInstantiatedFunctionTemplateConstraints()
and all libcxx and clang regressions still passed. I guess we probably could remove these setups there
/*RelativeToPrimary=*/true, | ||
/*ForConstraintInstantiation=*/true); | ||
|
||
std::optional<Sema::CXXThisScopeRAII> ThisScope; |
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.
Do we need to point CurContext to the function here as well?
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.
Yes, I think so - but I couldn't find a case where that affects anything.
This patch partially implements CWG 2369 for non-lambda-constrained functions.
Lambdas are left intact at this point because we need extra work to correctly instantiate captures before the function instantiation.
As a premise of CWG2369, this patch also implements CWG2770 to ensure the function parameters are instantiated on demand.
Closes #54440