Thanks to visit codestin.com
Credit goes to clang.llvm.org

clang 22.0.0git
SemaConcept.cpp
Go to the documentation of this file.
1//===-- SemaConcept.cpp - Semantic Analysis for Constraints and Concepts --===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements semantic analysis for C++ constraints and concepts.
10//
11//===----------------------------------------------------------------------===//
12
14#include "TreeTransform.h"
16#include "clang/AST/ASTLambda.h"
17#include "clang/AST/DeclCXX.h"
23#include "clang/Sema/Overload.h"
25#include "clang/Sema/Sema.h"
27#include "clang/Sema/Template.h"
29#include "llvm/ADT/DenseMap.h"
30#include "llvm/ADT/PointerUnion.h"
31#include "llvm/ADT/StringExtras.h"
32#include "llvm/Support/SaveAndRestore.h"
33
34using namespace clang;
35using namespace sema;
36
37namespace {
38class LogicalBinOp {
39 SourceLocation Loc;
41 const Expr *LHS = nullptr;
42 const Expr *RHS = nullptr;
43
44public:
45 LogicalBinOp(const Expr *E) {
46 if (auto *BO = dyn_cast<BinaryOperator>(E)) {
47 Op = BinaryOperator::getOverloadedOperator(BO->getOpcode());
48 LHS = BO->getLHS();
49 RHS = BO->getRHS();
50 Loc = BO->getExprLoc();
51 } else if (auto *OO = dyn_cast<CXXOperatorCallExpr>(E)) {
52 // If OO is not || or && it might not have exactly 2 arguments.
53 if (OO->getNumArgs() == 2) {
54 Op = OO->getOperator();
55 LHS = OO->getArg(0);
56 RHS = OO->getArg(1);
57 Loc = OO->getOperatorLoc();
58 }
59 }
60 }
61
62 bool isAnd() const { return Op == OO_AmpAmp; }
63 bool isOr() const { return Op == OO_PipePipe; }
64 explicit operator bool() const { return isAnd() || isOr(); }
65
66 const Expr *getLHS() const { return LHS; }
67 const Expr *getRHS() const { return RHS; }
68 OverloadedOperatorKind getOp() const { return Op; }
69
70 ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS) const {
71 return recreateBinOp(SemaRef, LHS, const_cast<Expr *>(getRHS()));
72 }
73
74 ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS,
75 ExprResult RHS) const {
76 assert((isAnd() || isOr()) && "Not the right kind of op?");
77 assert((!LHS.isInvalid() && !RHS.isInvalid()) && "not good expressions?");
78
79 if (!LHS.isUsable() || !RHS.isUsable())
80 return ExprEmpty();
81
82 // We should just be able to 'normalize' these to the builtin Binary
83 // Operator, since that is how they are evaluated in constriant checks.
84 return BinaryOperator::Create(SemaRef.Context, LHS.get(), RHS.get(),
86 SemaRef.Context.BoolTy, VK_PRValue,
87 OK_Ordinary, Loc, FPOptionsOverride{});
88 }
89};
90} // namespace
91
92bool Sema::CheckConstraintExpression(const Expr *ConstraintExpression,
93 Token NextToken, bool *PossibleNonPrimary,
94 bool IsTrailingRequiresClause) {
95 // C++2a [temp.constr.atomic]p1
96 // ..E shall be a constant expression of type bool.
97
98 ConstraintExpression = ConstraintExpression->IgnoreParenImpCasts();
99
100 if (LogicalBinOp BO = ConstraintExpression) {
101 return CheckConstraintExpression(BO.getLHS(), NextToken,
102 PossibleNonPrimary) &&
103 CheckConstraintExpression(BO.getRHS(), NextToken,
104 PossibleNonPrimary);
105 } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpression))
106 return CheckConstraintExpression(C->getSubExpr(), NextToken,
107 PossibleNonPrimary);
108
109 QualType Type = ConstraintExpression->getType();
110
111 auto CheckForNonPrimary = [&] {
112 if (!PossibleNonPrimary)
113 return;
114
115 *PossibleNonPrimary =
116 // We have the following case:
117 // template<typename> requires func(0) struct S { };
118 // The user probably isn't aware of the parentheses required around
119 // the function call, and we're only going to parse 'func' as the
120 // primary-expression, and complain that it is of non-bool type.
121 //
122 // However, if we're in a lambda, this might also be:
123 // []<typename> requires var () {};
124 // Which also looks like a function call due to the lambda parentheses,
125 // but unlike the first case, isn't an error, so this check is skipped.
126 (NextToken.is(tok::l_paren) &&
127 (IsTrailingRequiresClause ||
128 (Type->isDependentType() &&
129 isa<UnresolvedLookupExpr>(ConstraintExpression) &&
130 !dyn_cast_if_present<LambdaScopeInfo>(getCurFunction())) ||
131 Type->isFunctionType() ||
132 Type->isSpecificBuiltinType(BuiltinType::Overload))) ||
133 // We have the following case:
134 // template<typename T> requires size_<T> == 0 struct S { };
135 // The user probably isn't aware of the parentheses required around
136 // the binary operator, and we're only going to parse 'func' as the
137 // first operand, and complain that it is of non-bool type.
138 getBinOpPrecedence(NextToken.getKind(),
139 /*GreaterThanIsOperator=*/true,
141 };
142
143 // An atomic constraint!
144 if (ConstraintExpression->isTypeDependent()) {
145 CheckForNonPrimary();
146 return true;
147 }
148
149 if (!Context.hasSameUnqualifiedType(Type, Context.BoolTy)) {
150 Diag(ConstraintExpression->getExprLoc(),
151 diag::err_non_bool_atomic_constraint)
152 << Type << ConstraintExpression->getSourceRange();
153 CheckForNonPrimary();
154 return false;
155 }
156
157 if (PossibleNonPrimary)
158 *PossibleNonPrimary = false;
159 return true;
160}
161
162namespace {
163struct SatisfactionStackRAII {
164 Sema &SemaRef;
165 bool Inserted = false;
166 SatisfactionStackRAII(Sema &SemaRef, const NamedDecl *ND,
167 const llvm::FoldingSetNodeID &FSNID)
168 : SemaRef(SemaRef) {
169 if (ND) {
170 SemaRef.PushSatisfactionStackEntry(ND, FSNID);
171 Inserted = true;
172 }
173 }
174 ~SatisfactionStackRAII() {
175 if (Inserted)
177 }
178};
179} // namespace
180
182 Sema &S, llvm::FoldingSetNodeID &ID, const NamedDecl *Templ, const Expr *E,
183 const MultiLevelTemplateArgumentList *MLTAL = nullptr) {
184 E->Profile(ID, S.Context, /*Canonical=*/true);
185 if (MLTAL) {
186 for (const auto &List : *MLTAL)
187 for (const auto &TemplateArg : List.Args)
189 .Profile(ID, S.Context);
190 }
191 if (S.SatisfactionStackContains(Templ, ID)) {
192 S.Diag(E->getExprLoc(), diag::err_constraint_depends_on_self)
193 << E << E->getSourceRange();
194 return true;
195 }
196 return false;
197}
198
199// Figure out the to-translation-unit depth for this function declaration for
200// the purpose of seeing if they differ by constraints. This isn't the same as
201// getTemplateDepth, because it includes already instantiated parents.
202static unsigned
204 bool SkipForSpecialization = false) {
206 ND, ND->getLexicalDeclContext(), /*Final=*/false,
207 /*Innermost=*/std::nullopt,
208 /*RelativeToPrimary=*/true,
209 /*Pattern=*/nullptr,
210 /*ForConstraintInstantiation=*/true, SkipForSpecialization);
211 return MLTAL.getNumLevels();
212}
213
214namespace {
215class AdjustConstraintDepth : public TreeTransform<AdjustConstraintDepth> {
216 unsigned TemplateDepth = 0;
217
218public:
219 using inherited = TreeTransform<AdjustConstraintDepth>;
220 AdjustConstraintDepth(Sema &SemaRef, unsigned TemplateDepth)
221 : inherited(SemaRef), TemplateDepth(TemplateDepth) {}
222
223 using inherited::TransformTemplateTypeParmType;
224 QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
225 TemplateTypeParmTypeLoc TL, bool) {
226 const TemplateTypeParmType *T = TL.getTypePtr();
227
228 TemplateTypeParmDecl *NewTTPDecl = nullptr;
229 if (TemplateTypeParmDecl *OldTTPDecl = T->getDecl())
230 NewTTPDecl = cast_or_null<TemplateTypeParmDecl>(
231 TransformDecl(TL.getNameLoc(), OldTTPDecl));
232
233 QualType Result = getSema().Context.getTemplateTypeParmType(
234 T->getDepth() + TemplateDepth, T->getIndex(), T->isParameterPack(),
235 NewTTPDecl);
236 TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
237 NewTL.setNameLoc(TL.getNameLoc());
238 return Result;
239 }
240
241 bool AlreadyTransformed(QualType T) {
242 if (T.isNull())
243 return true;
244
247 return false;
248 return true;
249 }
250};
251} // namespace
252
253namespace {
254
255// FIXME: Convert it to DynamicRecursiveASTVisitor
256class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> {
257 using inherited = RecursiveASTVisitor<HashParameterMapping>;
258 friend inherited;
259
260 Sema &SemaRef;
261 const MultiLevelTemplateArgumentList &TemplateArgs;
262 llvm::FoldingSetNodeID &ID;
263 llvm::SmallVector<TemplateArgument, 10> UsedTemplateArgs;
264
265 UnsignedOrNone OuterPackSubstIndex;
266
267 TemplateArgument getPackSubstitutedTemplateArgument(TemplateArgument Arg) {
268 assert(*SemaRef.ArgPackSubstIndex < Arg.pack_size());
269 Arg = Arg.pack_begin()[*SemaRef.ArgPackSubstIndex];
270 if (Arg.isPackExpansion())
271 Arg = Arg.getPackExpansionPattern();
272 return Arg;
273 }
274
275 bool shouldVisitTemplateInstantiations() const { return true; }
276
277public:
278 HashParameterMapping(Sema &SemaRef,
279 const MultiLevelTemplateArgumentList &TemplateArgs,
280 llvm::FoldingSetNodeID &ID,
281 UnsignedOrNone OuterPackSubstIndex)
282 : SemaRef(SemaRef), TemplateArgs(TemplateArgs), ID(ID),
283 OuterPackSubstIndex(OuterPackSubstIndex) {}
284
285 bool VisitTemplateTypeParmType(TemplateTypeParmType *T) {
286 // A lambda expression can introduce template parameters that don't have
287 // corresponding template arguments yet.
288 if (T->getDepth() >= TemplateArgs.getNumLevels())
289 return true;
290
291 TemplateArgument Arg = TemplateArgs(T->getDepth(), T->getIndex());
292
293 if (T->isParameterPack() && SemaRef.ArgPackSubstIndex) {
294 assert(Arg.getKind() == TemplateArgument::Pack &&
295 "Missing argument pack");
296
297 Arg = getPackSubstitutedTemplateArgument(Arg);
298 }
299
300 UsedTemplateArgs.push_back(
302 return true;
303 }
304
305 bool VisitDeclRefExpr(DeclRefExpr *E) {
306 NamedDecl *D = E->getDecl();
307 NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D);
308 if (!NTTP)
309 return TraverseDecl(D);
310
311 TemplateArgument Arg = TemplateArgs(NTTP->getDepth(), NTTP->getPosition());
312 if (NTTP->isParameterPack() && SemaRef.ArgPackSubstIndex) {
313 assert(Arg.getKind() == TemplateArgument::Pack &&
314 "Missing argument pack");
315 Arg = getPackSubstitutedTemplateArgument(Arg);
316 }
317
318 UsedTemplateArgs.push_back(
320 return true;
321 }
322
323 bool VisitTypedefType(TypedefType *TT) {
324 return inherited::TraverseType(TT->desugar());
325 }
326
327 bool TraverseDecl(Decl *D) {
328 if (auto *VD = dyn_cast<ValueDecl>(D))
329 return TraverseType(VD->getType());
330
331 return inherited::TraverseDecl(D);
332 }
333
334 bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true) {
335 // We don't care about TypeLocs. So traverse Types instead.
336 return TraverseType(TL.getType(), TraverseQualifier);
337 }
338
339 bool TraverseTagType(const TagType *T, bool TraverseQualifier) {
340 // T's parent can be dependent while T doesn't have any template arguments.
341 // We should have already traversed its qualifier.
342 // FIXME: Add an assert to catch cases where we failed to profile the
343 // concept. assert(!T->isDependentType() && "We missed a case in profiling
344 // concepts!");
345 return true;
346 }
347
348 bool TraverseInjectedClassNameType(InjectedClassNameType *T,
349 bool TraverseQualifier) {
350 return TraverseTemplateArguments(T->getTemplateArgs(SemaRef.Context));
351 }
352
353 bool TraverseTemplateArgument(const TemplateArgument &Arg) {
355 // Act as if we are fully expanding this pack, if it is a PackExpansion.
356 Sema::ArgPackSubstIndexRAII _1(SemaRef, std::nullopt);
357 llvm::SaveAndRestore<UnsignedOrNone> _2(OuterPackSubstIndex,
358 std::nullopt);
359 return inherited::TraverseTemplateArgument(Arg);
360 }
361
362 Sema::ArgPackSubstIndexRAII _1(SemaRef, OuterPackSubstIndex);
363 return inherited::TraverseTemplateArgument(Arg);
364 }
365
366 void VisitConstraint(const NormalizedConstraintWithParamMapping &Constraint) {
367 if (!Constraint.hasParameterMapping()) {
368 for (const auto &List : TemplateArgs)
369 for (const TemplateArgument &Arg : List.Args)
371 ID, SemaRef.Context);
372 return;
373 }
374
375 llvm::ArrayRef<TemplateArgumentLoc> Mapping =
376 Constraint.getParameterMapping();
377 for (auto &ArgLoc : Mapping) {
378 TemplateArgument Canonical =
379 SemaRef.Context.getCanonicalTemplateArgument(ArgLoc.getArgument());
380 // We don't want sugars to impede the profile of cache.
381 UsedTemplateArgs.push_back(Canonical);
382 TraverseTemplateArgument(Canonical);
383 }
384
385 for (auto &Used : UsedTemplateArgs) {
386 llvm::FoldingSetNodeID R;
387 Used.Profile(R, SemaRef.Context);
388 ID.AddNodeID(R);
389 }
390 }
391};
392
393class ConstraintSatisfactionChecker {
394 Sema &S;
395 const NamedDecl *Template;
396 SourceLocation TemplateNameLoc;
397 UnsignedOrNone PackSubstitutionIndex;
398
399 ConstraintSatisfaction &Satisfaction;
400
401private:
403 EvaluateAtomicConstraint(const Expr *AtomicExpr,
404 const MultiLevelTemplateArgumentList &MLTAL);
405
406 UnsignedOrNone EvaluateFoldExpandedConstraintSize(
407 const FoldExpandedConstraint &FE,
408 const MultiLevelTemplateArgumentList &MLTAL);
409
410 // XXX: It is SLOW! Use it very carefully.
411 std::optional<MultiLevelTemplateArgumentList> SubstitutionInTemplateArguments(
412 const NormalizedConstraintWithParamMapping &Constraint,
413 MultiLevelTemplateArgumentList MLTAL,
414 llvm::SmallVector<TemplateArgument> &SubstitutedOuterMost);
415
416 ExprResult EvaluateSlow(const AtomicConstraint &Constraint,
417 const MultiLevelTemplateArgumentList &MLTAL);
418
419 ExprResult Evaluate(const AtomicConstraint &Constraint,
420 const MultiLevelTemplateArgumentList &MLTAL);
421
422 ExprResult EvaluateSlow(const FoldExpandedConstraint &Constraint,
423 const MultiLevelTemplateArgumentList &MLTAL);
424
425 ExprResult Evaluate(const FoldExpandedConstraint &Constraint,
426 const MultiLevelTemplateArgumentList &MLTAL);
427
428 ExprResult EvaluateSlow(const ConceptIdConstraint &Constraint,
429 const MultiLevelTemplateArgumentList &MLTAL,
430 unsigned int Size);
431
432 ExprResult Evaluate(const ConceptIdConstraint &Constraint,
433 const MultiLevelTemplateArgumentList &MLTAL);
434
435 ExprResult Evaluate(const CompoundConstraint &Constraint,
436 const MultiLevelTemplateArgumentList &MLTAL);
437
438public:
439 ConstraintSatisfactionChecker(Sema &SemaRef, const NamedDecl *Template,
440 SourceLocation TemplateNameLoc,
441 UnsignedOrNone PackSubstitutionIndex,
442 ConstraintSatisfaction &Satisfaction)
443 : S(SemaRef), Template(Template), TemplateNameLoc(TemplateNameLoc),
444 PackSubstitutionIndex(PackSubstitutionIndex),
445 Satisfaction(Satisfaction) {}
446
447 ExprResult Evaluate(const NormalizedConstraint &Constraint,
448 const MultiLevelTemplateArgumentList &MLTAL);
449};
450
451StringRef allocateStringFromConceptDiagnostic(const Sema &S,
452 const PartialDiagnostic Diag) {
453 SmallString<128> DiagString;
454 DiagString = ": ";
455 Diag.EmitToString(S.getDiagnostics(), DiagString);
456 return S.getASTContext().backupStr(DiagString);
457}
458
459} // namespace
460
461ExprResult ConstraintSatisfactionChecker::EvaluateAtomicConstraint(
462 const Expr *AtomicExpr, const MultiLevelTemplateArgumentList &MLTAL) {
463 EnterExpressionEvaluationContext ConstantEvaluated(
466
467 llvm::FoldingSetNodeID ID;
468 if (Template &&
470 Satisfaction.IsSatisfied = false;
471 Satisfaction.ContainsErrors = true;
472 return ExprEmpty();
473 }
474 SatisfactionStackRAII StackRAII(S, Template, ID);
475
476 // Atomic constraint - substitute arguments and check satisfaction.
477 ExprResult SubstitutedExpression = const_cast<Expr *>(AtomicExpr);
478 {
479 TemplateDeductionInfo Info(TemplateNameLoc);
483 // FIXME: improve const-correctness of InstantiatingTemplate
484 const_cast<NamedDecl *>(Template), Info, AtomicExpr->getSourceRange());
485 if (Inst.isInvalid())
486 return ExprError();
487
488 // We do not want error diagnostics escaping here.
489 Sema::SFINAETrap Trap(S);
490 SubstitutedExpression =
491 S.SubstConstraintExpr(const_cast<Expr *>(AtomicExpr), MLTAL);
492
493 if (SubstitutedExpression.isInvalid() || Trap.hasErrorOccurred()) {
494 // C++2a [temp.constr.atomic]p1
495 // ...If substitution results in an invalid type or expression, the
496 // constraint is not satisfied.
497 if (!Trap.hasErrorOccurred())
498 // A non-SFINAE error has occurred as a result of this
499 // substitution.
500 return ExprError();
501
504 Info.takeSFINAEDiagnostic(SubstDiag);
505 // FIXME: This is an unfortunate consequence of there
506 // being no serialization code for PartialDiagnostics and the fact
507 // that serializing them would likely take a lot more storage than
508 // just storing them as strings. We would still like, in the
509 // future, to serialize the proper PartialDiagnostic as serializing
510 // it as a string defeats the purpose of the diagnostic mechanism.
511 Satisfaction.Details.emplace_back(
513 SubstDiag.first,
514 allocateStringFromConceptDiagnostic(S, SubstDiag.second)});
515 Satisfaction.IsSatisfied = false;
516 return ExprEmpty();
517 }
518 }
519
520 if (!S.CheckConstraintExpression(SubstitutedExpression.get()))
521 return ExprError();
522
523 // [temp.constr.atomic]p3: To determine if an atomic constraint is
524 // satisfied, the parameter mapping and template arguments are first
525 // substituted into its expression. If substitution results in an
526 // invalid type or expression, the constraint is not satisfied.
527 // Otherwise, the lvalue-to-rvalue conversion is performed if necessary,
528 // and E shall be a constant expression of type bool.
529 //
530 // Perform the L to R Value conversion if necessary. We do so for all
531 // non-PRValue categories, else we fail to extend the lifetime of
532 // temporaries, and that fails the constant expression check.
533 if (!SubstitutedExpression.get()->isPRValue())
534 SubstitutedExpression = ImplicitCastExpr::Create(
535 S.Context, SubstitutedExpression.get()->getType(), CK_LValueToRValue,
536 SubstitutedExpression.get(),
537 /*BasePath=*/nullptr, VK_PRValue, FPOptionsOverride());
538
539 return SubstitutedExpression;
540}
541
542std::optional<MultiLevelTemplateArgumentList>
543ConstraintSatisfactionChecker::SubstitutionInTemplateArguments(
544 const NormalizedConstraintWithParamMapping &Constraint,
546 llvm::SmallVector<TemplateArgument> &SubstitutedOuterMost) {
547
548 if (!Constraint.hasParameterMapping())
549 return std::move(MLTAL);
550
551 TemplateDeductionInfo Info(Constraint.getBeginLoc());
553 S, Constraint.getBeginLoc(),
555 // FIXME: improve const-correctness of InstantiatingTemplate
556 const_cast<NamedDecl *>(Template), Info, Constraint.getSourceRange());
557 if (Inst.isInvalid())
558 return std::nullopt;
559
560 Sema::SFINAETrap Trap(S);
561
562 TemplateArgumentListInfo SubstArgs;
564 S, Constraint.getPackSubstitutionIndex()
565 ? Constraint.getPackSubstitutionIndex()
566 : PackSubstitutionIndex);
567
569 Constraint.getParameterMapping(), Constraint.getBeginLoc(), MLTAL,
570 SubstArgs, /*BuildPackExpansionTypes=*/true)) {
571 Satisfaction.IsSatisfied = false;
572 return std::nullopt;
573 }
574
576 auto *TD = const_cast<TemplateDecl *>(
579 TD->getLocation(), SubstArgs,
580 /*DefaultArguments=*/{},
581 /*PartialTemplateArgs=*/false, CTAI))
582 return std::nullopt;
584 Constraint.mappingOccurenceList();
585 SubstitutedOuterMost =
586 llvm::to_vector_of<TemplateArgument>(MLTAL.getOutermost());
587 unsigned Offset = 0;
588 for (unsigned I = 0, MappedIndex = 0; I < Used.size(); I++) {
590 if (Used[I])
592 CTAI.SugaredConverted[MappedIndex++]);
593 if (I < SubstitutedOuterMost.size()) {
594 SubstitutedOuterMost[I] = Arg;
595 Offset = I + 1;
596 } else {
597 SubstitutedOuterMost.push_back(Arg);
598 Offset = SubstitutedOuterMost.size();
599 }
600 }
601 if (Offset < SubstitutedOuterMost.size())
602 SubstitutedOuterMost.erase(SubstitutedOuterMost.begin() + Offset);
603
605 const_cast<NamedDecl *>(Constraint.getConstraintDecl()),
606 SubstitutedOuterMost);
607 return std::move(MLTAL);
608}
609
610ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
611 const AtomicConstraint &Constraint,
612 const MultiLevelTemplateArgumentList &MLTAL) {
613
614 llvm::SmallVector<TemplateArgument> SubstitutedOuterMost;
615 std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs =
616 SubstitutionInTemplateArguments(Constraint, MLTAL, SubstitutedOuterMost);
617 if (!SubstitutedArgs) {
618 Satisfaction.IsSatisfied = false;
619 return ExprEmpty();
620 }
621
622 Sema::ArgPackSubstIndexRAII SubstIndex(S, PackSubstitutionIndex);
623 ExprResult SubstitutedAtomicExpr = EvaluateAtomicConstraint(
624 Constraint.getConstraintExpr(), *SubstitutedArgs);
625
626 if (SubstitutedAtomicExpr.isInvalid())
627 return ExprError();
628
629 if (SubstitutedAtomicExpr.isUnset())
630 // Evaluator has decided satisfaction without yielding an expression.
631 return ExprEmpty();
632
633 // We don't have the ability to evaluate this, since it contains a
634 // RecoveryExpr, so we want to fail overload resolution. Otherwise,
635 // we'd potentially pick up a different overload, and cause confusing
636 // diagnostics. SO, add a failure detail that will cause us to make this
637 // overload set not viable.
638 if (SubstitutedAtomicExpr.get()->containsErrors()) {
639 Satisfaction.IsSatisfied = false;
640 Satisfaction.ContainsErrors = true;
641
642 PartialDiagnostic Msg = S.PDiag(diag::note_constraint_references_error);
643 Satisfaction.Details.emplace_back(
645 SubstitutedAtomicExpr.get()->getBeginLoc(),
646 allocateStringFromConceptDiagnostic(S, Msg)});
647 return SubstitutedAtomicExpr;
648 }
649
650 if (SubstitutedAtomicExpr.get()->isValueDependent()) {
651 Satisfaction.IsSatisfied = true;
652 Satisfaction.ContainsErrors = false;
653 return SubstitutedAtomicExpr;
654 }
655
656 EnterExpressionEvaluationContext ConstantEvaluated(
659 Expr::EvalResult EvalResult;
660 EvalResult.Diag = &EvaluationDiags;
661 if (!SubstitutedAtomicExpr.get()->EvaluateAsConstantExpr(EvalResult,
662 S.Context) ||
663 !EvaluationDiags.empty()) {
664 // C++2a [temp.constr.atomic]p1
665 // ...E shall be a constant expression of type bool.
666 S.Diag(SubstitutedAtomicExpr.get()->getBeginLoc(),
667 diag::err_non_constant_constraint_expression)
668 << SubstitutedAtomicExpr.get()->getSourceRange();
669 for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
670 S.Diag(PDiag.first, PDiag.second);
671 return ExprError();
672 }
673
674 assert(EvalResult.Val.isInt() &&
675 "evaluating bool expression didn't produce int");
676 Satisfaction.IsSatisfied = EvalResult.Val.getInt().getBoolValue();
677 if (!Satisfaction.IsSatisfied)
678 Satisfaction.Details.emplace_back(SubstitutedAtomicExpr.get());
679
680 return SubstitutedAtomicExpr;
681}
682
683ExprResult ConstraintSatisfactionChecker::Evaluate(
684 const AtomicConstraint &Constraint,
685 const MultiLevelTemplateArgumentList &MLTAL) {
686
687 unsigned Size = Satisfaction.Details.size();
688 llvm::FoldingSetNodeID ID;
689 UnsignedOrNone OuterPackSubstIndex =
690 Constraint.getPackSubstitutionIndex()
691 ? Constraint.getPackSubstitutionIndex()
692 : PackSubstitutionIndex;
693
694 ID.AddPointer(Constraint.getConstraintExpr());
695 ID.AddInteger(OuterPackSubstIndex.toInternalRepresentation());
696 HashParameterMapping(S, MLTAL, ID, OuterPackSubstIndex)
697 .VisitConstraint(Constraint);
698
699 if (auto Iter = S.UnsubstitutedConstraintSatisfactionCache.find(ID);
701
702 auto &Cached = Iter->second.Satisfaction;
703 Satisfaction.ContainsErrors = Cached.ContainsErrors;
704 Satisfaction.IsSatisfied = Cached.IsSatisfied;
705 Satisfaction.Details.insert(Satisfaction.Details.begin() + Size,
706 Cached.Details.begin(), Cached.Details.end());
707 return Iter->second.SubstExpr;
708 }
709
710 ExprResult E = EvaluateSlow(Constraint, MLTAL);
711
713 Cache.Satisfaction.ContainsErrors = Satisfaction.ContainsErrors;
714 Cache.Satisfaction.IsSatisfied = Satisfaction.IsSatisfied;
715 std::copy(Satisfaction.Details.begin() + Size, Satisfaction.Details.end(),
716 std::back_inserter(Cache.Satisfaction.Details));
717 Cache.SubstExpr = E;
718 S.UnsubstitutedConstraintSatisfactionCache.insert({ID, std::move(Cache)});
719
720 return E;
721}
722
724ConstraintSatisfactionChecker::EvaluateFoldExpandedConstraintSize(
725 const FoldExpandedConstraint &FE,
726 const MultiLevelTemplateArgumentList &MLTAL) {
727
728 // We should ignore errors in the presence of packs of different size.
729 Sema::SFINAETrap Trap(S);
730
731 Expr *Pattern = const_cast<Expr *>(FE.getPattern());
732
734 S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
735 assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
736 bool Expand = true;
737 bool RetainExpansion = false;
738 UnsignedOrNone NumExpansions(std::nullopt);
740 Pattern->getExprLoc(), Pattern->getSourceRange(), Unexpanded, MLTAL,
741 /*FailOnPackProducingTemplates=*/false, Expand, RetainExpansion,
742 NumExpansions) ||
743 !Expand || RetainExpansion)
744 return std::nullopt;
745
746 if (NumExpansions && S.getLangOpts().BracketDepth < *NumExpansions) {
747 S.Diag(Pattern->getExprLoc(),
748 clang::diag::err_fold_expression_limit_exceeded)
749 << *NumExpansions << S.getLangOpts().BracketDepth
750 << Pattern->getSourceRange();
751 S.Diag(Pattern->getExprLoc(), diag::note_bracket_depth);
752 return std::nullopt;
753 }
754 return NumExpansions;
755}
756
757ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
758 const FoldExpandedConstraint &Constraint,
759 const MultiLevelTemplateArgumentList &MLTAL) {
760
761 bool Conjunction = Constraint.getFoldOperator() ==
763 unsigned EffectiveDetailEndIndex = Satisfaction.Details.size();
764
765 llvm::SmallVector<TemplateArgument> SubstitutedOuterMost;
766 // FIXME: Is PackSubstitutionIndex correct?
767 llvm::SaveAndRestore _(PackSubstitutionIndex, S.ArgPackSubstIndex);
768 std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs =
769 SubstitutionInTemplateArguments(
770 static_cast<const NormalizedConstraintWithParamMapping &>(Constraint),
771 MLTAL, SubstitutedOuterMost);
772 if (!SubstitutedArgs) {
773 Satisfaction.IsSatisfied = false;
774 return ExprError();
775 }
776
778 UnsignedOrNone NumExpansions =
779 EvaluateFoldExpandedConstraintSize(Constraint, *SubstitutedArgs);
780 if (!NumExpansions)
781 return ExprEmpty();
782
783 if (*NumExpansions == 0) {
784 Satisfaction.IsSatisfied = Conjunction;
785 return ExprEmpty();
786 }
787
788 for (unsigned I = 0; I < *NumExpansions; I++) {
789 Sema::ArgPackSubstIndexRAII SubstIndex(S, I);
790 Satisfaction.IsSatisfied = false;
791 Satisfaction.ContainsErrors = false;
793 ConstraintSatisfactionChecker(S, Template, TemplateNameLoc,
794 UnsignedOrNone(I), Satisfaction)
795 .Evaluate(Constraint.getNormalizedPattern(), *SubstitutedArgs);
796 if (Expr.isUsable()) {
797 if (Out.isUnset())
798 Out = Expr;
799 else
800 Out = BinaryOperator::Create(S.Context, Out.get(), Expr.get(),
801 Conjunction ? BinaryOperatorKind::BO_LAnd
802 : BinaryOperatorKind::BO_LOr,
804 Constraint.getBeginLoc(),
806 } else {
807 assert(!Satisfaction.IsSatisfied);
808 }
809 if (!Conjunction && Satisfaction.IsSatisfied) {
810 Satisfaction.Details.erase(Satisfaction.Details.begin() +
811 EffectiveDetailEndIndex,
812 Satisfaction.Details.end());
813 break;
814 }
815 if (Satisfaction.IsSatisfied != Conjunction)
816 return Out;
817 }
818
819 return Out;
820}
821
822ExprResult ConstraintSatisfactionChecker::Evaluate(
823 const FoldExpandedConstraint &Constraint,
824 const MultiLevelTemplateArgumentList &MLTAL) {
825
826 llvm::FoldingSetNodeID ID;
827 ID.AddPointer(Constraint.getPattern());
828 HashParameterMapping(S, MLTAL, ID, std::nullopt).VisitConstraint(Constraint);
829
830 if (auto Iter = S.UnsubstitutedConstraintSatisfactionCache.find(ID);
832
833 auto &Cached = Iter->second.Satisfaction;
834 Satisfaction.ContainsErrors = Cached.ContainsErrors;
835 Satisfaction.IsSatisfied = Cached.IsSatisfied;
836 Satisfaction.Details.insert(Satisfaction.Details.end(),
837 Cached.Details.begin(), Cached.Details.end());
838 return Iter->second.SubstExpr;
839 }
840
841 unsigned Size = Satisfaction.Details.size();
842
843 ExprResult E = EvaluateSlow(Constraint, MLTAL);
845 Cache.Satisfaction.ContainsErrors = Satisfaction.ContainsErrors;
846 Cache.Satisfaction.IsSatisfied = Satisfaction.IsSatisfied;
847 std::copy(Satisfaction.Details.begin() + Size, Satisfaction.Details.end(),
848 std::back_inserter(Cache.Satisfaction.Details));
849 Cache.SubstExpr = E;
850 S.UnsubstitutedConstraintSatisfactionCache.insert({ID, std::move(Cache)});
851 return E;
852}
853
854ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
855 const ConceptIdConstraint &Constraint,
856 const MultiLevelTemplateArgumentList &MLTAL, unsigned Size) {
857 const ConceptReference *ConceptId = Constraint.getConceptId();
858
859 llvm::SmallVector<TemplateArgument> SubstitutedOuterMost;
860 std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs =
861 SubstitutionInTemplateArguments(Constraint, MLTAL, SubstitutedOuterMost);
862
863 if (!SubstitutedArgs) {
864 Satisfaction.IsSatisfied = false;
865 // FIXME: diagnostics?
866 return ExprError();
867 }
868
869 Sema::SFINAETrap Trap(S);
871 S, Constraint.getPackSubstitutionIndex()
872 ? Constraint.getPackSubstitutionIndex()
873 : PackSubstitutionIndex);
874
875 const ASTTemplateArgumentListInfo *Ori =
876 ConceptId->getTemplateArgsAsWritten();
877 TemplateDeductionInfo Info(TemplateNameLoc);
880 const_cast<NamedDecl *>(Template), Info, Constraint.getSourceRange());
881
882 TemplateArgumentListInfo OutArgs(Ori->LAngleLoc, Ori->RAngleLoc);
883 if (S.SubstTemplateArguments(Ori->arguments(), *SubstitutedArgs, OutArgs) ||
884 Trap.hasErrorOccurred()) {
885 Satisfaction.IsSatisfied = false;
886 if (!Trap.hasErrorOccurred())
887 return ExprError();
888
891 Info.takeSFINAEDiagnostic(SubstDiag);
892 // FIXME: This is an unfortunate consequence of there
893 // being no serialization code for PartialDiagnostics and the fact
894 // that serializing them would likely take a lot more storage than
895 // just storing them as strings. We would still like, in the
896 // future, to serialize the proper PartialDiagnostic as serializing
897 // it as a string defeats the purpose of the diagnostic mechanism.
898 Satisfaction.Details.insert(
899 Satisfaction.Details.begin() + Size,
901 SubstDiag.first,
902 allocateStringFromConceptDiagnostic(S, SubstDiag.second)});
903 return ExprError();
904 }
905
906 CXXScopeSpec SS;
907 SS.Adopt(ConceptId->getNestedNameSpecifierLoc());
908
909 ExprResult SubstitutedConceptId = S.CheckConceptTemplateId(
910 SS, ConceptId->getTemplateKWLoc(), ConceptId->getConceptNameInfo(),
911 ConceptId->getFoundDecl(), ConceptId->getNamedConcept(), &OutArgs,
912 /*DoCheckConstraintSatisfaction=*/false);
913
914 if (SubstitutedConceptId.isInvalid() || Trap.hasErrorOccurred())
915 return ExprError();
916
917 if (Size != Satisfaction.Details.size()) {
918 Satisfaction.Details.insert(
919 Satisfaction.Details.begin() + Size,
921 SubstitutedConceptId.getAs<ConceptSpecializationExpr>()
923 }
924 return SubstitutedConceptId;
925}
926
927ExprResult ConstraintSatisfactionChecker::Evaluate(
928 const ConceptIdConstraint &Constraint,
929 const MultiLevelTemplateArgumentList &MLTAL) {
930
931 const ConceptReference *ConceptId = Constraint.getConceptId();
932
933 UnsignedOrNone OuterPackSubstIndex =
934 Constraint.getPackSubstitutionIndex()
935 ? Constraint.getPackSubstitutionIndex()
936 : PackSubstitutionIndex;
937
940 ConceptId->getNamedConcept(),
941 MLTAL.getInnermost(),
942 Constraint.getSourceRange());
943
944 unsigned Size = Satisfaction.Details.size();
945
946 ExprResult E = Evaluate(Constraint.getNormalizedConstraint(), MLTAL);
947
948 if (!E.isUsable()) {
949 Satisfaction.Details.insert(Satisfaction.Details.begin() + Size, ConceptId);
950 return E;
951 }
952
953 // ConceptIdConstraint is only relevant for diagnostics,
954 // so if the normalized constraint is satisfied, we should not
955 // substitute into the constraint.
956 if (Satisfaction.IsSatisfied)
957 return E;
958
959 llvm::FoldingSetNodeID ID;
960 ID.AddPointer(Constraint.getConceptId());
961 ID.AddInteger(OuterPackSubstIndex.toInternalRepresentation());
962 HashParameterMapping(S, MLTAL, ID, OuterPackSubstIndex)
963 .VisitConstraint(Constraint);
964
965 if (auto Iter = S.UnsubstitutedConstraintSatisfactionCache.find(ID);
967
968 auto &Cached = Iter->second.Satisfaction;
969 Satisfaction.ContainsErrors = Cached.ContainsErrors;
970 Satisfaction.IsSatisfied = Cached.IsSatisfied;
971 Satisfaction.Details.insert(Satisfaction.Details.begin() + Size,
972 Cached.Details.begin(), Cached.Details.end());
973 return Iter->second.SubstExpr;
974 }
975
976 ExprResult CE = EvaluateSlow(Constraint, MLTAL, Size);
977 if (CE.isInvalid())
978 return E;
980 Cache.Satisfaction.ContainsErrors = Satisfaction.ContainsErrors;
981 Cache.Satisfaction.IsSatisfied = Satisfaction.IsSatisfied;
982 std::copy(Satisfaction.Details.begin() + Size, Satisfaction.Details.end(),
983 std::back_inserter(Cache.Satisfaction.Details));
984 Cache.SubstExpr = CE;
985 S.UnsubstitutedConstraintSatisfactionCache.insert({ID, std::move(Cache)});
986 return CE;
987}
988
989ExprResult ConstraintSatisfactionChecker::Evaluate(
990 const CompoundConstraint &Constraint,
991 const MultiLevelTemplateArgumentList &MLTAL) {
992
993 unsigned EffectiveDetailEndIndex = Satisfaction.Details.size();
994
995 bool Conjunction =
997
998 ExprResult LHS = Evaluate(Constraint.getLHS(), MLTAL);
999
1000 if (Conjunction && (!Satisfaction.IsSatisfied || Satisfaction.ContainsErrors))
1001 return LHS;
1002
1003 if (!Conjunction && LHS.isUsable() && Satisfaction.IsSatisfied &&
1004 !Satisfaction.ContainsErrors)
1005 return LHS;
1006
1007 Satisfaction.ContainsErrors = false;
1008 Satisfaction.IsSatisfied = false;
1009
1010 ExprResult RHS = Evaluate(Constraint.getRHS(), MLTAL);
1011
1012 if (RHS.isUsable() && Satisfaction.IsSatisfied &&
1013 !Satisfaction.ContainsErrors)
1014 Satisfaction.Details.erase(Satisfaction.Details.begin() +
1015 EffectiveDetailEndIndex,
1016 Satisfaction.Details.end());
1017
1018 if (!LHS.isUsable())
1019 return RHS;
1020
1021 if (!RHS.isUsable())
1022 return LHS;
1023
1024 return BinaryOperator::Create(S.Context, LHS.get(), RHS.get(),
1025 Conjunction ? BinaryOperatorKind::BO_LAnd
1026 : BinaryOperatorKind::BO_LOr,
1028 Constraint.getBeginLoc(), FPOptionsOverride{});
1029}
1030
1031ExprResult ConstraintSatisfactionChecker::Evaluate(
1032 const NormalizedConstraint &Constraint,
1033 const MultiLevelTemplateArgumentList &MLTAL) {
1034 switch (Constraint.getKind()) {
1036 return Evaluate(static_cast<const AtomicConstraint &>(Constraint), MLTAL);
1037
1039 return Evaluate(static_cast<const FoldExpandedConstraint &>(Constraint),
1040 MLTAL);
1041
1043 return Evaluate(static_cast<const ConceptIdConstraint &>(Constraint),
1044 MLTAL);
1045
1047 return Evaluate(static_cast<const CompoundConstraint &>(Constraint), MLTAL);
1048 }
1049}
1050
1052 Sema &S, const NamedDecl *Template,
1053 ArrayRef<AssociatedConstraint> AssociatedConstraints,
1054 const MultiLevelTemplateArgumentList &TemplateArgsLists,
1055 SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction,
1056 Expr **ConvertedExpr, const ConceptReference *TopLevelConceptId = nullptr) {
1057
1058 if (ConvertedExpr)
1059 *ConvertedExpr = nullptr;
1060
1061 if (AssociatedConstraints.empty()) {
1062 Satisfaction.IsSatisfied = true;
1063 return false;
1064 }
1065
1066 if (TemplateArgsLists.isAnyArgInstantiationDependent()) {
1067 // No need to check satisfaction for dependent constraint expressions.
1068 Satisfaction.IsSatisfied = true;
1069 return false;
1070 }
1071
1073 if (TemplateArgsLists.getNumLevels() != 0)
1074 Args = TemplateArgsLists.getInnermost();
1075
1076 std::optional<Sema::InstantiatingTemplate> SynthesisContext;
1077 if (!TopLevelConceptId) {
1078 SynthesisContext.emplace(S, TemplateIDRange.getBegin(),
1080 const_cast<NamedDecl *>(Template), Args,
1081 TemplateIDRange);
1082 }
1083
1084 const NormalizedConstraint *C =
1085 S.getNormalizedAssociatedConstraints(Template, AssociatedConstraints);
1086 if (!C) {
1087 Satisfaction.IsSatisfied = false;
1088 return true;
1089 }
1090
1091 if (TopLevelConceptId)
1092 C = ConceptIdConstraint::Create(S.getASTContext(), TopLevelConceptId,
1093 const_cast<NormalizedConstraint *>(C),
1094 Template, /*CSE=*/nullptr,
1096
1097 ExprResult Res =
1098 ConstraintSatisfactionChecker(S, Template, TemplateIDRange.getBegin(),
1099 S.ArgPackSubstIndex, Satisfaction)
1100 .Evaluate(*C, TemplateArgsLists);
1101
1102 if (Res.isInvalid())
1103 return true;
1104
1105 if (Res.isUsable() && ConvertedExpr)
1106 *ConvertedExpr = Res.get();
1107
1108 return false;
1109}
1110
1113 ArrayRef<AssociatedConstraint> AssociatedConstraints,
1114 const MultiLevelTemplateArgumentList &TemplateArgsLists,
1115 SourceRange TemplateIDRange, ConstraintSatisfaction &OutSatisfaction,
1116 const ConceptReference *TopLevelConceptId, Expr **ConvertedExpr) {
1117 if (AssociatedConstraints.empty()) {
1118 OutSatisfaction.IsSatisfied = true;
1119 return false;
1120 }
1121 const auto *Template = Entity.dyn_cast<const NamedDecl *>();
1122 if (!Template) {
1123 return ::CheckConstraintSatisfaction(
1124 *this, nullptr, AssociatedConstraints, TemplateArgsLists,
1125 TemplateIDRange, OutSatisfaction, ConvertedExpr, TopLevelConceptId);
1126 }
1127 // Invalid templates could make their way here. Substituting them could result
1128 // in dependent expressions.
1129 if (Template->isInvalidDecl()) {
1130 OutSatisfaction.IsSatisfied = false;
1131 return true;
1132 }
1133
1134 // A list of the template argument list flattened in a predictible manner for
1135 // the purposes of caching. The ConstraintSatisfaction type is in AST so it
1136 // has no access to the MultiLevelTemplateArgumentList, so this has to happen
1137 // here.
1139 for (auto List : TemplateArgsLists)
1140 for (const TemplateArgument &Arg : List.Args)
1141 FlattenedArgs.emplace_back(Context.getCanonicalTemplateArgument(Arg));
1142
1143 const NamedDecl *Owner = Template;
1144 if (TopLevelConceptId)
1145 Owner = TopLevelConceptId->getNamedConcept();
1146
1147 llvm::FoldingSetNodeID ID;
1148 ConstraintSatisfaction::Profile(ID, Context, Owner, FlattenedArgs);
1149 void *InsertPos;
1150 if (auto *Cached = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos)) {
1151 OutSatisfaction = *Cached;
1152 return false;
1153 }
1154
1155 auto Satisfaction =
1156 std::make_unique<ConstraintSatisfaction>(Owner, FlattenedArgs);
1158 *this, Template, AssociatedConstraints, TemplateArgsLists,
1159 TemplateIDRange, *Satisfaction, ConvertedExpr, TopLevelConceptId)) {
1160 OutSatisfaction = std::move(*Satisfaction);
1161 return true;
1162 }
1163
1164 if (auto *Cached = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos)) {
1165 // The evaluation of this constraint resulted in us trying to re-evaluate it
1166 // recursively. This isn't really possible, except we try to form a
1167 // RecoveryExpr as a part of the evaluation. If this is the case, just
1168 // return the 'cached' version (which will have the same result), and save
1169 // ourselves the extra-insert. If it ever becomes possible to legitimately
1170 // recursively check a constraint, we should skip checking the 'inner' one
1171 // above, and replace the cached version with this one, as it would be more
1172 // specific.
1173 OutSatisfaction = *Cached;
1174 return false;
1175 }
1176
1177 // Else we can simply add this satisfaction to the list.
1178 OutSatisfaction = *Satisfaction;
1179 // We cannot use InsertPos here because CheckConstraintSatisfaction might have
1180 // invalidated it.
1181 // Note that entries of SatisfactionCache are deleted in Sema's destructor.
1182 SatisfactionCache.InsertNode(Satisfaction.release());
1183 return false;
1184}
1185
1187 const ConceptSpecializationExpr *ConstraintExpr,
1188 ConstraintSatisfaction &Satisfaction) {
1189
1191 Constraints.emplace_back(
1192 ConstraintExpr->getNamedConcept()->getConstraintExpr());
1193
1194 MultiLevelTemplateArgumentList MLTAL(ConstraintExpr->getNamedConcept(),
1195 ConstraintExpr->getTemplateArguments(),
1196 true);
1197
1199 ConstraintExpr->getNamedConcept(), Constraints, MLTAL,
1200 ConstraintExpr->getSourceRange(), Satisfaction,
1201 ConstraintExpr->getConceptReference());
1202}
1203
1204bool Sema::SetupConstraintScope(
1205 FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
1206 const MultiLevelTemplateArgumentList &MLTAL,
1208 assert(!isLambdaCallOperator(FD) &&
1209 "Use LambdaScopeForCallOperatorInstantiationRAII to handle lambda "
1210 "instantiations");
1211 if (FD->isTemplateInstantiation() && FD->getPrimaryTemplate()) {
1212 FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate();
1213 InstantiatingTemplate Inst(
1214 *this, FD->getPointOfInstantiation(),
1216 TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
1217 SourceRange());
1218 if (Inst.isInvalid())
1219 return true;
1220
1221 // addInstantiatedParametersToScope creates a map of 'uninstantiated' to
1222 // 'instantiated' parameters and adds it to the context. For the case where
1223 // this function is a template being instantiated NOW, we also need to add
1224 // the list of current template arguments to the list so that they also can
1225 // be picked out of the map.
1226 if (auto *SpecArgs = FD->getTemplateSpecializationArgs()) {
1227 MultiLevelTemplateArgumentList JustTemplArgs(FD, SpecArgs->asArray(),
1228 /*Final=*/false);
1229 if (addInstantiatedParametersToScope(
1230 FD, PrimaryTemplate->getTemplatedDecl(), Scope, JustTemplArgs))
1231 return true;
1232 }
1233
1234 // If this is a member function, make sure we get the parameters that
1235 // reference the original primary template.
1236 if (FunctionTemplateDecl *FromMemTempl =
1237 PrimaryTemplate->getInstantiatedFromMemberTemplate()) {
1238 if (addInstantiatedParametersToScope(FD, FromMemTempl->getTemplatedDecl(),
1239 Scope, MLTAL))
1240 return true;
1241 }
1242
1243 return false;
1244 }
1245
1248 FunctionDecl *InstantiatedFrom =
1252
1254 *this, FD->getPointOfInstantiation(),
1255 Sema::InstantiatingTemplate::ConstraintsCheck{}, InstantiatedFrom,
1256 TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
1257 SourceRange());
1258 if (Inst.isInvalid())
1259 return true;
1260
1261 // Case where this was not a template, but instantiated as a
1262 // child-function.
1263 if (addInstantiatedParametersToScope(FD, InstantiatedFrom, Scope, MLTAL))
1264 return true;
1265 }
1266
1267 return false;
1268}
1269
1270// This function collects all of the template arguments for the purposes of
1271// constraint-instantiation and checking.
1272std::optional<MultiLevelTemplateArgumentList>
1273Sema::SetupConstraintCheckingTemplateArgumentsAndScope(
1274 FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
1276 MultiLevelTemplateArgumentList MLTAL;
1277
1278 // Collect the list of template arguments relative to the 'primary' template.
1279 // We need the entire list, since the constraint is completely uninstantiated
1280 // at this point.
1281 MLTAL =
1283 /*Final=*/false, /*Innermost=*/std::nullopt,
1284 /*RelativeToPrimary=*/true,
1285 /*Pattern=*/nullptr,
1286 /*ForConstraintInstantiation=*/true);
1287 // Lambdas are handled by LambdaScopeForCallOperatorInstantiationRAII.
1288 if (isLambdaCallOperator(FD))
1289 return MLTAL;
1290 if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope))
1291 return std::nullopt;
1292
1293 return MLTAL;
1294}
1295
1297 ConstraintSatisfaction &Satisfaction,
1298 SourceLocation UsageLoc,
1299 bool ForOverloadResolution) {
1300 // Don't check constraints if the function is dependent. Also don't check if
1301 // this is a function template specialization, as the call to
1302 // CheckFunctionTemplateConstraints after this will check it
1303 // better.
1304 if (FD->isDependentContext() ||
1305 FD->getTemplatedKind() ==
1307 Satisfaction.IsSatisfied = true;
1308 return false;
1309 }
1310
1311 // A lambda conversion operator has the same constraints as the call operator
1312 // and constraints checking relies on whether we are in a lambda call operator
1313 // (and may refer to its parameters), so check the call operator instead.
1314 // Note that the declarations outside of the lambda should also be
1315 // considered. Turning on the 'ForOverloadResolution' flag results in the
1316 // LocalInstantiationScope not looking into its parents, but we can still
1317 // access Decls from the parents while building a lambda RAII scope later.
1318 if (const auto *MD = dyn_cast<CXXConversionDecl>(FD);
1319 MD && isLambdaConversionOperator(const_cast<CXXConversionDecl *>(MD)))
1320 return CheckFunctionConstraints(MD->getParent()->getLambdaCallOperator(),
1321 Satisfaction, UsageLoc,
1322 /*ShouldAddDeclsFromParentScope=*/true);
1323
1324 DeclContext *CtxToSave = const_cast<FunctionDecl *>(FD);
1325
1326 while (isLambdaCallOperator(CtxToSave) || FD->isTransparentContext()) {
1327 if (isLambdaCallOperator(CtxToSave))
1328 CtxToSave = CtxToSave->getParent()->getParent();
1329 else
1330 CtxToSave = CtxToSave->getNonTransparentContext();
1331 }
1332
1333 ContextRAII SavedContext{*this, CtxToSave};
1334 LocalInstantiationScope Scope(*this, !ForOverloadResolution);
1335 std::optional<MultiLevelTemplateArgumentList> MLTAL =
1336 SetupConstraintCheckingTemplateArgumentsAndScope(
1337 const_cast<FunctionDecl *>(FD), {}, Scope);
1338
1339 if (!MLTAL)
1340 return true;
1341
1342 Qualifiers ThisQuals;
1343 CXXRecordDecl *Record = nullptr;
1344 if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
1345 ThisQuals = Method->getMethodQualifiers();
1346 Record = const_cast<CXXRecordDecl *>(Method->getParent());
1347 }
1348 CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
1349
1351 *this, const_cast<FunctionDecl *>(FD), *MLTAL, Scope,
1352 ForOverloadResolution);
1353
1355 FD, FD->getTrailingRequiresClause(), *MLTAL,
1356 SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()),
1357 Satisfaction);
1358}
1359
1361 Sema &S, const Sema::TemplateCompareNewDeclInfo &DeclInfo,
1362 const Expr *ConstrExpr) {
1364 DeclInfo.getDecl(), DeclInfo.getDeclContext(), /*Final=*/false,
1365 /*Innermost=*/std::nullopt,
1366 /*RelativeToPrimary=*/true,
1367 /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true,
1368 /*SkipForSpecialization*/ false);
1369
1370 if (MLTAL.getNumSubstitutedLevels() == 0)
1371 return ConstrExpr;
1372
1373 Sema::SFINAETrap SFINAE(S);
1374
1376 S, DeclInfo.getLocation(),
1378 const_cast<NamedDecl *>(DeclInfo.getDecl()), SourceRange{});
1379 if (Inst.isInvalid())
1380 return nullptr;
1381
1382 // Set up a dummy 'instantiation' scope in the case of reference to function
1383 // parameters that the surrounding function hasn't been instantiated yet. Note
1384 // this may happen while we're comparing two templates' constraint
1385 // equivalence.
1386 std::optional<LocalInstantiationScope> ScopeForParameters;
1387 if (const NamedDecl *ND = DeclInfo.getDecl();
1388 ND && ND->isFunctionOrFunctionTemplate()) {
1389 ScopeForParameters.emplace(S, /*CombineWithOuterScope=*/true);
1390 const FunctionDecl *FD = ND->getAsFunction();
1392 Template && Template->getInstantiatedFromMemberTemplate())
1393 FD = Template->getInstantiatedFromMemberTemplate()->getTemplatedDecl();
1394 for (auto *PVD : FD->parameters()) {
1395 if (ScopeForParameters->getInstantiationOfIfExists(PVD))
1396 continue;
1397 if (!PVD->isParameterPack()) {
1398 ScopeForParameters->InstantiatedLocal(PVD, PVD);
1399 continue;
1400 }
1401 // This is hacky: we're mapping the parameter pack to a size-of-1 argument
1402 // to avoid building SubstTemplateTypeParmPackTypes for
1403 // PackExpansionTypes. The SubstTemplateTypeParmPackType node would
1404 // otherwise reference the AssociatedDecl of the template arguments, which
1405 // is, in this case, the template declaration.
1406 //
1407 // However, as we are in the process of comparing potential
1408 // re-declarations, the canonical declaration is the declaration itself at
1409 // this point. So if we didn't expand these packs, we would end up with an
1410 // incorrect profile difference because we will be profiling the
1411 // canonical types!
1412 //
1413 // FIXME: Improve the "no-transform" machinery in FindInstantiatedDecl so
1414 // that we can eliminate the Scope in the cases where the declarations are
1415 // not necessarily instantiated. It would also benefit the noexcept
1416 // specifier comparison.
1417 ScopeForParameters->MakeInstantiatedLocalArgPack(PVD);
1418 ScopeForParameters->InstantiatedLocalPackArg(PVD, PVD);
1419 }
1420 }
1421
1422 std::optional<Sema::CXXThisScopeRAII> ThisScope;
1423
1424 // See TreeTransform::RebuildTemplateSpecializationType. A context scope is
1425 // essential for having an injected class as the canonical type for a template
1426 // specialization type at the rebuilding stage. This guarantees that, for
1427 // out-of-line definitions, injected class name types and their equivalent
1428 // template specializations can be profiled to the same value, which makes it
1429 // possible that e.g. constraints involving C<Class<T>> and C<Class> are
1430 // perceived identical.
1431 std::optional<Sema::ContextRAII> ContextScope;
1432 const DeclContext *DC = [&] {
1433 if (!DeclInfo.getDecl())
1434 return DeclInfo.getDeclContext();
1435 return DeclInfo.getDecl()->getFriendObjectKind()
1436 ? DeclInfo.getLexicalDeclContext()
1437 : DeclInfo.getDeclContext();
1438 }();
1439 if (auto *RD = dyn_cast<CXXRecordDecl>(DC)) {
1440 ThisScope.emplace(S, const_cast<CXXRecordDecl *>(RD), Qualifiers());
1441 ContextScope.emplace(S, const_cast<DeclContext *>(cast<DeclContext>(RD)),
1442 /*NewThisContext=*/false);
1443 }
1444 EnterExpressionEvaluationContext UnevaluatedContext(
1448 const_cast<clang::Expr *>(ConstrExpr), MLTAL);
1449 if (SFINAE.hasErrorOccurred() || !SubstConstr.isUsable())
1450 return nullptr;
1451 return SubstConstr.get();
1452}
1453
1455 const Expr *OldConstr,
1457 const Expr *NewConstr) {
1458 if (OldConstr == NewConstr)
1459 return true;
1460 // C++ [temp.constr.decl]p4
1461 if (Old && !New.isInvalid() && !New.ContainsDecl(Old) &&
1462 Old->getLexicalDeclContext() != New.getLexicalDeclContext()) {
1463 if (const Expr *SubstConstr =
1465 OldConstr))
1466 OldConstr = SubstConstr;
1467 else
1468 return false;
1469 if (const Expr *SubstConstr =
1471 NewConstr))
1472 NewConstr = SubstConstr;
1473 else
1474 return false;
1475 }
1476
1477 llvm::FoldingSetNodeID ID1, ID2;
1478 OldConstr->Profile(ID1, Context, /*Canonical=*/true);
1479 NewConstr->Profile(ID2, Context, /*Canonical=*/true);
1480 return ID1 == ID2;
1481}
1482
1484 assert(FD->getFriendObjectKind() && "Must be a friend!");
1485
1486 // The logic for non-templates is handled in ASTContext::isSameEntity, so we
1487 // don't have to bother checking 'DependsOnEnclosingTemplate' for a
1488 // non-function-template.
1489 assert(FD->getDescribedFunctionTemplate() &&
1490 "Non-function templates don't need to be checked");
1491
1494
1495 unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
1496 for (const AssociatedConstraint &AC : ACs)
1497 if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth,
1498 AC.ConstraintExpr))
1499 return true;
1500
1501 return false;
1502}
1503
1505 TemplateDecl *TD, const MultiLevelTemplateArgumentList &TemplateArgsLists,
1506 SourceRange TemplateIDRange) {
1507 ConstraintSatisfaction Satisfaction;
1508 llvm::SmallVector<AssociatedConstraint, 3> AssociatedConstraints;
1509 TD->getAssociatedConstraints(AssociatedConstraints);
1510 if (CheckConstraintSatisfaction(TD, AssociatedConstraints, TemplateArgsLists,
1511 TemplateIDRange, Satisfaction))
1512 return true;
1513
1514 if (!Satisfaction.IsSatisfied) {
1515 SmallString<128> TemplateArgString;
1516 TemplateArgString = " ";
1517 TemplateArgString += getTemplateArgumentBindingsText(
1518 TD->getTemplateParameters(), TemplateArgsLists.getInnermost().data(),
1519 TemplateArgsLists.getInnermost().size());
1520
1521 Diag(TemplateIDRange.getBegin(),
1522 diag::err_template_arg_list_constraints_not_satisfied)
1524 << TemplateArgString << TemplateIDRange;
1525 DiagnoseUnsatisfiedConstraint(Satisfaction);
1526 return true;
1527 }
1528 return false;
1529}
1530
1532 Sema &SemaRef, SourceLocation PointOfInstantiation,
1534 ConstraintSatisfaction &Satisfaction) {
1536 Template->getAssociatedConstraints(TemplateAC);
1537 if (TemplateAC.empty()) {
1538 Satisfaction.IsSatisfied = true;
1539 return false;
1540 }
1541
1543
1544 FunctionDecl *FD = Template->getTemplatedDecl();
1545 // Collect the list of template arguments relative to the 'primary'
1546 // template. We need the entire list, since the constraint is completely
1547 // uninstantiated at this point.
1548
1550 {
1551 // getTemplateInstantiationArgs uses this instantiation context to find out
1552 // template arguments for uninstantiated functions.
1553 // We don't want this RAII object to persist, because there would be
1554 // otherwise duplicate diagnostic notes.
1556 SemaRef, PointOfInstantiation,
1558 PointOfInstantiation);
1559 if (Inst.isInvalid())
1560 return true;
1561 MLTAL = SemaRef.getTemplateInstantiationArgs(
1562 /*D=*/FD, FD,
1563 /*Final=*/false, /*Innermost=*/{}, /*RelativeToPrimary=*/true,
1564 /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true);
1565 }
1566
1567 Sema::ContextRAII SavedContext(SemaRef, FD);
1568 return SemaRef.CheckConstraintSatisfaction(
1569 Template, TemplateAC, MLTAL, PointOfInstantiation, Satisfaction);
1570}
1571
1573 SourceLocation PointOfInstantiation, FunctionDecl *Decl,
1574 ArrayRef<TemplateArgument> TemplateArgs,
1575 ConstraintSatisfaction &Satisfaction) {
1576 // In most cases we're not going to have constraints, so check for that first.
1577 FunctionTemplateDecl *Template = Decl->getPrimaryTemplate();
1578
1579 if (!Template)
1580 return ::CheckFunctionConstraintsWithoutInstantiation(
1581 *this, PointOfInstantiation, Decl->getDescribedFunctionTemplate(),
1582 TemplateArgs, Satisfaction);
1583
1584 // Note - code synthesis context for the constraints check is created
1585 // inside CheckConstraintsSatisfaction.
1587 Template->getAssociatedConstraints(TemplateAC);
1588 if (TemplateAC.empty()) {
1589 Satisfaction.IsSatisfied = true;
1590 return false;
1591 }
1592
1593 // Enter the scope of this instantiation. We don't use
1594 // PushDeclContext because we don't have a scope.
1595 Sema::ContextRAII savedContext(*this, Decl);
1597
1598 std::optional<MultiLevelTemplateArgumentList> MLTAL =
1599 SetupConstraintCheckingTemplateArgumentsAndScope(Decl, TemplateArgs,
1600 Scope);
1601
1602 if (!MLTAL)
1603 return true;
1604
1605 Qualifiers ThisQuals;
1606 CXXRecordDecl *Record = nullptr;
1607 if (auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
1608 ThisQuals = Method->getMethodQualifiers();
1609 Record = Method->getParent();
1610 }
1611
1612 CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
1613 LambdaScopeForCallOperatorInstantiationRAII LambdaScope(*this, Decl, *MLTAL,
1614 Scope);
1615
1616 return CheckConstraintSatisfaction(Template, TemplateAC, *MLTAL,
1617 PointOfInstantiation, Satisfaction);
1618}
1619
1622 bool First) {
1623 assert(!Req->isSatisfied() &&
1624 "Diagnose() can only be used on an unsatisfied requirement");
1625 switch (Req->getSatisfactionStatus()) {
1627 llvm_unreachable("Diagnosing a dependent requirement");
1628 break;
1630 auto *SubstDiag = Req->getExprSubstitutionDiagnostic();
1631 if (!SubstDiag->DiagMessage.empty())
1632 S.Diag(SubstDiag->DiagLoc,
1633 diag::note_expr_requirement_expr_substitution_error)
1634 << (int)First << SubstDiag->SubstitutedEntity
1635 << SubstDiag->DiagMessage;
1636 else
1637 S.Diag(SubstDiag->DiagLoc,
1638 diag::note_expr_requirement_expr_unknown_substitution_error)
1639 << (int)First << SubstDiag->SubstitutedEntity;
1640 break;
1641 }
1643 S.Diag(Req->getNoexceptLoc(), diag::note_expr_requirement_noexcept_not_met)
1644 << (int)First << Req->getExpr();
1645 break;
1647 auto *SubstDiag =
1649 if (!SubstDiag->DiagMessage.empty())
1650 S.Diag(SubstDiag->DiagLoc,
1651 diag::note_expr_requirement_type_requirement_substitution_error)
1652 << (int)First << SubstDiag->SubstitutedEntity
1653 << SubstDiag->DiagMessage;
1654 else
1655 S.Diag(
1656 SubstDiag->DiagLoc,
1657 diag::
1658 note_expr_requirement_type_requirement_unknown_substitution_error)
1659 << (int)First << SubstDiag->SubstitutedEntity;
1660 break;
1661 }
1663 ConceptSpecializationExpr *ConstraintExpr =
1665 S.DiagnoseUnsatisfiedConstraint(ConstraintExpr);
1666 break;
1667 }
1669 llvm_unreachable("We checked this above");
1670 }
1671}
1672
1675 bool First) {
1676 assert(!Req->isSatisfied() &&
1677 "Diagnose() can only be used on an unsatisfied requirement");
1678 switch (Req->getSatisfactionStatus()) {
1680 llvm_unreachable("Diagnosing a dependent requirement");
1681 return;
1683 auto *SubstDiag = Req->getSubstitutionDiagnostic();
1684 if (!SubstDiag->DiagMessage.empty())
1685 S.Diag(SubstDiag->DiagLoc, diag::note_type_requirement_substitution_error)
1686 << (int)First << SubstDiag->SubstitutedEntity
1687 << SubstDiag->DiagMessage;
1688 else
1689 S.Diag(SubstDiag->DiagLoc,
1690 diag::note_type_requirement_unknown_substitution_error)
1691 << (int)First << SubstDiag->SubstitutedEntity;
1692 return;
1693 }
1694 default:
1695 llvm_unreachable("Unknown satisfaction status");
1696 return;
1697 }
1698}
1699
1702 SourceLocation Loc, bool First) {
1703 if (Concept->getTemplateArgsAsWritten()->NumTemplateArgs == 1) {
1704 S.Diag(
1705 Loc,
1706 diag::
1707 note_single_arg_concept_specialization_constraint_evaluated_to_false)
1708 << (int)First
1709 << Concept->getTemplateArgsAsWritten()->arguments()[0].getArgument()
1710 << Concept->getNamedConcept();
1711 } else {
1712 S.Diag(Loc, diag::note_concept_specialization_constraint_evaluated_to_false)
1713 << (int)First << Concept;
1714 }
1715}
1716
1719 bool First, concepts::NestedRequirement *Req = nullptr);
1720
1723 bool First = true, concepts::NestedRequirement *Req = nullptr) {
1724 for (auto &Record : Records) {
1726 Loc = {};
1728 }
1729}
1730
1740
1742 const Expr *SubstExpr,
1743 bool First) {
1744 SubstExpr = SubstExpr->IgnoreParenImpCasts();
1745 if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(SubstExpr)) {
1746 switch (BO->getOpcode()) {
1747 // These two cases will in practice only be reached when using fold
1748 // expressions with || and &&, since otherwise the || and && will have been
1749 // broken down into atomic constraints during satisfaction checking.
1750 case BO_LOr:
1751 // Or evaluated to false - meaning both RHS and LHS evaluated to false.
1754 /*First=*/false);
1755 return;
1756 case BO_LAnd: {
1757 bool LHSSatisfied =
1758 BO->getLHS()->EvaluateKnownConstInt(S.Context).getBoolValue();
1759 if (LHSSatisfied) {
1760 // LHS is true, so RHS must be false.
1762 return;
1763 }
1764 // LHS is false
1766
1767 // RHS might also be false
1768 bool RHSSatisfied =
1769 BO->getRHS()->EvaluateKnownConstInt(S.Context).getBoolValue();
1770 if (!RHSSatisfied)
1772 /*First=*/false);
1773 return;
1774 }
1775 case BO_GE:
1776 case BO_LE:
1777 case BO_GT:
1778 case BO_LT:
1779 case BO_EQ:
1780 case BO_NE:
1781 if (BO->getLHS()->getType()->isIntegerType() &&
1782 BO->getRHS()->getType()->isIntegerType()) {
1783 Expr::EvalResult SimplifiedLHS;
1784 Expr::EvalResult SimplifiedRHS;
1785 BO->getLHS()->EvaluateAsInt(SimplifiedLHS, S.Context,
1787 /*InConstantContext=*/true);
1788 BO->getRHS()->EvaluateAsInt(SimplifiedRHS, S.Context,
1790 /*InConstantContext=*/true);
1791 if (!SimplifiedLHS.Diag && !SimplifiedRHS.Diag) {
1792 S.Diag(SubstExpr->getBeginLoc(),
1793 diag::note_atomic_constraint_evaluated_to_false_elaborated)
1794 << (int)First << SubstExpr
1795 << toString(SimplifiedLHS.Val.getInt(), 10)
1796 << BinaryOperator::getOpcodeStr(BO->getOpcode())
1797 << toString(SimplifiedRHS.Val.getInt(), 10);
1798 return;
1799 }
1800 }
1801 break;
1802
1803 default:
1804 break;
1805 }
1806 } else if (auto *RE = dyn_cast<RequiresExpr>(SubstExpr)) {
1807 // FIXME: RequiresExpr should store dependent diagnostics.
1808 for (concepts::Requirement *Req : RE->getRequirements())
1809 if (!Req->isDependent() && !Req->isSatisfied()) {
1810 if (auto *E = dyn_cast<concepts::ExprRequirement>(Req))
1812 else if (auto *T = dyn_cast<concepts::TypeRequirement>(Req))
1814 else
1817 break;
1818 }
1819 return;
1820 } else if (auto *CSE = dyn_cast<ConceptSpecializationExpr>(SubstExpr)) {
1821 // Drill down concept ids treated as atomic constraints
1823 return;
1824 } else if (auto *TTE = dyn_cast<TypeTraitExpr>(SubstExpr);
1825 TTE && TTE->getTrait() == clang::TypeTrait::BTT_IsDeducible) {
1826 assert(TTE->getNumArgs() == 2);
1827 S.Diag(SubstExpr->getSourceRange().getBegin(),
1828 diag::note_is_deducible_constraint_evaluated_to_false)
1829 << TTE->getArg(0)->getType() << TTE->getArg(1)->getType();
1830 return;
1831 }
1832
1833 S.Diag(SubstExpr->getSourceRange().getBegin(),
1834 diag::note_atomic_constraint_evaluated_to_false)
1835 << (int)First << SubstExpr;
1836 S.DiagnoseTypeTraitDetails(SubstExpr);
1837}
1838
1842 if (auto *Diag =
1843 Record
1844 .template dyn_cast<const ConstraintSubstitutionDiagnostic *>()) {
1845 if (Req)
1846 S.Diag(Diag->first, diag::note_nested_requirement_substitution_error)
1847 << (int)First << Req->getInvalidConstraintEntity() << Diag->second;
1848 else
1849 S.Diag(Diag->first, diag::note_substituted_constraint_expr_is_ill_formed)
1850 << Diag->second;
1851 return;
1852 }
1853 if (const auto *Concept = dyn_cast<const ConceptReference *>(Record)) {
1854 if (Loc.isInvalid())
1855 Loc = Concept->getBeginLoc();
1857 return;
1858 }
1861}
1862
1864 const ConstraintSatisfaction &Satisfaction, SourceLocation Loc,
1865 bool First) {
1866
1867 assert(!Satisfaction.IsSatisfied &&
1868 "Attempted to diagnose a satisfied constraint");
1869 ::DiagnoseUnsatisfiedConstraint(*this, Satisfaction.Details, Loc, First);
1870}
1871
1873 const ConceptSpecializationExpr *ConstraintExpr, bool First) {
1874
1875 const ASTConstraintSatisfaction &Satisfaction =
1876 ConstraintExpr->getSatisfaction();
1877
1878 assert(!Satisfaction.IsSatisfied &&
1879 "Attempted to diagnose a satisfied constraint");
1880
1881 ::DiagnoseUnsatisfiedConstraint(*this, Satisfaction.records(),
1882 ConstraintExpr->getBeginLoc(), First);
1883}
1884
1885namespace {
1886
1887class SubstituteParameterMappings {
1888 Sema &SemaRef;
1889
1890 const MultiLevelTemplateArgumentList *MLTAL;
1891 const ASTTemplateArgumentListInfo *ArgsAsWritten;
1892
1893 bool InFoldExpr;
1894
1895 SubstituteParameterMappings(Sema &SemaRef,
1896 const MultiLevelTemplateArgumentList *MLTAL,
1897 const ASTTemplateArgumentListInfo *ArgsAsWritten,
1898 bool InFoldExpr)
1899 : SemaRef(SemaRef), MLTAL(MLTAL), ArgsAsWritten(ArgsAsWritten),
1900 InFoldExpr(InFoldExpr) {}
1901
1902 void buildParameterMapping(NormalizedConstraintWithParamMapping &N);
1903
1904 bool substitute(NormalizedConstraintWithParamMapping &N);
1905
1906 bool substitute(ConceptIdConstraint &CC);
1907
1908public:
1909 SubstituteParameterMappings(Sema &SemaRef, bool InFoldExpr = false)
1910 : SemaRef(SemaRef), MLTAL(nullptr), ArgsAsWritten(nullptr),
1911 InFoldExpr(InFoldExpr) {}
1912
1913 bool substitute(NormalizedConstraint &N);
1914};
1915
1916void SubstituteParameterMappings::buildParameterMapping(
1918 TemplateParameterList *TemplateParams =
1919 cast<TemplateDecl>(N.getConstraintDecl())->getTemplateParameters();
1920
1921 llvm::SmallBitVector OccurringIndices(TemplateParams->size());
1922 llvm::SmallBitVector OccurringIndicesForSubsumption(TemplateParams->size());
1923
1926 static_cast<AtomicConstraint &>(N).getConstraintExpr(),
1927 /*OnlyDeduced=*/false,
1928 /*Depth=*/0, OccurringIndices);
1929
1931 static_cast<AtomicConstraint &>(N).getConstraintExpr(),
1932 /*Depth=*/0, OccurringIndicesForSubsumption);
1933
1934 } else if (N.getKind() ==
1937 static_cast<FoldExpandedConstraint &>(N).getPattern(),
1938 /*OnlyDeduced=*/false,
1939 /*Depth=*/0, OccurringIndices);
1941 auto *Args = static_cast<ConceptIdConstraint &>(N)
1942 .getConceptId()
1943 ->getTemplateArgsAsWritten();
1944 if (Args)
1945 SemaRef.MarkUsedTemplateParameters(Args->arguments(),
1946 /*Depth=*/0, OccurringIndices);
1947 }
1948 TemplateArgumentLoc *TempArgs =
1949 new (SemaRef.Context) TemplateArgumentLoc[OccurringIndices.count()];
1951 for (unsigned I = 0, J = 0, C = TemplateParams->size(); I != C; ++I) {
1952 SourceLocation Loc = ArgsAsWritten->NumTemplateArgs > I
1953 ? ArgsAsWritten->arguments()[I].getLocation()
1954 : SourceLocation();
1955 // FIXME: Investigate why we couldn't always preserve the SourceLoc. We
1956 // can't assert Loc.isValid() now.
1957 if (OccurringIndices[I]) {
1958 NamedDecl *Param = TemplateParams->begin()[I];
1959 new (&(TempArgs)[J]) TemplateArgumentLoc(
1960 SemaRef.getIdentityTemplateArgumentLoc(Param, Loc));
1961 UsedParams.push_back(Param);
1962 J++;
1963 }
1964 }
1965 auto *UsedList = TemplateParameterList::Create(
1966 SemaRef.Context, TemplateParams->getTemplateLoc(),
1967 TemplateParams->getLAngleLoc(), UsedParams,
1968 /*RAngleLoc=*/SourceLocation(),
1969 /*RequiresClause=*/nullptr);
1970 unsigned Size = OccurringIndices.count();
1972 std::move(OccurringIndices), std::move(OccurringIndicesForSubsumption),
1973 MutableArrayRef<TemplateArgumentLoc>{TempArgs, Size}, UsedList);
1974}
1975
1976bool SubstituteParameterMappings::substitute(
1978 if (!N.hasParameterMapping())
1979 buildParameterMapping(N);
1980
1981 SourceLocation InstLocBegin, InstLocEnd;
1982 llvm::ArrayRef Arguments = ArgsAsWritten->arguments();
1983 if (Arguments.empty()) {
1984 InstLocBegin = ArgsAsWritten->getLAngleLoc();
1985 InstLocEnd = ArgsAsWritten->getRAngleLoc();
1986 } else {
1987 auto SR = Arguments[0].getSourceRange();
1988 InstLocBegin = SR.getBegin();
1989 InstLocEnd = SR.getEnd();
1990 }
1992 SemaRef, InstLocBegin,
1994 const_cast<NamedDecl *>(N.getConstraintDecl()),
1995 {InstLocBegin, InstLocEnd});
1996 if (Inst.isInvalid())
1997 return true;
1998
1999 // TransformTemplateArguments is unable to preserve the source location of a
2000 // pack. The SourceLocation is necessary for the instantiation location.
2001 // FIXME: The BaseLoc will be used as the location of the pack expansion,
2002 // which is wrong.
2003 TemplateArgumentListInfo SubstArgs;
2005 N.getParameterMapping(), N.getBeginLoc(), *MLTAL, SubstArgs,
2006 /*BuildPackExpansionTypes=*/!InFoldExpr))
2007 return true;
2009 auto *TD =
2012 TD->getLocation(), SubstArgs,
2013 /*DefaultArguments=*/{},
2014 /*PartialTemplateArgs=*/false, CTAI))
2015 return true;
2016
2017 TemplateArgumentLoc *TempArgs =
2018 new (SemaRef.Context) TemplateArgumentLoc[CTAI.SugaredConverted.size()];
2019
2020 for (unsigned I = 0; I < CTAI.SugaredConverted.size(); ++I) {
2021 SourceLocation Loc;
2022 // If this is an empty pack, we have no corresponding SubstArgs.
2023 if (I < SubstArgs.size())
2024 Loc = SubstArgs.arguments()[I].getLocation();
2025
2026 TempArgs[I] = SemaRef.getTrivialTemplateArgumentLoc(
2027 CTAI.SugaredConverted[I], QualType(), Loc);
2028 }
2029
2030 MutableArrayRef<TemplateArgumentLoc> Mapping(TempArgs,
2031 CTAI.SugaredConverted.size());
2035 return false;
2036}
2037
2038bool SubstituteParameterMappings::substitute(ConceptIdConstraint &CC) {
2039 assert(CC.getConstraintDecl() && MLTAL && ArgsAsWritten);
2040
2041 if (substitute(static_cast<NormalizedConstraintWithParamMapping &>(CC)))
2042 return true;
2043
2044 auto *CSE = CC.getConceptSpecializationExpr();
2045 assert(CSE);
2046 assert(!CC.getBeginLoc().isInvalid());
2047
2048 SourceLocation InstLocBegin, InstLocEnd;
2049 if (llvm::ArrayRef Arguments = ArgsAsWritten->arguments();
2050 Arguments.empty()) {
2051 InstLocBegin = ArgsAsWritten->getLAngleLoc();
2052 InstLocEnd = ArgsAsWritten->getRAngleLoc();
2053 } else {
2054 auto SR = Arguments[0].getSourceRange();
2055 InstLocBegin = SR.getBegin();
2056 InstLocEnd = SR.getEnd();
2057 }
2058 // This is useful for name lookup across modules; see Sema::getLookupModules.
2060 SemaRef, InstLocBegin,
2062 const_cast<NamedDecl *>(CC.getConstraintDecl()),
2063 {InstLocBegin, InstLocEnd});
2064 if (Inst.isInvalid())
2065 return true;
2066
2068 // TransformTemplateArguments is unable to preserve the source location of a
2069 // pack. The SourceLocation is necessary for the instantiation location.
2070 // FIXME: The BaseLoc will be used as the location of the pack expansion,
2071 // which is wrong.
2072 const ASTTemplateArgumentListInfo *ArgsAsWritten =
2073 CSE->getTemplateArgsAsWritten();
2075 ArgsAsWritten->arguments(), CC.getBeginLoc(), *MLTAL, Out,
2076 /*BuildPackExpansionTypes=*/!InFoldExpr))
2077 return true;
2079 if (SemaRef.CheckTemplateArgumentList(CSE->getNamedConcept(),
2080 CSE->getConceptNameInfo().getLoc(), Out,
2081 /*DefaultArgs=*/{},
2082 /*PartialTemplateArgs=*/false, CTAI,
2083 /*UpdateArgsWithConversions=*/false))
2084 return true;
2085 auto TemplateArgs = *MLTAL;
2087 TemplateArgs.getAssociatedDecl(0).first, CTAI.SugaredConverted);
2088 return SubstituteParameterMappings(SemaRef, &TemplateArgs, ArgsAsWritten,
2089 InFoldExpr)
2090 .substitute(CC.getNormalizedConstraint());
2091}
2092
2093bool SubstituteParameterMappings::substitute(NormalizedConstraint &N) {
2094 switch (N.getKind()) {
2096 if (!MLTAL) {
2097 assert(!ArgsAsWritten);
2098 return false;
2099 }
2100 return substitute(static_cast<NormalizedConstraintWithParamMapping &>(N));
2101 }
2103 auto &FE = static_cast<FoldExpandedConstraint &>(N);
2104 if (!MLTAL) {
2105 llvm::SaveAndRestore _1(InFoldExpr, true);
2106 assert(!ArgsAsWritten);
2107 return substitute(FE.getNormalizedPattern());
2108 }
2109 Sema::ArgPackSubstIndexRAII _(SemaRef, std::nullopt);
2110 substitute(static_cast<NormalizedConstraintWithParamMapping &>(FE));
2111 return SubstituteParameterMappings(SemaRef, /*InFoldExpr=*/true)
2112 .substitute(FE.getNormalizedPattern());
2113 }
2115 auto &CC = static_cast<ConceptIdConstraint &>(N);
2116 if (MLTAL) {
2117 assert(ArgsAsWritten);
2118 return substitute(CC);
2119 }
2120 assert(!ArgsAsWritten);
2124 Concept, Concept->getLexicalDeclContext(),
2125 /*Final=*/true, CSE->getTemplateArguments(),
2126 /*RelativeToPrimary=*/true,
2127 /*Pattern=*/nullptr,
2128 /*ForConstraintInstantiation=*/true);
2129
2130 return SubstituteParameterMappings(
2131 SemaRef, &MLTAL, CSE->getTemplateArgsAsWritten(), InFoldExpr)
2132 .substitute(CC.getNormalizedConstraint());
2133 }
2135 auto &Compound = static_cast<CompoundConstraint &>(N);
2136 if (substitute(Compound.getLHS()))
2137 return true;
2138 return substitute(Compound.getRHS());
2139 }
2140 }
2141}
2142
2143} // namespace
2144
2145NormalizedConstraint *NormalizedConstraint::fromAssociatedConstraints(
2146 Sema &S, const NamedDecl *D, ArrayRef<AssociatedConstraint> ACs) {
2147 assert(ACs.size() != 0);
2148 auto *Conjunction =
2149 fromConstraintExpr(S, D, ACs[0].ConstraintExpr, ACs[0].ArgPackSubstIndex);
2150 if (!Conjunction)
2151 return nullptr;
2152 for (unsigned I = 1; I < ACs.size(); ++I) {
2153 auto *Next = fromConstraintExpr(S, D, ACs[I].ConstraintExpr,
2154 ACs[I].ArgPackSubstIndex);
2155 if (!Next)
2156 return nullptr;
2158 Conjunction, Next);
2159 }
2160 return Conjunction;
2161}
2162
2163NormalizedConstraint *NormalizedConstraint::fromConstraintExpr(
2164 Sema &S, const NamedDecl *D, const Expr *E, UnsignedOrNone SubstIndex) {
2165 assert(E != nullptr);
2166
2167 // C++ [temp.constr.normal]p1.1
2168 // [...]
2169 // - The normal form of an expression (E) is the normal form of E.
2170 // [...]
2171 E = E->IgnoreParenImpCasts();
2172
2173 llvm::FoldingSetNodeID ID;
2174 if (D && DiagRecursiveConstraintEval(S, ID, D, E)) {
2175 return nullptr;
2176 }
2177 SatisfactionStackRAII StackRAII(S, D, ID);
2178
2179 // C++2a [temp.param]p4:
2180 // [...] If T is not a pack, then E is E', otherwise E is (E' && ...).
2181 // Fold expression is considered atomic constraints per current wording.
2182 // See http://cplusplus.github.io/concepts-ts/ts-active.html#28
2183
2184 if (LogicalBinOp BO = E) {
2185 auto *LHS = fromConstraintExpr(S, D, BO.getLHS(), SubstIndex);
2186 if (!LHS)
2187 return nullptr;
2188 auto *RHS = fromConstraintExpr(S, D, BO.getRHS(), SubstIndex);
2189 if (!RHS)
2190 return nullptr;
2191
2193 S.Context, LHS, BO.isAnd() ? CCK_Conjunction : CCK_Disjunction, RHS);
2194 } else if (auto *CSE = dyn_cast<const ConceptSpecializationExpr>(E)) {
2195 NormalizedConstraint *SubNF;
2196 {
2197 Sema::InstantiatingTemplate Inst(
2198 S, CSE->getExprLoc(),
2199 Sema::InstantiatingTemplate::ConstraintNormalization{},
2200 // FIXME: improve const-correctness of InstantiatingTemplate
2201 const_cast<NamedDecl *>(D), CSE->getSourceRange());
2202 if (Inst.isInvalid())
2203 return nullptr;
2204 // C++ [temp.constr.normal]p1.1
2205 // [...]
2206 // The normal form of an id-expression of the form C<A1, A2, ..., AN>,
2207 // where C names a concept, is the normal form of the
2208 // constraint-expression of C, after substituting A1, A2, ..., AN for C’s
2209 // respective template parameters in the parameter mappings in each atomic
2210 // constraint. If any such substitution results in an invalid type or
2211 // expression, the program is ill-formed; no diagnostic is required.
2212 // [...]
2213
2214 // Use canonical declarations to merge ConceptDecls across
2215 // different modules.
2216 ConceptDecl *CD = CSE->getNamedConcept()->getCanonicalDecl();
2217 SubNF = NormalizedConstraint::fromAssociatedConstraints(
2218 S, CD, AssociatedConstraint(CD->getConstraintExpr(), SubstIndex));
2219
2220 if (!SubNF)
2221 return nullptr;
2222 }
2223
2225 CSE->getConceptReference(), SubNF, D,
2226 CSE, SubstIndex);
2227
2228 } else if (auto *FE = dyn_cast<const CXXFoldExpr>(E);
2229 FE && S.getLangOpts().CPlusPlus26 &&
2230 (FE->getOperator() == BinaryOperatorKind::BO_LAnd ||
2231 FE->getOperator() == BinaryOperatorKind::BO_LOr)) {
2232
2233 // Normalize fold expressions in C++26.
2234
2236 FE->getOperator() == BinaryOperatorKind::BO_LAnd
2239
2240 if (FE->getInit()) {
2241 auto *LHS = fromConstraintExpr(S, D, FE->getLHS(), SubstIndex);
2242 auto *RHS = fromConstraintExpr(S, D, FE->getRHS(), SubstIndex);
2243 if (!LHS || !RHS)
2244 return nullptr;
2245
2246 if (FE->isRightFold())
2248 FE->getPattern(), D, Kind, LHS);
2249 else
2251 FE->getPattern(), D, Kind, RHS);
2252
2254 S.getASTContext(), LHS,
2255 (FE->getOperator() == BinaryOperatorKind::BO_LAnd ? CCK_Conjunction
2256 : CCK_Disjunction),
2257 RHS);
2258 }
2259 auto *Sub = fromConstraintExpr(S, D, FE->getPattern(), SubstIndex);
2260 if (!Sub)
2261 return nullptr;
2263 D, Kind, Sub);
2264 }
2265 return AtomicConstraint::Create(S.getASTContext(), E, D, SubstIndex);
2266}
2267
2269 ConstrainedDeclOrNestedRequirement ConstrainedDeclOrNestedReq,
2270 ArrayRef<AssociatedConstraint> AssociatedConstraints) {
2271 if (!ConstrainedDeclOrNestedReq) {
2272 auto *Normalized = NormalizedConstraint::fromAssociatedConstraints(
2273 *this, nullptr, AssociatedConstraints);
2274 if (!Normalized ||
2275 SubstituteParameterMappings(*this).substitute(*Normalized))
2276 return nullptr;
2277
2278 return Normalized;
2279 }
2280
2281 // FIXME: ConstrainedDeclOrNestedReq is never a NestedRequirement!
2282 const NamedDecl *ND =
2283 ConstrainedDeclOrNestedReq.dyn_cast<const NamedDecl *>();
2284 auto CacheEntry = NormalizationCache.find(ConstrainedDeclOrNestedReq);
2285 if (CacheEntry == NormalizationCache.end()) {
2286 auto *Normalized = NormalizedConstraint::fromAssociatedConstraints(
2287 *this, ND, AssociatedConstraints);
2288 CacheEntry =
2289 NormalizationCache.try_emplace(ConstrainedDeclOrNestedReq, Normalized)
2290 .first;
2291 if (!Normalized ||
2292 SubstituteParameterMappings(*this).substitute(*Normalized))
2293 return nullptr;
2294 }
2295 return CacheEntry->second;
2296}
2297
2300
2301 // [C++26] [temp.constr.fold]
2302 // Two fold expanded constraints are compatible for subsumption
2303 // if their respective constraints both contain an equivalent unexpanded pack.
2304
2307 APacks);
2309 BPacks);
2310
2311 for (const UnexpandedParameterPack &APack : APacks) {
2312 auto ADI = getDepthAndIndex(APack);
2313 if (!ADI)
2314 continue;
2315 auto It = llvm::find_if(BPacks, [&](const UnexpandedParameterPack &BPack) {
2316 return getDepthAndIndex(BPack) == ADI;
2317 });
2318 if (It != BPacks.end())
2319 return true;
2320 }
2321 return false;
2322}
2323
2326 const NamedDecl *D2,
2328 bool &Result) {
2329#ifndef NDEBUG
2330 if (const auto *FD1 = dyn_cast<FunctionDecl>(D1)) {
2331 auto IsExpectedEntity = [](const FunctionDecl *FD) {
2333 return Kind == FunctionDecl::TK_NonTemplate ||
2335 };
2336 const auto *FD2 = dyn_cast<FunctionDecl>(D2);
2337 assert(IsExpectedEntity(FD1) && FD2 && IsExpectedEntity(FD2) &&
2338 "use non-instantiated function declaration for constraints partial "
2339 "ordering");
2340 }
2341#endif
2342
2343 if (AC1.empty()) {
2344 Result = AC2.empty();
2345 return false;
2346 }
2347 if (AC2.empty()) {
2348 // TD1 has associated constraints and TD2 does not.
2349 Result = true;
2350 return false;
2351 }
2352
2353 std::pair<const NamedDecl *, const NamedDecl *> Key{D1, D2};
2354 auto CacheEntry = SubsumptionCache.find(Key);
2355 if (CacheEntry != SubsumptionCache.end()) {
2356 Result = CacheEntry->second;
2357 return false;
2358 }
2359
2360 unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1, true);
2361 unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2, true);
2362
2363 for (size_t I = 0; I != AC1.size() && I != AC2.size(); ++I) {
2364 if (Depth2 > Depth1) {
2365 AC1[I].ConstraintExpr =
2366 AdjustConstraintDepth(*this, Depth2 - Depth1)
2367 .TransformExpr(const_cast<Expr *>(AC1[I].ConstraintExpr))
2368 .get();
2369 } else if (Depth1 > Depth2) {
2370 AC2[I].ConstraintExpr =
2371 AdjustConstraintDepth(*this, Depth1 - Depth2)
2372 .TransformExpr(const_cast<Expr *>(AC2[I].ConstraintExpr))
2373 .get();
2374 }
2375 }
2376
2377 SubsumptionChecker SC(*this);
2378 std::optional<bool> Subsumes = SC.Subsumes(D1, AC1, D2, AC2);
2379 if (!Subsumes) {
2380 // Normalization failed
2381 return true;
2382 }
2383 Result = *Subsumes;
2384 SubsumptionCache.try_emplace(Key, *Subsumes);
2385 return false;
2386}
2387
2391 if (isSFINAEContext())
2392 // No need to work here because our notes would be discarded.
2393 return false;
2394
2395 if (AC1.empty() || AC2.empty())
2396 return false;
2397
2398 const Expr *AmbiguousAtomic1 = nullptr, *AmbiguousAtomic2 = nullptr;
2399 auto IdenticalExprEvaluator = [&](const AtomicConstraint &A,
2400 const AtomicConstraint &B) {
2402 return false;
2403 const Expr *EA = A.getConstraintExpr(), *EB = B.getConstraintExpr();
2404 if (EA == EB)
2405 return true;
2406
2407 // Not the same source level expression - are the expressions
2408 // identical?
2409 llvm::FoldingSetNodeID IDA, IDB;
2410 EA->Profile(IDA, Context, /*Canonical=*/true);
2411 EB->Profile(IDB, Context, /*Canonical=*/true);
2412 if (IDA != IDB)
2413 return false;
2414
2415 AmbiguousAtomic1 = EA;
2416 AmbiguousAtomic2 = EB;
2417 return true;
2418 };
2419
2420 {
2421 // The subsumption checks might cause diagnostics
2422 SFINAETrap Trap(*this);
2423 auto *Normalized1 = getNormalizedAssociatedConstraints(D1, AC1);
2424 if (!Normalized1)
2425 return false;
2426
2427 auto *Normalized2 = getNormalizedAssociatedConstraints(D2, AC2);
2428 if (!Normalized2)
2429 return false;
2430
2431 SubsumptionChecker SC(*this);
2432
2433 bool Is1AtLeastAs2Normally = SC.Subsumes(Normalized1, Normalized2);
2434 bool Is2AtLeastAs1Normally = SC.Subsumes(Normalized2, Normalized1);
2435
2436 SubsumptionChecker SC2(*this, IdenticalExprEvaluator);
2437 bool Is1AtLeastAs2 = SC2.Subsumes(Normalized1, Normalized2);
2438 bool Is2AtLeastAs1 = SC2.Subsumes(Normalized2, Normalized1);
2439
2440 if (Is1AtLeastAs2 == Is1AtLeastAs2Normally &&
2441 Is2AtLeastAs1 == Is2AtLeastAs1Normally)
2442 // Same result - no ambiguity was caused by identical atomic expressions.
2443 return false;
2444 }
2445 // A different result! Some ambiguous atomic constraint(s) caused a difference
2446 assert(AmbiguousAtomic1 && AmbiguousAtomic2);
2447
2448 Diag(AmbiguousAtomic1->getBeginLoc(), diag::note_ambiguous_atomic_constraints)
2449 << AmbiguousAtomic1->getSourceRange();
2450 Diag(AmbiguousAtomic2->getBeginLoc(),
2451 diag::note_ambiguous_atomic_constraints_similar_expression)
2452 << AmbiguousAtomic2->getSourceRange();
2453 return true;
2454}
2455
2456//
2457//
2458// ------------------------ Subsumption -----------------------------------
2459//
2460//
2462 SubsumptionCallable Callable)
2463 : SemaRef(SemaRef), Callable(Callable), NextID(1) {}
2464
2465uint16_t SubsumptionChecker::getNewLiteralId() {
2466 assert((unsigned(NextID) + 1 < std::numeric_limits<uint16_t>::max()) &&
2467 "too many constraints!");
2468 return NextID++;
2469}
2470
2471auto SubsumptionChecker::find(const AtomicConstraint *Ori) -> Literal {
2472 auto &Elems = AtomicMap[Ori->getConstraintExpr()];
2473 // C++ [temp.constr.order] p2
2474 // - an atomic constraint A subsumes another atomic constraint B
2475 // if and only if the A and B are identical [...]
2476 //
2477 // C++ [temp.constr.atomic] p2
2478 // Two atomic constraints are identical if they are formed from the
2479 // same expression and the targets of the parameter mappings are
2480 // equivalent according to the rules for expressions [...]
2481
2482 // Because subsumption of atomic constraints is an identity
2483 // relationship that does not require further analysis
2484 // We cache the results such that if an atomic constraint literal
2485 // subsumes another, their literal will be the same
2486
2487 llvm::FoldingSetNodeID ID;
2488 ID.AddBoolean(Ori->hasParameterMapping());
2489 if (Ori->hasParameterMapping()) {
2490 const auto &Mapping = Ori->getParameterMapping();
2492 Ori->mappingOccurenceListForSubsumption();
2493 for (auto [Idx, TAL] : llvm::enumerate(Mapping)) {
2494 if (Indexes[Idx])
2495 SemaRef.getASTContext()
2496 .getCanonicalTemplateArgument(TAL.getArgument())
2497 .Profile(ID, SemaRef.getASTContext());
2498 }
2499 }
2500 auto It = Elems.find(ID);
2501 if (It == Elems.end()) {
2502 It = Elems
2503 .insert({ID,
2504 MappedAtomicConstraint{
2505 Ori, {getNewLiteralId(), Literal::Atomic}}})
2506 .first;
2507 ReverseMap[It->second.ID.Value] = Ori;
2508 }
2509 return It->getSecond().ID;
2510}
2511
2512auto SubsumptionChecker::find(const FoldExpandedConstraint *Ori) -> Literal {
2513 auto &Elems = FoldMap[Ori->getPattern()];
2514
2515 FoldExpendedConstraintKey K;
2516 K.Kind = Ori->getFoldOperator();
2517
2518 auto It = llvm::find_if(Elems, [&K](const FoldExpendedConstraintKey &Other) {
2519 return K.Kind == Other.Kind;
2520 });
2521 if (It == Elems.end()) {
2522 K.ID = {getNewLiteralId(), Literal::FoldExpanded};
2523 It = Elems.insert(Elems.end(), std::move(K));
2524 ReverseMap[It->ID.Value] = Ori;
2525 }
2526 return It->ID;
2527}
2528
2529auto SubsumptionChecker::CNF(const NormalizedConstraint &C) -> CNFFormula {
2530 return SubsumptionChecker::Normalize<CNFFormula>(C);
2531}
2532auto SubsumptionChecker::DNF(const NormalizedConstraint &C) -> DNFFormula {
2533 return SubsumptionChecker::Normalize<DNFFormula>(C);
2534}
2535
2536///
2537/// \brief SubsumptionChecker::Normalize
2538///
2539/// Normalize a formula to Conjunctive Normal Form or
2540/// Disjunctive normal form.
2541///
2542/// Each Atomic (and Fold Expanded) constraint gets represented by
2543/// a single id to reduce space.
2544///
2545/// To minimize risks of exponential blow up, if two atomic
2546/// constraints subsumes each other (same constraint and mapping),
2547/// they are represented by the same literal.
2548///
2549template <typename FormulaType>
2550FormulaType SubsumptionChecker::Normalize(const NormalizedConstraint &NC) {
2551 FormulaType Res;
2552
2553 auto Add = [&, this](Clause C) {
2554 // Sort each clause and remove duplicates for faster comparisons.
2555 llvm::sort(C);
2556 C.erase(llvm::unique(C), C.end());
2557 AddUniqueClauseToFormula(Res, std::move(C));
2558 };
2559
2560 switch (NC.getKind()) {
2561
2563 return {{find(&static_cast<const AtomicConstraint &>(NC))}};
2564
2566 return {{find(&static_cast<const FoldExpandedConstraint &>(NC))}};
2567
2569 return Normalize<FormulaType>(
2570 static_cast<const ConceptIdConstraint &>(NC).getNormalizedConstraint());
2571
2573 const auto &Compound = static_cast<const CompoundConstraint &>(NC);
2574 FormulaType Left, Right;
2575 SemaRef.runWithSufficientStackSpace(SourceLocation(), [&] {
2576 Left = Normalize<FormulaType>(Compound.getLHS());
2577 Right = Normalize<FormulaType>(Compound.getRHS());
2578 });
2579
2580 if (Compound.getCompoundKind() == FormulaType::Kind) {
2581 Res = std::move(Left);
2582 Res.reserve(Left.size() + Right.size());
2583 std::for_each(std::make_move_iterator(Right.begin()),
2584 std::make_move_iterator(Right.end()), Add);
2585 return Res;
2586 }
2587
2588 Res.reserve(Left.size() * Right.size());
2589 for (const auto &LTransform : Left) {
2590 for (const auto &RTransform : Right) {
2591 Clause Combined;
2592 Combined.reserve(LTransform.size() + RTransform.size());
2593 llvm::copy(LTransform, std::back_inserter(Combined));
2594 llvm::copy(RTransform, std::back_inserter(Combined));
2595 Add(std::move(Combined));
2596 }
2597 }
2598 return Res;
2599 }
2600 }
2601}
2602
2603void SubsumptionChecker::AddUniqueClauseToFormula(Formula &F, Clause C) {
2604 for (auto &Other : F) {
2605 if (llvm::equal(C, Other))
2606 return;
2607 }
2608 F.push_back(C);
2609}
2610
2612 const NamedDecl *DP, ArrayRef<AssociatedConstraint> P, const NamedDecl *DQ,
2614 const NormalizedConstraint *PNormalized =
2615 SemaRef.getNormalizedAssociatedConstraints(DP, P);
2616 if (!PNormalized)
2617 return std::nullopt;
2618
2619 const NormalizedConstraint *QNormalized =
2620 SemaRef.getNormalizedAssociatedConstraints(DQ, Q);
2621 if (!QNormalized)
2622 return std::nullopt;
2623
2624 return Subsumes(PNormalized, QNormalized);
2625}
2626
2628 const NormalizedConstraint *Q) {
2629
2630 DNFFormula DNFP = DNF(*P);
2631 CNFFormula CNFQ = CNF(*Q);
2632 return Subsumes(DNFP, CNFQ);
2633}
2634
2635bool SubsumptionChecker::Subsumes(const DNFFormula &PDNF,
2636 const CNFFormula &QCNF) {
2637 for (const auto &Pi : PDNF) {
2638 for (const auto &Qj : QCNF) {
2639 // C++ [temp.constr.order] p2
2640 // - [...] a disjunctive clause Pi subsumes a conjunctive clause Qj if
2641 // and only if there exists an atomic constraint Pia in Pi for which
2642 // there exists an atomic constraint, Qjb, in Qj such that Pia
2643 // subsumes Qjb.
2644 if (!DNFSubsumes(Pi, Qj))
2645 return false;
2646 }
2647 }
2648 return true;
2649}
2650
2651bool SubsumptionChecker::DNFSubsumes(const Clause &P, const Clause &Q) {
2652
2653 return llvm::any_of(P, [&](Literal LP) {
2654 return llvm::any_of(Q, [this, LP](Literal LQ) { return Subsumes(LP, LQ); });
2655 });
2656}
2657
2659 const FoldExpandedConstraint *B) {
2660 std::pair<const FoldExpandedConstraint *, const FoldExpandedConstraint *> Key{
2661 A, B};
2662
2663 auto It = FoldSubsumptionCache.find(Key);
2664 if (It == FoldSubsumptionCache.end()) {
2665 // C++ [temp.constr.order]
2666 // a fold expanded constraint A subsumes another fold expanded
2667 // constraint B if they are compatible for subsumption, have the same
2668 // fold-operator, and the constraint of A subsumes that of B.
2669 bool DoesSubsume =
2670 A->getFoldOperator() == B->getFoldOperator() &&
2673 It = FoldSubsumptionCache.try_emplace(std::move(Key), DoesSubsume).first;
2674 }
2675 return It->second;
2676}
2677
2678bool SubsumptionChecker::Subsumes(Literal A, Literal B) {
2679 if (A.Kind != B.Kind)
2680 return false;
2681 switch (A.Kind) {
2682 case Literal::Atomic:
2683 if (!Callable)
2684 return A.Value == B.Value;
2685 return Callable(
2686 *static_cast<const AtomicConstraint *>(ReverseMap[A.Value]),
2687 *static_cast<const AtomicConstraint *>(ReverseMap[B.Value]));
2688 case Literal::FoldExpanded:
2689 return Subsumes(
2690 static_cast<const FoldExpandedConstraint *>(ReverseMap[A.Value]),
2691 static_cast<const FoldExpandedConstraint *>(ReverseMap[B.Value]));
2692 }
2693 llvm_unreachable("unknown literal kind");
2694}
This file provides AST data structures related to concepts.
This file provides some common utility functions for processing Lambda related AST Constructs.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines Expressions and AST nodes for C++2a concepts.
static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E)
FormatToken * Next
The next token in the unwrapped line.
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
llvm::MachO::Records Records
Definition MachO.h:40
llvm::MachO::Record Record
Definition MachO.h:31
Defines and computes precedence levels for binary/ternary operators.
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
static void diagnoseUnsatisfiedConstraintExpr(Sema &S, const UnsatisfiedConstraintRecord &Record, SourceLocation Loc, bool First, concepts::NestedRequirement *Req=nullptr)
static void DiagnoseUnsatisfiedConstraint(Sema &S, ArrayRef< UnsatisfiedConstraintRecord > Records, SourceLocation Loc, bool First=true, concepts::NestedRequirement *Req=nullptr)
static const Expr * SubstituteConstraintExpressionWithoutSatisfaction(Sema &S, const Sema::TemplateCompareNewDeclInfo &DeclInfo, const Expr *ConstrExpr)
static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S, const Expr *SubstExpr, bool First)
static bool DiagRecursiveConstraintEval(Sema &S, llvm::FoldingSetNodeID &ID, const NamedDecl *Templ, const Expr *E, const MultiLevelTemplateArgumentList *MLTAL=nullptr)
static bool CheckConstraintSatisfaction(Sema &S, const NamedDecl *Template, ArrayRef< AssociatedConstraint > AssociatedConstraints, const MultiLevelTemplateArgumentList &TemplateArgsLists, SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction, Expr **ConvertedExpr, const ConceptReference *TopLevelConceptId=nullptr)
static void diagnoseUnsatisfiedRequirement(Sema &S, concepts::ExprRequirement *Req, bool First)
static void diagnoseUnsatisfiedConceptIdExpr(Sema &S, const ConceptReference *Concept, SourceLocation Loc, bool First)
static bool CheckFunctionConstraintsWithoutInstantiation(Sema &SemaRef, SourceLocation PointOfInstantiation, FunctionTemplateDecl *Template, ArrayRef< TemplateArgument > TemplateArgs, ConstraintSatisfaction &Satisfaction)
static unsigned CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND, bool SkipForSpecialization=false)
APSInt & getInt()
Definition APValue.h:489
bool isInt() const
Definition APValue.h:467
TemplateArgument getCanonicalTemplateArgument(const TemplateArgument &Arg) const
Retrieve the "canonical" template argument.
CanQualType BoolTy
llvm::StringRef backupStr(llvm::StringRef S) const
Definition ASTContext.h:854
bool isUnset() const
Definition Ownership.h:168
PtrTy get() const
Definition Ownership.h:171
bool isInvalid() const
Definition Ownership.h:167
bool isUsable() const
Definition Ownership.h:169
const Expr * getConstraintExpr() const
static AtomicConstraint * Create(ASTContext &Ctx, const Expr *ConstraintExpr, const NamedDecl *ConstraintDecl, UnsignedOrNone PackIndex)
AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*, __atomic_load,...
Definition Expr.h:6814
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Expr.h:6945
A builtin binary operation expression such as "x + y" or "x <= y".
Definition Expr.h:3972
static OverloadedOperatorKind getOverloadedOperator(Opcode Opc)
Retrieve the overloaded operator kind that corresponds to the given binary opcode.
Definition Expr.cpp:2175
StringRef getOpcodeStr() const
Definition Expr.h:4038
static BinaryOperator * Create(const ASTContext &C, Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc, FPOptionsOverride FPFeatures)
Definition Expr.cpp:4979
static Opcode getOverloadedOpcode(OverloadedOperatorKind OO)
Retrieve the binary opcode that corresponds to the given overloaded operator.
Definition Expr.cpp:2137
Represents a C++ conversion function within a class.
Definition DeclCXX.h:2943
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
Represents a C++ nested-name-specifier or a global scope specifier.
Definition DeclSpec.h:73
void Adopt(NestedNameSpecifierLoc Other)
Adopt an existing nested-name-specifier (with source-range information).
Definition DeclSpec.cpp:103
const NormalizedConstraint & getLHS() const
static CompoundConstraint * CreateConjunction(ASTContext &Ctx, NormalizedConstraint *LHS, NormalizedConstraint *RHS)
CompoundConstraintKind getCompoundKind() const
const NormalizedConstraint & getRHS() const
static CompoundConstraint * Create(ASTContext &Ctx, NormalizedConstraint *LHS, CompoundConstraintKind CCK, NormalizedConstraint *RHS)
Declaration of a C++20 concept.
Expr * getConstraintExpr() const
ConceptDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
const NormalizedConstraint & getNormalizedConstraint() const
const ConceptSpecializationExpr * getConceptSpecializationExpr() const
static ConceptIdConstraint * Create(ASTContext &Ctx, const ConceptReference *ConceptId, NormalizedConstraint *SubConstraint, const NamedDecl *ConstraintDecl, const ConceptSpecializationExpr *CSE, UnsignedOrNone PackIndex)
const ConceptReference * getConceptId() const
A reference to a concept and its template args, as it appears in the code.
Definition ASTConcept.h:130
const NestedNameSpecifierLoc & getNestedNameSpecifierLoc() const
Definition ASTConcept.h:170
NamedDecl * getFoundDecl() const
Definition ASTConcept.h:197
const DeclarationNameInfo & getConceptNameInfo() const
Definition ASTConcept.h:174
SourceLocation getBeginLoc() const LLVM_READONLY
const ASTTemplateArgumentListInfo * getTemplateArgsAsWritten() const
Definition ASTConcept.h:203
TemplateDecl * getNamedConcept() const
Definition ASTConcept.h:201
SourceLocation getTemplateKWLoc() const
Definition ASTConcept.h:180
Represents the specialization of a concept - evaluates to a prvalue of type bool.
SourceLocation getBeginLoc() const LLVM_READONLY
SourceLocation getExprLoc() const LLVM_READONLY
ArrayRef< TemplateArgument > getTemplateArguments() const
const ASTTemplateArgumentListInfo * getTemplateArgsAsWritten() const
ConceptReference * getConceptReference() const
const ASTConstraintSatisfaction & getSatisfaction() const
Get elaborated satisfaction info about the template arguments' satisfaction of the named concept.
ConceptDecl * getNamedConcept() const
The result of a constraint satisfaction check, containing the necessary information to diagnose an un...
Definition ASTConcept.h:47
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C)
Definition ASTConcept.h:69
llvm::SmallVector< UnsatisfiedConstraintRecord, 4 > Details
The substituted constraint expr, if the template arguments could be substituted into them,...
Definition ASTConcept.h:67
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition DeclBase.h:1449
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition DeclBase.h:2109
bool isTransparentContext() const
isTransparentContext - Determines whether this context is a "transparent" context,...
bool isDependentContext() const
Determines whether this context is dependent on a template parameter.
DeclContext * getNonTransparentContext()
ValueDecl * getDecl()
Definition Expr.h:1338
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
FriendObjectKind getFriendObjectKind() const
Determines whether this declaration is the object of a friend declaration and, if so,...
Definition DeclBase.h:1226
bool isFunctionOrFunctionTemplate() const
Whether this declaration is a function or function template.
Definition DeclBase.h:1119
FunctionDecl * getAsFunction() LLVM_READONLY
Returns the function itself, or the templated function if this is a function template.
Definition DeclBase.cpp:251
SourceLocation getLocation() const
Definition DeclBase.h:439
DeclContext * getLexicalDeclContext()
getLexicalDeclContext - The declaration context where this Decl was lexically declared (LexicalDC).
Definition DeclBase.h:918
const AssociatedConstraint & getTrailingRequiresClause() const
Get the constraint-expression introduced by the trailing requires-clause in the function/member decla...
Definition Decl.h:855
RAII object that enters a new expression evaluation context.
This represents one expression.
Definition Expr.h:112
@ SE_NoSideEffects
Strictly evaluate the expression.
Definition Expr.h:671
bool isValueDependent() const
Determines whether the value of this expression depends on.
Definition Expr.h:177
bool isTypeDependent() const
Determines whether the type of this expression depends on.
Definition Expr.h:194
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition Expr.cpp:3085
bool containsErrors() const
Whether this expression contains subexpressions which had errors.
Definition Expr.h:246
bool isPRValue() const
Definition Expr.h:285
bool EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx, ConstantExprKind Kind=ConstantExprKind::Normal) const
Evaluate an expression that is required to be a constant expression.
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:273
QualType getType() const
Definition Expr.h:144
Represents difference between two FPOptions values.
static bool AreCompatibleForSubsumption(const FoldExpandedConstraint &A, const FoldExpandedConstraint &B)
FoldOperatorKind getFoldOperator() const
const Expr * getPattern() const
static FoldExpandedConstraint * Create(ASTContext &Ctx, const Expr *Pattern, const NamedDecl *ConstraintDecl, FoldOperatorKind OpKind, NormalizedConstraint *Constraint)
const NormalizedConstraint & getNormalizedPattern() const
Represents a function declaration or definition.
Definition Decl.h:2000
FunctionTemplateDecl * getDescribedFunctionTemplate() const
Retrieves the function template that is described by this function declaration.
Definition Decl.cpp:4181
SourceLocation getPointOfInstantiation() const
Retrieve the (first) point of instantiation of a function template specialization or a member of a cl...
Definition Decl.cpp:4502
ArrayRef< ParmVarDecl * > parameters() const
Definition Decl.h:2774
FunctionTemplateDecl * getPrimaryTemplate() const
Retrieve the primary template that this function template specialization either specializes or was in...
Definition Decl.cpp:4301
const TemplateArgumentList * getTemplateSpecializationArgs() const
Retrieve the template arguments used to produce this function template specialization from the primar...
Definition Decl.cpp:4317
bool isTemplateInstantiation() const
Determines if the given function was instantiated from a function template.
Definition Decl.cpp:4245
TemplatedKind
The kind of templated function a FunctionDecl can be.
Definition Decl.h:2005
@ TK_FunctionTemplateSpecialization
Definition Decl.h:2016
TemplatedKind getTemplatedKind() const
What kind of templated function this is.
Definition Decl.cpp:4132
FunctionDecl * getInstantiatedFromDecl() const
Definition Decl.cpp:4205
FunctionDecl * getInstantiatedFromMemberFunction() const
If this function is an instantiation of a member function of a class template specialization,...
Definition Decl.cpp:4153
Declaration of a template function.
FunctionDecl * getTemplatedDecl() const
Get the underlying function declaration of the template.
FunctionTemplateDecl * getInstantiatedFromMemberTemplate() const
static ImplicitCastExpr * Create(const ASTContext &Context, QualType T, CastKind Kind, Expr *Operand, const CXXCastPath *BasePath, ExprValueKind Cat, FPOptionsOverride FPO)
Definition Expr.cpp:2068
const TypeClass * getTypePtr() const
Definition TypeLoc.h:531
A stack-allocated class that identifies which local variable declaration instantiations are present i...
Definition Template.h:369
Data structure that captures multiple levels of template argument lists for use in template instantia...
Definition Template.h:76
const ArgList & getInnermost() const
Retrieve the innermost template argument list.
Definition Template.h:269
unsigned getNumLevels() const
Determine the number of levels in this template argument list.
Definition Template.h:123
unsigned getNumSubstitutedLevels() const
Determine the number of substituted levels in this template argument list.
Definition Template.h:129
void replaceOutermostTemplateArguments(Decl *AssociatedDecl, ArgList Args)
Definition Template.h:251
const ArgList & getOutermost() const
Retrieve the outermost template argument list.
Definition Template.h:273
This represents a decl that may have a name.
Definition Decl.h:274
unsigned getPosition() const
Get the position of the template parameter within its parameter list.
bool isParameterPack() const
Whether this parameter is a non-type template parameter pack.
unsigned getDepth() const
Get the nesting depth of the template parameter.
UnsignedOrNone getPackSubstitutionIndex() const
const NamedDecl * getConstraintDecl() const
bool hasMatchingParameterMapping(ASTContext &C, const NormalizedConstraint &Other) const
const OccurenceList & mappingOccurenceList() const
const OccurenceList & mappingOccurenceListForSubsumption() const
TemplateParameterList * getUsedTemplateParamList() const
llvm::MutableArrayRef< TemplateArgumentLoc > getParameterMapping() const
void updateParameterMapping(OccurenceList Indexes, OccurenceList IndexesForSubsumption, llvm::MutableArrayRef< TemplateArgumentLoc > Args, TemplateParameterList *ParamList)
A (possibly-)qualified type.
Definition TypeBase.h:937
The collection of all-type qualifiers we support.
Definition TypeBase.h:331
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
Scope - A scope is a transient data structure that is used while parsing the program.
Definition Scope.h:41
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, bool DeferHint=false)
Emit a diagnostic.
Definition SemaBase.cpp:61
PartialDiagnostic PDiag(unsigned DiagID=0)
Build a partial diagnostic.
Definition SemaBase.cpp:33
RAII object used to change the argument pack substitution index within a Sema object.
Definition Sema.h:13552
RAII object used to temporarily allow the C++ 'this' expression to be used, with the given qualifiers...
Definition Sema.h:8401
A RAII object to temporarily push a declaration context.
Definition Sema.h:3476
RAII class used to determine whether SFINAE has trapped any errors that occur during template argumen...
Definition Sema.h:12392
bool hasErrorOccurred() const
Determine whether any SFINAE errors have been trapped.
Definition Sema.h:12425
SourceLocation getLocation() const
Definition Sema.h:12166
const DeclContext * getDeclContext() const
Definition Sema.h:12162
const NamedDecl * getDecl() const
Definition Sema.h:12154
const DeclContext * getLexicalDeclContext() const
Definition Sema.h:12158
Sema - This implements semantic analysis and AST building for C.
Definition Sema.h:854
TemplateArgumentLoc getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, QualType NTTPType, SourceLocation Loc, NamedDecl *TemplateParam=nullptr)
Allocate a TemplateArgumentLoc where all locations have been initialized to the given location.
llvm::DenseMap< llvm::FoldingSetNodeID, UnsubstitutedConstraintSatisfactionCacheResult > UnsubstitutedConstraintSatisfactionCache
Cache the satisfaction of an atomic constraint.
Definition Sema.h:14888
ASTContext & Context
Definition Sema.h:1283
bool ConstraintExpressionDependsOnEnclosingTemplate(const FunctionDecl *Friend, unsigned TemplateDepth, const Expr *Constraint)
void MarkUsedTemplateParametersForSubsumptionParameterMapping(const Expr *E, unsigned Depth, llvm::SmallBitVector &Used)
Mark which template parameters are named in a given expression.
DiagnosticsEngine & getDiagnostics() const
Definition Sema.h:922
void DiagnoseTypeTraitDetails(const Expr *E)
If E represents a built-in type trait, or a known standard type trait, try to print more information ...
ExprResult SubstConstraintExprWithoutSatisfaction(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs)
bool CheckConstraintExpression(const Expr *CE, Token NextToken=Token(), bool *PossibleNonPrimary=nullptr, bool IsTrailingRequiresClause=false)
Check whether the given expression is a valid constraint expression.
ASTContext & getASTContext() const
Definition Sema.h:925
ExprResult CheckConceptTemplateId(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &ConceptNameInfo, NamedDecl *FoundDecl, TemplateDecl *NamedConcept, const TemplateArgumentListInfo *TemplateArgs, bool DoCheckConstraintSatisfaction=true)
llvm::PointerUnion< const NamedDecl *, const concepts::NestedRequirement * > ConstrainedDeclOrNestedRequirement
Definition Sema.h:14747
bool SubstTemplateArguments(ArrayRef< TemplateArgumentLoc > Args, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateArgumentListInfo &Outputs)
bool CheckConstraintSatisfaction(ConstrainedDeclOrNestedRequirement Entity, ArrayRef< AssociatedConstraint > AssociatedConstraints, const MultiLevelTemplateArgumentList &TemplateArgLists, SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction, const ConceptReference *TopLevelConceptId=nullptr, Expr **ConvertedExpr=nullptr)
Check whether the given list of constraint expressions are satisfied (as if in a 'conjunction') given...
const NormalizedConstraint * getNormalizedAssociatedConstraints(ConstrainedDeclOrNestedRequirement Entity, ArrayRef< AssociatedConstraint > AssociatedConstraints)
bool FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD)
bool EnsureTemplateArgumentListConstraints(TemplateDecl *Template, const MultiLevelTemplateArgumentList &TemplateArgs, SourceRange TemplateIDRange)
Ensure that the given template arguments satisfy the constraints associated with the given template,...
const LangOptions & getLangOpts() const
Definition Sema.h:918
@ ReuseLambdaContextDecl
Definition Sema.h:6978
void collectUnexpandedParameterPacks(TemplateArgument Arg, SmallVectorImpl< UnexpandedParameterPack > &Unexpanded)
Collect the set of unexpanded parameter packs within the given template argument.
bool AreConstraintExpressionsEqual(const NamedDecl *Old, const Expr *OldConstr, const TemplateCompareNewDeclInfo &New, const Expr *NewConstr)
sema::FunctionScopeInfo * getCurFunction() const
Definition Sema.h:1314
std::optional< sema::TemplateDeductionInfo * > isSFINAEContext() const
Determines whether we are currently in a context where template argument substitution failures are no...
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(const NamedDecl *D, const DeclContext *DC=nullptr, bool Final=false, std::optional< ArrayRef< TemplateArgument > > Innermost=std::nullopt, bool RelativeToPrimary=false, const FunctionDecl *Pattern=nullptr, bool ForConstraintInstantiation=false, bool SkipForSpecialization=false, bool ForDefaultArgumentSubstitution=false)
Retrieve the template argument list(s) that should be used to instantiate the definition of the given...
void DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction &Satisfaction, SourceLocation Loc={}, bool First=true)
Emit diagnostics explaining why a constraint expression was deemed unsatisfied.
bool CheckFunctionConstraints(const FunctionDecl *FD, ConstraintSatisfaction &Satisfaction, SourceLocation UsageLoc=SourceLocation(), bool ForOverloadResolution=false)
Check whether the given function decl's trailing requires clause is satisfied, if any.
TemplateNameKindForDiagnostics getTemplateNameKindForDiagnostics(TemplateName Name)
UnsignedOrNone ArgPackSubstIndex
The current index into pack expansion arguments that will be used for substitution of parameter packs...
Definition Sema.h:13546
void PushSatisfactionStackEntry(const NamedDecl *D, const llvm::FoldingSetNodeID &ID)
Definition Sema.h:14707
void PopSatisfactionStackEntry()
Definition Sema.h:14713
ExprResult SubstConstraintExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs)
void MarkUsedTemplateParameters(const Expr *E, bool OnlyDeduced, unsigned Depth, llvm::SmallBitVector &Used)
Mark which template parameters are used in a given expression.
@ ConstantEvaluated
The current context is "potentially evaluated" in C++11 terms, but the expression is evaluated at com...
Definition Sema.h:6696
@ Unevaluated
The current expression and its subexpressions occur within an unevaluated operand (C++11 [expr]p7),...
Definition Sema.h:6675
bool SatisfactionStackContains(const NamedDecl *D, const llvm::FoldingSetNodeID &ID) const
Definition Sema.h:14715
bool CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, SourceRange PatternRange, ArrayRef< UnexpandedParameterPack > Unexpanded, const MultiLevelTemplateArgumentList &TemplateArgs, bool FailOnPackProducingTemplates, bool &ShouldExpand, bool &RetainExpansion, UnsignedOrNone &NumExpansions)
Determine whether we could expand a pack expansion with the given set of parameter packs into separat...
bool IsAtLeastAsConstrained(const NamedDecl *D1, MutableArrayRef< AssociatedConstraint > AC1, const NamedDecl *D2, MutableArrayRef< AssociatedConstraint > AC2, bool &Result)
Check whether the given declaration's associated constraints are at least as constrained than another...
TemplateArgumentLoc getIdentityTemplateArgumentLoc(NamedDecl *Param, SourceLocation Location)
Get a template argument mapping the given template parameter to itself, e.g.
bool CheckFunctionTemplateConstraints(SourceLocation PointOfInstantiation, FunctionDecl *Decl, ArrayRef< TemplateArgument > TemplateArgs, ConstraintSatisfaction &Satisfaction)
bool SubstTemplateArgumentsInParameterMapping(ArrayRef< TemplateArgumentLoc > Args, SourceLocation BaseLoc, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateArgumentListInfo &Out, bool BuildPackExpansionTypes)
std::string getTemplateArgumentBindingsText(const TemplateParameterList *Params, const TemplateArgumentList &Args)
Produces a formatted string that describes the binding of template parameters to template arguments.
bool MaybeEmitAmbiguousAtomicConstraintsDiagnostic(const NamedDecl *D1, ArrayRef< AssociatedConstraint > AC1, const NamedDecl *D2, ArrayRef< AssociatedConstraint > AC2)
If D1 was not at least as constrained as D2, but would've been if a pair of atomic constraints involv...
bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs, const DefaultArguments &DefaultArgs, bool PartialTemplateArgs, CheckTemplateArgumentInfo &CTAI, bool UpdateArgsWithConversions=true, bool *ConstraintsNotSatisfied=nullptr)
Check that the given template arguments can be provided to the given template, converting the argumen...
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
A trivial tuple used to represent a source range.
SourceLocation getBegin() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:334
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, bool Canonical, bool ProfileLambdaExpr=false) const
Produce a unique representation of the given statement.
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Stmt.cpp:346
SubsumptionChecker establishes subsumption between two set of constraints.
std::optional< bool > Subsumes(const NamedDecl *DP, ArrayRef< AssociatedConstraint > P, const NamedDecl *DQ, ArrayRef< AssociatedConstraint > Q)
SubsumptionChecker(Sema &SemaRef, SubsumptionCallable Callable={})
llvm::function_ref< bool( const AtomicConstraint &, const AtomicConstraint &)> SubsumptionCallable
A convenient class for passing around template argument information.
ArrayRef< TemplateArgumentLoc > arguments() const
Location wrapper for a TemplateArgument.
Represents a template argument.
pack_iterator pack_begin() const
Iterator referencing the first argument of a template argument pack.
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const
Used to insert TemplateArguments into FoldingSets.
bool containsUnexpandedParameterPack() const
Whether this template argument contains an unexpanded parameter pack.
TemplateArgument getPackExpansionPattern() const
When the template argument is a pack expansion, returns the pattern of the pack expansion.
unsigned pack_size() const
The number of template arguments in the given template argument pack.
@ Pack
The template argument is actually a parameter pack.
ArgKind getKind() const
Return the kind of stored template argument.
bool isPackExpansion() const
Determine whether this template argument is a pack expansion.
The base class of all kinds of template declarations (e.g., class, function, etc.).
void getAssociatedConstraints(llvm::SmallVectorImpl< AssociatedConstraint > &AC) const
Get the total constraint-expression associated with this template, including constraint-expressions d...
TemplateParameterList * getTemplateParameters() const
Get the list of template parameters.
Stores a list of template parameters for a TemplateDecl and its derived classes.
static TemplateParameterList * Create(const ASTContext &C, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ArrayRef< NamedDecl * > Params, SourceLocation RAngleLoc, Expr *RequiresClause)
SourceLocation getLAngleLoc() const
SourceLocation getTemplateLoc() const
Token - This structure provides full information about a lexed token.
Definition Token.h:36
bool is(tok::TokenKind K) const
is/isNot - Predicates to check if this token is a specific kind, as in "if (Tok.is(tok::l_brace)) {....
Definition Token.h:102
tok::TokenKind getKind() const
Definition Token.h:97
A semantic tree transformation that allows one to transform one abstract syntax tree into another.
TyLocType push(QualType T)
Pushes space for a new TypeLoc of the given type.
QualType getType() const
Get the type for which this source info wrapper provides information.
Definition TypeLoc.h:133
SourceLocation getNameLoc() const
Definition TypeLoc.h:552
void setNameLoc(SourceLocation Loc)
Definition TypeLoc.h:556
The base class of the type hierarchy.
Definition TypeBase.h:1833
bool isInstantiationDependentType() const
Determine whether this type is an instantiation-dependent type, meaning that the type involves a temp...
Definition TypeBase.h:2790
bool isSpecificBuiltinType(unsigned K) const
Test for a particular builtin type.
Definition TypeBase.h:8856
bool isDependentType() const
Whether this type is a dependent type, meaning that its definition somehow depends on a template para...
Definition TypeBase.h:2782
bool containsUnexpandedParameterPack() const
Whether this type is or contains an unexpanded parameter pack, used to support C++0x variadic templat...
Definition TypeBase.h:2405
bool isVariablyModifiedType() const
Whether this type is a variably-modified type (C99 6.7.5).
Definition TypeBase.h:2800
bool isFunctionType() const
Definition TypeBase.h:8527
QualType desugar() const
Definition Type.cpp:4041
SubstitutionDiagnostic * getSubstitutionDiagnostic() const
A requires-expression requirement which queries the validity and properties of an expression ('simple...
SubstitutionDiagnostic * getExprSubstitutionDiagnostic() const
ConceptSpecializationExpr * getReturnTypeRequirementSubstitutedConstraintExpr() const
const ReturnTypeRequirement & getReturnTypeRequirement() const
SatisfactionStatus getSatisfactionStatus() const
SourceLocation getNoexceptLoc() const
A requires-expression requirement which is satisfied when a general constraint expression is satisfie...
const ASTConstraintSatisfaction & getConstraintSatisfaction() const
A static requirement that can be used in a requires-expression to check properties of types and expre...
A requires-expression requirement which queries the existence of a type name or type template special...
SubstitutionDiagnostic * getSubstitutionDiagnostic() const
SatisfactionStatus getSatisfactionStatus() const
Provides information about an attempted template argument deduction, whose success or failure was des...
#define bool
Definition gpuintrin.h:32
__inline void unsigned int _2
uint32_t Literal
Literals are represented as positive integers.
Definition CNFFormula.h:35
bool Sub(InterpState &S, CodePtr OpPC)
Definition Interp.h:425
bool Add(InterpState &S, CodePtr OpPC)
Definition Interp.h:398
The JSON file list parser is used to communicate input to InstallAPI.
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
@ OO_None
Not an overloaded operator.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ CPlusPlus11
@ CPlusPlus26
@ TemplateName
The identifier is a template name. FIXME: Add an annotation for that.
Definition Parser.h:61
@ OK_Ordinary
An ordinary object is located at an address in memory.
Definition Specifiers.h:151
llvm::PointerUnion< const Expr *, const ConceptReference *, const ConstraintSubstitutionDiagnostic * > UnsatisfiedConstraintRecord
Definition ASTConcept.h:41
std::pair< llvm::PointerUnion< const TemplateTypeParmType *, NamedDecl *, const TemplateSpecializationType *, const SubstBuiltinTemplatePackType * >, SourceLocation > UnexpandedParameterPack
Definition Sema.h:236
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
ExprResult ExprEmpty()
Definition Ownership.h:272
bool isLambdaCallOperator(const CXXMethodDecl *MD)
Definition ASTLambda.h:28
@ Result
The result type of a method or function.
Definition TypeBase.h:905
std::pair< unsigned, unsigned > getDepthAndIndex(const NamedDecl *ND)
Retrieve the depth and index of a template parameter.
const FunctionProtoType * T
@ Template
We are parsing a template declaration.
Definition Parser.h:81
ExprResult ExprError()
Definition Ownership.h:265
@ Concept
The name was classified as a concept name.
Definition Sema.h:589
std::pair< SourceLocation, StringRef > ConstraintSubstitutionDiagnostic
Unsatisfied constraint expressions if the template arguments could be substituted into them,...
Definition ASTConcept.h:40
prec::Level getBinOpPrecedence(tok::TokenKind Kind, bool GreaterThanIsOperator, bool CPlusPlus11)
Return the precedence of the specified binary operator token.
bool isLambdaConversionOperator(CXXConversionDecl *C)
Definition ASTLambda.h:69
std::pair< SourceLocation, PartialDiagnostic > PartialDiagnosticAt
A partial diagnostic along with the source location where this diagnostic occurs.
@ VK_PRValue
A pr-value expression (in the C++11 taxonomy) produces a temporary value.
Definition Specifiers.h:135
U cast(CodeGen::Address addr)
Definition Address.h:327
ActionResult< Expr * > ExprResult
Definition Ownership.h:249
@ Other
Other implicit parameter.
Definition Decl.h:1746
The result of a constraint satisfaction check, containing the necessary information to diagnose an un...
Definition ASTConcept.h:91
ArrayRef< UnsatisfiedConstraintRecord > records() const
Definition ASTConcept.h:104
Represents an explicit template argument list in C++, e.g., the "<int>" in "sort<int>".
SourceLocation RAngleLoc
The source location of the right angle bracket ('>').
SourceLocation LAngleLoc
The source location of the left angle bracket ('<').
ArrayRef< TemplateArgumentLoc > arguments() const
EvalResult is a struct with detailed info about an evaluated expression.
Definition Expr.h:645
APValue Val
Val - This is the value the expression can be folded to.
Definition Expr.h:647
SmallVectorImpl< PartialDiagnosticAt > * Diag
Diag - If this is non-null, it will be filled in with a stack of notes indicating why evaluation fail...
Definition Expr.h:633
A normalized constraint, as defined in C++ [temp.constr.normal], is either an atomic constraint,...
Definition SemaConcept.h:36
NormalizedConstraint(const Expr *ConstraintExpr, const NamedDecl *ConstraintDecl, UnsignedOrNone PackIndex)
SourceRange getSourceRange() const
ConstraintKind getKind() const
SourceLocation getBeginLoc() const
llvm::SmallBitVector OccurenceList
Definition SemaConcept.h:51
SmallVector< TemplateArgument, 4 > SugaredConverted
The checked, converted argument will be added to the end of these vectors.
Definition Sema.h:11942
A stack object to be created when performing template instantiation.
Definition Sema.h:13197
bool isInvalid() const
Determines whether we have exceeded the maximum recursive template instantiations.
Definition Sema.h:13357
constexpr unsigned toInternalRepresentation() const