Skip to content
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

Open
wants to merge 25 commits into
base: main
Choose a base branch
from

Conversation

zyn0217
Copy link
Contributor

@zyn0217 zyn0217 commented Aug 12, 2024

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

@zyn0217 zyn0217 requested a review from cor3ntin August 12, 2024 07:35
Copy link

github-actions bot commented Aug 18, 2024

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

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.

mordante added a commit to mordante/llvm-project that referenced this pull request Aug 18, 2024
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
mordante and others added 2 commits August 19, 2024 09:51
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.
@zyn0217
Copy link
Contributor Author

zyn0217 commented Aug 19, 2024

@mordante
I saw some tests are "unexpectedly passed" on ARM platforms: https://buildkite.com/llvm-project/libcxx-ci/builds/37165#0191685f-c770-41d1-a8a4-8819da1b1802
Is that something undesired / why did we mark them XFAIL previously?

mordante added a commit that referenced this pull request Aug 20, 2024
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
@zyn0217 zyn0217 marked this pull request as ready for review August 28, 2024 10:40
@zyn0217 zyn0217 requested a review from Endilll as a code owner August 28, 2024 10:40
@zyn0217 zyn0217 requested a review from mizvekov August 28, 2024 10:40
@zyn0217 zyn0217 requested a review from Sirraide August 28, 2024 10:40
@Sirraide Sirraide removed their request for review August 28, 2024 11:13
@Sirraide
Copy link
Member

(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? :)

@zyn0217
Copy link
Contributor Author

zyn0217 commented Aug 28, 2024

(Unassigning myself because I’m not familiar enough w/ the details of substitution to review this in a meaningful way).

No problem :)

That said, I think this is still missing a release note isn’t it? :)

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.

@cor3ntin cor3ntin added c++20 clang:frontend Language frontend issues, e.g. anything involving "Sema" concepts C++20 concepts labels Aug 29, 2024
Copy link
Contributor

@cor3ntin cor3ntin left a 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 Show resolved Hide resolved
Comment on lines 13059 to 13060
/// template declaration passed as \p ND. The next declaration context would
/// be switched to \p DC if present; otherwise, it would be the semantic
Copy link
Contributor

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

Copy link
Contributor

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/SemaConcept.cpp Outdated Show resolved Hide resolved
Comment on lines 5588 to 5593
MultiLevelTemplateArgumentList MLTAL =
getTemplateInstantiationArgs(Template, Template->getDeclContext(),
/*Final=*/false, CanonicalConverted,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConceptInstantiation=*/true);
Copy link
Contributor

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?

Copy link
Contributor Author

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.

clang/lib/Sema/SemaTemplateDeduction.cpp Outdated Show resolved Hide resolved
clang/lib/Sema/SemaTemplateDeduction.cpp Outdated Show resolved Hide resolved
clang/lib/Sema/SemaTemplateDeduction.cpp Show resolved Hide resolved
clang/lib/Sema/SemaTemplateInstantiate.cpp Outdated Show resolved Hide resolved
clang/lib/Sema/SemaTemplateInstantiate.cpp Outdated Show resolved Hide resolved
clang/lib/Sema/SemaConcept.cpp Outdated Show resolved Hide resolved
clang/lib/Sema/SemaConcept.cpp Outdated Show resolved Hide resolved
dmpolukhin pushed a commit to dmpolukhin/llvm-project that referenced this pull request Sep 2, 2024
…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
@zyn0217
Copy link
Contributor Author

zyn0217 commented Oct 8, 2024

(Sorry for picking up this late, and this is ready for the second round of review - apart from the getTemplateInstantiationArgs() pieces, which can be ditched after the MLTAL refactoring patch lands)

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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// 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) {
Copy link
Contributor

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?

Copy link
Contributor Author

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]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// C++ [temp.deduct.call]p10: [DR1391]
// CWG1391

Copy link
Contributor Author

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...

Comment on lines +4014 to +4015
Info.reset(Info.takeSugared(),
TemplateArgumentList::CreateCopy(Context, CanonicalBuilder));
Copy link
Contributor

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(),
Copy link
Contributor

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?

Copy link
Contributor Author

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

Comment on lines +1137 to +1139
if (auto *Method = dyn_cast<CXXMethodDecl>(FD))
ThisScope.emplace(SemaRef, /*Record=*/Method->getParent(),
/*ThisQuals=*/Method->getMethodQualifiers());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When is that useful?

Copy link
Contributor Author

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...

Copy link
Contributor Author

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;
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++20 clang:frontend Language frontend issues, e.g. anything involving "Sema" concepts C++20 concepts
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement CWG2369
6 participants