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/SemaDiagnostic.h" 16 #include "clang/Sema/TemplateDeduction.h" 17 #include "clang/Sema/Template.h" 18 #include "clang/AST/ExprCXX.h" 19 using namespace clang; 20 using namespace sema; 21 22 bool Sema::CheckConstraintExpression(Expr *ConstraintExpression) { 23 // C++2a [temp.constr.atomic]p1 24 // ..E shall be a constant expression of type bool. 25 26 ConstraintExpression = ConstraintExpression->IgnoreParenImpCasts(); 27 28 if (auto *BinOp = dyn_cast<BinaryOperator>(ConstraintExpression)) { 29 if (BinOp->getOpcode() == BO_LAnd || BinOp->getOpcode() == BO_LOr) 30 return CheckConstraintExpression(BinOp->getLHS()) && 31 CheckConstraintExpression(BinOp->getRHS()); 32 } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpression)) 33 return CheckConstraintExpression(C->getSubExpr()); 34 35 // An atomic constraint! 36 if (ConstraintExpression->isTypeDependent()) 37 return true; 38 39 QualType Type = ConstraintExpression->getType(); 40 if (!Context.hasSameUnqualifiedType(Type, Context.BoolTy)) { 41 Diag(ConstraintExpression->getExprLoc(), 42 diag::err_non_bool_atomic_constraint) << Type 43 << ConstraintExpression->getSourceRange(); 44 return false; 45 } 46 return true; 47 } 48 49 bool 50 Sema::CalculateConstraintSatisfaction(ConceptDecl *NamedConcept, 51 MultiLevelTemplateArgumentList &MLTAL, 52 Expr *ConstraintExpr, 53 bool &IsSatisfied) { 54 ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts(); 55 56 if (auto *BO = dyn_cast<BinaryOperator>(ConstraintExpr)) { 57 if (BO->getOpcode() == BO_LAnd) { 58 if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(), 59 IsSatisfied)) 60 return true; 61 if (!IsSatisfied) 62 return false; 63 return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(), 64 IsSatisfied); 65 } else if (BO->getOpcode() == BO_LOr) { 66 if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(), 67 IsSatisfied)) 68 return true; 69 if (IsSatisfied) 70 return false; 71 return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(), 72 IsSatisfied); 73 } 74 } 75 else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) 76 return CalculateConstraintSatisfaction(NamedConcept, MLTAL, C->getSubExpr(), 77 IsSatisfied); 78 79 EnterExpressionEvaluationContext ConstantEvaluated( 80 *this, Sema::ExpressionEvaluationContext::ConstantEvaluated); 81 82 // Atomic constraint - substitute arguments and check satisfaction. 83 ExprResult E; 84 { 85 TemplateDeductionInfo Info(ConstraintExpr->getBeginLoc()); 86 InstantiatingTemplate Inst(*this, ConstraintExpr->getBeginLoc(), 87 InstantiatingTemplate::ConstraintSubstitution{}, 88 NamedConcept, Info, 89 ConstraintExpr->getSourceRange()); 90 if (Inst.isInvalid()) 91 return true; 92 // We do not want error diagnostics escaping here. 93 Sema::SFINAETrap Trap(*this); 94 95 E = SubstExpr(ConstraintExpr, MLTAL); 96 if (E.isInvalid() || Trap.hasErrorOccurred()) { 97 // C++2a [temp.constr.atomic]p1 98 // ...If substitution results in an invalid type or expression, the 99 // constraint is not satisfied. 100 IsSatisfied = false; 101 return false; 102 } 103 } 104 105 if (!CheckConstraintExpression(E.get())) 106 return true; 107 108 SmallVector<PartialDiagnosticAt, 2> EvaluationDiags; 109 Expr::EvalResult EvalResult; 110 EvalResult.Diag = &EvaluationDiags; 111 if (!E.get()->EvaluateAsRValue(EvalResult, Context)) { 112 // C++2a [temp.constr.atomic]p1 113 // ...E shall be a constant expression of type bool. 114 Diag(E.get()->getBeginLoc(), 115 diag::err_non_constant_constraint_expression) 116 << E.get()->getSourceRange(); 117 for (const PartialDiagnosticAt &PDiag : EvaluationDiags) 118 Diag(PDiag.first, PDiag.second); 119 return true; 120 } 121 122 IsSatisfied = EvalResult.Val.getInt().getBoolValue(); 123 124 return false; 125 }