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 }