reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  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;
}