blob: 7f0bdc9b47822f2e3b158ebfce47abc84739d943 [file] [log] [blame]
Saar Raz5d98ba62019-10-15 15:24:26 +00001//===-- SemaConcept.cpp - Semantic Analysis for Constraints and Concepts --===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements semantic analysis for C++ constraints and concepts.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Sema/Sema.h"
Saar Razfdf80e82019-12-06 01:30:21 +020015#include "clang/Sema/SemaInternal.h"
Saar Raz5d98ba62019-10-15 15:24:26 +000016#include "clang/Sema/SemaDiagnostic.h"
17#include "clang/Sema/TemplateDeduction.h"
18#include "clang/Sema/Template.h"
19#include "clang/AST/ExprCXX.h"
Saar Razdf061c32019-12-23 08:37:35 +020020#include "clang/AST/RecursiveASTVisitor.h"
Saar Razfdf80e82019-12-06 01:30:21 +020021#include "llvm/ADT/DenseMap.h"
22#include "llvm/ADT/PointerUnion.h"
Saar Raz5d98ba62019-10-15 15:24:26 +000023using namespace clang;
24using namespace sema;
25
26bool Sema::CheckConstraintExpression(Expr *ConstraintExpression) {
27 // C++2a [temp.constr.atomic]p1
28 // ..E shall be a constant expression of type bool.
29
30 ConstraintExpression = ConstraintExpression->IgnoreParenImpCasts();
31
32 if (auto *BinOp = dyn_cast<BinaryOperator>(ConstraintExpression)) {
33 if (BinOp->getOpcode() == BO_LAnd || BinOp->getOpcode() == BO_LOr)
34 return CheckConstraintExpression(BinOp->getLHS()) &&
35 CheckConstraintExpression(BinOp->getRHS());
36 } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpression))
37 return CheckConstraintExpression(C->getSubExpr());
38
39 // An atomic constraint!
40 if (ConstraintExpression->isTypeDependent())
41 return true;
42
43 QualType Type = ConstraintExpression->getType();
44 if (!Context.hasSameUnqualifiedType(Type, Context.BoolTy)) {
45 Diag(ConstraintExpression->getExprLoc(),
46 diag::err_non_bool_atomic_constraint) << Type
47 << ConstraintExpression->getSourceRange();
48 return false;
49 }
50 return true;
51}
52
Saar Razfdf80e82019-12-06 01:30:21 +020053template <typename AtomicEvaluator>
54static bool
55calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
56 ConstraintSatisfaction &Satisfaction,
57 AtomicEvaluator &&Evaluator) {
Saar Raz5d98ba62019-10-15 15:24:26 +000058 ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts();
59
60 if (auto *BO = dyn_cast<BinaryOperator>(ConstraintExpr)) {
Saar Razfdf80e82019-12-06 01:30:21 +020061 if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) {
62 if (calculateConstraintSatisfaction(S, BO->getLHS(), Satisfaction,
63 Evaluator))
Saar Raz5d98ba62019-10-15 15:24:26 +000064 return true;
Saar Razfdf80e82019-12-06 01:30:21 +020065
66 bool IsLHSSatisfied = Satisfaction.IsSatisfied;
67
68 if (BO->getOpcode() == BO_LOr && IsLHSSatisfied)
69 // [temp.constr.op] p3
70 // A disjunction is a constraint taking two operands. To determine if
71 // a disjunction is satisfied, the satisfaction of the first operand
72 // is checked. If that is satisfied, the disjunction is satisfied.
73 // Otherwise, the disjunction is satisfied if and only if the second
74 // operand is satisfied.
Saar Raz5d98ba62019-10-15 15:24:26 +000075 return false;
Saar Razfdf80e82019-12-06 01:30:21 +020076
77 if (BO->getOpcode() == BO_LAnd && !IsLHSSatisfied)
78 // [temp.constr.op] p2
79 // A conjunction is a constraint taking two operands. To determine if
80 // a conjunction is satisfied, the satisfaction of the first operand
81 // is checked. If that is not satisfied, the conjunction is not
82 // satisfied. Otherwise, the conjunction is satisfied if and only if
83 // the second operand is satisfied.
Saar Raz5d98ba62019-10-15 15:24:26 +000084 return false;
Saar Razfdf80e82019-12-06 01:30:21 +020085
86 return calculateConstraintSatisfaction(S, BO->getRHS(), Satisfaction,
87 std::forward<AtomicEvaluator>(Evaluator));
Saar Raz5d98ba62019-10-15 15:24:26 +000088 }
89 }
90 else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr))
Saar Razfdf80e82019-12-06 01:30:21 +020091 return calculateConstraintSatisfaction(S, C->getSubExpr(), Satisfaction,
92 std::forward<AtomicEvaluator>(Evaluator));
Saar Razffa214e2019-10-25 00:09:37 +030093
Saar Razfdf80e82019-12-06 01:30:21 +020094 // An atomic constraint expression
95 ExprResult SubstitutedAtomicExpr = Evaluator(ConstraintExpr);
Vlad Tsyrklevich38839d02019-10-28 14:36:31 -070096
Saar Razfdf80e82019-12-06 01:30:21 +020097 if (SubstitutedAtomicExpr.isInvalid())
Vlad Tsyrklevich38839d02019-10-28 14:36:31 -070098 return true;
99
Saar Razfdf80e82019-12-06 01:30:21 +0200100 if (!SubstitutedAtomicExpr.isUsable())
101 // Evaluator has decided satisfaction without yielding an expression.
102 return false;
103
104 EnterExpressionEvaluationContext ConstantEvaluated(
105 S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
Saar Raz5d98ba62019-10-15 15:24:26 +0000106 SmallVector<PartialDiagnosticAt, 2> EvaluationDiags;
107 Expr::EvalResult EvalResult;
108 EvalResult.Diag = &EvaluationDiags;
Saar Razfdf80e82019-12-06 01:30:21 +0200109 if (!SubstitutedAtomicExpr.get()->EvaluateAsRValue(EvalResult, S.Context)) {
110 // C++2a [temp.constr.atomic]p1
111 // ...E shall be a constant expression of type bool.
112 S.Diag(SubstitutedAtomicExpr.get()->getBeginLoc(),
113 diag::err_non_constant_constraint_expression)
114 << SubstitutedAtomicExpr.get()->getSourceRange();
Saar Raz5d98ba62019-10-15 15:24:26 +0000115 for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
Saar Razfdf80e82019-12-06 01:30:21 +0200116 S.Diag(PDiag.first, PDiag.second);
Saar Raz5d98ba62019-10-15 15:24:26 +0000117 return true;
118 }
119
Saar Razfdf80e82019-12-06 01:30:21 +0200120 Satisfaction.IsSatisfied = EvalResult.Val.getInt().getBoolValue();
121 if (!Satisfaction.IsSatisfied)
122 Satisfaction.Details.emplace_back(ConstraintExpr,
123 SubstitutedAtomicExpr.get());
Saar Raz5d98ba62019-10-15 15:24:26 +0000124
125 return false;
Saar Razfdf80e82019-12-06 01:30:21 +0200126}
127
128template <typename TemplateDeclT>
129static bool calculateConstraintSatisfaction(
130 Sema &S, TemplateDeclT *Template, ArrayRef<TemplateArgument> TemplateArgs,
131 SourceLocation TemplateNameLoc, MultiLevelTemplateArgumentList &MLTAL,
132 const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) {
133 return calculateConstraintSatisfaction(
134 S, ConstraintExpr, Satisfaction, [&](const Expr *AtomicExpr) {
135 EnterExpressionEvaluationContext ConstantEvaluated(
136 S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
137
138 // Atomic constraint - substitute arguments and check satisfaction.
139 ExprResult SubstitutedExpression;
140 {
141 TemplateDeductionInfo Info(TemplateNameLoc);
142 Sema::InstantiatingTemplate Inst(S, AtomicExpr->getBeginLoc(),
143 Sema::InstantiatingTemplate::ConstraintSubstitution{}, Template,
144 Info, AtomicExpr->getSourceRange());
145 if (Inst.isInvalid())
146 return ExprError();
147 // We do not want error diagnostics escaping here.
148 Sema::SFINAETrap Trap(S);
149 SubstitutedExpression = S.SubstExpr(const_cast<Expr *>(AtomicExpr),
150 MLTAL);
151 if (SubstitutedExpression.isInvalid() || Trap.hasErrorOccurred()) {
152 // C++2a [temp.constr.atomic]p1
153 // ...If substitution results in an invalid type or expression, the
154 // constraint is not satisfied.
155 if (!Trap.hasErrorOccurred())
156 // A non-SFINAE error has occured as a result of this
157 // substitution.
158 return ExprError();
159
160 PartialDiagnosticAt SubstDiag{SourceLocation(),
161 PartialDiagnostic::NullDiagnostic()};
162 Info.takeSFINAEDiagnostic(SubstDiag);
163 // FIXME: Concepts: This is an unfortunate consequence of there
164 // being no serialization code for PartialDiagnostics and the fact
165 // that serializing them would likely take a lot more storage than
166 // just storing them as strings. We would still like, in the
167 // future, to serialize the proper PartialDiagnostic as serializing
168 // it as a string defeats the purpose of the diagnostic mechanism.
169 SmallString<128> DiagString;
170 DiagString = ": ";
171 SubstDiag.second.EmitToString(S.getDiagnostics(), DiagString);
172 unsigned MessageSize = DiagString.size();
173 char *Mem = new (S.Context) char[MessageSize];
174 memcpy(Mem, DiagString.c_str(), MessageSize);
175 Satisfaction.Details.emplace_back(
176 AtomicExpr,
177 new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
178 SubstDiag.first, StringRef(Mem, MessageSize)});
179 Satisfaction.IsSatisfied = false;
180 return ExprEmpty();
181 }
182 }
183
184 if (!S.CheckConstraintExpression(SubstitutedExpression.get()))
185 return ExprError();
186
187 return SubstitutedExpression;
188 });
189}
190
191template<typename TemplateDeclT>
192static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template,
193 ArrayRef<const Expr *> ConstraintExprs,
194 ArrayRef<TemplateArgument> TemplateArgs,
195 SourceRange TemplateIDRange,
196 ConstraintSatisfaction &Satisfaction) {
197 if (ConstraintExprs.empty()) {
198 Satisfaction.IsSatisfied = true;
199 return false;
200 }
201
202 for (auto& Arg : TemplateArgs)
203 if (Arg.isInstantiationDependent()) {
204 // No need to check satisfaction for dependent constraint expressions.
205 Satisfaction.IsSatisfied = true;
206 return false;
207 }
208
209 Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
210 Sema::InstantiatingTemplate::ConstraintsCheck{}, Template, TemplateArgs,
211 TemplateIDRange);
212 if (Inst.isInvalid())
213 return true;
214
215 MultiLevelTemplateArgumentList MLTAL;
216 MLTAL.addOuterTemplateArguments(TemplateArgs);
217
218 for (const Expr *ConstraintExpr : ConstraintExprs) {
219 if (calculateConstraintSatisfaction(S, Template, TemplateArgs,
220 TemplateIDRange.getBegin(), MLTAL,
221 ConstraintExpr, Satisfaction))
222 return true;
223 if (!Satisfaction.IsSatisfied)
224 // [temp.constr.op] p2
225 // [...] To determine if a conjunction is satisfied, the satisfaction
226 // of the first operand is checked. If that is not satisfied, the
227 // conjunction is not satisfied. [...]
228 return false;
229 }
230 return false;
231}
232
233bool Sema::CheckConstraintSatisfaction(TemplateDecl *Template,
234 ArrayRef<const Expr *> ConstraintExprs,
235 ArrayRef<TemplateArgument> TemplateArgs,
236 SourceRange TemplateIDRange,
237 ConstraintSatisfaction &Satisfaction) {
238 return ::CheckConstraintSatisfaction(*this, Template, ConstraintExprs,
239 TemplateArgs, TemplateIDRange,
240 Satisfaction);
241}
242
243bool
244Sema::CheckConstraintSatisfaction(ClassTemplatePartialSpecializationDecl* Part,
245 ArrayRef<const Expr *> ConstraintExprs,
246 ArrayRef<TemplateArgument> TemplateArgs,
247 SourceRange TemplateIDRange,
248 ConstraintSatisfaction &Satisfaction) {
249 return ::CheckConstraintSatisfaction(*this, Part, ConstraintExprs,
250 TemplateArgs, TemplateIDRange,
251 Satisfaction);
252}
253
254bool
255Sema::CheckConstraintSatisfaction(VarTemplatePartialSpecializationDecl* Partial,
256 ArrayRef<const Expr *> ConstraintExprs,
257 ArrayRef<TemplateArgument> TemplateArgs,
258 SourceRange TemplateIDRange,
259 ConstraintSatisfaction &Satisfaction) {
260 return ::CheckConstraintSatisfaction(*this, Partial, ConstraintExprs,
261 TemplateArgs, TemplateIDRange,
262 Satisfaction);
263}
264
265bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr,
266 ConstraintSatisfaction &Satisfaction) {
267 return calculateConstraintSatisfaction(
268 *this, ConstraintExpr, Satisfaction,
269 [](const Expr *AtomicExpr) -> ExprResult {
270 return ExprResult(const_cast<Expr *>(AtomicExpr));
271 });
272}
273
274bool Sema::EnsureTemplateArgumentListConstraints(
275 TemplateDecl *TD, ArrayRef<TemplateArgument> TemplateArgs,
276 SourceRange TemplateIDRange) {
277 ConstraintSatisfaction Satisfaction;
278 llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
279 TD->getAssociatedConstraints(AssociatedConstraints);
280 if (CheckConstraintSatisfaction(TD, AssociatedConstraints, TemplateArgs,
281 TemplateIDRange, Satisfaction))
282 return true;
283
284 if (!Satisfaction.IsSatisfied) {
285 SmallString<128> TemplateArgString;
286 TemplateArgString = " ";
287 TemplateArgString += getTemplateArgumentBindingsText(
288 TD->getTemplateParameters(), TemplateArgs.data(), TemplateArgs.size());
289
290 Diag(TemplateIDRange.getBegin(),
291 diag::err_template_arg_list_constraints_not_satisfied)
292 << (int)getTemplateNameKindForDiagnostics(TemplateName(TD)) << TD
293 << TemplateArgString << TemplateIDRange;
294 DiagnoseUnsatisfiedConstraint(Satisfaction);
295 return true;
296 }
297 return false;
298}
299
300static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
301 Expr *SubstExpr,
302 bool First = true) {
303 SubstExpr = SubstExpr->IgnoreParenImpCasts();
304 if (BinaryOperator *BO = dyn_cast<BinaryOperator>(SubstExpr)) {
305 switch (BO->getOpcode()) {
306 // These two cases will in practice only be reached when using fold
307 // expressions with || and &&, since otherwise the || and && will have been
308 // broken down into atomic constraints during satisfaction checking.
309 case BO_LOr:
310 // Or evaluated to false - meaning both RHS and LHS evaluated to false.
311 diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getLHS(), First);
312 diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(),
313 /*First=*/false);
314 return;
315 case BO_LAnd:
316 bool LHSSatisfied;
317 BO->getLHS()->EvaluateAsBooleanCondition(LHSSatisfied, S.Context);
318 if (LHSSatisfied) {
319 // LHS is true, so RHS must be false.
320 diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(), First);
321 return;
322 }
323 // LHS is false
324 diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getLHS(), First);
325
326 // RHS might also be false
327 bool RHSSatisfied;
328 BO->getRHS()->EvaluateAsBooleanCondition(RHSSatisfied, S.Context);
329 if (!RHSSatisfied)
330 diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(),
331 /*First=*/false);
332 return;
333 case BO_GE:
334 case BO_LE:
335 case BO_GT:
336 case BO_LT:
337 case BO_EQ:
338 case BO_NE:
339 if (BO->getLHS()->getType()->isIntegerType() &&
340 BO->getRHS()->getType()->isIntegerType()) {
341 Expr::EvalResult SimplifiedLHS;
342 Expr::EvalResult SimplifiedRHS;
343 BO->getLHS()->EvaluateAsInt(SimplifiedLHS, S.Context);
344 BO->getRHS()->EvaluateAsInt(SimplifiedRHS, S.Context);
345 if (!SimplifiedLHS.Diag && ! SimplifiedRHS.Diag) {
346 S.Diag(SubstExpr->getBeginLoc(),
347 diag::note_atomic_constraint_evaluated_to_false_elaborated)
348 << (int)First << SubstExpr
349 << SimplifiedLHS.Val.getInt().toString(10)
350 << BinaryOperator::getOpcodeStr(BO->getOpcode())
351 << SimplifiedRHS.Val.getInt().toString(10);
352 return;
353 }
354 }
355 break;
356
357 default:
358 break;
359 }
360 } else if (auto *CSE = dyn_cast<ConceptSpecializationExpr>(SubstExpr)) {
361 if (CSE->getTemplateArgsAsWritten()->NumTemplateArgs == 1) {
362 S.Diag(
363 CSE->getSourceRange().getBegin(),
364 diag::
365 note_single_arg_concept_specialization_constraint_evaluated_to_false)
366 << (int)First
367 << CSE->getTemplateArgsAsWritten()->arguments()[0].getArgument()
368 << CSE->getNamedConcept();
369 } else {
370 S.Diag(SubstExpr->getSourceRange().getBegin(),
371 diag::note_concept_specialization_constraint_evaluated_to_false)
372 << (int)First << CSE;
373 }
374 S.DiagnoseUnsatisfiedConstraint(CSE->getSatisfaction());
375 return;
376 }
377
378 S.Diag(SubstExpr->getSourceRange().getBegin(),
379 diag::note_atomic_constraint_evaluated_to_false)
380 << (int)First << SubstExpr;
381}
382
383template<typename SubstitutionDiagnostic>
384static void diagnoseUnsatisfiedConstraintExpr(
385 Sema &S, const Expr *E,
386 const llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> &Record,
387 bool First = true) {
388 if (auto *Diag = Record.template dyn_cast<SubstitutionDiagnostic *>()){
389 S.Diag(Diag->first, diag::note_substituted_constraint_expr_is_ill_formed)
390 << Diag->second;
391 return;
392 }
393
394 diagnoseWellFormedUnsatisfiedConstraintExpr(S,
395 Record.template get<Expr *>(), First);
396}
397
398void Sema::DiagnoseUnsatisfiedConstraint(
399 const ConstraintSatisfaction& Satisfaction) {
400 assert(!Satisfaction.IsSatisfied &&
401 "Attempted to diagnose a satisfied constraint");
402 bool First = true;
403 for (auto &Pair : Satisfaction.Details) {
404 diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First);
405 First = false;
406 }
407}
408
409void Sema::DiagnoseUnsatisfiedConstraint(
410 const ASTConstraintSatisfaction &Satisfaction) {
411 assert(!Satisfaction.IsSatisfied &&
412 "Attempted to diagnose a satisfied constraint");
413 bool First = true;
414 for (auto &Pair : Satisfaction) {
415 diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First);
416 First = false;
417 }
Saar Razdf061c32019-12-23 08:37:35 +0200418}
419
420namespace {
421struct AtomicConstraint {
422 const Expr *ConstraintExpr;
423 llvm::Optional<llvm::SmallVector<TemplateArgumentLoc, 3>> ParameterMapping;
424
425 AtomicConstraint(Sema &S, const Expr *ConstraintExpr) :
426 ConstraintExpr(ConstraintExpr) { };
427
428 bool hasMatchingParameterMapping(ASTContext &C,
429 const AtomicConstraint &Other) const {
430 if (!ParameterMapping != !Other.ParameterMapping)
431 return false;
432 if (!ParameterMapping)
433 return true;
434 if (ParameterMapping->size() != Other.ParameterMapping->size())
435 return false;
436
437 for (unsigned I = 0, S = ParameterMapping->size(); I < S; ++I)
438 if (!C.getCanonicalTemplateArgument((*ParameterMapping)[I].getArgument())
439 .structurallyEquals(C.getCanonicalTemplateArgument(
440 (*Other.ParameterMapping)[I].getArgument())))
441 return false;
442 return true;
443 }
444
445 bool subsumes(ASTContext &C, const AtomicConstraint &Other) const {
446 // C++ [temp.constr.order] p2
447 // - an atomic constraint A subsumes another atomic constraint B
448 // if and only if the A and B are identical [...]
449 //
450 // C++ [temp.constr.atomic] p2
451 // Two atomic constraints are identical if they are formed from the
452 // same expression and the targets of the parameter mappings are
453 // equivalent according to the rules for expressions [...]
454
455 // We do not actually substitute the parameter mappings into the
456 // constraint expressions, therefore the constraint expressions are
457 // the originals, and comparing them will suffice.
458 if (ConstraintExpr != Other.ConstraintExpr)
459 return false;
460
461 // Check that the parameter lists are identical
462 return hasMatchingParameterMapping(C, Other);
463 }
464};
465
466/// \brief A normalized constraint, as defined in C++ [temp.constr.normal], is
467/// either an atomic constraint, a conjunction of normalized constraints or a
468/// disjunction of normalized constraints.
469struct NormalizedConstraint {
470 enum CompoundConstraintKind { CCK_Conjunction, CCK_Disjunction };
471
472 using CompoundConstraint = llvm::PointerIntPair<
473 std::pair<NormalizedConstraint, NormalizedConstraint> *, 1,
474 CompoundConstraintKind>;
475
476 llvm::PointerUnion<AtomicConstraint *, CompoundConstraint> Constraint;
477
478 NormalizedConstraint(AtomicConstraint *C): Constraint{C} { };
479 NormalizedConstraint(ASTContext &C, NormalizedConstraint LHS,
480 NormalizedConstraint RHS, CompoundConstraintKind Kind)
481 : Constraint{CompoundConstraint{
482 new (C) std::pair<NormalizedConstraint, NormalizedConstraint>{LHS,
483 RHS},
484 Kind}} { };
485
486 CompoundConstraintKind getCompoundKind() const {
487 assert(!isAtomic() && "getCompoundKind called on atomic constraint.");
488 return Constraint.get<CompoundConstraint>().getInt();
489 }
490
491 bool isAtomic() const { return Constraint.is<AtomicConstraint *>(); }
492
493 NormalizedConstraint &getLHS() const {
494 assert(!isAtomic() && "getLHS called on atomic constraint.");
495 return Constraint.get<CompoundConstraint>().getPointer()->first;
496 }
497
498 NormalizedConstraint &getRHS() const {
499 assert(!isAtomic() && "getRHS called on atomic constraint.");
500 return Constraint.get<CompoundConstraint>().getPointer()->second;
501 }
502
503 AtomicConstraint *getAtomicConstraint() const {
504 assert(isAtomic() &&
505 "getAtomicConstraint called on non-atomic constraint.");
506 return Constraint.get<AtomicConstraint *>();
507 }
508
509 static llvm::Optional<NormalizedConstraint>
510 fromConstraintExprs(Sema &S, NamedDecl *D, ArrayRef<const Expr *> E) {
511 assert(E.size() != 0);
512 auto First = fromConstraintExpr(S, D, E[0]);
513 if (E.size() == 1)
514 return First;
515 auto Second = fromConstraintExpr(S, D, E[1]);
516 if (!Second)
517 return llvm::Optional<NormalizedConstraint>{};
518 llvm::Optional<NormalizedConstraint> Conjunction;
519 Conjunction.emplace(S.Context, std::move(*First), std::move(*Second),
520 CCK_Conjunction);
521 for (unsigned I = 2; I < E.size(); ++I) {
522 auto Next = fromConstraintExpr(S, D, E[I]);
523 if (!Next)
524 return llvm::Optional<NormalizedConstraint>{};
525 NormalizedConstraint NewConjunction(S.Context, std::move(*Conjunction),
526 std::move(*Next), CCK_Conjunction);
527 *Conjunction = std::move(NewConjunction);
528 }
529 return Conjunction;
530 }
531
532private:
533 static llvm::Optional<NormalizedConstraint> fromConstraintExpr(Sema &S,
534 NamedDecl *D,
535 const Expr *E);
536};
537
538static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
539 ConceptDecl *Concept, ArrayRef<TemplateArgument> TemplateArgs,
540 const ASTTemplateArgumentListInfo *ArgsAsWritten) {
541 if (!N.isAtomic()) {
542 if (substituteParameterMappings(S, N.getLHS(), Concept, TemplateArgs,
543 ArgsAsWritten))
544 return true;
545 return substituteParameterMappings(S, N.getRHS(), Concept, TemplateArgs,
546 ArgsAsWritten);
547 }
548 TemplateParameterList *TemplateParams = Concept->getTemplateParameters();
549
550 AtomicConstraint &Atomic = *N.getAtomicConstraint();
551 TemplateArgumentListInfo SubstArgs;
552 MultiLevelTemplateArgumentList MLTAL;
553 MLTAL.addOuterTemplateArguments(TemplateArgs);
554 if (!Atomic.ParameterMapping) {
555 llvm::SmallBitVector OccurringIndices(TemplateParams->size());
556 S.MarkUsedTemplateParameters(Atomic.ConstraintExpr, /*OnlyDeduced=*/false,
557 /*Depth=*/0, OccurringIndices);
558 Atomic.ParameterMapping.emplace();
559 Atomic.ParameterMapping->reserve(OccurringIndices.size());
560 for (unsigned I = 0, C = TemplateParams->size(); I != C; ++I)
561 if (OccurringIndices[I])
562 Atomic.ParameterMapping->push_back(
563 S.getIdentityTemplateArgumentLoc(TemplateParams->begin()[I],
564 // Here we assume we do not support things like
565 // template<typename A, typename B>
566 // concept C = ...;
567 //
568 // template<typename... Ts> requires C<Ts...>
569 // struct S { };
570 // The above currently yields a diagnostic.
571 // We still might have default arguments for concept parameters.
572 ArgsAsWritten->NumTemplateArgs > I ?
573 ArgsAsWritten->arguments()[I].getLocation() :
574 SourceLocation()));
575 }
576 Sema::InstantiatingTemplate Inst(
577 S, ArgsAsWritten->arguments().front().getSourceRange().getBegin(),
578 Sema::InstantiatingTemplate::ParameterMappingSubstitution{}, Concept,
579 SourceRange(ArgsAsWritten->arguments()[0].getSourceRange().getBegin(),
580 ArgsAsWritten->arguments().back().getSourceRange().getEnd()));
581 if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs))
582 return true;
583 std::copy(SubstArgs.arguments().begin(), SubstArgs.arguments().end(),
584 N.getAtomicConstraint()->ParameterMapping->begin());
585 return false;
586}
587
588llvm::Optional<NormalizedConstraint>
589NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) {
590 assert(E != nullptr);
591
592 // C++ [temp.constr.normal]p1.1
593 // [...]
594 // - The normal form of an expression (E) is the normal form of E.
595 // [...]
596 E = E->IgnoreParenImpCasts();
597 if (auto *BO = dyn_cast<const BinaryOperator>(E)) {
598 if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) {
599 auto LHS = fromConstraintExpr(S, D, BO->getLHS());
600 if (!LHS)
601 return None;
602 auto RHS = fromConstraintExpr(S, D, BO->getRHS());
603 if (!RHS)
604 return None;
605
606 return NormalizedConstraint(
607 S.Context, *LHS, *RHS,
608 BO->getOpcode() == BO_LAnd ? CCK_Conjunction : CCK_Disjunction);
609 }
610 } else if (auto *CSE = dyn_cast<const ConceptSpecializationExpr>(E)) {
611 Optional<NormalizedConstraint> SubNF;
612 {
613 Sema::InstantiatingTemplate Inst(
614 S, CSE->getExprLoc(),
615 Sema::InstantiatingTemplate::ConstraintNormalization{}, D,
616 CSE->getSourceRange());
617 // C++ [temp.constr.normal]p1.1
618 // [...]
619 // The normal form of an id-expression of the form C<A1, A2, ..., AN>,
620 // where C names a concept, is the normal form of the
621 // constraint-expression of C, after substituting A1, A2, ..., AN for C’s
622 // respective template parameters in the parameter mappings in each atomic
623 // constraint. If any such substitution results in an invalid type or
624 // expression, the program is ill-formed; no diagnostic is required.
625 // [...]
626 SubNF = fromConstraintExpr(S, CSE->getNamedConcept(),
627 CSE->getNamedConcept()->getConstraintExpr());
628 if (!SubNF)
629 return None;
630 }
631
632 if (substituteParameterMappings(
633 S, *SubNF, CSE->getNamedConcept(),
634 CSE->getTemplateArguments(), CSE->getTemplateArgsAsWritten()))
635 return None;
636
637 return SubNF;
638 }
639 return NormalizedConstraint{new (S.Context) AtomicConstraint(S, E)};
640}
641
642} // namespace
643
644using NormalForm =
645 llvm::SmallVector<llvm::SmallVector<AtomicConstraint *, 2>, 4>;
646
647static NormalForm makeCNF(const NormalizedConstraint &Normalized) {
648 if (Normalized.isAtomic())
649 return {{Normalized.getAtomicConstraint()}};
650
651 NormalForm LCNF = makeCNF(Normalized.getLHS());
652 NormalForm RCNF = makeCNF(Normalized.getRHS());
653 if (Normalized.getCompoundKind() == NormalizedConstraint::CCK_Conjunction) {
654 LCNF.reserve(LCNF.size() + RCNF.size());
655 while (!RCNF.empty())
656 LCNF.push_back(RCNF.pop_back_val());
657 return LCNF;
658 }
659
660 // Disjunction
661 NormalForm Res;
662 Res.reserve(LCNF.size() * RCNF.size());
663 for (auto &LDisjunction : LCNF)
664 for (auto &RDisjunction : RCNF) {
665 NormalForm::value_type Combined;
666 Combined.reserve(LDisjunction.size() + RDisjunction.size());
667 std::copy(LDisjunction.begin(), LDisjunction.end(),
668 std::back_inserter(Combined));
669 std::copy(RDisjunction.begin(), RDisjunction.end(),
670 std::back_inserter(Combined));
671 Res.emplace_back(Combined);
672 }
673 return Res;
674}
675
676static NormalForm makeDNF(const NormalizedConstraint &Normalized) {
677 if (Normalized.isAtomic())
678 return {{Normalized.getAtomicConstraint()}};
679
680 NormalForm LDNF = makeDNF(Normalized.getLHS());
681 NormalForm RDNF = makeDNF(Normalized.getRHS());
682 if (Normalized.getCompoundKind() == NormalizedConstraint::CCK_Disjunction) {
683 LDNF.reserve(LDNF.size() + RDNF.size());
684 while (!RDNF.empty())
685 LDNF.push_back(RDNF.pop_back_val());
686 return LDNF;
687 }
688
689 // Conjunction
690 NormalForm Res;
691 Res.reserve(LDNF.size() * RDNF.size());
692 for (auto &LConjunction : LDNF) {
693 for (auto &RConjunction : RDNF) {
694 NormalForm::value_type Combined;
695 Combined.reserve(LConjunction.size() + RConjunction.size());
696 std::copy(LConjunction.begin(), LConjunction.end(),
697 std::back_inserter(Combined));
698 std::copy(RConjunction.begin(), RConjunction.end(),
699 std::back_inserter(Combined));
700 Res.emplace_back(Combined);
701 }
702 }
703 return Res;
704}
705
706static bool subsumes(Sema &S, NamedDecl *DP, ArrayRef<const Expr *> P,
707 NamedDecl *DQ, ArrayRef<const Expr *> Q, bool &Subsumes) {
708 // C++ [temp.constr.order] p2
709 // In order to determine if a constraint P subsumes a constraint Q, P is
710 // transformed into disjunctive normal form, and Q is transformed into
711 // conjunctive normal form. [...]
712 auto PNormalized = NormalizedConstraint::fromConstraintExprs(S, DP, P);
713 if (!PNormalized)
714 return true;
715 const NormalForm PDNF = makeDNF(*PNormalized);
716
717 auto QNormalized = NormalizedConstraint::fromConstraintExprs(S, DQ, Q);
718 if (!QNormalized)
719 return true;
720 const NormalForm QCNF = makeCNF(*QNormalized);
721
722 // C++ [temp.constr.order] p2
723 // Then, P subsumes Q if and only if, for every disjunctive clause Pi in the
724 // disjunctive normal form of P, Pi subsumes every conjunctive clause Qj in
725 // the conjuctive normal form of Q, where [...]
726 for (const auto &Pi : PDNF) {
727 for (const auto &Qj : QCNF) {
728 // C++ [temp.constr.order] p2
729 // - [...] a disjunctive clause Pi subsumes a conjunctive clause Qj if
730 // and only if there exists an atomic constraint Pia in Pi for which
731 // there exists an atomic constraint, Qjb, in Qj such that Pia
732 // subsumes Qjb.
733 bool Found = false;
734 for (const AtomicConstraint *Pia : Pi) {
735 for (const AtomicConstraint *Qjb : Qj) {
736 if (Pia->subsumes(S.Context, *Qjb)) {
737 Found = true;
738 break;
739 }
740 }
741 if (Found)
742 break;
743 }
744 if (!Found) {
745 Subsumes = false;
746 return false;
747 }
748 }
749 }
750 Subsumes = true;
751 return false;
752}
753
754bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef<const Expr *> AC1,
755 NamedDecl *D2, ArrayRef<const Expr *> AC2,
756 bool &Result) {
757 if (AC1.empty()) {
758 Result = AC2.empty();
759 return false;
760 }
761 if (AC2.empty()) {
762 // TD1 has associated constraints and TD2 does not.
763 Result = true;
764 return false;
765 }
766
767 std::pair<NamedDecl *, NamedDecl *> Key{D1, D2};
768 auto CacheEntry = SubsumptionCache.find(Key);
769 if (CacheEntry != SubsumptionCache.end()) {
770 Result = CacheEntry->second;
771 return false;
772 }
773 if (subsumes(*this, D1, AC1, D2, AC2, Result))
774 return true;
775 SubsumptionCache.try_emplace(Key, Result);
776 return false;
Saar Raz0330fba2019-10-15 18:44:06 +0000777}