Changeset View
Standalone View
clang/lib/Sema/SemaTemplate.cpp
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
Show First 20 Lines • Show All 4,678 Lines • ▼ Show 20 Lines | if (CheckTemplateArgumentList(NamedConcept, ConceptNameInfo.getLoc(), | ||||||||||||||||||||||||
/*PartialTemplateArgs=*/false, Converted, | /*PartialTemplateArgs=*/false, Converted, | ||||||||||||||||||||||||
/*UpdateArgsWithConversions=*/false)) | /*UpdateArgsWithConversions=*/false)) | ||||||||||||||||||||||||
return ExprError(); | return ExprError(); | ||||||||||||||||||||||||
ConstraintSatisfaction Satisfaction; | ConstraintSatisfaction Satisfaction; | ||||||||||||||||||||||||
bool AreArgsDependent = | bool AreArgsDependent = | ||||||||||||||||||||||||
TemplateSpecializationType::anyDependentTemplateArguments(*TemplateArgs, | TemplateSpecializationType::anyDependentTemplateArguments(*TemplateArgs, | ||||||||||||||||||||||||
Converted); | Converted); | ||||||||||||||||||||||||
MultiLevelTemplateArgumentList MLTAL; | |||||||||||||||||||||||||
MLTAL.addOuterTemplateArguments(Converted); | |||||||||||||||||||||||||
if (!AreArgsDependent && | if (!AreArgsDependent && | ||||||||||||||||||||||||
CheckConstraintSatisfaction( | CheckConstraintSatisfaction( | ||||||||||||||||||||||||
NamedConcept, {NamedConcept->getConstraintExpr()}, Converted, | NamedConcept, {NamedConcept->getConstraintExpr()}, MLTAL, | ||||||||||||||||||||||||
ChuanqiXu: I would feel better if we could write:
```
CheckConstraintSatisfaction(
NamedConcept… | |||||||||||||||||||||||||
I'm not sure I get the suggestion? Why would you want to put the MultiLevelTemplateArgumentList in curleys? erichkeane: I'm not sure I get the suggestion? Why would you want to put the… | |||||||||||||||||||||||||
I just feel like the style is more cleaner. But I found the constructor might not allow us to do so... So this one might not be a suggestion. ChuanqiXu: I just feel like the style is more cleaner. But I found the constructor might not allow us to… | |||||||||||||||||||||||||
Ah, you mean to pass 'converted' directly in, so: CheckConstraintSatisfaction( NamedConcept, {NamedConcept->getConstraintExpr()}, {Converted}, SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(), TemplateArgs->getRAngleLoc()), Satisfaction) (notice 'Converted' instead of MLTAL). I agree with you, that WOULD be nicer, but unfortunately I think the constructor for that type was created explicitly to avoid us doing that :) erichkeane: Ah, you mean to pass 'converted' directly in, so:
```
CheckConstraintSatisfaction… | |||||||||||||||||||||||||
Yeah, this is what mean. I understood it is not easy/good to implement. ChuanqiXu: Yeah, this is what mean. I understood it is not easy/good to implement. | |||||||||||||||||||||||||
SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(), | SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(), | ||||||||||||||||||||||||
TemplateArgs->getRAngleLoc()), | TemplateArgs->getRAngleLoc()), | ||||||||||||||||||||||||
Satisfaction)) | Satisfaction)) | ||||||||||||||||||||||||
return ExprError(); | return ExprError(); | ||||||||||||||||||||||||
return ConceptSpecializationExpr::Create(Context, | return ConceptSpecializationExpr::Create(Context, | ||||||||||||||||||||||||
SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{}, | SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{}, | ||||||||||||||||||||||||
TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept, | TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept, | ||||||||||||||||||||||||
▲ Show 20 Lines • Show All 842 Lines • ▼ Show 20 Lines | bool Sema::CheckTemplateArgument(NamedDecl *Param, | ||||||||||||||||||||||||
{ | { | ||||||||||||||||||||||||
// Set up a template instantiation context. | // Set up a template instantiation context. | ||||||||||||||||||||||||
LocalInstantiationScope Scope(*this); | LocalInstantiationScope Scope(*this); | ||||||||||||||||||||||||
InstantiatingTemplate Inst(*this, TemplateLoc, Template, | InstantiatingTemplate Inst(*this, TemplateLoc, Template, | ||||||||||||||||||||||||
TempParm, Converted, | TempParm, Converted, | ||||||||||||||||||||||||
SourceRange(TemplateLoc, RAngleLoc)); | SourceRange(TemplateLoc, RAngleLoc)); | ||||||||||||||||||||||||
if (Inst.isInvalid()) | if (Inst.isInvalid()) | ||||||||||||||||||||||||
return true; | return true; | ||||||||||||||||||||||||
ChuanqiXu: | |||||||||||||||||||||||||
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); | TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); | ||||||||||||||||||||||||
Params = SubstTemplateParams(Params, CurContext, | Params = SubstTemplateParams(Params, CurContext, | ||||||||||||||||||||||||
MultiLevelTemplateArgumentList(TemplateArgs)); | MultiLevelTemplateArgumentList(TemplateArgs)); | ||||||||||||||||||||||||
if (!Params) | if (!Params) | ||||||||||||||||||||||||
return true; | return true; | ||||||||||||||||||||||||
} | } | ||||||||||||||||||||||||
// C++1z [temp.local]p1: (DR1004) | // C++1z [temp.local]p1: (DR1004) | ||||||||||||||||||||||||
▲ Show 20 Lines • Show All 341 Lines • ▼ Show 20 Lines | if (ArgIdx < NumArgs) { | ||||||||||||||||||||||||
return true; | return true; | ||||||||||||||||||||||||
} | } | ||||||||||||||||||||||||
// No problems found with the new argument list, propagate changes back | // No problems found with the new argument list, propagate changes back | ||||||||||||||||||||||||
// to caller. | // to caller. | ||||||||||||||||||||||||
if (UpdateArgsWithConversions) | if (UpdateArgsWithConversions) | ||||||||||||||||||||||||
TemplateArgs = std::move(NewArgs); | TemplateArgs = std::move(NewArgs); | ||||||||||||||||||||||||
if (!PartialTemplateArgs && | if (!PartialTemplateArgs) { | ||||||||||||||||||||||||
EnsureTemplateArgumentListConstraints( | TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack, | ||||||||||||||||||||||||
Template, Converted, SourceRange(TemplateLoc, | Converted); | ||||||||||||||||||||||||
TemplateArgs.getRAngleLoc()))) { | MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs( | ||||||||||||||||||||||||
Template, &StackTemplateArgs, /*RelativeToPrimary*/ true, | |||||||||||||||||||||||||
/*Pattern*/ nullptr, | |||||||||||||||||||||||||
/*LookBeyondLambda*/ true, /*IncludeContainingStruct*/ true); | |||||||||||||||||||||||||
if (EnsureTemplateArgumentListConstraints( | |||||||||||||||||||||||||
Template, MLTAL, | |||||||||||||||||||||||||
SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) { | |||||||||||||||||||||||||
if (ConstraintsNotSatisfied) | if (ConstraintsNotSatisfied) | ||||||||||||||||||||||||
*ConstraintsNotSatisfied = true; | *ConstraintsNotSatisfied = true; | ||||||||||||||||||||||||
return true; | return true; | ||||||||||||||||||||||||
} | } | ||||||||||||||||||||||||
} | |||||||||||||||||||||||||
return false; | return false; | ||||||||||||||||||||||||
} | } | ||||||||||||||||||||||||
namespace { | namespace { | ||||||||||||||||||||||||
class UnnamedLocalNoLinkageFinder | class UnnamedLocalNoLinkageFinder | ||||||||||||||||||||||||
: public TypeVisitor<UnnamedLocalNoLinkageFinder, bool> | : public TypeVisitor<UnnamedLocalNoLinkageFinder, bool> | ||||||||||||||||||||||||
{ | { | ||||||||||||||||||||||||
▲ Show 20 Lines • Show All 1,510 Lines • ▼ Show 20 Lines | if (isTemplateTemplateParameterAtLeastAsSpecializedAs(Params, Template, | ||||||||||||||||||||||||
// [temp.constr.order]. | // [temp.constr.order]. | ||||||||||||||||||||||||
SmallVector<const Expr *, 3> ParamsAC, TemplateAC; | SmallVector<const Expr *, 3> ParamsAC, TemplateAC; | ||||||||||||||||||||||||
Params->getAssociatedConstraints(ParamsAC); | Params->getAssociatedConstraints(ParamsAC); | ||||||||||||||||||||||||
// C++2a[temp.arg.template]p3 | // C++2a[temp.arg.template]p3 | ||||||||||||||||||||||||
// [...] In this comparison, if P is unconstrained, the constraints on A | // [...] In this comparison, if P is unconstrained, the constraints on A | ||||||||||||||||||||||||
// are not considered. | // are not considered. | ||||||||||||||||||||||||
if (ParamsAC.empty()) | if (ParamsAC.empty()) | ||||||||||||||||||||||||
return false; | return false; | ||||||||||||||||||||||||
Template->getAssociatedConstraints(TemplateAC); | Template->getAssociatedConstraints(TemplateAC); | ||||||||||||||||||||||||
// Attn Reviewers: This works and fixes the constraint comparison issues, | |||||||||||||||||||||||||
// but I don't have a good idea why this is, nor if it is the 'right' | |||||||||||||||||||||||||
// thing. I THINK it is pulling off the 'template template' level of the | |||||||||||||||||||||||||
// constraint, but I have no idea if that is the correct thing to do. | |||||||||||||||||||||||||
SmallVector<const Expr *, 3> ConvertedParamsAC; | |||||||||||||||||||||||||
TemplateArgumentList Empty(TemplateArgumentList::OnStack, {}); | |||||||||||||||||||||||||
MultiLevelTemplateArgumentList MLTAL{Empty}; | |||||||||||||||||||||||||
for (const auto *E : ParamsAC) { | |||||||||||||||||||||||||
// Both SubstExpr and SubstConstraintExpr work here, but I'm not sure | |||||||||||||||||||||||||
// which is correct. I THINK SubstConstraintExpr should be right, but I | |||||||||||||||||||||||||
// honestly have no idea. | |||||||||||||||||||||||||
ExprResult Res = SubstConstraintExpr(const_cast<Expr *>(E), MLTAL); | |||||||||||||||||||||||||
if (Res.isInvalid()) | |||||||||||||||||||||||||
return true; | |||||||||||||||||||||||||
ConvertedParamsAC.push_back(Res.get()); | |||||||||||||||||||||||||
} | |||||||||||||||||||||||||
I've spent some time to playing it myself to figure it out. And I found that we could fix this cleaner we adopt above suggestions. The problem here is that the instantiation is started half way. But the conversion for the constraint have been deferred. So here is the problem. I guess there are other similar problems. But let's fix them after we met them actually. ChuanqiXu: I've spent some time to playing it myself to figure it out. And I found that we could fix this… | |||||||||||||||||||||||||
Ah, neat! Thanks for this. Done. erichkeane: Ah, neat! Thanks for this. Done. | |||||||||||||||||||||||||
bool IsParamAtLeastAsConstrained; | bool IsParamAtLeastAsConstrained; | ||||||||||||||||||||||||
if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC, | if (IsAtLeastAsConstrained(Param, ConvertedParamsAC, Template, TemplateAC, | ||||||||||||||||||||||||
IsParamAtLeastAsConstrained)) | IsParamAtLeastAsConstrained)) | ||||||||||||||||||||||||
return true; | return true; | ||||||||||||||||||||||||
if (!IsParamAtLeastAsConstrained) { | if (!IsParamAtLeastAsConstrained) { | ||||||||||||||||||||||||
Diag(Arg.getLocation(), | Diag(Arg.getLocation(), | ||||||||||||||||||||||||
diag::err_template_template_parameter_not_at_least_as_constrained) | diag::err_template_template_parameter_not_at_least_as_constrained) | ||||||||||||||||||||||||
<< Template << Param << Arg.getSourceRange(); | << Template << Param << Arg.getSourceRange(); | ||||||||||||||||||||||||
Diag(Param->getLocation(), diag::note_entity_declared_at) << Param; | Diag(Param->getLocation(), diag::note_entity_declared_at) << Param; | ||||||||||||||||||||||||
Diag(Template->getLocation(), diag::note_entity_declared_at) | Diag(Template->getLocation(), diag::note_entity_declared_at) | ||||||||||||||||||||||||
▲ Show 20 Lines • Show All 3,652 Lines • Show Last 20 Lines |
I would feel better if we could write:
But it looks unimplementable.