[Concepts] Concept Specialization Expressions

Part of C++20 Concepts implementation effort. Added Concept Specialization Expressions that are created when a concept is refe$

D41217 on Phabricator.

(recommit after fixing failing Parser test on windows)

llvm-svn: 374903
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
new file mode 100644
index 0000000..3131609
--- /dev/null
+++ b/clang/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;
+}