|  | //===-- SemaConcept.cpp - Semantic Analysis for Constraints and Concepts --===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | //  This file implements semantic analysis for C++ constraints and concepts. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "clang/Sema/Sema.h" | 
|  | #include "clang/Sema/SemaDiagnostic.h" | 
|  | #include "clang/Sema/TemplateDeduction.h" | 
|  | #include "clang/Sema/Template.h" | 
|  | #include "clang/AST/ExprCXX.h" | 
|  | using namespace clang; | 
|  | using namespace sema; | 
|  |  | 
|  | bool Sema::CheckConstraintExpression(Expr *ConstraintExpression) { | 
|  | // C++2a [temp.constr.atomic]p1 | 
|  | // ..E shall be a constant expression of type bool. | 
|  |  | 
|  | ConstraintExpression = ConstraintExpression->IgnoreParenImpCasts(); | 
|  |  | 
|  | if (auto *BinOp = dyn_cast<BinaryOperator>(ConstraintExpression)) { | 
|  | if (BinOp->getOpcode() == BO_LAnd || BinOp->getOpcode() == BO_LOr) | 
|  | return CheckConstraintExpression(BinOp->getLHS()) && | 
|  | CheckConstraintExpression(BinOp->getRHS()); | 
|  | } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpression)) | 
|  | return CheckConstraintExpression(C->getSubExpr()); | 
|  |  | 
|  | // An atomic constraint! | 
|  | if (ConstraintExpression->isTypeDependent()) | 
|  | return true; | 
|  |  | 
|  | QualType Type = ConstraintExpression->getType(); | 
|  | if (!Context.hasSameUnqualifiedType(Type, Context.BoolTy)) { | 
|  | Diag(ConstraintExpression->getExprLoc(), | 
|  | diag::err_non_bool_atomic_constraint) << Type | 
|  | << ConstraintExpression->getSourceRange(); | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool | 
|  | Sema::CalculateConstraintSatisfaction(ConceptDecl *NamedConcept, | 
|  | MultiLevelTemplateArgumentList &MLTAL, | 
|  | Expr *ConstraintExpr, | 
|  | bool &IsSatisfied) { | 
|  | ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts(); | 
|  |  | 
|  | if (auto *BO = dyn_cast<BinaryOperator>(ConstraintExpr)) { | 
|  | if (BO->getOpcode() == BO_LAnd) { | 
|  | if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(), | 
|  | IsSatisfied)) | 
|  | return true; | 
|  | if (!IsSatisfied) | 
|  | return false; | 
|  | return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(), | 
|  | IsSatisfied); | 
|  | } else if (BO->getOpcode() == BO_LOr) { | 
|  | if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(), | 
|  | IsSatisfied)) | 
|  | return true; | 
|  | if (IsSatisfied) | 
|  | return false; | 
|  | return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(), | 
|  | IsSatisfied); | 
|  | } | 
|  | } | 
|  | else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) | 
|  | return CalculateConstraintSatisfaction(NamedConcept, MLTAL, C->getSubExpr(), | 
|  | IsSatisfied); | 
|  |  | 
|  | EnterExpressionEvaluationContext ConstantEvaluated( | 
|  | *this, Sema::ExpressionEvaluationContext::ConstantEvaluated); | 
|  |  | 
|  | // Atomic constraint - substitute arguments and check satisfaction. | 
|  | ExprResult E; | 
|  | { | 
|  | TemplateDeductionInfo Info(ConstraintExpr->getBeginLoc()); | 
|  | InstantiatingTemplate Inst(*this, ConstraintExpr->getBeginLoc(), | 
|  | InstantiatingTemplate::ConstraintSubstitution{}, | 
|  | NamedConcept, Info, | 
|  | ConstraintExpr->getSourceRange()); | 
|  | if (Inst.isInvalid()) | 
|  | return true; | 
|  | // We do not want error diagnostics escaping here. | 
|  | Sema::SFINAETrap Trap(*this); | 
|  |  | 
|  | E = SubstExpr(ConstraintExpr, MLTAL); | 
|  | if (E.isInvalid() || Trap.hasErrorOccurred()) { | 
|  | // C++2a [temp.constr.atomic]p1 | 
|  | //   ...If substitution results in an invalid type or expression, the | 
|  | //   constraint is not satisfied. | 
|  | IsSatisfied = false; | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!CheckConstraintExpression(E.get())) | 
|  | return true; | 
|  |  | 
|  | SmallVector<PartialDiagnosticAt, 2> EvaluationDiags; | 
|  | Expr::EvalResult EvalResult; | 
|  | EvalResult.Diag = &EvaluationDiags; | 
|  | if (!E.get()->EvaluateAsRValue(EvalResult, Context)) { | 
|  | // C++2a [temp.constr.atomic]p1 | 
|  | //   ...E shall be a constant expression of type bool. | 
|  | Diag(E.get()->getBeginLoc(), | 
|  | diag::err_non_constant_constraint_expression) | 
|  | << E.get()->getSourceRange(); | 
|  | for (const PartialDiagnosticAt &PDiag : EvaluationDiags) | 
|  | Diag(PDiag.first, PDiag.second); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | IsSatisfied = EvalResult.Val.getInt().getBoolValue(); | 
|  |  | 
|  | return false; | 
|  | } |