Home | History | Annotate | Line # | Download | only in Sema
SemaConcept.cpp revision 1.1.1.1
      1 //===-- SemaConcept.cpp - Semantic Analysis for Constraints and Concepts --===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 //  This file implements semantic analysis for C++ constraints and concepts.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "clang/Sema/Sema.h"
     15 #include "clang/Sema/SemaDiagnostic.h"
     16 #include "clang/Sema/TemplateDeduction.h"
     17 #include "clang/Sema/Template.h"
     18 #include "clang/AST/ExprCXX.h"
     19 using namespace clang;
     20 using namespace sema;
     21 
     22 bool Sema::CheckConstraintExpression(Expr *ConstraintExpression) {
     23   // C++2a [temp.constr.atomic]p1
     24   // ..E shall be a constant expression of type bool.
     25 
     26   ConstraintExpression = ConstraintExpression->IgnoreParenImpCasts();
     27 
     28   if (auto *BinOp = dyn_cast<BinaryOperator>(ConstraintExpression)) {
     29     if (BinOp->getOpcode() == BO_LAnd || BinOp->getOpcode() == BO_LOr)
     30       return CheckConstraintExpression(BinOp->getLHS()) &&
     31              CheckConstraintExpression(BinOp->getRHS());
     32   } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpression))
     33     return CheckConstraintExpression(C->getSubExpr());
     34 
     35   // An atomic constraint!
     36   if (ConstraintExpression->isTypeDependent())
     37     return true;
     38 
     39   QualType Type = ConstraintExpression->getType();
     40   if (!Context.hasSameUnqualifiedType(Type, Context.BoolTy)) {
     41     Diag(ConstraintExpression->getExprLoc(),
     42          diag::err_non_bool_atomic_constraint) << Type
     43         << ConstraintExpression->getSourceRange();
     44     return false;
     45   }
     46   return true;
     47 }
     48 
     49 bool
     50 Sema::CalculateConstraintSatisfaction(ConceptDecl *NamedConcept,
     51                                       MultiLevelTemplateArgumentList &MLTAL,
     52                                       Expr *ConstraintExpr,
     53                                       bool &IsSatisfied) {
     54   ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts();
     55 
     56   if (auto *BO = dyn_cast<BinaryOperator>(ConstraintExpr)) {
     57     if (BO->getOpcode() == BO_LAnd) {
     58       if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(),
     59                                           IsSatisfied))
     60         return true;
     61       if (!IsSatisfied)
     62         return false;
     63       return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(),
     64                                              IsSatisfied);
     65     } else if (BO->getOpcode() == BO_LOr) {
     66       if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(),
     67                                           IsSatisfied))
     68         return true;
     69       if (IsSatisfied)
     70         return false;
     71       return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(),
     72                                              IsSatisfied);
     73     }
     74   }
     75   else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr))
     76     return CalculateConstraintSatisfaction(NamedConcept, MLTAL, C->getSubExpr(),
     77                                            IsSatisfied);
     78 
     79   EnterExpressionEvaluationContext ConstantEvaluated(
     80       *this, Sema::ExpressionEvaluationContext::ConstantEvaluated);
     81 
     82   // Atomic constraint - substitute arguments and check satisfaction.
     83   ExprResult E;
     84   {
     85     TemplateDeductionInfo Info(ConstraintExpr->getBeginLoc());
     86     InstantiatingTemplate Inst(*this, ConstraintExpr->getBeginLoc(),
     87                                InstantiatingTemplate::ConstraintSubstitution{},
     88                                NamedConcept, Info,
     89                                ConstraintExpr->getSourceRange());
     90     if (Inst.isInvalid())
     91       return true;
     92     // We do not want error diagnostics escaping here.
     93     Sema::SFINAETrap Trap(*this);
     94 
     95     E = SubstExpr(ConstraintExpr, MLTAL);
     96     if (E.isInvalid() || Trap.hasErrorOccurred()) {
     97       // C++2a [temp.constr.atomic]p1
     98       //   ...If substitution results in an invalid type or expression, the
     99       //   constraint is not satisfied.
    100       IsSatisfied = false;
    101       return false;
    102     }
    103   }
    104 
    105   if (!CheckConstraintExpression(E.get()))
    106     return true;
    107 
    108   SmallVector<PartialDiagnosticAt, 2> EvaluationDiags;
    109   Expr::EvalResult EvalResult;
    110   EvalResult.Diag = &EvaluationDiags;
    111   if (!E.get()->EvaluateAsRValue(EvalResult, Context)) {
    112     // C++2a [temp.constr.atomic]p1
    113     //   ...E shall be a constant expression of type bool.
    114     Diag(E.get()->getBeginLoc(),
    115          diag::err_non_constant_constraint_expression)
    116         << E.get()->getSourceRange();
    117     for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
    118       Diag(PDiag.first, PDiag.second);
    119     return true;
    120   }
    121 
    122   IsSatisfied = EvalResult.Val.getInt().getBoolValue();
    123 
    124   return false;
    125 }