-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[Clang] Implement CWG2369 "Ordering between constraints and substitution" #102857
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
Changes from 10 commits
1119f0a
ca00718
2dd772d
96bf64c
6b7072d
bb31d36
631be75
7d484e2
c515407
a9da5a3
cebe706
e0b21a5
30dc1d1
9d3981f
afb8a90
6a5085a
974a0ad
d19e700
5be9921
8ace714
da61fab
18da86a
1b8f0f6
ef5acad
6fc2f7d
d457f02
f07c4a9
a2818ba
8f2dc77
d16f2cf
7e7ed8e
7bc252a
f0b1e7c
2e9061b
9f935ab
e623bf5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13033,11 +13033,14 @@ class Sema final : public SemaBase { | |
/// instantiation arguments. | ||
/// | ||
/// \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 `Innermost` | ||
/// should likely be provided. If ND is non-null, this is ignored. | ||
/// the decl context where it will be created. In this case, the \p | ||
/// Innermost should likely be provided. If \p ND is non-null and \p | ||
/// Innermost is NULL, this is ignored. | ||
/// | ||
/// \param Innermost if non-NULL, specifies a template argument list for the | ||
/// template declaration passed as ND. | ||
/// 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 commentThe 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 commentThe 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. |
||
/// declaration context of \p ND. | ||
/// | ||
/// \param RelativeToPrimary true if we should get the template | ||
/// arguments relative to the primary template, even when we're | ||
|
@@ -13053,6 +13056,9 @@ class Sema final : public SemaBase { | |
/// ForConstraintInstantiation indicates we should continue looking when | ||
/// encountering a lambda generic call operator, and continue looking for | ||
/// arguments on an enclosing class template. | ||
/// | ||
/// \param SkipForSpecialization when specified, any template specializations | ||
/// in a traversal would be ignored. | ||
MultiLevelTemplateArgumentList getTemplateInstantiationArgs( | ||
const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false, | ||
std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt, | ||
|
@@ -14443,6 +14449,11 @@ class Sema final : public SemaBase { | |
ArrayRef<TemplateArgument> TemplateArgs, | ||
ConstraintSatisfaction &Satisfaction); | ||
|
||
bool CheckFunctionConstraintsWithoutInstantiation( | ||
SourceLocation PointOfInstantiation, FunctionTemplateDecl *Template, | ||
ArrayRef<TemplateArgument> TemplateArgs, | ||
ConstraintSatisfaction &Satisfaction); | ||
|
||
/// \brief Emit diagnostics explaining why a constraint expression was deemed | ||
/// unsatisfied. | ||
/// \param First whether this is the first time an unsatisfied constraint is | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5582,11 +5582,12 @@ bool Sema::CheckTemplateArgumentList( | |
ContextRAII Context(*this, NewContext); | ||
CXXThisScopeRAII(*this, RD, ThisQuals, RD != nullptr); | ||
|
||
MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs( | ||
Template, NewContext, /*Final=*/false, CanonicalConverted, | ||
/*RelativeToPrimary=*/true, | ||
/*Pattern=*/nullptr, | ||
/*ForConceptInstantiation=*/true); | ||
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 commentThe reason will be displayed to describe this comment to others. Learn more. Can you explain why we do not use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The However, I can revert the changes on |
||
if (EnsureTemplateArgumentListConstraints( | ||
Template, MLTAL, | ||
SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3834,18 +3834,6 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( | |
Result != TemplateDeductionResult::Success) | ||
return Result; | ||
|
||
// C++ [temp.deduct.call]p10: [DR1391] | ||
// If deduction succeeds for all parameters that contain | ||
// template-parameters that participate in template argument deduction, | ||
// and all template arguments are explicitly specified, deduced, or | ||
// obtained from default template arguments, remaining parameters are then | ||
// compared with the corresponding arguments. For each remaining parameter | ||
// P with a type that was non-dependent before substitution of any | ||
// explicitly-specified template arguments, if the corresponding argument | ||
// A cannot be implicitly converted to P, deduction fails. | ||
if (CheckNonDependent()) | ||
return TemplateDeductionResult::NonDependentConversionFailure; | ||
|
||
// Form the template argument list from the deduced template arguments. | ||
TemplateArgumentList *SugaredDeducedArgumentList = | ||
TemplateArgumentList::CreateCopy(Context, SugaredBuilder); | ||
|
@@ -3875,6 +3863,40 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( | |
FD = const_cast<FunctionDecl *>(FDFriend); | ||
Owner = FD->getLexicalDeclContext(); | ||
} | ||
|
||
// [DR2369] | ||
// FIXME: We have to partially instantiate lambda's captures for constraint | ||
// evaluation. | ||
bool NeedConstraintChecking = | ||
!PartialOverloading || | ||
CanonicalBuilder.size() == | ||
FunctionTemplate->getTemplateParameters()->size(); | ||
bool IsLambda = isLambdaCallOperator(FD) || isLambdaConversionOperator(FD); | ||
#if 1 | ||
if (!IsLambda && NeedConstraintChecking) { | ||
if (CheckFunctionConstraintsWithoutInstantiation( | ||
Info.getLocation(), FunctionTemplate->getCanonicalDecl(), | ||
CanonicalBuilder, Info.AssociatedConstraintsSatisfaction)) | ||
return TemplateDeductionResult::MiscellaneousDeductionFailure; | ||
if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) { | ||
Info.reset(Info.takeSugared(), | ||
TemplateArgumentList::CreateCopy(Context, CanonicalBuilder)); | ||
Comment on lines
+3981
to
+3982
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is that necessary? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Frankly these lines are also copied from the previous failure handling) I guess the instantiated concept-related nodes that were created during the checking would use the TemplateArgumentLists created on the ASTContext, or rather they would take ownership of the TemplateArgumentList. So, in order for the pilfered argument lists to work for other clients of TemplateDeductionInfo, we have to make a copy of the list. (I saw the patch that tried to preserve sugars in concepts turn this line into "copy sugared arguments, but do nothing for canonical arguments") But I'm not entirely sure of such deduction things, so probably @mizvekov would correct my understanding in some way. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ping @mizvekov There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, what @zyn0217 said is correct, the canonical argument list will have references persist in AST nodes, so it needs to be copied here. |
||
return TemplateDeductionResult::ConstraintsNotSatisfied; | ||
} | ||
} | ||
#endif | ||
// C++ [temp.deduct.call]p10: [DR1391] | ||
zyn0217 marked this conversation as resolved.
Show resolved
Hide resolved
zyn0217 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// If deduction succeeds for all parameters that contain | ||
// template-parameters that participate in template argument deduction, | ||
// and all template arguments are explicitly specified, deduced, or | ||
// obtained from default template arguments, remaining parameters are then | ||
// compared with the corresponding arguments. For each remaining parameter | ||
// P with a type that was non-dependent before substitution of any | ||
// explicitly-specified template arguments, if the corresponding argument | ||
// A cannot be implicitly converted to P, deduction fails. | ||
if (CheckNonDependent()) | ||
return TemplateDeductionResult::NonDependentConversionFailure; | ||
|
||
MultiLevelTemplateArgumentList SubstArgs( | ||
FunctionTemplate, CanonicalDeducedArgumentList->asArray(), | ||
/*Final=*/false); | ||
|
@@ -3909,9 +3931,7 @@ 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 (!PartialOverloading || | ||
(CanonicalBuilder.size() == | ||
FunctionTemplate->getTemplateParameters()->size())) { | ||
if (IsLambda && NeedConstraintChecking) { | ||
if (CheckInstantiatedFunctionTemplateConstraints( | ||
Info.getLocation(), Specialization, CanonicalBuilder, | ||
Info.AssociatedConstraintsSatisfaction)) | ||
|
Uh oh!
There was an error while loading. Please reload this page.