//===-- 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(ConstraintExpression)) { if (BinOp->getOpcode() == BO_LAnd || BinOp->getOpcode() == BO_LOr) return CheckConstraintExpression(BinOp->getLHS()) && CheckConstraintExpression(BinOp->getRHS()); } else if (auto *C = dyn_cast(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(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(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 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; }