1 //===-- 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" 15 #include "clang/Sema/SemaInternal.h" 16 #include "clang/Sema/SemaDiagnostic.h" 17 #include "clang/Sema/TemplateDeduction.h" 18 #include "clang/Sema/Template.h" 19 #include "clang/AST/ExprCXX.h" 20 #include "clang/AST/RecursiveASTVisitor.h" 21 #include "llvm/ADT/DenseMap.h" 22 #include "llvm/ADT/PointerUnion.h" 23 using namespace clang; 24 using namespace sema; 25 26 bool 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 53 template <typename AtomicEvaluator> 54 static bool 55 calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, 56 ConstraintSatisfaction &Satisfaction, 57 AtomicEvaluator &&Evaluator) { 58 ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts(); 59 60 if (auto *BO = dyn_cast<BinaryOperator>(ConstraintExpr)) { 61 if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) { 62 if (calculateConstraintSatisfaction(S, BO->getLHS(), Satisfaction, 63 Evaluator)) 64 return true; 65 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. 75 return false; 76 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. 84 return false; 85 86 return calculateConstraintSatisfaction(S, BO->getRHS(), Satisfaction, 87 std::forward<AtomicEvaluator>(Evaluator)); 88 } 89 } 90 else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) 91 return calculateConstraintSatisfaction(S, C->getSubExpr(), Satisfaction, 92 std::forward<AtomicEvaluator>(Evaluator)); 93 94 // An atomic constraint expression 95 ExprResult SubstitutedAtomicExpr = Evaluator(ConstraintExpr); 96 97 if (SubstitutedAtomicExpr.isInvalid()) 98 return true; 99 100 if (!SubstitutedAtomicExpr.isUsable()) 101 // Evaluator has decided satisfaction without yielding an expression. 102 return false; 103 104 EnterExpressionEvaluationContext ConstantEvaluated( 105 S, Sema::ExpressionEvaluationContext::ConstantEvaluated); 106 SmallVector<PartialDiagnosticAt, 2> EvaluationDiags; 107 Expr::EvalResult EvalResult; 108 EvalResult.Diag = &EvaluationDiags; 109 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(); 115 for (const PartialDiagnosticAt &PDiag : EvaluationDiags) 116 S.Diag(PDiag.first, PDiag.second); 117 return true; 118 } 119 120 Satisfaction.IsSatisfied = EvalResult.Val.getInt().getBoolValue(); 121 if (!Satisfaction.IsSatisfied) 122 Satisfaction.Details.emplace_back(ConstraintExpr, 123 SubstitutedAtomicExpr.get()); 124 125 return false; 126 } 127 128 template <typename TemplateDeclT> 129 static 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 191 template<typename TemplateDeclT> 192 static 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 233 bool 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 243 bool 244 Sema::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 254 bool 255 Sema::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 265 bool 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 274 bool 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 300 static 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 383 template<typename SubstitutionDiagnostic> 384 static 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 398 void 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 409 void 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 } 418 } 419 420 namespace { 421 struct 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. 469 struct 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 532 private: 533 static llvm::Optional<NormalizedConstraint> fromConstraintExpr(Sema &S, 534 NamedDecl *D, 535 const Expr *E); 536 }; 537 538 static 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 588 llvm::Optional<NormalizedConstraint> 589 NormalizedConstraint::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 644 using NormalForm = 645 llvm::SmallVector<llvm::SmallVector<AtomicConstraint *, 2>, 4>; 646 647 static 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 676 static 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 706 static 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 754 bool 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; 777 }