1e5dd7070Spatrick //===-- SemaConcept.cpp - Semantic Analysis for Constraints and Concepts --===//
2e5dd7070Spatrick //
3*12c85518Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*12c85518Srobert // See https://llvm.org/LICENSE.txt for license information.
5*12c85518Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file implements semantic analysis for C++ constraints and concepts.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick
13*12c85518Srobert #include "TreeTransform.h"
14e5dd7070Spatrick #include "clang/Sema/SemaConcept.h"
15e5dd7070Spatrick #include "clang/Sema/Sema.h"
16e5dd7070Spatrick #include "clang/Sema/SemaInternal.h"
17e5dd7070Spatrick #include "clang/Sema/SemaDiagnostic.h"
18e5dd7070Spatrick #include "clang/Sema/TemplateDeduction.h"
19e5dd7070Spatrick #include "clang/Sema/Template.h"
20e5dd7070Spatrick #include "clang/Sema/Overload.h"
21e5dd7070Spatrick #include "clang/Sema/Initialization.h"
22*12c85518Srobert #include "clang/AST/ASTLambda.h"
23e5dd7070Spatrick #include "clang/AST/ExprConcepts.h"
24e5dd7070Spatrick #include "clang/AST/RecursiveASTVisitor.h"
25e5dd7070Spatrick #include "clang/Basic/OperatorPrecedence.h"
26e5dd7070Spatrick #include "llvm/ADT/DenseMap.h"
27e5dd7070Spatrick #include "llvm/ADT/PointerUnion.h"
28a9ac8606Spatrick #include "llvm/ADT/StringExtras.h"
29*12c85518Srobert #include <optional>
30a9ac8606Spatrick
31e5dd7070Spatrick using namespace clang;
32e5dd7070Spatrick using namespace sema;
33e5dd7070Spatrick
34ec727ea7Spatrick namespace {
35ec727ea7Spatrick class LogicalBinOp {
36*12c85518Srobert SourceLocation Loc;
37ec727ea7Spatrick OverloadedOperatorKind Op = OO_None;
38ec727ea7Spatrick const Expr *LHS = nullptr;
39ec727ea7Spatrick const Expr *RHS = nullptr;
40ec727ea7Spatrick
41ec727ea7Spatrick public:
LogicalBinOp(const Expr * E)42ec727ea7Spatrick LogicalBinOp(const Expr *E) {
43ec727ea7Spatrick if (auto *BO = dyn_cast<BinaryOperator>(E)) {
44ec727ea7Spatrick Op = BinaryOperator::getOverloadedOperator(BO->getOpcode());
45ec727ea7Spatrick LHS = BO->getLHS();
46ec727ea7Spatrick RHS = BO->getRHS();
47*12c85518Srobert Loc = BO->getExprLoc();
48ec727ea7Spatrick } else if (auto *OO = dyn_cast<CXXOperatorCallExpr>(E)) {
49a9ac8606Spatrick // If OO is not || or && it might not have exactly 2 arguments.
50a9ac8606Spatrick if (OO->getNumArgs() == 2) {
51ec727ea7Spatrick Op = OO->getOperator();
52ec727ea7Spatrick LHS = OO->getArg(0);
53ec727ea7Spatrick RHS = OO->getArg(1);
54*12c85518Srobert Loc = OO->getOperatorLoc();
55ec727ea7Spatrick }
56ec727ea7Spatrick }
57a9ac8606Spatrick }
58ec727ea7Spatrick
isAnd() const59ec727ea7Spatrick bool isAnd() const { return Op == OO_AmpAmp; }
isOr() const60ec727ea7Spatrick bool isOr() const { return Op == OO_PipePipe; }
operator bool() const61ec727ea7Spatrick explicit operator bool() const { return isAnd() || isOr(); }
62ec727ea7Spatrick
getLHS() const63ec727ea7Spatrick const Expr *getLHS() const { return LHS; }
getRHS() const64ec727ea7Spatrick const Expr *getRHS() const { return RHS; }
65*12c85518Srobert
recreateBinOp(Sema & SemaRef,ExprResult LHS) const66*12c85518Srobert ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS) const {
67*12c85518Srobert return recreateBinOp(SemaRef, LHS, const_cast<Expr *>(getRHS()));
68*12c85518Srobert }
69*12c85518Srobert
recreateBinOp(Sema & SemaRef,ExprResult LHS,ExprResult RHS) const70*12c85518Srobert ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS,
71*12c85518Srobert ExprResult RHS) const {
72*12c85518Srobert assert((isAnd() || isOr()) && "Not the right kind of op?");
73*12c85518Srobert assert((!LHS.isInvalid() && !RHS.isInvalid()) && "not good expressions?");
74*12c85518Srobert
75*12c85518Srobert if (!LHS.isUsable() || !RHS.isUsable())
76*12c85518Srobert return ExprEmpty();
77*12c85518Srobert
78*12c85518Srobert // We should just be able to 'normalize' these to the builtin Binary
79*12c85518Srobert // Operator, since that is how they are evaluated in constriant checks.
80*12c85518Srobert return BinaryOperator::Create(SemaRef.Context, LHS.get(), RHS.get(),
81*12c85518Srobert BinaryOperator::getOverloadedOpcode(Op),
82*12c85518Srobert SemaRef.Context.BoolTy, VK_PRValue,
83*12c85518Srobert OK_Ordinary, Loc, FPOptionsOverride{});
84*12c85518Srobert }
85ec727ea7Spatrick };
86ec727ea7Spatrick }
87ec727ea7Spatrick
CheckConstraintExpression(const Expr * ConstraintExpression,Token NextToken,bool * PossibleNonPrimary,bool IsTrailingRequiresClause)88ec727ea7Spatrick bool Sema::CheckConstraintExpression(const Expr *ConstraintExpression,
89ec727ea7Spatrick Token NextToken, bool *PossibleNonPrimary,
90e5dd7070Spatrick bool IsTrailingRequiresClause) {
91e5dd7070Spatrick // C++2a [temp.constr.atomic]p1
92e5dd7070Spatrick // ..E shall be a constant expression of type bool.
93e5dd7070Spatrick
94e5dd7070Spatrick ConstraintExpression = ConstraintExpression->IgnoreParenImpCasts();
95e5dd7070Spatrick
96ec727ea7Spatrick if (LogicalBinOp BO = ConstraintExpression) {
97ec727ea7Spatrick return CheckConstraintExpression(BO.getLHS(), NextToken,
98e5dd7070Spatrick PossibleNonPrimary) &&
99ec727ea7Spatrick CheckConstraintExpression(BO.getRHS(), NextToken,
100e5dd7070Spatrick PossibleNonPrimary);
101e5dd7070Spatrick } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpression))
102e5dd7070Spatrick return CheckConstraintExpression(C->getSubExpr(), NextToken,
103e5dd7070Spatrick PossibleNonPrimary);
104e5dd7070Spatrick
105e5dd7070Spatrick QualType Type = ConstraintExpression->getType();
106e5dd7070Spatrick
107e5dd7070Spatrick auto CheckForNonPrimary = [&] {
108e5dd7070Spatrick if (PossibleNonPrimary)
109e5dd7070Spatrick *PossibleNonPrimary =
110e5dd7070Spatrick // We have the following case:
111e5dd7070Spatrick // template<typename> requires func(0) struct S { };
112e5dd7070Spatrick // The user probably isn't aware of the parentheses required around
113e5dd7070Spatrick // the function call, and we're only going to parse 'func' as the
114e5dd7070Spatrick // primary-expression, and complain that it is of non-bool type.
115e5dd7070Spatrick (NextToken.is(tok::l_paren) &&
116e5dd7070Spatrick (IsTrailingRequiresClause ||
117e5dd7070Spatrick (Type->isDependentType() &&
118ec727ea7Spatrick isa<UnresolvedLookupExpr>(ConstraintExpression)) ||
119e5dd7070Spatrick Type->isFunctionType() ||
120e5dd7070Spatrick Type->isSpecificBuiltinType(BuiltinType::Overload))) ||
121e5dd7070Spatrick // We have the following case:
122e5dd7070Spatrick // template<typename T> requires size_<T> == 0 struct S { };
123e5dd7070Spatrick // The user probably isn't aware of the parentheses required around
124e5dd7070Spatrick // the binary operator, and we're only going to parse 'func' as the
125e5dd7070Spatrick // first operand, and complain that it is of non-bool type.
126e5dd7070Spatrick getBinOpPrecedence(NextToken.getKind(),
127e5dd7070Spatrick /*GreaterThanIsOperator=*/true,
128e5dd7070Spatrick getLangOpts().CPlusPlus11) > prec::LogicalAnd;
129e5dd7070Spatrick };
130e5dd7070Spatrick
131e5dd7070Spatrick // An atomic constraint!
132e5dd7070Spatrick if (ConstraintExpression->isTypeDependent()) {
133e5dd7070Spatrick CheckForNonPrimary();
134e5dd7070Spatrick return true;
135e5dd7070Spatrick }
136e5dd7070Spatrick
137e5dd7070Spatrick if (!Context.hasSameUnqualifiedType(Type, Context.BoolTy)) {
138e5dd7070Spatrick Diag(ConstraintExpression->getExprLoc(),
139e5dd7070Spatrick diag::err_non_bool_atomic_constraint) << Type
140e5dd7070Spatrick << ConstraintExpression->getSourceRange();
141e5dd7070Spatrick CheckForNonPrimary();
142e5dd7070Spatrick return false;
143e5dd7070Spatrick }
144e5dd7070Spatrick
145e5dd7070Spatrick if (PossibleNonPrimary)
146e5dd7070Spatrick *PossibleNonPrimary = false;
147e5dd7070Spatrick return true;
148e5dd7070Spatrick }
149e5dd7070Spatrick
150*12c85518Srobert namespace {
151*12c85518Srobert struct SatisfactionStackRAII {
152*12c85518Srobert Sema &SemaRef;
153*12c85518Srobert bool Inserted = false;
SatisfactionStackRAII__anon7c248e780311::SatisfactionStackRAII154*12c85518Srobert SatisfactionStackRAII(Sema &SemaRef, const NamedDecl *ND,
155*12c85518Srobert llvm::FoldingSetNodeID FSNID)
156*12c85518Srobert : SemaRef(SemaRef) {
157*12c85518Srobert if (ND) {
158*12c85518Srobert SemaRef.PushSatisfactionStackEntry(ND, FSNID);
159*12c85518Srobert Inserted = true;
160*12c85518Srobert }
161*12c85518Srobert }
~SatisfactionStackRAII__anon7c248e780311::SatisfactionStackRAII162*12c85518Srobert ~SatisfactionStackRAII() {
163*12c85518Srobert if (Inserted)
164*12c85518Srobert SemaRef.PopSatisfactionStackEntry();
165*12c85518Srobert }
166*12c85518Srobert };
167*12c85518Srobert } // namespace
168*12c85518Srobert
169e5dd7070Spatrick template <typename AtomicEvaluator>
170*12c85518Srobert static ExprResult
calculateConstraintSatisfaction(Sema & S,const Expr * ConstraintExpr,ConstraintSatisfaction & Satisfaction,AtomicEvaluator && Evaluator)171e5dd7070Spatrick calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
172e5dd7070Spatrick ConstraintSatisfaction &Satisfaction,
173e5dd7070Spatrick AtomicEvaluator &&Evaluator) {
174e5dd7070Spatrick ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts();
175e5dd7070Spatrick
176ec727ea7Spatrick if (LogicalBinOp BO = ConstraintExpr) {
177*12c85518Srobert ExprResult LHSRes = calculateConstraintSatisfaction(
178*12c85518Srobert S, BO.getLHS(), Satisfaction, Evaluator);
179*12c85518Srobert
180*12c85518Srobert if (LHSRes.isInvalid())
181*12c85518Srobert return ExprError();
182e5dd7070Spatrick
183e5dd7070Spatrick bool IsLHSSatisfied = Satisfaction.IsSatisfied;
184e5dd7070Spatrick
185ec727ea7Spatrick if (BO.isOr() && IsLHSSatisfied)
186e5dd7070Spatrick // [temp.constr.op] p3
187e5dd7070Spatrick // A disjunction is a constraint taking two operands. To determine if
188e5dd7070Spatrick // a disjunction is satisfied, the satisfaction of the first operand
189e5dd7070Spatrick // is checked. If that is satisfied, the disjunction is satisfied.
190e5dd7070Spatrick // Otherwise, the disjunction is satisfied if and only if the second
191e5dd7070Spatrick // operand is satisfied.
192*12c85518Srobert // LHS is instantiated while RHS is not. Skip creating invalid BinaryOp.
193*12c85518Srobert return LHSRes;
194e5dd7070Spatrick
195ec727ea7Spatrick if (BO.isAnd() && !IsLHSSatisfied)
196e5dd7070Spatrick // [temp.constr.op] p2
197e5dd7070Spatrick // A conjunction is a constraint taking two operands. To determine if
198e5dd7070Spatrick // a conjunction is satisfied, the satisfaction of the first operand
199e5dd7070Spatrick // is checked. If that is not satisfied, the conjunction is not
200e5dd7070Spatrick // satisfied. Otherwise, the conjunction is satisfied if and only if
201e5dd7070Spatrick // the second operand is satisfied.
202*12c85518Srobert // LHS is instantiated while RHS is not. Skip creating invalid BinaryOp.
203*12c85518Srobert return LHSRes;
204e5dd7070Spatrick
205*12c85518Srobert ExprResult RHSRes = calculateConstraintSatisfaction(
206ec727ea7Spatrick S, BO.getRHS(), Satisfaction, std::forward<AtomicEvaluator>(Evaluator));
207*12c85518Srobert if (RHSRes.isInvalid())
208*12c85518Srobert return ExprError();
209*12c85518Srobert
210*12c85518Srobert return BO.recreateBinOp(S, LHSRes, RHSRes);
211*12c85518Srobert }
212*12c85518Srobert
213*12c85518Srobert if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) {
214*12c85518Srobert // These aren't evaluated, so we don't care about cleanups, so we can just
215*12c85518Srobert // evaluate these as if the cleanups didn't exist.
216*12c85518Srobert return calculateConstraintSatisfaction(
217*12c85518Srobert S, C->getSubExpr(), Satisfaction,
218e5dd7070Spatrick std::forward<AtomicEvaluator>(Evaluator));
219ec727ea7Spatrick }
220e5dd7070Spatrick
221e5dd7070Spatrick // An atomic constraint expression
222e5dd7070Spatrick ExprResult SubstitutedAtomicExpr = Evaluator(ConstraintExpr);
223e5dd7070Spatrick
224e5dd7070Spatrick if (SubstitutedAtomicExpr.isInvalid())
225*12c85518Srobert return ExprError();
226e5dd7070Spatrick
227e5dd7070Spatrick if (!SubstitutedAtomicExpr.isUsable())
228e5dd7070Spatrick // Evaluator has decided satisfaction without yielding an expression.
229*12c85518Srobert return ExprEmpty();
230*12c85518Srobert
231*12c85518Srobert // We don't have the ability to evaluate this, since it contains a
232*12c85518Srobert // RecoveryExpr, so we want to fail overload resolution. Otherwise,
233*12c85518Srobert // we'd potentially pick up a different overload, and cause confusing
234*12c85518Srobert // diagnostics. SO, add a failure detail that will cause us to make this
235*12c85518Srobert // overload set not viable.
236*12c85518Srobert if (SubstitutedAtomicExpr.get()->containsErrors()) {
237*12c85518Srobert Satisfaction.IsSatisfied = false;
238*12c85518Srobert Satisfaction.ContainsErrors = true;
239*12c85518Srobert
240*12c85518Srobert PartialDiagnostic Msg = S.PDiag(diag::note_constraint_references_error);
241*12c85518Srobert SmallString<128> DiagString;
242*12c85518Srobert DiagString = ": ";
243*12c85518Srobert Msg.EmitToString(S.getDiagnostics(), DiagString);
244*12c85518Srobert unsigned MessageSize = DiagString.size();
245*12c85518Srobert char *Mem = new (S.Context) char[MessageSize];
246*12c85518Srobert memcpy(Mem, DiagString.c_str(), MessageSize);
247*12c85518Srobert Satisfaction.Details.emplace_back(
248*12c85518Srobert ConstraintExpr,
249*12c85518Srobert new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
250*12c85518Srobert SubstitutedAtomicExpr.get()->getBeginLoc(),
251*12c85518Srobert StringRef(Mem, MessageSize)});
252*12c85518Srobert return SubstitutedAtomicExpr;
253*12c85518Srobert }
254e5dd7070Spatrick
255e5dd7070Spatrick EnterExpressionEvaluationContext ConstantEvaluated(
256e5dd7070Spatrick S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
257e5dd7070Spatrick SmallVector<PartialDiagnosticAt, 2> EvaluationDiags;
258e5dd7070Spatrick Expr::EvalResult EvalResult;
259e5dd7070Spatrick EvalResult.Diag = &EvaluationDiags;
260a9ac8606Spatrick if (!SubstitutedAtomicExpr.get()->EvaluateAsConstantExpr(EvalResult,
261a9ac8606Spatrick S.Context) ||
262a9ac8606Spatrick !EvaluationDiags.empty()) {
263e5dd7070Spatrick // C++2a [temp.constr.atomic]p1
264e5dd7070Spatrick // ...E shall be a constant expression of type bool.
265e5dd7070Spatrick S.Diag(SubstitutedAtomicExpr.get()->getBeginLoc(),
266e5dd7070Spatrick diag::err_non_constant_constraint_expression)
267e5dd7070Spatrick << SubstitutedAtomicExpr.get()->getSourceRange();
268e5dd7070Spatrick for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
269e5dd7070Spatrick S.Diag(PDiag.first, PDiag.second);
270*12c85518Srobert return ExprError();
271e5dd7070Spatrick }
272e5dd7070Spatrick
273a9ac8606Spatrick assert(EvalResult.Val.isInt() &&
274a9ac8606Spatrick "evaluating bool expression didn't produce int");
275e5dd7070Spatrick Satisfaction.IsSatisfied = EvalResult.Val.getInt().getBoolValue();
276e5dd7070Spatrick if (!Satisfaction.IsSatisfied)
277e5dd7070Spatrick Satisfaction.Details.emplace_back(ConstraintExpr,
278e5dd7070Spatrick SubstitutedAtomicExpr.get());
279e5dd7070Spatrick
280*12c85518Srobert return SubstitutedAtomicExpr;
281*12c85518Srobert }
282*12c85518Srobert
283*12c85518Srobert static bool
DiagRecursiveConstraintEval(Sema & S,llvm::FoldingSetNodeID & ID,const NamedDecl * Templ,const Expr * E,const MultiLevelTemplateArgumentList & MLTAL)284*12c85518Srobert DiagRecursiveConstraintEval(Sema &S, llvm::FoldingSetNodeID &ID,
285*12c85518Srobert const NamedDecl *Templ, const Expr *E,
286*12c85518Srobert const MultiLevelTemplateArgumentList &MLTAL) {
287*12c85518Srobert E->Profile(ID, S.Context, /*Canonical=*/true);
288*12c85518Srobert for (const auto &List : MLTAL)
289*12c85518Srobert for (const auto &TemplateArg : List.Args)
290*12c85518Srobert TemplateArg.Profile(ID, S.Context);
291*12c85518Srobert
292*12c85518Srobert // Note that we have to do this with our own collection, because there are
293*12c85518Srobert // times where a constraint-expression check can cause us to need to evaluate
294*12c85518Srobert // other constriants that are unrelated, such as when evaluating a recovery
295*12c85518Srobert // expression, or when trying to determine the constexpr-ness of special
296*12c85518Srobert // members. Otherwise we could just use the
297*12c85518Srobert // Sema::InstantiatingTemplate::isAlreadyBeingInstantiated function.
298*12c85518Srobert if (S.SatisfactionStackContains(Templ, ID)) {
299*12c85518Srobert S.Diag(E->getExprLoc(), diag::err_constraint_depends_on_self)
300*12c85518Srobert << const_cast<Expr *>(E) << E->getSourceRange();
301*12c85518Srobert return true;
302*12c85518Srobert }
303*12c85518Srobert
304e5dd7070Spatrick return false;
305e5dd7070Spatrick }
306e5dd7070Spatrick
calculateConstraintSatisfaction(Sema & S,const NamedDecl * Template,SourceLocation TemplateNameLoc,const MultiLevelTemplateArgumentList & MLTAL,const Expr * ConstraintExpr,ConstraintSatisfaction & Satisfaction)307*12c85518Srobert static ExprResult calculateConstraintSatisfaction(
308*12c85518Srobert Sema &S, const NamedDecl *Template, SourceLocation TemplateNameLoc,
309*12c85518Srobert const MultiLevelTemplateArgumentList &MLTAL, const Expr *ConstraintExpr,
310*12c85518Srobert ConstraintSatisfaction &Satisfaction) {
311e5dd7070Spatrick return calculateConstraintSatisfaction(
312e5dd7070Spatrick S, ConstraintExpr, Satisfaction, [&](const Expr *AtomicExpr) {
313e5dd7070Spatrick EnterExpressionEvaluationContext ConstantEvaluated(
314*12c85518Srobert S, Sema::ExpressionEvaluationContext::ConstantEvaluated,
315*12c85518Srobert Sema::ReuseLambdaContextDecl);
316e5dd7070Spatrick
317e5dd7070Spatrick // Atomic constraint - substitute arguments and check satisfaction.
318e5dd7070Spatrick ExprResult SubstitutedExpression;
319e5dd7070Spatrick {
320e5dd7070Spatrick TemplateDeductionInfo Info(TemplateNameLoc);
321e5dd7070Spatrick Sema::InstantiatingTemplate Inst(S, AtomicExpr->getBeginLoc(),
322e5dd7070Spatrick Sema::InstantiatingTemplate::ConstraintSubstitution{},
323e5dd7070Spatrick const_cast<NamedDecl *>(Template), Info,
324e5dd7070Spatrick AtomicExpr->getSourceRange());
325e5dd7070Spatrick if (Inst.isInvalid())
326e5dd7070Spatrick return ExprError();
327*12c85518Srobert
328*12c85518Srobert llvm::FoldingSetNodeID ID;
329*12c85518Srobert if (Template &&
330*12c85518Srobert DiagRecursiveConstraintEval(S, ID, Template, AtomicExpr, MLTAL)) {
331*12c85518Srobert Satisfaction.IsSatisfied = false;
332*12c85518Srobert Satisfaction.ContainsErrors = true;
333*12c85518Srobert return ExprEmpty();
334*12c85518Srobert }
335*12c85518Srobert
336*12c85518Srobert SatisfactionStackRAII StackRAII(S, Template, ID);
337*12c85518Srobert
338e5dd7070Spatrick // We do not want error diagnostics escaping here.
339e5dd7070Spatrick Sema::SFINAETrap Trap(S);
340a9ac8606Spatrick SubstitutedExpression =
341*12c85518Srobert S.SubstConstraintExpr(const_cast<Expr *>(AtomicExpr), MLTAL);
342*12c85518Srobert
343e5dd7070Spatrick if (SubstitutedExpression.isInvalid() || Trap.hasErrorOccurred()) {
344e5dd7070Spatrick // C++2a [temp.constr.atomic]p1
345e5dd7070Spatrick // ...If substitution results in an invalid type or expression, the
346e5dd7070Spatrick // constraint is not satisfied.
347e5dd7070Spatrick if (!Trap.hasErrorOccurred())
348*12c85518Srobert // A non-SFINAE error has occurred as a result of this
349e5dd7070Spatrick // substitution.
350e5dd7070Spatrick return ExprError();
351e5dd7070Spatrick
352e5dd7070Spatrick PartialDiagnosticAt SubstDiag{SourceLocation(),
353e5dd7070Spatrick PartialDiagnostic::NullDiagnostic()};
354e5dd7070Spatrick Info.takeSFINAEDiagnostic(SubstDiag);
355e5dd7070Spatrick // FIXME: Concepts: This is an unfortunate consequence of there
356e5dd7070Spatrick // being no serialization code for PartialDiagnostics and the fact
357e5dd7070Spatrick // that serializing them would likely take a lot more storage than
358e5dd7070Spatrick // just storing them as strings. We would still like, in the
359e5dd7070Spatrick // future, to serialize the proper PartialDiagnostic as serializing
360e5dd7070Spatrick // it as a string defeats the purpose of the diagnostic mechanism.
361e5dd7070Spatrick SmallString<128> DiagString;
362e5dd7070Spatrick DiagString = ": ";
363e5dd7070Spatrick SubstDiag.second.EmitToString(S.getDiagnostics(), DiagString);
364e5dd7070Spatrick unsigned MessageSize = DiagString.size();
365e5dd7070Spatrick char *Mem = new (S.Context) char[MessageSize];
366e5dd7070Spatrick memcpy(Mem, DiagString.c_str(), MessageSize);
367e5dd7070Spatrick Satisfaction.Details.emplace_back(
368e5dd7070Spatrick AtomicExpr,
369e5dd7070Spatrick new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
370e5dd7070Spatrick SubstDiag.first, StringRef(Mem, MessageSize)});
371e5dd7070Spatrick Satisfaction.IsSatisfied = false;
372e5dd7070Spatrick return ExprEmpty();
373e5dd7070Spatrick }
374e5dd7070Spatrick }
375e5dd7070Spatrick
376e5dd7070Spatrick if (!S.CheckConstraintExpression(SubstitutedExpression.get()))
377e5dd7070Spatrick return ExprError();
378e5dd7070Spatrick
379*12c85518Srobert // [temp.constr.atomic]p3: To determine if an atomic constraint is
380*12c85518Srobert // satisfied, the parameter mapping and template arguments are first
381*12c85518Srobert // substituted into its expression. If substitution results in an
382*12c85518Srobert // invalid type or expression, the constraint is not satisfied.
383*12c85518Srobert // Otherwise, the lvalue-to-rvalue conversion is performed if necessary,
384*12c85518Srobert // and E shall be a constant expression of type bool.
385*12c85518Srobert //
386*12c85518Srobert // Perform the L to R Value conversion if necessary. We do so for all
387*12c85518Srobert // non-PRValue categories, else we fail to extend the lifetime of
388*12c85518Srobert // temporaries, and that fails the constant expression check.
389*12c85518Srobert if (!SubstitutedExpression.get()->isPRValue())
390*12c85518Srobert SubstitutedExpression = ImplicitCastExpr::Create(
391*12c85518Srobert S.Context, SubstitutedExpression.get()->getType(),
392*12c85518Srobert CK_LValueToRValue, SubstitutedExpression.get(),
393*12c85518Srobert /*BasePath=*/nullptr, VK_PRValue, FPOptionsOverride());
394*12c85518Srobert
395e5dd7070Spatrick return SubstitutedExpression;
396e5dd7070Spatrick });
397e5dd7070Spatrick }
398e5dd7070Spatrick
CheckConstraintSatisfaction(Sema & S,const NamedDecl * Template,ArrayRef<const Expr * > ConstraintExprs,llvm::SmallVectorImpl<Expr * > & Converted,const MultiLevelTemplateArgumentList & TemplateArgsLists,SourceRange TemplateIDRange,ConstraintSatisfaction & Satisfaction)399*12c85518Srobert static bool CheckConstraintSatisfaction(
400*12c85518Srobert Sema &S, const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
401*12c85518Srobert llvm::SmallVectorImpl<Expr *> &Converted,
402*12c85518Srobert const MultiLevelTemplateArgumentList &TemplateArgsLists,
403*12c85518Srobert SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
404e5dd7070Spatrick if (ConstraintExprs.empty()) {
405e5dd7070Spatrick Satisfaction.IsSatisfied = true;
406e5dd7070Spatrick return false;
407e5dd7070Spatrick }
408e5dd7070Spatrick
409*12c85518Srobert if (TemplateArgsLists.isAnyArgInstantiationDependent()) {
410e5dd7070Spatrick // No need to check satisfaction for dependent constraint expressions.
411e5dd7070Spatrick Satisfaction.IsSatisfied = true;
412e5dd7070Spatrick return false;
413e5dd7070Spatrick }
414e5dd7070Spatrick
415*12c85518Srobert ArrayRef<TemplateArgument> TemplateArgs =
416*12c85518Srobert TemplateArgsLists.getNumSubstitutedLevels() > 0
417*12c85518Srobert ? TemplateArgsLists.getOutermost()
418*12c85518Srobert : ArrayRef<TemplateArgument> {};
419e5dd7070Spatrick Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
420e5dd7070Spatrick Sema::InstantiatingTemplate::ConstraintsCheck{},
421e5dd7070Spatrick const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange);
422e5dd7070Spatrick if (Inst.isInvalid())
423e5dd7070Spatrick return true;
424e5dd7070Spatrick
425e5dd7070Spatrick for (const Expr *ConstraintExpr : ConstraintExprs) {
426*12c85518Srobert ExprResult Res = calculateConstraintSatisfaction(
427*12c85518Srobert S, Template, TemplateIDRange.getBegin(), TemplateArgsLists,
428*12c85518Srobert ConstraintExpr, Satisfaction);
429*12c85518Srobert if (Res.isInvalid())
430e5dd7070Spatrick return true;
431*12c85518Srobert
432*12c85518Srobert Converted.push_back(Res.get());
433*12c85518Srobert if (!Satisfaction.IsSatisfied) {
434*12c85518Srobert // Backfill the 'converted' list with nulls so we can keep the Converted
435*12c85518Srobert // and unconverted lists in sync.
436*12c85518Srobert Converted.append(ConstraintExprs.size() - Converted.size(), nullptr);
437e5dd7070Spatrick // [temp.constr.op] p2
438e5dd7070Spatrick // [...] To determine if a conjunction is satisfied, the satisfaction
439e5dd7070Spatrick // of the first operand is checked. If that is not satisfied, the
440e5dd7070Spatrick // conjunction is not satisfied. [...]
441e5dd7070Spatrick return false;
442e5dd7070Spatrick }
443*12c85518Srobert }
444e5dd7070Spatrick return false;
445e5dd7070Spatrick }
446e5dd7070Spatrick
CheckConstraintSatisfaction(const NamedDecl * Template,ArrayRef<const Expr * > ConstraintExprs,llvm::SmallVectorImpl<Expr * > & ConvertedConstraints,const MultiLevelTemplateArgumentList & TemplateArgsLists,SourceRange TemplateIDRange,ConstraintSatisfaction & OutSatisfaction)447e5dd7070Spatrick bool Sema::CheckConstraintSatisfaction(
448e5dd7070Spatrick const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
449*12c85518Srobert llvm::SmallVectorImpl<Expr *> &ConvertedConstraints,
450*12c85518Srobert const MultiLevelTemplateArgumentList &TemplateArgsLists,
451*12c85518Srobert SourceRange TemplateIDRange, ConstraintSatisfaction &OutSatisfaction) {
452e5dd7070Spatrick if (ConstraintExprs.empty()) {
453e5dd7070Spatrick OutSatisfaction.IsSatisfied = true;
454e5dd7070Spatrick return false;
455e5dd7070Spatrick }
456*12c85518Srobert if (!Template) {
457*12c85518Srobert return ::CheckConstraintSatisfaction(
458*12c85518Srobert *this, nullptr, ConstraintExprs, ConvertedConstraints,
459*12c85518Srobert TemplateArgsLists, TemplateIDRange, OutSatisfaction);
460*12c85518Srobert }
461*12c85518Srobert
462*12c85518Srobert // A list of the template argument list flattened in a predictible manner for
463*12c85518Srobert // the purposes of caching. The ConstraintSatisfaction type is in AST so it
464*12c85518Srobert // has no access to the MultiLevelTemplateArgumentList, so this has to happen
465*12c85518Srobert // here.
466*12c85518Srobert llvm::SmallVector<TemplateArgument, 4> FlattenedArgs;
467*12c85518Srobert for (auto List : TemplateArgsLists)
468*12c85518Srobert FlattenedArgs.insert(FlattenedArgs.end(), List.Args.begin(),
469*12c85518Srobert List.Args.end());
470e5dd7070Spatrick
471e5dd7070Spatrick llvm::FoldingSetNodeID ID;
472*12c85518Srobert ConstraintSatisfaction::Profile(ID, Context, Template, FlattenedArgs);
473e5dd7070Spatrick void *InsertPos;
474*12c85518Srobert if (auto *Cached = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos)) {
475*12c85518Srobert OutSatisfaction = *Cached;
476e5dd7070Spatrick return false;
477e5dd7070Spatrick }
478*12c85518Srobert
479*12c85518Srobert auto Satisfaction =
480*12c85518Srobert std::make_unique<ConstraintSatisfaction>(Template, FlattenedArgs);
481e5dd7070Spatrick if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs,
482*12c85518Srobert ConvertedConstraints, TemplateArgsLists,
483*12c85518Srobert TemplateIDRange, *Satisfaction)) {
484*12c85518Srobert OutSatisfaction = *Satisfaction;
485e5dd7070Spatrick return true;
486e5dd7070Spatrick }
487e5dd7070Spatrick
488*12c85518Srobert if (auto *Cached = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos)) {
489*12c85518Srobert // The evaluation of this constraint resulted in us trying to re-evaluate it
490*12c85518Srobert // recursively. This isn't really possible, except we try to form a
491*12c85518Srobert // RecoveryExpr as a part of the evaluation. If this is the case, just
492*12c85518Srobert // return the 'cached' version (which will have the same result), and save
493*12c85518Srobert // ourselves the extra-insert. If it ever becomes possible to legitimately
494*12c85518Srobert // recursively check a constraint, we should skip checking the 'inner' one
495*12c85518Srobert // above, and replace the cached version with this one, as it would be more
496*12c85518Srobert // specific.
497*12c85518Srobert OutSatisfaction = *Cached;
498*12c85518Srobert return false;
499e5dd7070Spatrick }
500*12c85518Srobert
501*12c85518Srobert // Else we can simply add this satisfaction to the list.
502*12c85518Srobert OutSatisfaction = *Satisfaction;
503*12c85518Srobert // We cannot use InsertPos here because CheckConstraintSatisfaction might have
504*12c85518Srobert // invalidated it.
505*12c85518Srobert // Note that entries of SatisfactionCache are deleted in Sema's destructor.
506*12c85518Srobert SatisfactionCache.InsertNode(Satisfaction.release());
507e5dd7070Spatrick return false;
508e5dd7070Spatrick }
509e5dd7070Spatrick
CheckConstraintSatisfaction(const Expr * ConstraintExpr,ConstraintSatisfaction & Satisfaction)510e5dd7070Spatrick bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr,
511e5dd7070Spatrick ConstraintSatisfaction &Satisfaction) {
512e5dd7070Spatrick return calculateConstraintSatisfaction(
513e5dd7070Spatrick *this, ConstraintExpr, Satisfaction,
514*12c85518Srobert [this](const Expr *AtomicExpr) -> ExprResult {
515*12c85518Srobert // We only do this to immitate lvalue-to-rvalue conversion.
516*12c85518Srobert return PerformContextuallyConvertToBool(
517*12c85518Srobert const_cast<Expr *>(AtomicExpr));
518*12c85518Srobert })
519*12c85518Srobert .isInvalid();
520*12c85518Srobert }
521*12c85518Srobert
SetupConstraintScope(FunctionDecl * FD,std::optional<ArrayRef<TemplateArgument>> TemplateArgs,MultiLevelTemplateArgumentList MLTAL,LocalInstantiationScope & Scope)522*12c85518Srobert bool Sema::SetupConstraintScope(
523*12c85518Srobert FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
524*12c85518Srobert MultiLevelTemplateArgumentList MLTAL, LocalInstantiationScope &Scope) {
525*12c85518Srobert if (FD->isTemplateInstantiation() && FD->getPrimaryTemplate()) {
526*12c85518Srobert FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate();
527*12c85518Srobert InstantiatingTemplate Inst(
528*12c85518Srobert *this, FD->getPointOfInstantiation(),
529*12c85518Srobert Sema::InstantiatingTemplate::ConstraintsCheck{}, PrimaryTemplate,
530*12c85518Srobert TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
531*12c85518Srobert SourceRange());
532*12c85518Srobert if (Inst.isInvalid())
533*12c85518Srobert return true;
534*12c85518Srobert
535*12c85518Srobert // addInstantiatedParametersToScope creates a map of 'uninstantiated' to
536*12c85518Srobert // 'instantiated' parameters and adds it to the context. For the case where
537*12c85518Srobert // this function is a template being instantiated NOW, we also need to add
538*12c85518Srobert // the list of current template arguments to the list so that they also can
539*12c85518Srobert // be picked out of the map.
540*12c85518Srobert if (auto *SpecArgs = FD->getTemplateSpecializationArgs()) {
541*12c85518Srobert MultiLevelTemplateArgumentList JustTemplArgs(FD, SpecArgs->asArray(),
542*12c85518Srobert /*Final=*/false);
543*12c85518Srobert if (addInstantiatedParametersToScope(
544*12c85518Srobert FD, PrimaryTemplate->getTemplatedDecl(), Scope, JustTemplArgs))
545*12c85518Srobert return true;
546*12c85518Srobert }
547*12c85518Srobert
548*12c85518Srobert // If this is a member function, make sure we get the parameters that
549*12c85518Srobert // reference the original primary template.
550*12c85518Srobert if (const auto *FromMemTempl =
551*12c85518Srobert PrimaryTemplate->getInstantiatedFromMemberTemplate()) {
552*12c85518Srobert if (addInstantiatedParametersToScope(FD, FromMemTempl->getTemplatedDecl(),
553*12c85518Srobert Scope, MLTAL))
554*12c85518Srobert return true;
555*12c85518Srobert }
556*12c85518Srobert
557*12c85518Srobert return false;
558*12c85518Srobert }
559*12c85518Srobert
560*12c85518Srobert if (FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization ||
561*12c85518Srobert FD->getTemplatedKind() == FunctionDecl::TK_DependentNonTemplate) {
562*12c85518Srobert FunctionDecl *InstantiatedFrom =
563*12c85518Srobert FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization
564*12c85518Srobert ? FD->getInstantiatedFromMemberFunction()
565*12c85518Srobert : FD->getInstantiatedFromDecl();
566*12c85518Srobert
567*12c85518Srobert InstantiatingTemplate Inst(
568*12c85518Srobert *this, FD->getPointOfInstantiation(),
569*12c85518Srobert Sema::InstantiatingTemplate::ConstraintsCheck{}, InstantiatedFrom,
570*12c85518Srobert TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
571*12c85518Srobert SourceRange());
572*12c85518Srobert if (Inst.isInvalid())
573*12c85518Srobert return true;
574*12c85518Srobert
575*12c85518Srobert // Case where this was not a template, but instantiated as a
576*12c85518Srobert // child-function.
577*12c85518Srobert if (addInstantiatedParametersToScope(FD, InstantiatedFrom, Scope, MLTAL))
578*12c85518Srobert return true;
579*12c85518Srobert }
580*12c85518Srobert
581*12c85518Srobert return false;
582*12c85518Srobert }
583*12c85518Srobert
584*12c85518Srobert // This function collects all of the template arguments for the purposes of
585*12c85518Srobert // constraint-instantiation and checking.
586*12c85518Srobert std::optional<MultiLevelTemplateArgumentList>
SetupConstraintCheckingTemplateArgumentsAndScope(FunctionDecl * FD,std::optional<ArrayRef<TemplateArgument>> TemplateArgs,LocalInstantiationScope & Scope)587*12c85518Srobert Sema::SetupConstraintCheckingTemplateArgumentsAndScope(
588*12c85518Srobert FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
589*12c85518Srobert LocalInstantiationScope &Scope) {
590*12c85518Srobert MultiLevelTemplateArgumentList MLTAL;
591*12c85518Srobert
592*12c85518Srobert // Collect the list of template arguments relative to the 'primary' template.
593*12c85518Srobert // We need the entire list, since the constraint is completely uninstantiated
594*12c85518Srobert // at this point.
595*12c85518Srobert MLTAL =
596*12c85518Srobert getTemplateInstantiationArgs(FD, /*Final=*/false, /*Innermost=*/nullptr,
597*12c85518Srobert /*RelativeToPrimary=*/true,
598*12c85518Srobert /*Pattern=*/nullptr,
599*12c85518Srobert /*ForConstraintInstantiation=*/true);
600*12c85518Srobert if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope))
601*12c85518Srobert return std::nullopt;
602*12c85518Srobert
603*12c85518Srobert return MLTAL;
604e5dd7070Spatrick }
605e5dd7070Spatrick
CheckFunctionConstraints(const FunctionDecl * FD,ConstraintSatisfaction & Satisfaction,SourceLocation UsageLoc,bool ForOverloadResolution)606e5dd7070Spatrick bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
607e5dd7070Spatrick ConstraintSatisfaction &Satisfaction,
608*12c85518Srobert SourceLocation UsageLoc,
609*12c85518Srobert bool ForOverloadResolution) {
610*12c85518Srobert // Don't check constraints if the function is dependent. Also don't check if
611*12c85518Srobert // this is a function template specialization, as the call to
612*12c85518Srobert // CheckinstantiatedFunctionTemplateConstraints after this will check it
613*12c85518Srobert // better.
614*12c85518Srobert if (FD->isDependentContext() ||
615*12c85518Srobert FD->getTemplatedKind() ==
616*12c85518Srobert FunctionDecl::TK_FunctionTemplateSpecialization) {
617e5dd7070Spatrick Satisfaction.IsSatisfied = true;
618e5dd7070Spatrick return false;
619e5dd7070Spatrick }
620*12c85518Srobert
621*12c85518Srobert DeclContext *CtxToSave = const_cast<FunctionDecl *>(FD);
622*12c85518Srobert
623*12c85518Srobert while (isLambdaCallOperator(CtxToSave) || FD->isTransparentContext()) {
624*12c85518Srobert if (isLambdaCallOperator(CtxToSave))
625*12c85518Srobert CtxToSave = CtxToSave->getParent()->getParent();
626*12c85518Srobert else
627*12c85518Srobert CtxToSave = CtxToSave->getNonTransparentContext();
628*12c85518Srobert }
629*12c85518Srobert
630*12c85518Srobert ContextRAII SavedContext{*this, CtxToSave};
631*12c85518Srobert LocalInstantiationScope Scope(*this, !ForOverloadResolution ||
632*12c85518Srobert isLambdaCallOperator(FD));
633*12c85518Srobert std::optional<MultiLevelTemplateArgumentList> MLTAL =
634*12c85518Srobert SetupConstraintCheckingTemplateArgumentsAndScope(
635*12c85518Srobert const_cast<FunctionDecl *>(FD), {}, Scope);
636*12c85518Srobert
637*12c85518Srobert if (!MLTAL)
638*12c85518Srobert return true;
639*12c85518Srobert
640e5dd7070Spatrick Qualifiers ThisQuals;
641e5dd7070Spatrick CXXRecordDecl *Record = nullptr;
642e5dd7070Spatrick if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
643e5dd7070Spatrick ThisQuals = Method->getMethodQualifiers();
644e5dd7070Spatrick Record = const_cast<CXXRecordDecl *>(Method->getParent());
645e5dd7070Spatrick }
646e5dd7070Spatrick CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
647e5dd7070Spatrick // We substitute with empty arguments in order to rebuild the atomic
648e5dd7070Spatrick // constraint in a constant-evaluated context.
649e5dd7070Spatrick // FIXME: Should this be a dedicated TreeTransform?
650*12c85518Srobert const Expr *RC = FD->getTrailingRequiresClause();
651*12c85518Srobert llvm::SmallVector<Expr *, 1> Converted;
652*12c85518Srobert
653*12c85518Srobert if (CheckConstraintSatisfaction(
654*12c85518Srobert FD, {RC}, Converted, *MLTAL,
655e5dd7070Spatrick SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()),
656*12c85518Srobert Satisfaction))
657*12c85518Srobert return true;
658*12c85518Srobert
659*12c85518Srobert // FIXME: we need to do this for the function constraints for
660*12c85518Srobert // comparison of constraints to work, but do we also need to do it for
661*12c85518Srobert // CheckInstantiatedFunctionConstraints? That one is more difficult, but we
662*12c85518Srobert // seem to always just pick up the constraints from the primary template.
663*12c85518Srobert assert(Converted.size() <= 1 && "Got more expressions converted?");
664*12c85518Srobert if (!Converted.empty() && Converted[0] != nullptr)
665*12c85518Srobert const_cast<FunctionDecl *>(FD)->setTrailingRequiresClause(Converted[0]);
666*12c85518Srobert return false;
667*12c85518Srobert }
668*12c85518Srobert
669*12c85518Srobert
670*12c85518Srobert // Figure out the to-translation-unit depth for this function declaration for
671*12c85518Srobert // the purpose of seeing if they differ by constraints. This isn't the same as
672*12c85518Srobert // getTemplateDepth, because it includes already instantiated parents.
673*12c85518Srobert static unsigned
CalculateTemplateDepthForConstraints(Sema & S,const NamedDecl * ND,bool SkipForSpecialization=false)674*12c85518Srobert CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND,
675*12c85518Srobert bool SkipForSpecialization = false) {
676*12c85518Srobert MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
677*12c85518Srobert ND, /*Final=*/false, /*Innermost=*/nullptr, /*RelativeToPrimary=*/true,
678*12c85518Srobert /*Pattern=*/nullptr,
679*12c85518Srobert /*ForConstraintInstantiation=*/true, SkipForSpecialization);
680*12c85518Srobert return MLTAL.getNumSubstitutedLevels();
681*12c85518Srobert }
682*12c85518Srobert
683*12c85518Srobert namespace {
684*12c85518Srobert class AdjustConstraintDepth : public TreeTransform<AdjustConstraintDepth> {
685*12c85518Srobert unsigned TemplateDepth = 0;
686*12c85518Srobert public:
687*12c85518Srobert using inherited = TreeTransform<AdjustConstraintDepth>;
AdjustConstraintDepth(Sema & SemaRef,unsigned TemplateDepth)688*12c85518Srobert AdjustConstraintDepth(Sema &SemaRef, unsigned TemplateDepth)
689*12c85518Srobert : inherited(SemaRef), TemplateDepth(TemplateDepth) {}
690*12c85518Srobert
691*12c85518Srobert using inherited::TransformTemplateTypeParmType;
TransformTemplateTypeParmType(TypeLocBuilder & TLB,TemplateTypeParmTypeLoc TL,bool)692*12c85518Srobert QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
693*12c85518Srobert TemplateTypeParmTypeLoc TL, bool) {
694*12c85518Srobert const TemplateTypeParmType *T = TL.getTypePtr();
695*12c85518Srobert
696*12c85518Srobert TemplateTypeParmDecl *NewTTPDecl = nullptr;
697*12c85518Srobert if (TemplateTypeParmDecl *OldTTPDecl = T->getDecl())
698*12c85518Srobert NewTTPDecl = cast_or_null<TemplateTypeParmDecl>(
699*12c85518Srobert TransformDecl(TL.getNameLoc(), OldTTPDecl));
700*12c85518Srobert
701*12c85518Srobert QualType Result = getSema().Context.getTemplateTypeParmType(
702*12c85518Srobert T->getDepth() + TemplateDepth, T->getIndex(), T->isParameterPack(),
703*12c85518Srobert NewTTPDecl);
704*12c85518Srobert TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
705*12c85518Srobert NewTL.setNameLoc(TL.getNameLoc());
706*12c85518Srobert return Result;
707*12c85518Srobert }
708*12c85518Srobert };
709*12c85518Srobert } // namespace
710*12c85518Srobert
AreConstraintExpressionsEqual(const NamedDecl * Old,const Expr * OldConstr,const NamedDecl * New,const Expr * NewConstr)711*12c85518Srobert bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old,
712*12c85518Srobert const Expr *OldConstr,
713*12c85518Srobert const NamedDecl *New,
714*12c85518Srobert const Expr *NewConstr) {
715*12c85518Srobert if (Old && New && Old != New) {
716*12c85518Srobert unsigned Depth1 = CalculateTemplateDepthForConstraints(
717*12c85518Srobert *this, Old);
718*12c85518Srobert unsigned Depth2 = CalculateTemplateDepthForConstraints(
719*12c85518Srobert *this, New);
720*12c85518Srobert
721*12c85518Srobert // Adjust the 'shallowest' verison of this to increase the depth to match
722*12c85518Srobert // the 'other'.
723*12c85518Srobert if (Depth2 > Depth1) {
724*12c85518Srobert OldConstr = AdjustConstraintDepth(*this, Depth2 - Depth1)
725*12c85518Srobert .TransformExpr(const_cast<Expr *>(OldConstr))
726*12c85518Srobert .get();
727*12c85518Srobert } else if (Depth1 > Depth2) {
728*12c85518Srobert NewConstr = AdjustConstraintDepth(*this, Depth1 - Depth2)
729*12c85518Srobert .TransformExpr(const_cast<Expr *>(NewConstr))
730*12c85518Srobert .get();
731*12c85518Srobert }
732*12c85518Srobert }
733*12c85518Srobert
734*12c85518Srobert llvm::FoldingSetNodeID ID1, ID2;
735*12c85518Srobert OldConstr->Profile(ID1, Context, /*Canonical=*/true);
736*12c85518Srobert NewConstr->Profile(ID2, Context, /*Canonical=*/true);
737*12c85518Srobert return ID1 == ID2;
738*12c85518Srobert }
739*12c85518Srobert
FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl * FD)740*12c85518Srobert bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) {
741*12c85518Srobert assert(FD->getFriendObjectKind() && "Must be a friend!");
742*12c85518Srobert
743*12c85518Srobert // The logic for non-templates is handled in ASTContext::isSameEntity, so we
744*12c85518Srobert // don't have to bother checking 'DependsOnEnclosingTemplate' for a
745*12c85518Srobert // non-function-template.
746*12c85518Srobert assert(FD->getDescribedFunctionTemplate() &&
747*12c85518Srobert "Non-function templates don't need to be checked");
748*12c85518Srobert
749*12c85518Srobert SmallVector<const Expr *, 3> ACs;
750*12c85518Srobert FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs);
751*12c85518Srobert
752*12c85518Srobert unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
753*12c85518Srobert for (const Expr *Constraint : ACs)
754*12c85518Srobert if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth,
755*12c85518Srobert Constraint))
756*12c85518Srobert return true;
757*12c85518Srobert
758*12c85518Srobert return false;
759e5dd7070Spatrick }
760e5dd7070Spatrick
EnsureTemplateArgumentListConstraints(TemplateDecl * TD,const MultiLevelTemplateArgumentList & TemplateArgsLists,SourceRange TemplateIDRange)761e5dd7070Spatrick bool Sema::EnsureTemplateArgumentListConstraints(
762*12c85518Srobert TemplateDecl *TD, const MultiLevelTemplateArgumentList &TemplateArgsLists,
763e5dd7070Spatrick SourceRange TemplateIDRange) {
764e5dd7070Spatrick ConstraintSatisfaction Satisfaction;
765e5dd7070Spatrick llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
766e5dd7070Spatrick TD->getAssociatedConstraints(AssociatedConstraints);
767*12c85518Srobert if (CheckConstraintSatisfaction(TD, AssociatedConstraints, TemplateArgsLists,
768e5dd7070Spatrick TemplateIDRange, Satisfaction))
769e5dd7070Spatrick return true;
770e5dd7070Spatrick
771e5dd7070Spatrick if (!Satisfaction.IsSatisfied) {
772e5dd7070Spatrick SmallString<128> TemplateArgString;
773e5dd7070Spatrick TemplateArgString = " ";
774e5dd7070Spatrick TemplateArgString += getTemplateArgumentBindingsText(
775*12c85518Srobert TD->getTemplateParameters(), TemplateArgsLists.getInnermost().data(),
776*12c85518Srobert TemplateArgsLists.getInnermost().size());
777e5dd7070Spatrick
778e5dd7070Spatrick Diag(TemplateIDRange.getBegin(),
779e5dd7070Spatrick diag::err_template_arg_list_constraints_not_satisfied)
780e5dd7070Spatrick << (int)getTemplateNameKindForDiagnostics(TemplateName(TD)) << TD
781e5dd7070Spatrick << TemplateArgString << TemplateIDRange;
782e5dd7070Spatrick DiagnoseUnsatisfiedConstraint(Satisfaction);
783e5dd7070Spatrick return true;
784e5dd7070Spatrick }
785e5dd7070Spatrick return false;
786e5dd7070Spatrick }
787e5dd7070Spatrick
CheckInstantiatedFunctionTemplateConstraints(SourceLocation PointOfInstantiation,FunctionDecl * Decl,ArrayRef<TemplateArgument> TemplateArgs,ConstraintSatisfaction & Satisfaction)788*12c85518Srobert bool Sema::CheckInstantiatedFunctionTemplateConstraints(
789*12c85518Srobert SourceLocation PointOfInstantiation, FunctionDecl *Decl,
790*12c85518Srobert ArrayRef<TemplateArgument> TemplateArgs,
791*12c85518Srobert ConstraintSatisfaction &Satisfaction) {
792*12c85518Srobert // In most cases we're not going to have constraints, so check for that first.
793*12c85518Srobert FunctionTemplateDecl *Template = Decl->getPrimaryTemplate();
794*12c85518Srobert // Note - code synthesis context for the constraints check is created
795*12c85518Srobert // inside CheckConstraintsSatisfaction.
796*12c85518Srobert SmallVector<const Expr *, 3> TemplateAC;
797*12c85518Srobert Template->getAssociatedConstraints(TemplateAC);
798*12c85518Srobert if (TemplateAC.empty()) {
799*12c85518Srobert Satisfaction.IsSatisfied = true;
800*12c85518Srobert return false;
801*12c85518Srobert }
802*12c85518Srobert
803*12c85518Srobert // Enter the scope of this instantiation. We don't use
804*12c85518Srobert // PushDeclContext because we don't have a scope.
805*12c85518Srobert Sema::ContextRAII savedContext(*this, Decl);
806*12c85518Srobert LocalInstantiationScope Scope(*this);
807*12c85518Srobert
808*12c85518Srobert std::optional<MultiLevelTemplateArgumentList> MLTAL =
809*12c85518Srobert SetupConstraintCheckingTemplateArgumentsAndScope(Decl, TemplateArgs,
810*12c85518Srobert Scope);
811*12c85518Srobert
812*12c85518Srobert if (!MLTAL)
813*12c85518Srobert return true;
814*12c85518Srobert
815*12c85518Srobert Qualifiers ThisQuals;
816*12c85518Srobert CXXRecordDecl *Record = nullptr;
817*12c85518Srobert if (auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
818*12c85518Srobert ThisQuals = Method->getMethodQualifiers();
819*12c85518Srobert Record = Method->getParent();
820*12c85518Srobert }
821*12c85518Srobert CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
822*12c85518Srobert FunctionScopeRAII FuncScope(*this);
823*12c85518Srobert if (isLambdaCallOperator(Decl))
824*12c85518Srobert PushLambdaScope();
825*12c85518Srobert else
826*12c85518Srobert FuncScope.disable();
827*12c85518Srobert
828*12c85518Srobert llvm::SmallVector<Expr *, 1> Converted;
829*12c85518Srobert return CheckConstraintSatisfaction(Template, TemplateAC, Converted, *MLTAL,
830*12c85518Srobert PointOfInstantiation, Satisfaction);
831*12c85518Srobert }
832*12c85518Srobert
diagnoseUnsatisfiedRequirement(Sema & S,concepts::ExprRequirement * Req,bool First)833e5dd7070Spatrick static void diagnoseUnsatisfiedRequirement(Sema &S,
834e5dd7070Spatrick concepts::ExprRequirement *Req,
835e5dd7070Spatrick bool First) {
836e5dd7070Spatrick assert(!Req->isSatisfied()
837e5dd7070Spatrick && "Diagnose() can only be used on an unsatisfied requirement");
838e5dd7070Spatrick switch (Req->getSatisfactionStatus()) {
839e5dd7070Spatrick case concepts::ExprRequirement::SS_Dependent:
840e5dd7070Spatrick llvm_unreachable("Diagnosing a dependent requirement");
841e5dd7070Spatrick break;
842e5dd7070Spatrick case concepts::ExprRequirement::SS_ExprSubstitutionFailure: {
843e5dd7070Spatrick auto *SubstDiag = Req->getExprSubstitutionDiagnostic();
844e5dd7070Spatrick if (!SubstDiag->DiagMessage.empty())
845e5dd7070Spatrick S.Diag(SubstDiag->DiagLoc,
846e5dd7070Spatrick diag::note_expr_requirement_expr_substitution_error)
847e5dd7070Spatrick << (int)First << SubstDiag->SubstitutedEntity
848e5dd7070Spatrick << SubstDiag->DiagMessage;
849e5dd7070Spatrick else
850e5dd7070Spatrick S.Diag(SubstDiag->DiagLoc,
851e5dd7070Spatrick diag::note_expr_requirement_expr_unknown_substitution_error)
852e5dd7070Spatrick << (int)First << SubstDiag->SubstitutedEntity;
853e5dd7070Spatrick break;
854e5dd7070Spatrick }
855e5dd7070Spatrick case concepts::ExprRequirement::SS_NoexceptNotMet:
856e5dd7070Spatrick S.Diag(Req->getNoexceptLoc(),
857e5dd7070Spatrick diag::note_expr_requirement_noexcept_not_met)
858e5dd7070Spatrick << (int)First << Req->getExpr();
859e5dd7070Spatrick break;
860e5dd7070Spatrick case concepts::ExprRequirement::SS_TypeRequirementSubstitutionFailure: {
861e5dd7070Spatrick auto *SubstDiag =
862e5dd7070Spatrick Req->getReturnTypeRequirement().getSubstitutionDiagnostic();
863e5dd7070Spatrick if (!SubstDiag->DiagMessage.empty())
864e5dd7070Spatrick S.Diag(SubstDiag->DiagLoc,
865e5dd7070Spatrick diag::note_expr_requirement_type_requirement_substitution_error)
866e5dd7070Spatrick << (int)First << SubstDiag->SubstitutedEntity
867e5dd7070Spatrick << SubstDiag->DiagMessage;
868e5dd7070Spatrick else
869e5dd7070Spatrick S.Diag(SubstDiag->DiagLoc,
870e5dd7070Spatrick diag::note_expr_requirement_type_requirement_unknown_substitution_error)
871e5dd7070Spatrick << (int)First << SubstDiag->SubstitutedEntity;
872e5dd7070Spatrick break;
873e5dd7070Spatrick }
874e5dd7070Spatrick case concepts::ExprRequirement::SS_ConstraintsNotSatisfied: {
875e5dd7070Spatrick ConceptSpecializationExpr *ConstraintExpr =
876e5dd7070Spatrick Req->getReturnTypeRequirementSubstitutedConstraintExpr();
877a9ac8606Spatrick if (ConstraintExpr->getTemplateArgsAsWritten()->NumTemplateArgs == 1) {
878e5dd7070Spatrick // A simple case - expr type is the type being constrained and the concept
879e5dd7070Spatrick // was not provided arguments.
880a9ac8606Spatrick Expr *e = Req->getExpr();
881a9ac8606Spatrick S.Diag(e->getBeginLoc(),
882e5dd7070Spatrick diag::note_expr_requirement_constraints_not_satisfied_simple)
883*12c85518Srobert << (int)First << S.Context.getReferenceQualifiedType(e)
884e5dd7070Spatrick << ConstraintExpr->getNamedConcept();
885a9ac8606Spatrick } else {
886e5dd7070Spatrick S.Diag(ConstraintExpr->getBeginLoc(),
887e5dd7070Spatrick diag::note_expr_requirement_constraints_not_satisfied)
888e5dd7070Spatrick << (int)First << ConstraintExpr;
889a9ac8606Spatrick }
890e5dd7070Spatrick S.DiagnoseUnsatisfiedConstraint(ConstraintExpr->getSatisfaction());
891e5dd7070Spatrick break;
892e5dd7070Spatrick }
893e5dd7070Spatrick case concepts::ExprRequirement::SS_Satisfied:
894e5dd7070Spatrick llvm_unreachable("We checked this above");
895e5dd7070Spatrick }
896e5dd7070Spatrick }
897e5dd7070Spatrick
diagnoseUnsatisfiedRequirement(Sema & S,concepts::TypeRequirement * Req,bool First)898e5dd7070Spatrick static void diagnoseUnsatisfiedRequirement(Sema &S,
899e5dd7070Spatrick concepts::TypeRequirement *Req,
900e5dd7070Spatrick bool First) {
901e5dd7070Spatrick assert(!Req->isSatisfied()
902e5dd7070Spatrick && "Diagnose() can only be used on an unsatisfied requirement");
903e5dd7070Spatrick switch (Req->getSatisfactionStatus()) {
904e5dd7070Spatrick case concepts::TypeRequirement::SS_Dependent:
905e5dd7070Spatrick llvm_unreachable("Diagnosing a dependent requirement");
906e5dd7070Spatrick return;
907e5dd7070Spatrick case concepts::TypeRequirement::SS_SubstitutionFailure: {
908e5dd7070Spatrick auto *SubstDiag = Req->getSubstitutionDiagnostic();
909e5dd7070Spatrick if (!SubstDiag->DiagMessage.empty())
910e5dd7070Spatrick S.Diag(SubstDiag->DiagLoc,
911e5dd7070Spatrick diag::note_type_requirement_substitution_error) << (int)First
912e5dd7070Spatrick << SubstDiag->SubstitutedEntity << SubstDiag->DiagMessage;
913e5dd7070Spatrick else
914e5dd7070Spatrick S.Diag(SubstDiag->DiagLoc,
915e5dd7070Spatrick diag::note_type_requirement_unknown_substitution_error)
916e5dd7070Spatrick << (int)First << SubstDiag->SubstitutedEntity;
917e5dd7070Spatrick return;
918e5dd7070Spatrick }
919e5dd7070Spatrick default:
920e5dd7070Spatrick llvm_unreachable("Unknown satisfaction status");
921e5dd7070Spatrick return;
922e5dd7070Spatrick }
923e5dd7070Spatrick }
924*12c85518Srobert static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
925*12c85518Srobert Expr *SubstExpr,
926*12c85518Srobert bool First = true);
927e5dd7070Spatrick
diagnoseUnsatisfiedRequirement(Sema & S,concepts::NestedRequirement * Req,bool First)928e5dd7070Spatrick static void diagnoseUnsatisfiedRequirement(Sema &S,
929e5dd7070Spatrick concepts::NestedRequirement *Req,
930e5dd7070Spatrick bool First) {
931*12c85518Srobert using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>;
932*12c85518Srobert for (auto &Pair : Req->getConstraintSatisfaction()) {
933*12c85518Srobert if (auto *SubstDiag = Pair.second.dyn_cast<SubstitutionDiagnostic *>())
934*12c85518Srobert S.Diag(SubstDiag->first, diag::note_nested_requirement_substitution_error)
935*12c85518Srobert << (int)First << Req->getInvalidConstraintEntity() << SubstDiag->second;
936e5dd7070Spatrick else
937*12c85518Srobert diagnoseWellFormedUnsatisfiedConstraintExpr(
938*12c85518Srobert S, Pair.second.dyn_cast<Expr *>(), First);
939*12c85518Srobert First = false;
940e5dd7070Spatrick }
941e5dd7070Spatrick }
942e5dd7070Spatrick
diagnoseWellFormedUnsatisfiedConstraintExpr(Sema & S,Expr * SubstExpr,bool First)943e5dd7070Spatrick static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
944e5dd7070Spatrick Expr *SubstExpr,
945*12c85518Srobert bool First) {
946e5dd7070Spatrick SubstExpr = SubstExpr->IgnoreParenImpCasts();
947e5dd7070Spatrick if (BinaryOperator *BO = dyn_cast<BinaryOperator>(SubstExpr)) {
948e5dd7070Spatrick switch (BO->getOpcode()) {
949e5dd7070Spatrick // These two cases will in practice only be reached when using fold
950e5dd7070Spatrick // expressions with || and &&, since otherwise the || and && will have been
951e5dd7070Spatrick // broken down into atomic constraints during satisfaction checking.
952e5dd7070Spatrick case BO_LOr:
953e5dd7070Spatrick // Or evaluated to false - meaning both RHS and LHS evaluated to false.
954e5dd7070Spatrick diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getLHS(), First);
955e5dd7070Spatrick diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(),
956e5dd7070Spatrick /*First=*/false);
957e5dd7070Spatrick return;
958a9ac8606Spatrick case BO_LAnd: {
959a9ac8606Spatrick bool LHSSatisfied =
960a9ac8606Spatrick BO->getLHS()->EvaluateKnownConstInt(S.Context).getBoolValue();
961e5dd7070Spatrick if (LHSSatisfied) {
962e5dd7070Spatrick // LHS is true, so RHS must be false.
963e5dd7070Spatrick diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(), First);
964e5dd7070Spatrick return;
965e5dd7070Spatrick }
966e5dd7070Spatrick // LHS is false
967e5dd7070Spatrick diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getLHS(), First);
968e5dd7070Spatrick
969e5dd7070Spatrick // RHS might also be false
970a9ac8606Spatrick bool RHSSatisfied =
971a9ac8606Spatrick BO->getRHS()->EvaluateKnownConstInt(S.Context).getBoolValue();
972e5dd7070Spatrick if (!RHSSatisfied)
973e5dd7070Spatrick diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(),
974e5dd7070Spatrick /*First=*/false);
975e5dd7070Spatrick return;
976a9ac8606Spatrick }
977e5dd7070Spatrick case BO_GE:
978e5dd7070Spatrick case BO_LE:
979e5dd7070Spatrick case BO_GT:
980e5dd7070Spatrick case BO_LT:
981e5dd7070Spatrick case BO_EQ:
982e5dd7070Spatrick case BO_NE:
983e5dd7070Spatrick if (BO->getLHS()->getType()->isIntegerType() &&
984e5dd7070Spatrick BO->getRHS()->getType()->isIntegerType()) {
985e5dd7070Spatrick Expr::EvalResult SimplifiedLHS;
986e5dd7070Spatrick Expr::EvalResult SimplifiedRHS;
987a9ac8606Spatrick BO->getLHS()->EvaluateAsInt(SimplifiedLHS, S.Context,
988a9ac8606Spatrick Expr::SE_NoSideEffects,
989a9ac8606Spatrick /*InConstantContext=*/true);
990a9ac8606Spatrick BO->getRHS()->EvaluateAsInt(SimplifiedRHS, S.Context,
991a9ac8606Spatrick Expr::SE_NoSideEffects,
992a9ac8606Spatrick /*InConstantContext=*/true);
993e5dd7070Spatrick if (!SimplifiedLHS.Diag && ! SimplifiedRHS.Diag) {
994e5dd7070Spatrick S.Diag(SubstExpr->getBeginLoc(),
995e5dd7070Spatrick diag::note_atomic_constraint_evaluated_to_false_elaborated)
996e5dd7070Spatrick << (int)First << SubstExpr
997a9ac8606Spatrick << toString(SimplifiedLHS.Val.getInt(), 10)
998e5dd7070Spatrick << BinaryOperator::getOpcodeStr(BO->getOpcode())
999a9ac8606Spatrick << toString(SimplifiedRHS.Val.getInt(), 10);
1000e5dd7070Spatrick return;
1001e5dd7070Spatrick }
1002e5dd7070Spatrick }
1003e5dd7070Spatrick break;
1004e5dd7070Spatrick
1005e5dd7070Spatrick default:
1006e5dd7070Spatrick break;
1007e5dd7070Spatrick }
1008e5dd7070Spatrick } else if (auto *CSE = dyn_cast<ConceptSpecializationExpr>(SubstExpr)) {
1009e5dd7070Spatrick if (CSE->getTemplateArgsAsWritten()->NumTemplateArgs == 1) {
1010e5dd7070Spatrick S.Diag(
1011e5dd7070Spatrick CSE->getSourceRange().getBegin(),
1012e5dd7070Spatrick diag::
1013e5dd7070Spatrick note_single_arg_concept_specialization_constraint_evaluated_to_false)
1014e5dd7070Spatrick << (int)First
1015e5dd7070Spatrick << CSE->getTemplateArgsAsWritten()->arguments()[0].getArgument()
1016e5dd7070Spatrick << CSE->getNamedConcept();
1017e5dd7070Spatrick } else {
1018e5dd7070Spatrick S.Diag(SubstExpr->getSourceRange().getBegin(),
1019e5dd7070Spatrick diag::note_concept_specialization_constraint_evaluated_to_false)
1020e5dd7070Spatrick << (int)First << CSE;
1021e5dd7070Spatrick }
1022e5dd7070Spatrick S.DiagnoseUnsatisfiedConstraint(CSE->getSatisfaction());
1023e5dd7070Spatrick return;
1024e5dd7070Spatrick } else if (auto *RE = dyn_cast<RequiresExpr>(SubstExpr)) {
1025*12c85518Srobert // FIXME: RequiresExpr should store dependent diagnostics.
1026e5dd7070Spatrick for (concepts::Requirement *Req : RE->getRequirements())
1027e5dd7070Spatrick if (!Req->isDependent() && !Req->isSatisfied()) {
1028e5dd7070Spatrick if (auto *E = dyn_cast<concepts::ExprRequirement>(Req))
1029e5dd7070Spatrick diagnoseUnsatisfiedRequirement(S, E, First);
1030e5dd7070Spatrick else if (auto *T = dyn_cast<concepts::TypeRequirement>(Req))
1031e5dd7070Spatrick diagnoseUnsatisfiedRequirement(S, T, First);
1032e5dd7070Spatrick else
1033e5dd7070Spatrick diagnoseUnsatisfiedRequirement(
1034e5dd7070Spatrick S, cast<concepts::NestedRequirement>(Req), First);
1035e5dd7070Spatrick break;
1036e5dd7070Spatrick }
1037e5dd7070Spatrick return;
1038e5dd7070Spatrick }
1039e5dd7070Spatrick
1040e5dd7070Spatrick S.Diag(SubstExpr->getSourceRange().getBegin(),
1041e5dd7070Spatrick diag::note_atomic_constraint_evaluated_to_false)
1042e5dd7070Spatrick << (int)First << SubstExpr;
1043e5dd7070Spatrick }
1044e5dd7070Spatrick
1045e5dd7070Spatrick template<typename SubstitutionDiagnostic>
diagnoseUnsatisfiedConstraintExpr(Sema & S,const Expr * E,const llvm::PointerUnion<Expr *,SubstitutionDiagnostic * > & Record,bool First=true)1046e5dd7070Spatrick static void diagnoseUnsatisfiedConstraintExpr(
1047e5dd7070Spatrick Sema &S, const Expr *E,
1048e5dd7070Spatrick const llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> &Record,
1049e5dd7070Spatrick bool First = true) {
1050e5dd7070Spatrick if (auto *Diag = Record.template dyn_cast<SubstitutionDiagnostic *>()){
1051e5dd7070Spatrick S.Diag(Diag->first, diag::note_substituted_constraint_expr_is_ill_formed)
1052e5dd7070Spatrick << Diag->second;
1053e5dd7070Spatrick return;
1054e5dd7070Spatrick }
1055e5dd7070Spatrick
1056e5dd7070Spatrick diagnoseWellFormedUnsatisfiedConstraintExpr(S,
1057e5dd7070Spatrick Record.template get<Expr *>(), First);
1058e5dd7070Spatrick }
1059e5dd7070Spatrick
1060e5dd7070Spatrick void
DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction & Satisfaction,bool First)1061e5dd7070Spatrick Sema::DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction& Satisfaction,
1062e5dd7070Spatrick bool First) {
1063e5dd7070Spatrick assert(!Satisfaction.IsSatisfied &&
1064e5dd7070Spatrick "Attempted to diagnose a satisfied constraint");
1065e5dd7070Spatrick for (auto &Pair : Satisfaction.Details) {
1066e5dd7070Spatrick diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First);
1067e5dd7070Spatrick First = false;
1068e5dd7070Spatrick }
1069e5dd7070Spatrick }
1070e5dd7070Spatrick
DiagnoseUnsatisfiedConstraint(const ASTConstraintSatisfaction & Satisfaction,bool First)1071e5dd7070Spatrick void Sema::DiagnoseUnsatisfiedConstraint(
1072e5dd7070Spatrick const ASTConstraintSatisfaction &Satisfaction,
1073e5dd7070Spatrick bool First) {
1074e5dd7070Spatrick assert(!Satisfaction.IsSatisfied &&
1075e5dd7070Spatrick "Attempted to diagnose a satisfied constraint");
1076e5dd7070Spatrick for (auto &Pair : Satisfaction) {
1077e5dd7070Spatrick diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First);
1078e5dd7070Spatrick First = false;
1079e5dd7070Spatrick }
1080e5dd7070Spatrick }
1081e5dd7070Spatrick
1082e5dd7070Spatrick const NormalizedConstraint *
getNormalizedAssociatedConstraints(NamedDecl * ConstrainedDecl,ArrayRef<const Expr * > AssociatedConstraints)1083e5dd7070Spatrick Sema::getNormalizedAssociatedConstraints(
1084e5dd7070Spatrick NamedDecl *ConstrainedDecl, ArrayRef<const Expr *> AssociatedConstraints) {
1085e5dd7070Spatrick auto CacheEntry = NormalizationCache.find(ConstrainedDecl);
1086e5dd7070Spatrick if (CacheEntry == NormalizationCache.end()) {
1087e5dd7070Spatrick auto Normalized =
1088e5dd7070Spatrick NormalizedConstraint::fromConstraintExprs(*this, ConstrainedDecl,
1089e5dd7070Spatrick AssociatedConstraints);
1090e5dd7070Spatrick CacheEntry =
1091e5dd7070Spatrick NormalizationCache
1092e5dd7070Spatrick .try_emplace(ConstrainedDecl,
1093e5dd7070Spatrick Normalized
1094e5dd7070Spatrick ? new (Context) NormalizedConstraint(
1095e5dd7070Spatrick std::move(*Normalized))
1096e5dd7070Spatrick : nullptr)
1097e5dd7070Spatrick .first;
1098e5dd7070Spatrick }
1099e5dd7070Spatrick return CacheEntry->second;
1100e5dd7070Spatrick }
1101e5dd7070Spatrick
1102*12c85518Srobert static bool
substituteParameterMappings(Sema & S,NormalizedConstraint & N,ConceptDecl * Concept,const MultiLevelTemplateArgumentList & MLTAL,const ASTTemplateArgumentListInfo * ArgsAsWritten)1103*12c85518Srobert substituteParameterMappings(Sema &S, NormalizedConstraint &N,
1104*12c85518Srobert ConceptDecl *Concept,
1105*12c85518Srobert const MultiLevelTemplateArgumentList &MLTAL,
1106e5dd7070Spatrick const ASTTemplateArgumentListInfo *ArgsAsWritten) {
1107e5dd7070Spatrick if (!N.isAtomic()) {
1108*12c85518Srobert if (substituteParameterMappings(S, N.getLHS(), Concept, MLTAL,
1109e5dd7070Spatrick ArgsAsWritten))
1110e5dd7070Spatrick return true;
1111*12c85518Srobert return substituteParameterMappings(S, N.getRHS(), Concept, MLTAL,
1112e5dd7070Spatrick ArgsAsWritten);
1113e5dd7070Spatrick }
1114e5dd7070Spatrick TemplateParameterList *TemplateParams = Concept->getTemplateParameters();
1115e5dd7070Spatrick
1116e5dd7070Spatrick AtomicConstraint &Atomic = *N.getAtomicConstraint();
1117e5dd7070Spatrick TemplateArgumentListInfo SubstArgs;
1118e5dd7070Spatrick if (!Atomic.ParameterMapping) {
1119e5dd7070Spatrick llvm::SmallBitVector OccurringIndices(TemplateParams->size());
1120e5dd7070Spatrick S.MarkUsedTemplateParameters(Atomic.ConstraintExpr, /*OnlyDeduced=*/false,
1121e5dd7070Spatrick /*Depth=*/0, OccurringIndices);
1122*12c85518Srobert TemplateArgumentLoc *TempArgs =
1123*12c85518Srobert new (S.Context) TemplateArgumentLoc[OccurringIndices.count()];
1124e5dd7070Spatrick for (unsigned I = 0, J = 0, C = TemplateParams->size(); I != C; ++I)
1125e5dd7070Spatrick if (OccurringIndices[I])
1126*12c85518Srobert new (&(TempArgs)[J++])
1127*12c85518Srobert TemplateArgumentLoc(S.getIdentityTemplateArgumentLoc(
1128*12c85518Srobert TemplateParams->begin()[I],
1129e5dd7070Spatrick // Here we assume we do not support things like
1130e5dd7070Spatrick // template<typename A, typename B>
1131e5dd7070Spatrick // concept C = ...;
1132e5dd7070Spatrick //
1133e5dd7070Spatrick // template<typename... Ts> requires C<Ts...>
1134e5dd7070Spatrick // struct S { };
1135e5dd7070Spatrick // The above currently yields a diagnostic.
1136e5dd7070Spatrick // We still might have default arguments for concept parameters.
1137*12c85518Srobert ArgsAsWritten->NumTemplateArgs > I
1138*12c85518Srobert ? ArgsAsWritten->arguments()[I].getLocation()
1139*12c85518Srobert : SourceLocation()));
1140*12c85518Srobert Atomic.ParameterMapping.emplace(TempArgs, OccurringIndices.count());
1141e5dd7070Spatrick }
1142e5dd7070Spatrick Sema::InstantiatingTemplate Inst(
1143e5dd7070Spatrick S, ArgsAsWritten->arguments().front().getSourceRange().getBegin(),
1144e5dd7070Spatrick Sema::InstantiatingTemplate::ParameterMappingSubstitution{}, Concept,
1145*12c85518Srobert ArgsAsWritten->arguments().front().getSourceRange());
1146e5dd7070Spatrick if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs))
1147e5dd7070Spatrick return true;
1148*12c85518Srobert
1149*12c85518Srobert TemplateArgumentLoc *TempArgs =
1150*12c85518Srobert new (S.Context) TemplateArgumentLoc[SubstArgs.size()];
1151e5dd7070Spatrick std::copy(SubstArgs.arguments().begin(), SubstArgs.arguments().end(),
1152*12c85518Srobert TempArgs);
1153*12c85518Srobert Atomic.ParameterMapping.emplace(TempArgs, SubstArgs.size());
1154e5dd7070Spatrick return false;
1155e5dd7070Spatrick }
1156e5dd7070Spatrick
substituteParameterMappings(Sema & S,NormalizedConstraint & N,const ConceptSpecializationExpr * CSE)1157*12c85518Srobert static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
1158*12c85518Srobert const ConceptSpecializationExpr *CSE) {
1159*12c85518Srobert TemplateArgumentList TAL{TemplateArgumentList::OnStack,
1160*12c85518Srobert CSE->getTemplateArguments()};
1161*12c85518Srobert MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
1162*12c85518Srobert CSE->getNamedConcept(), /*Final=*/false, &TAL,
1163*12c85518Srobert /*RelativeToPrimary=*/true,
1164*12c85518Srobert /*Pattern=*/nullptr,
1165*12c85518Srobert /*ForConstraintInstantiation=*/true);
1166*12c85518Srobert
1167*12c85518Srobert return substituteParameterMappings(S, N, CSE->getNamedConcept(), MLTAL,
1168*12c85518Srobert CSE->getTemplateArgsAsWritten());
1169*12c85518Srobert }
1170*12c85518Srobert
1171*12c85518Srobert std::optional<NormalizedConstraint>
fromConstraintExprs(Sema & S,NamedDecl * D,ArrayRef<const Expr * > E)1172e5dd7070Spatrick NormalizedConstraint::fromConstraintExprs(Sema &S, NamedDecl *D,
1173e5dd7070Spatrick ArrayRef<const Expr *> E) {
1174e5dd7070Spatrick assert(E.size() != 0);
1175a9ac8606Spatrick auto Conjunction = fromConstraintExpr(S, D, E[0]);
1176a9ac8606Spatrick if (!Conjunction)
1177*12c85518Srobert return std::nullopt;
1178a9ac8606Spatrick for (unsigned I = 1; I < E.size(); ++I) {
1179e5dd7070Spatrick auto Next = fromConstraintExpr(S, D, E[I]);
1180e5dd7070Spatrick if (!Next)
1181*12c85518Srobert return std::nullopt;
1182a9ac8606Spatrick *Conjunction = NormalizedConstraint(S.Context, std::move(*Conjunction),
1183e5dd7070Spatrick std::move(*Next), CCK_Conjunction);
1184e5dd7070Spatrick }
1185e5dd7070Spatrick return Conjunction;
1186e5dd7070Spatrick }
1187e5dd7070Spatrick
1188*12c85518Srobert std::optional<NormalizedConstraint>
fromConstraintExpr(Sema & S,NamedDecl * D,const Expr * E)1189e5dd7070Spatrick NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) {
1190e5dd7070Spatrick assert(E != nullptr);
1191e5dd7070Spatrick
1192e5dd7070Spatrick // C++ [temp.constr.normal]p1.1
1193e5dd7070Spatrick // [...]
1194e5dd7070Spatrick // - The normal form of an expression (E) is the normal form of E.
1195e5dd7070Spatrick // [...]
1196e5dd7070Spatrick E = E->IgnoreParenImpCasts();
1197*12c85518Srobert
1198*12c85518Srobert // C++2a [temp.param]p4:
1199*12c85518Srobert // [...] If T is not a pack, then E is E', otherwise E is (E' && ...).
1200*12c85518Srobert // Fold expression is considered atomic constraints per current wording.
1201*12c85518Srobert // See http://cplusplus.github.io/concepts-ts/ts-active.html#28
1202*12c85518Srobert
1203ec727ea7Spatrick if (LogicalBinOp BO = E) {
1204ec727ea7Spatrick auto LHS = fromConstraintExpr(S, D, BO.getLHS());
1205e5dd7070Spatrick if (!LHS)
1206*12c85518Srobert return std::nullopt;
1207ec727ea7Spatrick auto RHS = fromConstraintExpr(S, D, BO.getRHS());
1208e5dd7070Spatrick if (!RHS)
1209*12c85518Srobert return std::nullopt;
1210e5dd7070Spatrick
1211ec727ea7Spatrick return NormalizedConstraint(S.Context, std::move(*LHS), std::move(*RHS),
1212ec727ea7Spatrick BO.isAnd() ? CCK_Conjunction : CCK_Disjunction);
1213e5dd7070Spatrick } else if (auto *CSE = dyn_cast<const ConceptSpecializationExpr>(E)) {
1214e5dd7070Spatrick const NormalizedConstraint *SubNF;
1215e5dd7070Spatrick {
1216e5dd7070Spatrick Sema::InstantiatingTemplate Inst(
1217e5dd7070Spatrick S, CSE->getExprLoc(),
1218e5dd7070Spatrick Sema::InstantiatingTemplate::ConstraintNormalization{}, D,
1219e5dd7070Spatrick CSE->getSourceRange());
1220e5dd7070Spatrick // C++ [temp.constr.normal]p1.1
1221e5dd7070Spatrick // [...]
1222e5dd7070Spatrick // The normal form of an id-expression of the form C<A1, A2, ..., AN>,
1223e5dd7070Spatrick // where C names a concept, is the normal form of the
1224e5dd7070Spatrick // constraint-expression of C, after substituting A1, A2, ..., AN for C’s
1225e5dd7070Spatrick // respective template parameters in the parameter mappings in each atomic
1226e5dd7070Spatrick // constraint. If any such substitution results in an invalid type or
1227e5dd7070Spatrick // expression, the program is ill-formed; no diagnostic is required.
1228e5dd7070Spatrick // [...]
1229e5dd7070Spatrick ConceptDecl *CD = CSE->getNamedConcept();
1230e5dd7070Spatrick SubNF = S.getNormalizedAssociatedConstraints(CD,
1231e5dd7070Spatrick {CD->getConstraintExpr()});
1232e5dd7070Spatrick if (!SubNF)
1233*12c85518Srobert return std::nullopt;
1234e5dd7070Spatrick }
1235e5dd7070Spatrick
1236*12c85518Srobert std::optional<NormalizedConstraint> New;
1237e5dd7070Spatrick New.emplace(S.Context, *SubNF);
1238e5dd7070Spatrick
1239*12c85518Srobert if (substituteParameterMappings(S, *New, CSE))
1240*12c85518Srobert return std::nullopt;
1241e5dd7070Spatrick
1242e5dd7070Spatrick return New;
1243e5dd7070Spatrick }
1244e5dd7070Spatrick return NormalizedConstraint{new (S.Context) AtomicConstraint(S, E)};
1245e5dd7070Spatrick }
1246e5dd7070Spatrick
1247e5dd7070Spatrick using NormalForm =
1248e5dd7070Spatrick llvm::SmallVector<llvm::SmallVector<AtomicConstraint *, 2>, 4>;
1249e5dd7070Spatrick
makeCNF(const NormalizedConstraint & Normalized)1250e5dd7070Spatrick static NormalForm makeCNF(const NormalizedConstraint &Normalized) {
1251e5dd7070Spatrick if (Normalized.isAtomic())
1252e5dd7070Spatrick return {{Normalized.getAtomicConstraint()}};
1253e5dd7070Spatrick
1254e5dd7070Spatrick NormalForm LCNF = makeCNF(Normalized.getLHS());
1255e5dd7070Spatrick NormalForm RCNF = makeCNF(Normalized.getRHS());
1256e5dd7070Spatrick if (Normalized.getCompoundKind() == NormalizedConstraint::CCK_Conjunction) {
1257e5dd7070Spatrick LCNF.reserve(LCNF.size() + RCNF.size());
1258e5dd7070Spatrick while (!RCNF.empty())
1259e5dd7070Spatrick LCNF.push_back(RCNF.pop_back_val());
1260e5dd7070Spatrick return LCNF;
1261e5dd7070Spatrick }
1262e5dd7070Spatrick
1263e5dd7070Spatrick // Disjunction
1264e5dd7070Spatrick NormalForm Res;
1265e5dd7070Spatrick Res.reserve(LCNF.size() * RCNF.size());
1266e5dd7070Spatrick for (auto &LDisjunction : LCNF)
1267e5dd7070Spatrick for (auto &RDisjunction : RCNF) {
1268e5dd7070Spatrick NormalForm::value_type Combined;
1269e5dd7070Spatrick Combined.reserve(LDisjunction.size() + RDisjunction.size());
1270e5dd7070Spatrick std::copy(LDisjunction.begin(), LDisjunction.end(),
1271e5dd7070Spatrick std::back_inserter(Combined));
1272e5dd7070Spatrick std::copy(RDisjunction.begin(), RDisjunction.end(),
1273e5dd7070Spatrick std::back_inserter(Combined));
1274e5dd7070Spatrick Res.emplace_back(Combined);
1275e5dd7070Spatrick }
1276e5dd7070Spatrick return Res;
1277e5dd7070Spatrick }
1278e5dd7070Spatrick
makeDNF(const NormalizedConstraint & Normalized)1279e5dd7070Spatrick static NormalForm makeDNF(const NormalizedConstraint &Normalized) {
1280e5dd7070Spatrick if (Normalized.isAtomic())
1281e5dd7070Spatrick return {{Normalized.getAtomicConstraint()}};
1282e5dd7070Spatrick
1283e5dd7070Spatrick NormalForm LDNF = makeDNF(Normalized.getLHS());
1284e5dd7070Spatrick NormalForm RDNF = makeDNF(Normalized.getRHS());
1285e5dd7070Spatrick if (Normalized.getCompoundKind() == NormalizedConstraint::CCK_Disjunction) {
1286e5dd7070Spatrick LDNF.reserve(LDNF.size() + RDNF.size());
1287e5dd7070Spatrick while (!RDNF.empty())
1288e5dd7070Spatrick LDNF.push_back(RDNF.pop_back_val());
1289e5dd7070Spatrick return LDNF;
1290e5dd7070Spatrick }
1291e5dd7070Spatrick
1292e5dd7070Spatrick // Conjunction
1293e5dd7070Spatrick NormalForm Res;
1294e5dd7070Spatrick Res.reserve(LDNF.size() * RDNF.size());
1295e5dd7070Spatrick for (auto &LConjunction : LDNF) {
1296e5dd7070Spatrick for (auto &RConjunction : RDNF) {
1297e5dd7070Spatrick NormalForm::value_type Combined;
1298e5dd7070Spatrick Combined.reserve(LConjunction.size() + RConjunction.size());
1299e5dd7070Spatrick std::copy(LConjunction.begin(), LConjunction.end(),
1300e5dd7070Spatrick std::back_inserter(Combined));
1301e5dd7070Spatrick std::copy(RConjunction.begin(), RConjunction.end(),
1302e5dd7070Spatrick std::back_inserter(Combined));
1303e5dd7070Spatrick Res.emplace_back(Combined);
1304e5dd7070Spatrick }
1305e5dd7070Spatrick }
1306e5dd7070Spatrick return Res;
1307e5dd7070Spatrick }
1308e5dd7070Spatrick
1309e5dd7070Spatrick template<typename AtomicSubsumptionEvaluator>
subsumes(NormalForm PDNF,NormalForm QCNF,AtomicSubsumptionEvaluator E)1310e5dd7070Spatrick static bool subsumes(NormalForm PDNF, NormalForm QCNF,
1311e5dd7070Spatrick AtomicSubsumptionEvaluator E) {
1312e5dd7070Spatrick // C++ [temp.constr.order] p2
1313e5dd7070Spatrick // Then, P subsumes Q if and only if, for every disjunctive clause Pi in the
1314e5dd7070Spatrick // disjunctive normal form of P, Pi subsumes every conjunctive clause Qj in
1315e5dd7070Spatrick // the conjuctive normal form of Q, where [...]
1316e5dd7070Spatrick for (const auto &Pi : PDNF) {
1317e5dd7070Spatrick for (const auto &Qj : QCNF) {
1318e5dd7070Spatrick // C++ [temp.constr.order] p2
1319e5dd7070Spatrick // - [...] a disjunctive clause Pi subsumes a conjunctive clause Qj if
1320e5dd7070Spatrick // and only if there exists an atomic constraint Pia in Pi for which
1321e5dd7070Spatrick // there exists an atomic constraint, Qjb, in Qj such that Pia
1322e5dd7070Spatrick // subsumes Qjb.
1323e5dd7070Spatrick bool Found = false;
1324e5dd7070Spatrick for (const AtomicConstraint *Pia : Pi) {
1325e5dd7070Spatrick for (const AtomicConstraint *Qjb : Qj) {
1326e5dd7070Spatrick if (E(*Pia, *Qjb)) {
1327e5dd7070Spatrick Found = true;
1328e5dd7070Spatrick break;
1329e5dd7070Spatrick }
1330e5dd7070Spatrick }
1331e5dd7070Spatrick if (Found)
1332e5dd7070Spatrick break;
1333e5dd7070Spatrick }
1334e5dd7070Spatrick if (!Found)
1335e5dd7070Spatrick return false;
1336e5dd7070Spatrick }
1337e5dd7070Spatrick }
1338e5dd7070Spatrick return true;
1339e5dd7070Spatrick }
1340e5dd7070Spatrick
1341e5dd7070Spatrick template<typename AtomicSubsumptionEvaluator>
subsumes(Sema & S,NamedDecl * DP,ArrayRef<const Expr * > P,NamedDecl * DQ,ArrayRef<const Expr * > Q,bool & Subsumes,AtomicSubsumptionEvaluator E)1342e5dd7070Spatrick static bool subsumes(Sema &S, NamedDecl *DP, ArrayRef<const Expr *> P,
1343e5dd7070Spatrick NamedDecl *DQ, ArrayRef<const Expr *> Q, bool &Subsumes,
1344e5dd7070Spatrick AtomicSubsumptionEvaluator E) {
1345e5dd7070Spatrick // C++ [temp.constr.order] p2
1346e5dd7070Spatrick // In order to determine if a constraint P subsumes a constraint Q, P is
1347e5dd7070Spatrick // transformed into disjunctive normal form, and Q is transformed into
1348e5dd7070Spatrick // conjunctive normal form. [...]
1349e5dd7070Spatrick auto *PNormalized = S.getNormalizedAssociatedConstraints(DP, P);
1350e5dd7070Spatrick if (!PNormalized)
1351e5dd7070Spatrick return true;
1352e5dd7070Spatrick const NormalForm PDNF = makeDNF(*PNormalized);
1353e5dd7070Spatrick
1354e5dd7070Spatrick auto *QNormalized = S.getNormalizedAssociatedConstraints(DQ, Q);
1355e5dd7070Spatrick if (!QNormalized)
1356e5dd7070Spatrick return true;
1357e5dd7070Spatrick const NormalForm QCNF = makeCNF(*QNormalized);
1358e5dd7070Spatrick
1359e5dd7070Spatrick Subsumes = subsumes(PDNF, QCNF, E);
1360e5dd7070Spatrick return false;
1361e5dd7070Spatrick }
1362e5dd7070Spatrick
IsAtLeastAsConstrained(NamedDecl * D1,MutableArrayRef<const Expr * > AC1,NamedDecl * D2,MutableArrayRef<const Expr * > AC2,bool & Result)1363*12c85518Srobert bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
1364*12c85518Srobert MutableArrayRef<const Expr *> AC1,
1365*12c85518Srobert NamedDecl *D2,
1366*12c85518Srobert MutableArrayRef<const Expr *> AC2,
1367e5dd7070Spatrick bool &Result) {
1368*12c85518Srobert if (const auto *FD1 = dyn_cast<FunctionDecl>(D1)) {
1369*12c85518Srobert auto IsExpectedEntity = [](const FunctionDecl *FD) {
1370*12c85518Srobert FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
1371*12c85518Srobert return Kind == FunctionDecl::TK_NonTemplate ||
1372*12c85518Srobert Kind == FunctionDecl::TK_FunctionTemplate;
1373*12c85518Srobert };
1374*12c85518Srobert const auto *FD2 = dyn_cast<FunctionDecl>(D2);
1375*12c85518Srobert (void)IsExpectedEntity;
1376*12c85518Srobert (void)FD1;
1377*12c85518Srobert (void)FD2;
1378*12c85518Srobert assert(IsExpectedEntity(FD1) && FD2 && IsExpectedEntity(FD2) &&
1379*12c85518Srobert "use non-instantiated function declaration for constraints partial "
1380*12c85518Srobert "ordering");
1381*12c85518Srobert }
1382*12c85518Srobert
1383e5dd7070Spatrick if (AC1.empty()) {
1384e5dd7070Spatrick Result = AC2.empty();
1385e5dd7070Spatrick return false;
1386e5dd7070Spatrick }
1387e5dd7070Spatrick if (AC2.empty()) {
1388e5dd7070Spatrick // TD1 has associated constraints and TD2 does not.
1389e5dd7070Spatrick Result = true;
1390e5dd7070Spatrick return false;
1391e5dd7070Spatrick }
1392e5dd7070Spatrick
1393e5dd7070Spatrick std::pair<NamedDecl *, NamedDecl *> Key{D1, D2};
1394e5dd7070Spatrick auto CacheEntry = SubsumptionCache.find(Key);
1395e5dd7070Spatrick if (CacheEntry != SubsumptionCache.end()) {
1396e5dd7070Spatrick Result = CacheEntry->second;
1397e5dd7070Spatrick return false;
1398e5dd7070Spatrick }
1399e5dd7070Spatrick
1400*12c85518Srobert unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1, true);
1401*12c85518Srobert unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2, true);
1402*12c85518Srobert
1403*12c85518Srobert for (size_t I = 0; I != AC1.size() && I != AC2.size(); ++I) {
1404*12c85518Srobert if (Depth2 > Depth1) {
1405*12c85518Srobert AC1[I] = AdjustConstraintDepth(*this, Depth2 - Depth1)
1406*12c85518Srobert .TransformExpr(const_cast<Expr *>(AC1[I]))
1407*12c85518Srobert .get();
1408*12c85518Srobert } else if (Depth1 > Depth2) {
1409*12c85518Srobert AC2[I] = AdjustConstraintDepth(*this, Depth1 - Depth2)
1410*12c85518Srobert .TransformExpr(const_cast<Expr *>(AC2[I]))
1411*12c85518Srobert .get();
1412*12c85518Srobert }
1413*12c85518Srobert }
1414*12c85518Srobert
1415e5dd7070Spatrick if (subsumes(*this, D1, AC1, D2, AC2, Result,
1416e5dd7070Spatrick [this] (const AtomicConstraint &A, const AtomicConstraint &B) {
1417e5dd7070Spatrick return A.subsumes(Context, B);
1418e5dd7070Spatrick }))
1419e5dd7070Spatrick return true;
1420e5dd7070Spatrick SubsumptionCache.try_emplace(Key, Result);
1421e5dd7070Spatrick return false;
1422e5dd7070Spatrick }
1423e5dd7070Spatrick
MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl * D1,ArrayRef<const Expr * > AC1,NamedDecl * D2,ArrayRef<const Expr * > AC2)1424e5dd7070Spatrick bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1,
1425e5dd7070Spatrick ArrayRef<const Expr *> AC1, NamedDecl *D2, ArrayRef<const Expr *> AC2) {
1426e5dd7070Spatrick if (isSFINAEContext())
1427e5dd7070Spatrick // No need to work here because our notes would be discarded.
1428e5dd7070Spatrick return false;
1429e5dd7070Spatrick
1430e5dd7070Spatrick if (AC1.empty() || AC2.empty())
1431e5dd7070Spatrick return false;
1432e5dd7070Spatrick
1433e5dd7070Spatrick auto NormalExprEvaluator =
1434e5dd7070Spatrick [this] (const AtomicConstraint &A, const AtomicConstraint &B) {
1435e5dd7070Spatrick return A.subsumes(Context, B);
1436e5dd7070Spatrick };
1437e5dd7070Spatrick
1438e5dd7070Spatrick const Expr *AmbiguousAtomic1 = nullptr, *AmbiguousAtomic2 = nullptr;
1439e5dd7070Spatrick auto IdenticalExprEvaluator =
1440e5dd7070Spatrick [&] (const AtomicConstraint &A, const AtomicConstraint &B) {
1441e5dd7070Spatrick if (!A.hasMatchingParameterMapping(Context, B))
1442e5dd7070Spatrick return false;
1443e5dd7070Spatrick const Expr *EA = A.ConstraintExpr, *EB = B.ConstraintExpr;
1444e5dd7070Spatrick if (EA == EB)
1445e5dd7070Spatrick return true;
1446e5dd7070Spatrick
1447e5dd7070Spatrick // Not the same source level expression - are the expressions
1448e5dd7070Spatrick // identical?
1449e5dd7070Spatrick llvm::FoldingSetNodeID IDA, IDB;
1450*12c85518Srobert EA->Profile(IDA, Context, /*Canonical=*/true);
1451*12c85518Srobert EB->Profile(IDB, Context, /*Canonical=*/true);
1452e5dd7070Spatrick if (IDA != IDB)
1453e5dd7070Spatrick return false;
1454e5dd7070Spatrick
1455e5dd7070Spatrick AmbiguousAtomic1 = EA;
1456e5dd7070Spatrick AmbiguousAtomic2 = EB;
1457e5dd7070Spatrick return true;
1458e5dd7070Spatrick };
1459e5dd7070Spatrick
1460e5dd7070Spatrick {
1461e5dd7070Spatrick // The subsumption checks might cause diagnostics
1462e5dd7070Spatrick SFINAETrap Trap(*this);
1463e5dd7070Spatrick auto *Normalized1 = getNormalizedAssociatedConstraints(D1, AC1);
1464e5dd7070Spatrick if (!Normalized1)
1465e5dd7070Spatrick return false;
1466e5dd7070Spatrick const NormalForm DNF1 = makeDNF(*Normalized1);
1467e5dd7070Spatrick const NormalForm CNF1 = makeCNF(*Normalized1);
1468e5dd7070Spatrick
1469e5dd7070Spatrick auto *Normalized2 = getNormalizedAssociatedConstraints(D2, AC2);
1470e5dd7070Spatrick if (!Normalized2)
1471e5dd7070Spatrick return false;
1472e5dd7070Spatrick const NormalForm DNF2 = makeDNF(*Normalized2);
1473e5dd7070Spatrick const NormalForm CNF2 = makeCNF(*Normalized2);
1474e5dd7070Spatrick
1475e5dd7070Spatrick bool Is1AtLeastAs2Normally = subsumes(DNF1, CNF2, NormalExprEvaluator);
1476e5dd7070Spatrick bool Is2AtLeastAs1Normally = subsumes(DNF2, CNF1, NormalExprEvaluator);
1477e5dd7070Spatrick bool Is1AtLeastAs2 = subsumes(DNF1, CNF2, IdenticalExprEvaluator);
1478e5dd7070Spatrick bool Is2AtLeastAs1 = subsumes(DNF2, CNF1, IdenticalExprEvaluator);
1479e5dd7070Spatrick if (Is1AtLeastAs2 == Is1AtLeastAs2Normally &&
1480e5dd7070Spatrick Is2AtLeastAs1 == Is2AtLeastAs1Normally)
1481e5dd7070Spatrick // Same result - no ambiguity was caused by identical atomic expressions.
1482e5dd7070Spatrick return false;
1483e5dd7070Spatrick }
1484e5dd7070Spatrick
1485e5dd7070Spatrick // A different result! Some ambiguous atomic constraint(s) caused a difference
1486e5dd7070Spatrick assert(AmbiguousAtomic1 && AmbiguousAtomic2);
1487e5dd7070Spatrick
1488e5dd7070Spatrick Diag(AmbiguousAtomic1->getBeginLoc(), diag::note_ambiguous_atomic_constraints)
1489e5dd7070Spatrick << AmbiguousAtomic1->getSourceRange();
1490e5dd7070Spatrick Diag(AmbiguousAtomic2->getBeginLoc(),
1491e5dd7070Spatrick diag::note_ambiguous_atomic_constraints_similar_expression)
1492e5dd7070Spatrick << AmbiguousAtomic2->getSourceRange();
1493e5dd7070Spatrick return true;
1494e5dd7070Spatrick }
1495e5dd7070Spatrick
ExprRequirement(Expr * E,bool IsSimple,SourceLocation NoexceptLoc,ReturnTypeRequirement Req,SatisfactionStatus Status,ConceptSpecializationExpr * SubstitutedConstraintExpr)1496e5dd7070Spatrick concepts::ExprRequirement::ExprRequirement(
1497e5dd7070Spatrick Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
1498e5dd7070Spatrick ReturnTypeRequirement Req, SatisfactionStatus Status,
1499e5dd7070Spatrick ConceptSpecializationExpr *SubstitutedConstraintExpr) :
1500e5dd7070Spatrick Requirement(IsSimple ? RK_Simple : RK_Compound, Status == SS_Dependent,
1501e5dd7070Spatrick Status == SS_Dependent &&
1502e5dd7070Spatrick (E->containsUnexpandedParameterPack() ||
1503e5dd7070Spatrick Req.containsUnexpandedParameterPack()),
1504e5dd7070Spatrick Status == SS_Satisfied), Value(E), NoexceptLoc(NoexceptLoc),
1505e5dd7070Spatrick TypeReq(Req), SubstitutedConstraintExpr(SubstitutedConstraintExpr),
1506e5dd7070Spatrick Status(Status) {
1507e5dd7070Spatrick assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) &&
1508e5dd7070Spatrick "Simple requirement must not have a return type requirement or a "
1509e5dd7070Spatrick "noexcept specification");
1510e5dd7070Spatrick assert((Status > SS_TypeRequirementSubstitutionFailure && Req.isTypeConstraint()) ==
1511e5dd7070Spatrick (SubstitutedConstraintExpr != nullptr));
1512e5dd7070Spatrick }
1513e5dd7070Spatrick
ExprRequirement(SubstitutionDiagnostic * ExprSubstDiag,bool IsSimple,SourceLocation NoexceptLoc,ReturnTypeRequirement Req)1514e5dd7070Spatrick concepts::ExprRequirement::ExprRequirement(
1515e5dd7070Spatrick SubstitutionDiagnostic *ExprSubstDiag, bool IsSimple,
1516e5dd7070Spatrick SourceLocation NoexceptLoc, ReturnTypeRequirement Req) :
1517e5dd7070Spatrick Requirement(IsSimple ? RK_Simple : RK_Compound, Req.isDependent(),
1518e5dd7070Spatrick Req.containsUnexpandedParameterPack(), /*IsSatisfied=*/false),
1519e5dd7070Spatrick Value(ExprSubstDiag), NoexceptLoc(NoexceptLoc), TypeReq(Req),
1520e5dd7070Spatrick Status(SS_ExprSubstitutionFailure) {
1521e5dd7070Spatrick assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) &&
1522e5dd7070Spatrick "Simple requirement must not have a return type requirement or a "
1523e5dd7070Spatrick "noexcept specification");
1524e5dd7070Spatrick }
1525e5dd7070Spatrick
1526e5dd7070Spatrick concepts::ExprRequirement::ReturnTypeRequirement::
ReturnTypeRequirement(TemplateParameterList * TPL)1527e5dd7070Spatrick ReturnTypeRequirement(TemplateParameterList *TPL) :
1528*12c85518Srobert TypeConstraintInfo(TPL, false) {
1529e5dd7070Spatrick assert(TPL->size() == 1);
1530e5dd7070Spatrick const TypeConstraint *TC =
1531e5dd7070Spatrick cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint();
1532e5dd7070Spatrick assert(TC &&
1533e5dd7070Spatrick "TPL must have a template type parameter with a type constraint");
1534e5dd7070Spatrick auto *Constraint =
1535*12c85518Srobert cast<ConceptSpecializationExpr>(TC->getImmediatelyDeclaredConstraint());
1536a9ac8606Spatrick bool Dependent =
1537a9ac8606Spatrick Constraint->getTemplateArgsAsWritten() &&
1538a9ac8606Spatrick TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
1539a9ac8606Spatrick Constraint->getTemplateArgsAsWritten()->arguments().drop_front(1));
1540*12c85518Srobert TypeConstraintInfo.setInt(Dependent ? true : false);
1541e5dd7070Spatrick }
1542e5dd7070Spatrick
TypeRequirement(TypeSourceInfo * T)1543e5dd7070Spatrick concepts::TypeRequirement::TypeRequirement(TypeSourceInfo *T) :
1544a9ac8606Spatrick Requirement(RK_Type, T->getType()->isInstantiationDependentType(),
1545e5dd7070Spatrick T->getType()->containsUnexpandedParameterPack(),
1546e5dd7070Spatrick // We reach this ctor with either dependent types (in which
1547e5dd7070Spatrick // IsSatisfied doesn't matter) or with non-dependent type in
1548e5dd7070Spatrick // which the existence of the type indicates satisfaction.
1549a9ac8606Spatrick /*IsSatisfied=*/true),
1550a9ac8606Spatrick Value(T),
1551a9ac8606Spatrick Status(T->getType()->isInstantiationDependentType() ? SS_Dependent
1552a9ac8606Spatrick : SS_Satisfied) {}
1553