diff options
Diffstat (limited to 'lib/Sema/SemaConcept.cpp')
-rw-r--r-- | lib/Sema/SemaConcept.cpp | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/lib/Sema/SemaConcept.cpp b/lib/Sema/SemaConcept.cpp new file mode 100644 index 0000000000..3131609390 --- /dev/null +++ b/lib/Sema/SemaConcept.cpp @@ -0,0 +1,125 @@ +//===-- 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; +} |