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