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