File: | clang/lib/Sema/SemaConcept.cpp |
Warning: | line 1079, column 7 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- SemaConcept.cpp - Semantic Analysis for Constraints and Concepts --===// | |||
2 | // | |||
3 | // The LLVM Compiler Infrastructure | |||
4 | // | |||
5 | // This file is distributed under the University of Illinois Open Source | |||
6 | // License. See LICENSE.TXT for details. | |||
7 | // | |||
8 | //===----------------------------------------------------------------------===// | |||
9 | // | |||
10 | // This file implements semantic analysis for C++ constraints and concepts. | |||
11 | // | |||
12 | //===----------------------------------------------------------------------===// | |||
13 | ||||
14 | #include "clang/Sema/SemaConcept.h" | |||
15 | #include "clang/Sema/Sema.h" | |||
16 | #include "clang/Sema/SemaInternal.h" | |||
17 | #include "clang/Sema/SemaDiagnostic.h" | |||
18 | #include "clang/Sema/TemplateDeduction.h" | |||
19 | #include "clang/Sema/Template.h" | |||
20 | #include "clang/Sema/Overload.h" | |||
21 | #include "clang/Sema/Initialization.h" | |||
22 | #include "clang/Sema/SemaInternal.h" | |||
23 | #include "clang/AST/ExprConcepts.h" | |||
24 | #include "clang/AST/RecursiveASTVisitor.h" | |||
25 | #include "clang/Basic/OperatorPrecedence.h" | |||
26 | #include "llvm/ADT/DenseMap.h" | |||
27 | #include "llvm/ADT/PointerUnion.h" | |||
28 | #include "llvm/ADT/StringExtras.h" | |||
29 | ||||
30 | using namespace clang; | |||
31 | using namespace sema; | |||
32 | ||||
33 | namespace { | |||
34 | class LogicalBinOp { | |||
35 | OverloadedOperatorKind Op = OO_None; | |||
36 | const Expr *LHS = nullptr; | |||
37 | const Expr *RHS = nullptr; | |||
38 | ||||
39 | public: | |||
40 | LogicalBinOp(const Expr *E) { | |||
41 | if (auto *BO = dyn_cast<BinaryOperator>(E)) { | |||
42 | Op = BinaryOperator::getOverloadedOperator(BO->getOpcode()); | |||
43 | LHS = BO->getLHS(); | |||
44 | RHS = BO->getRHS(); | |||
45 | } else if (auto *OO = dyn_cast<CXXOperatorCallExpr>(E)) { | |||
46 | // If OO is not || or && it might not have exactly 2 arguments. | |||
47 | if (OO->getNumArgs() == 2) { | |||
48 | Op = OO->getOperator(); | |||
49 | LHS = OO->getArg(0); | |||
50 | RHS = OO->getArg(1); | |||
51 | } | |||
52 | } | |||
53 | } | |||
54 | ||||
55 | bool isAnd() const { return Op == OO_AmpAmp; } | |||
56 | bool isOr() const { return Op == OO_PipePipe; } | |||
57 | explicit operator bool() const { return isAnd() || isOr(); } | |||
58 | ||||
59 | const Expr *getLHS() const { return LHS; } | |||
60 | const Expr *getRHS() const { return RHS; } | |||
61 | }; | |||
62 | } | |||
63 | ||||
64 | bool Sema::CheckConstraintExpression(const Expr *ConstraintExpression, | |||
65 | Token NextToken, bool *PossibleNonPrimary, | |||
66 | bool IsTrailingRequiresClause) { | |||
67 | // C++2a [temp.constr.atomic]p1 | |||
68 | // ..E shall be a constant expression of type bool. | |||
69 | ||||
70 | ConstraintExpression = ConstraintExpression->IgnoreParenImpCasts(); | |||
71 | ||||
72 | if (LogicalBinOp BO = ConstraintExpression) { | |||
73 | return CheckConstraintExpression(BO.getLHS(), NextToken, | |||
74 | PossibleNonPrimary) && | |||
75 | CheckConstraintExpression(BO.getRHS(), NextToken, | |||
76 | PossibleNonPrimary); | |||
77 | } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpression)) | |||
78 | return CheckConstraintExpression(C->getSubExpr(), NextToken, | |||
79 | PossibleNonPrimary); | |||
80 | ||||
81 | QualType Type = ConstraintExpression->getType(); | |||
82 | ||||
83 | auto CheckForNonPrimary = [&] { | |||
84 | if (PossibleNonPrimary) | |||
85 | *PossibleNonPrimary = | |||
86 | // We have the following case: | |||
87 | // template<typename> requires func(0) struct S { }; | |||
88 | // The user probably isn't aware of the parentheses required around | |||
89 | // the function call, and we're only going to parse 'func' as the | |||
90 | // primary-expression, and complain that it is of non-bool type. | |||
91 | (NextToken.is(tok::l_paren) && | |||
92 | (IsTrailingRequiresClause || | |||
93 | (Type->isDependentType() && | |||
94 | isa<UnresolvedLookupExpr>(ConstraintExpression)) || | |||
95 | Type->isFunctionType() || | |||
96 | Type->isSpecificBuiltinType(BuiltinType::Overload))) || | |||
97 | // We have the following case: | |||
98 | // template<typename T> requires size_<T> == 0 struct S { }; | |||
99 | // The user probably isn't aware of the parentheses required around | |||
100 | // the binary operator, and we're only going to parse 'func' as the | |||
101 | // first operand, and complain that it is of non-bool type. | |||
102 | getBinOpPrecedence(NextToken.getKind(), | |||
103 | /*GreaterThanIsOperator=*/true, | |||
104 | getLangOpts().CPlusPlus11) > prec::LogicalAnd; | |||
105 | }; | |||
106 | ||||
107 | // An atomic constraint! | |||
108 | if (ConstraintExpression->isTypeDependent()) { | |||
109 | CheckForNonPrimary(); | |||
110 | return true; | |||
111 | } | |||
112 | ||||
113 | if (!Context.hasSameUnqualifiedType(Type, Context.BoolTy)) { | |||
114 | Diag(ConstraintExpression->getExprLoc(), | |||
115 | diag::err_non_bool_atomic_constraint) << Type | |||
116 | << ConstraintExpression->getSourceRange(); | |||
117 | CheckForNonPrimary(); | |||
118 | return false; | |||
119 | } | |||
120 | ||||
121 | if (PossibleNonPrimary) | |||
122 | *PossibleNonPrimary = false; | |||
123 | return true; | |||
124 | } | |||
125 | ||||
126 | template <typename AtomicEvaluator> | |||
127 | static bool | |||
128 | calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, | |||
129 | ConstraintSatisfaction &Satisfaction, | |||
130 | AtomicEvaluator &&Evaluator) { | |||
131 | ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts(); | |||
132 | ||||
133 | if (LogicalBinOp BO = ConstraintExpr) { | |||
134 | if (calculateConstraintSatisfaction(S, BO.getLHS(), Satisfaction, | |||
135 | Evaluator)) | |||
136 | return true; | |||
137 | ||||
138 | bool IsLHSSatisfied = Satisfaction.IsSatisfied; | |||
139 | ||||
140 | if (BO.isOr() && IsLHSSatisfied) | |||
141 | // [temp.constr.op] p3 | |||
142 | // A disjunction is a constraint taking two operands. To determine if | |||
143 | // a disjunction is satisfied, the satisfaction of the first operand | |||
144 | // is checked. If that is satisfied, the disjunction is satisfied. | |||
145 | // Otherwise, the disjunction is satisfied if and only if the second | |||
146 | // operand is satisfied. | |||
147 | return false; | |||
148 | ||||
149 | if (BO.isAnd() && !IsLHSSatisfied) | |||
150 | // [temp.constr.op] p2 | |||
151 | // A conjunction is a constraint taking two operands. To determine if | |||
152 | // a conjunction is satisfied, the satisfaction of the first operand | |||
153 | // is checked. If that is not satisfied, the conjunction is not | |||
154 | // satisfied. Otherwise, the conjunction is satisfied if and only if | |||
155 | // the second operand is satisfied. | |||
156 | return false; | |||
157 | ||||
158 | return calculateConstraintSatisfaction( | |||
159 | S, BO.getRHS(), Satisfaction, std::forward<AtomicEvaluator>(Evaluator)); | |||
160 | } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) { | |||
161 | return calculateConstraintSatisfaction(S, C->getSubExpr(), Satisfaction, | |||
162 | std::forward<AtomicEvaluator>(Evaluator)); | |||
163 | } | |||
164 | ||||
165 | // An atomic constraint expression | |||
166 | ExprResult SubstitutedAtomicExpr = Evaluator(ConstraintExpr); | |||
167 | ||||
168 | if (SubstitutedAtomicExpr.isInvalid()) | |||
169 | return true; | |||
170 | ||||
171 | if (!SubstitutedAtomicExpr.isUsable()) | |||
172 | // Evaluator has decided satisfaction without yielding an expression. | |||
173 | return false; | |||
174 | ||||
175 | EnterExpressionEvaluationContext ConstantEvaluated( | |||
176 | S, Sema::ExpressionEvaluationContext::ConstantEvaluated); | |||
177 | SmallVector<PartialDiagnosticAt, 2> EvaluationDiags; | |||
178 | Expr::EvalResult EvalResult; | |||
179 | EvalResult.Diag = &EvaluationDiags; | |||
180 | if (!SubstitutedAtomicExpr.get()->EvaluateAsConstantExpr(EvalResult, | |||
181 | S.Context) || | |||
182 | !EvaluationDiags.empty()) { | |||
183 | // C++2a [temp.constr.atomic]p1 | |||
184 | // ...E shall be a constant expression of type bool. | |||
185 | S.Diag(SubstitutedAtomicExpr.get()->getBeginLoc(), | |||
186 | diag::err_non_constant_constraint_expression) | |||
187 | << SubstitutedAtomicExpr.get()->getSourceRange(); | |||
188 | for (const PartialDiagnosticAt &PDiag : EvaluationDiags) | |||
189 | S.Diag(PDiag.first, PDiag.second); | |||
190 | return true; | |||
191 | } | |||
192 | ||||
193 | assert(EvalResult.Val.isInt() &&(static_cast <bool> (EvalResult.Val.isInt() && "evaluating bool expression didn't produce int" ) ? void (0) : __assert_fail ("EvalResult.Val.isInt() && \"evaluating bool expression didn't produce int\"" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 194, __extension__ __PRETTY_FUNCTION__)) | |||
194 | "evaluating bool expression didn't produce int")(static_cast <bool> (EvalResult.Val.isInt() && "evaluating bool expression didn't produce int" ) ? void (0) : __assert_fail ("EvalResult.Val.isInt() && \"evaluating bool expression didn't produce int\"" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 194, __extension__ __PRETTY_FUNCTION__)); | |||
195 | Satisfaction.IsSatisfied = EvalResult.Val.getInt().getBoolValue(); | |||
196 | if (!Satisfaction.IsSatisfied) | |||
197 | Satisfaction.Details.emplace_back(ConstraintExpr, | |||
198 | SubstitutedAtomicExpr.get()); | |||
199 | ||||
200 | return false; | |||
201 | } | |||
202 | ||||
203 | static bool calculateConstraintSatisfaction( | |||
204 | Sema &S, const NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs, | |||
205 | SourceLocation TemplateNameLoc, MultiLevelTemplateArgumentList &MLTAL, | |||
206 | const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) { | |||
207 | return calculateConstraintSatisfaction( | |||
208 | S, ConstraintExpr, Satisfaction, [&](const Expr *AtomicExpr) { | |||
209 | EnterExpressionEvaluationContext ConstantEvaluated( | |||
210 | S, Sema::ExpressionEvaluationContext::ConstantEvaluated); | |||
211 | ||||
212 | // Atomic constraint - substitute arguments and check satisfaction. | |||
213 | ExprResult SubstitutedExpression; | |||
214 | { | |||
215 | TemplateDeductionInfo Info(TemplateNameLoc); | |||
216 | Sema::InstantiatingTemplate Inst(S, AtomicExpr->getBeginLoc(), | |||
217 | Sema::InstantiatingTemplate::ConstraintSubstitution{}, | |||
218 | const_cast<NamedDecl *>(Template), Info, | |||
219 | AtomicExpr->getSourceRange()); | |||
220 | if (Inst.isInvalid()) | |||
221 | return ExprError(); | |||
222 | // We do not want error diagnostics escaping here. | |||
223 | Sema::SFINAETrap Trap(S); | |||
224 | SubstitutedExpression = S.SubstExpr(const_cast<Expr *>(AtomicExpr), | |||
225 | MLTAL); | |||
226 | // Substitution might have stripped off a contextual conversion to | |||
227 | // bool if this is the operand of an '&&' or '||'. For example, we | |||
228 | // might lose an lvalue-to-rvalue conversion here. If so, put it back | |||
229 | // before we try to evaluate. | |||
230 | if (!SubstitutedExpression.isInvalid()) | |||
231 | SubstitutedExpression = | |||
232 | S.PerformContextuallyConvertToBool(SubstitutedExpression.get()); | |||
233 | if (SubstitutedExpression.isInvalid() || Trap.hasErrorOccurred()) { | |||
234 | // C++2a [temp.constr.atomic]p1 | |||
235 | // ...If substitution results in an invalid type or expression, the | |||
236 | // constraint is not satisfied. | |||
237 | if (!Trap.hasErrorOccurred()) | |||
238 | // A non-SFINAE error has occured as a result of this | |||
239 | // substitution. | |||
240 | return ExprError(); | |||
241 | ||||
242 | PartialDiagnosticAt SubstDiag{SourceLocation(), | |||
243 | PartialDiagnostic::NullDiagnostic()}; | |||
244 | Info.takeSFINAEDiagnostic(SubstDiag); | |||
245 | // FIXME: Concepts: This is an unfortunate consequence of there | |||
246 | // being no serialization code for PartialDiagnostics and the fact | |||
247 | // that serializing them would likely take a lot more storage than | |||
248 | // just storing them as strings. We would still like, in the | |||
249 | // future, to serialize the proper PartialDiagnostic as serializing | |||
250 | // it as a string defeats the purpose of the diagnostic mechanism. | |||
251 | SmallString<128> DiagString; | |||
252 | DiagString = ": "; | |||
253 | SubstDiag.second.EmitToString(S.getDiagnostics(), DiagString); | |||
254 | unsigned MessageSize = DiagString.size(); | |||
255 | char *Mem = new (S.Context) char[MessageSize]; | |||
256 | memcpy(Mem, DiagString.c_str(), MessageSize); | |||
257 | Satisfaction.Details.emplace_back( | |||
258 | AtomicExpr, | |||
259 | new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{ | |||
260 | SubstDiag.first, StringRef(Mem, MessageSize)}); | |||
261 | Satisfaction.IsSatisfied = false; | |||
262 | return ExprEmpty(); | |||
263 | } | |||
264 | } | |||
265 | ||||
266 | if (!S.CheckConstraintExpression(SubstitutedExpression.get())) | |||
267 | return ExprError(); | |||
268 | ||||
269 | return SubstitutedExpression; | |||
270 | }); | |||
271 | } | |||
272 | ||||
273 | static bool CheckConstraintSatisfaction(Sema &S, const NamedDecl *Template, | |||
274 | ArrayRef<const Expr *> ConstraintExprs, | |||
275 | ArrayRef<TemplateArgument> TemplateArgs, | |||
276 | SourceRange TemplateIDRange, | |||
277 | ConstraintSatisfaction &Satisfaction) { | |||
278 | if (ConstraintExprs.empty()) { | |||
279 | Satisfaction.IsSatisfied = true; | |||
280 | return false; | |||
281 | } | |||
282 | ||||
283 | for (auto& Arg : TemplateArgs) | |||
284 | if (Arg.isInstantiationDependent()) { | |||
285 | // No need to check satisfaction for dependent constraint expressions. | |||
286 | Satisfaction.IsSatisfied = true; | |||
287 | return false; | |||
288 | } | |||
289 | ||||
290 | Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(), | |||
291 | Sema::InstantiatingTemplate::ConstraintsCheck{}, | |||
292 | const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange); | |||
293 | if (Inst.isInvalid()) | |||
294 | return true; | |||
295 | ||||
296 | MultiLevelTemplateArgumentList MLTAL; | |||
297 | MLTAL.addOuterTemplateArguments(TemplateArgs); | |||
298 | ||||
299 | for (const Expr *ConstraintExpr : ConstraintExprs) { | |||
300 | if (calculateConstraintSatisfaction(S, Template, TemplateArgs, | |||
301 | TemplateIDRange.getBegin(), MLTAL, | |||
302 | ConstraintExpr, Satisfaction)) | |||
303 | return true; | |||
304 | if (!Satisfaction.IsSatisfied) | |||
305 | // [temp.constr.op] p2 | |||
306 | // [...] To determine if a conjunction is satisfied, the satisfaction | |||
307 | // of the first operand is checked. If that is not satisfied, the | |||
308 | // conjunction is not satisfied. [...] | |||
309 | return false; | |||
310 | } | |||
311 | return false; | |||
312 | } | |||
313 | ||||
314 | bool Sema::CheckConstraintSatisfaction( | |||
315 | const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs, | |||
316 | ArrayRef<TemplateArgument> TemplateArgs, SourceRange TemplateIDRange, | |||
317 | ConstraintSatisfaction &OutSatisfaction) { | |||
318 | if (ConstraintExprs.empty()) { | |||
319 | OutSatisfaction.IsSatisfied = true; | |||
320 | return false; | |||
321 | } | |||
322 | ||||
323 | llvm::FoldingSetNodeID ID; | |||
324 | void *InsertPos; | |||
325 | ConstraintSatisfaction *Satisfaction = nullptr; | |||
326 | bool ShouldCache = LangOpts.ConceptSatisfactionCaching && Template; | |||
327 | if (ShouldCache) { | |||
328 | ConstraintSatisfaction::Profile(ID, Context, Template, TemplateArgs); | |||
329 | Satisfaction = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos); | |||
330 | if (Satisfaction) { | |||
331 | OutSatisfaction = *Satisfaction; | |||
332 | return false; | |||
333 | } | |||
334 | Satisfaction = new ConstraintSatisfaction(Template, TemplateArgs); | |||
335 | } else { | |||
336 | Satisfaction = &OutSatisfaction; | |||
337 | } | |||
338 | if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs, | |||
339 | TemplateArgs, TemplateIDRange, | |||
340 | *Satisfaction)) { | |||
341 | if (ShouldCache) | |||
342 | delete Satisfaction; | |||
343 | return true; | |||
344 | } | |||
345 | ||||
346 | if (ShouldCache) { | |||
347 | // We cannot use InsertNode here because CheckConstraintSatisfaction might | |||
348 | // have invalidated it. | |||
349 | SatisfactionCache.InsertNode(Satisfaction); | |||
350 | OutSatisfaction = *Satisfaction; | |||
351 | } | |||
352 | return false; | |||
353 | } | |||
354 | ||||
355 | bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr, | |||
356 | ConstraintSatisfaction &Satisfaction) { | |||
357 | return calculateConstraintSatisfaction( | |||
358 | *this, ConstraintExpr, Satisfaction, | |||
359 | [](const Expr *AtomicExpr) -> ExprResult { | |||
360 | return ExprResult(const_cast<Expr *>(AtomicExpr)); | |||
361 | }); | |||
362 | } | |||
363 | ||||
364 | bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, | |||
365 | ConstraintSatisfaction &Satisfaction, | |||
366 | SourceLocation UsageLoc) { | |||
367 | const Expr *RC = FD->getTrailingRequiresClause(); | |||
368 | if (RC->isInstantiationDependent()) { | |||
369 | Satisfaction.IsSatisfied = true; | |||
370 | return false; | |||
371 | } | |||
372 | Qualifiers ThisQuals; | |||
373 | CXXRecordDecl *Record = nullptr; | |||
374 | if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) { | |||
375 | ThisQuals = Method->getMethodQualifiers(); | |||
376 | Record = const_cast<CXXRecordDecl *>(Method->getParent()); | |||
377 | } | |||
378 | CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr); | |||
379 | // We substitute with empty arguments in order to rebuild the atomic | |||
380 | // constraint in a constant-evaluated context. | |||
381 | // FIXME: Should this be a dedicated TreeTransform? | |||
382 | return CheckConstraintSatisfaction( | |||
383 | FD, {RC}, /*TemplateArgs=*/{}, | |||
384 | SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()), | |||
385 | Satisfaction); | |||
386 | } | |||
387 | ||||
388 | bool Sema::EnsureTemplateArgumentListConstraints( | |||
389 | TemplateDecl *TD, ArrayRef<TemplateArgument> TemplateArgs, | |||
390 | SourceRange TemplateIDRange) { | |||
391 | ConstraintSatisfaction Satisfaction; | |||
392 | llvm::SmallVector<const Expr *, 3> AssociatedConstraints; | |||
393 | TD->getAssociatedConstraints(AssociatedConstraints); | |||
394 | if (CheckConstraintSatisfaction(TD, AssociatedConstraints, TemplateArgs, | |||
395 | TemplateIDRange, Satisfaction)) | |||
396 | return true; | |||
397 | ||||
398 | if (!Satisfaction.IsSatisfied) { | |||
399 | SmallString<128> TemplateArgString; | |||
400 | TemplateArgString = " "; | |||
401 | TemplateArgString += getTemplateArgumentBindingsText( | |||
402 | TD->getTemplateParameters(), TemplateArgs.data(), TemplateArgs.size()); | |||
403 | ||||
404 | Diag(TemplateIDRange.getBegin(), | |||
405 | diag::err_template_arg_list_constraints_not_satisfied) | |||
406 | << (int)getTemplateNameKindForDiagnostics(TemplateName(TD)) << TD | |||
407 | << TemplateArgString << TemplateIDRange; | |||
408 | DiagnoseUnsatisfiedConstraint(Satisfaction); | |||
409 | return true; | |||
410 | } | |||
411 | return false; | |||
412 | } | |||
413 | ||||
414 | static void diagnoseUnsatisfiedRequirement(Sema &S, | |||
415 | concepts::ExprRequirement *Req, | |||
416 | bool First) { | |||
417 | assert(!Req->isSatisfied()(static_cast <bool> (!Req->isSatisfied() && "Diagnose() can only be used on an unsatisfied requirement" ) ? void (0) : __assert_fail ("!Req->isSatisfied() && \"Diagnose() can only be used on an unsatisfied requirement\"" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 418, __extension__ __PRETTY_FUNCTION__)) | |||
418 | && "Diagnose() can only be used on an unsatisfied requirement")(static_cast <bool> (!Req->isSatisfied() && "Diagnose() can only be used on an unsatisfied requirement" ) ? void (0) : __assert_fail ("!Req->isSatisfied() && \"Diagnose() can only be used on an unsatisfied requirement\"" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 418, __extension__ __PRETTY_FUNCTION__)); | |||
419 | switch (Req->getSatisfactionStatus()) { | |||
420 | case concepts::ExprRequirement::SS_Dependent: | |||
421 | llvm_unreachable("Diagnosing a dependent requirement")::llvm::llvm_unreachable_internal("Diagnosing a dependent requirement" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 421); | |||
422 | break; | |||
423 | case concepts::ExprRequirement::SS_ExprSubstitutionFailure: { | |||
424 | auto *SubstDiag = Req->getExprSubstitutionDiagnostic(); | |||
425 | if (!SubstDiag->DiagMessage.empty()) | |||
426 | S.Diag(SubstDiag->DiagLoc, | |||
427 | diag::note_expr_requirement_expr_substitution_error) | |||
428 | << (int)First << SubstDiag->SubstitutedEntity | |||
429 | << SubstDiag->DiagMessage; | |||
430 | else | |||
431 | S.Diag(SubstDiag->DiagLoc, | |||
432 | diag::note_expr_requirement_expr_unknown_substitution_error) | |||
433 | << (int)First << SubstDiag->SubstitutedEntity; | |||
434 | break; | |||
435 | } | |||
436 | case concepts::ExprRequirement::SS_NoexceptNotMet: | |||
437 | S.Diag(Req->getNoexceptLoc(), | |||
438 | diag::note_expr_requirement_noexcept_not_met) | |||
439 | << (int)First << Req->getExpr(); | |||
440 | break; | |||
441 | case concepts::ExprRequirement::SS_TypeRequirementSubstitutionFailure: { | |||
442 | auto *SubstDiag = | |||
443 | Req->getReturnTypeRequirement().getSubstitutionDiagnostic(); | |||
444 | if (!SubstDiag->DiagMessage.empty()) | |||
445 | S.Diag(SubstDiag->DiagLoc, | |||
446 | diag::note_expr_requirement_type_requirement_substitution_error) | |||
447 | << (int)First << SubstDiag->SubstitutedEntity | |||
448 | << SubstDiag->DiagMessage; | |||
449 | else | |||
450 | S.Diag(SubstDiag->DiagLoc, | |||
451 | diag::note_expr_requirement_type_requirement_unknown_substitution_error) | |||
452 | << (int)First << SubstDiag->SubstitutedEntity; | |||
453 | break; | |||
454 | } | |||
455 | case concepts::ExprRequirement::SS_ConstraintsNotSatisfied: { | |||
456 | ConceptSpecializationExpr *ConstraintExpr = | |||
457 | Req->getReturnTypeRequirementSubstitutedConstraintExpr(); | |||
458 | if (ConstraintExpr->getTemplateArgsAsWritten()->NumTemplateArgs == 1) { | |||
459 | // A simple case - expr type is the type being constrained and the concept | |||
460 | // was not provided arguments. | |||
461 | Expr *e = Req->getExpr(); | |||
462 | S.Diag(e->getBeginLoc(), | |||
463 | diag::note_expr_requirement_constraints_not_satisfied_simple) | |||
464 | << (int)First << S.getDecltypeForParenthesizedExpr(e) | |||
465 | << ConstraintExpr->getNamedConcept(); | |||
466 | } else { | |||
467 | S.Diag(ConstraintExpr->getBeginLoc(), | |||
468 | diag::note_expr_requirement_constraints_not_satisfied) | |||
469 | << (int)First << ConstraintExpr; | |||
470 | } | |||
471 | S.DiagnoseUnsatisfiedConstraint(ConstraintExpr->getSatisfaction()); | |||
472 | break; | |||
473 | } | |||
474 | case concepts::ExprRequirement::SS_Satisfied: | |||
475 | llvm_unreachable("We checked this above")::llvm::llvm_unreachable_internal("We checked this above", "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 475); | |||
476 | } | |||
477 | } | |||
478 | ||||
479 | static void diagnoseUnsatisfiedRequirement(Sema &S, | |||
480 | concepts::TypeRequirement *Req, | |||
481 | bool First) { | |||
482 | assert(!Req->isSatisfied()(static_cast <bool> (!Req->isSatisfied() && "Diagnose() can only be used on an unsatisfied requirement" ) ? void (0) : __assert_fail ("!Req->isSatisfied() && \"Diagnose() can only be used on an unsatisfied requirement\"" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 483, __extension__ __PRETTY_FUNCTION__)) | |||
483 | && "Diagnose() can only be used on an unsatisfied requirement")(static_cast <bool> (!Req->isSatisfied() && "Diagnose() can only be used on an unsatisfied requirement" ) ? void (0) : __assert_fail ("!Req->isSatisfied() && \"Diagnose() can only be used on an unsatisfied requirement\"" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 483, __extension__ __PRETTY_FUNCTION__)); | |||
484 | switch (Req->getSatisfactionStatus()) { | |||
485 | case concepts::TypeRequirement::SS_Dependent: | |||
486 | llvm_unreachable("Diagnosing a dependent requirement")::llvm::llvm_unreachable_internal("Diagnosing a dependent requirement" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 486); | |||
487 | return; | |||
488 | case concepts::TypeRequirement::SS_SubstitutionFailure: { | |||
489 | auto *SubstDiag = Req->getSubstitutionDiagnostic(); | |||
490 | if (!SubstDiag->DiagMessage.empty()) | |||
491 | S.Diag(SubstDiag->DiagLoc, | |||
492 | diag::note_type_requirement_substitution_error) << (int)First | |||
493 | << SubstDiag->SubstitutedEntity << SubstDiag->DiagMessage; | |||
494 | else | |||
495 | S.Diag(SubstDiag->DiagLoc, | |||
496 | diag::note_type_requirement_unknown_substitution_error) | |||
497 | << (int)First << SubstDiag->SubstitutedEntity; | |||
498 | return; | |||
499 | } | |||
500 | default: | |||
501 | llvm_unreachable("Unknown satisfaction status")::llvm::llvm_unreachable_internal("Unknown satisfaction status" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 501); | |||
502 | return; | |||
503 | } | |||
504 | } | |||
505 | ||||
506 | static void diagnoseUnsatisfiedRequirement(Sema &S, | |||
507 | concepts::NestedRequirement *Req, | |||
508 | bool First) { | |||
509 | if (Req->isSubstitutionFailure()) { | |||
510 | concepts::Requirement::SubstitutionDiagnostic *SubstDiag = | |||
511 | Req->getSubstitutionDiagnostic(); | |||
512 | if (!SubstDiag->DiagMessage.empty()) | |||
513 | S.Diag(SubstDiag->DiagLoc, | |||
514 | diag::note_nested_requirement_substitution_error) | |||
515 | << (int)First << SubstDiag->SubstitutedEntity | |||
516 | << SubstDiag->DiagMessage; | |||
517 | else | |||
518 | S.Diag(SubstDiag->DiagLoc, | |||
519 | diag::note_nested_requirement_unknown_substitution_error) | |||
520 | << (int)First << SubstDiag->SubstitutedEntity; | |||
521 | return; | |||
522 | } | |||
523 | S.DiagnoseUnsatisfiedConstraint(Req->getConstraintSatisfaction(), First); | |||
524 | } | |||
525 | ||||
526 | ||||
527 | static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S, | |||
528 | Expr *SubstExpr, | |||
529 | bool First = true) { | |||
530 | SubstExpr = SubstExpr->IgnoreParenImpCasts(); | |||
531 | if (BinaryOperator *BO = dyn_cast<BinaryOperator>(SubstExpr)) { | |||
532 | switch (BO->getOpcode()) { | |||
533 | // These two cases will in practice only be reached when using fold | |||
534 | // expressions with || and &&, since otherwise the || and && will have been | |||
535 | // broken down into atomic constraints during satisfaction checking. | |||
536 | case BO_LOr: | |||
537 | // Or evaluated to false - meaning both RHS and LHS evaluated to false. | |||
538 | diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getLHS(), First); | |||
539 | diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(), | |||
540 | /*First=*/false); | |||
541 | return; | |||
542 | case BO_LAnd: { | |||
543 | bool LHSSatisfied = | |||
544 | BO->getLHS()->EvaluateKnownConstInt(S.Context).getBoolValue(); | |||
545 | if (LHSSatisfied) { | |||
546 | // LHS is true, so RHS must be false. | |||
547 | diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(), First); | |||
548 | return; | |||
549 | } | |||
550 | // LHS is false | |||
551 | diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getLHS(), First); | |||
552 | ||||
553 | // RHS might also be false | |||
554 | bool RHSSatisfied = | |||
555 | BO->getRHS()->EvaluateKnownConstInt(S.Context).getBoolValue(); | |||
556 | if (!RHSSatisfied) | |||
557 | diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(), | |||
558 | /*First=*/false); | |||
559 | return; | |||
560 | } | |||
561 | case BO_GE: | |||
562 | case BO_LE: | |||
563 | case BO_GT: | |||
564 | case BO_LT: | |||
565 | case BO_EQ: | |||
566 | case BO_NE: | |||
567 | if (BO->getLHS()->getType()->isIntegerType() && | |||
568 | BO->getRHS()->getType()->isIntegerType()) { | |||
569 | Expr::EvalResult SimplifiedLHS; | |||
570 | Expr::EvalResult SimplifiedRHS; | |||
571 | BO->getLHS()->EvaluateAsInt(SimplifiedLHS, S.Context, | |||
572 | Expr::SE_NoSideEffects, | |||
573 | /*InConstantContext=*/true); | |||
574 | BO->getRHS()->EvaluateAsInt(SimplifiedRHS, S.Context, | |||
575 | Expr::SE_NoSideEffects, | |||
576 | /*InConstantContext=*/true); | |||
577 | if (!SimplifiedLHS.Diag && ! SimplifiedRHS.Diag) { | |||
578 | S.Diag(SubstExpr->getBeginLoc(), | |||
579 | diag::note_atomic_constraint_evaluated_to_false_elaborated) | |||
580 | << (int)First << SubstExpr | |||
581 | << toString(SimplifiedLHS.Val.getInt(), 10) | |||
582 | << BinaryOperator::getOpcodeStr(BO->getOpcode()) | |||
583 | << toString(SimplifiedRHS.Val.getInt(), 10); | |||
584 | return; | |||
585 | } | |||
586 | } | |||
587 | break; | |||
588 | ||||
589 | default: | |||
590 | break; | |||
591 | } | |||
592 | } else if (auto *CSE = dyn_cast<ConceptSpecializationExpr>(SubstExpr)) { | |||
593 | if (CSE->getTemplateArgsAsWritten()->NumTemplateArgs == 1) { | |||
594 | S.Diag( | |||
595 | CSE->getSourceRange().getBegin(), | |||
596 | diag:: | |||
597 | note_single_arg_concept_specialization_constraint_evaluated_to_false) | |||
598 | << (int)First | |||
599 | << CSE->getTemplateArgsAsWritten()->arguments()[0].getArgument() | |||
600 | << CSE->getNamedConcept(); | |||
601 | } else { | |||
602 | S.Diag(SubstExpr->getSourceRange().getBegin(), | |||
603 | diag::note_concept_specialization_constraint_evaluated_to_false) | |||
604 | << (int)First << CSE; | |||
605 | } | |||
606 | S.DiagnoseUnsatisfiedConstraint(CSE->getSatisfaction()); | |||
607 | return; | |||
608 | } else if (auto *RE = dyn_cast<RequiresExpr>(SubstExpr)) { | |||
609 | for (concepts::Requirement *Req : RE->getRequirements()) | |||
610 | if (!Req->isDependent() && !Req->isSatisfied()) { | |||
611 | if (auto *E = dyn_cast<concepts::ExprRequirement>(Req)) | |||
612 | diagnoseUnsatisfiedRequirement(S, E, First); | |||
613 | else if (auto *T = dyn_cast<concepts::TypeRequirement>(Req)) | |||
614 | diagnoseUnsatisfiedRequirement(S, T, First); | |||
615 | else | |||
616 | diagnoseUnsatisfiedRequirement( | |||
617 | S, cast<concepts::NestedRequirement>(Req), First); | |||
618 | break; | |||
619 | } | |||
620 | return; | |||
621 | } | |||
622 | ||||
623 | S.Diag(SubstExpr->getSourceRange().getBegin(), | |||
624 | diag::note_atomic_constraint_evaluated_to_false) | |||
625 | << (int)First << SubstExpr; | |||
626 | } | |||
627 | ||||
628 | template<typename SubstitutionDiagnostic> | |||
629 | static void diagnoseUnsatisfiedConstraintExpr( | |||
630 | Sema &S, const Expr *E, | |||
631 | const llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> &Record, | |||
632 | bool First = true) { | |||
633 | if (auto *Diag = Record.template dyn_cast<SubstitutionDiagnostic *>()){ | |||
634 | S.Diag(Diag->first, diag::note_substituted_constraint_expr_is_ill_formed) | |||
635 | << Diag->second; | |||
636 | return; | |||
637 | } | |||
638 | ||||
639 | diagnoseWellFormedUnsatisfiedConstraintExpr(S, | |||
640 | Record.template get<Expr *>(), First); | |||
641 | } | |||
642 | ||||
643 | void | |||
644 | Sema::DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction& Satisfaction, | |||
645 | bool First) { | |||
646 | assert(!Satisfaction.IsSatisfied &&(static_cast <bool> (!Satisfaction.IsSatisfied && "Attempted to diagnose a satisfied constraint") ? void (0) : __assert_fail ("!Satisfaction.IsSatisfied && \"Attempted to diagnose a satisfied constraint\"" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 647, __extension__ __PRETTY_FUNCTION__)) | |||
647 | "Attempted to diagnose a satisfied constraint")(static_cast <bool> (!Satisfaction.IsSatisfied && "Attempted to diagnose a satisfied constraint") ? void (0) : __assert_fail ("!Satisfaction.IsSatisfied && \"Attempted to diagnose a satisfied constraint\"" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 647, __extension__ __PRETTY_FUNCTION__)); | |||
648 | for (auto &Pair : Satisfaction.Details) { | |||
649 | diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First); | |||
650 | First = false; | |||
651 | } | |||
652 | } | |||
653 | ||||
654 | void Sema::DiagnoseUnsatisfiedConstraint( | |||
655 | const ASTConstraintSatisfaction &Satisfaction, | |||
656 | bool First) { | |||
657 | assert(!Satisfaction.IsSatisfied &&(static_cast <bool> (!Satisfaction.IsSatisfied && "Attempted to diagnose a satisfied constraint") ? void (0) : __assert_fail ("!Satisfaction.IsSatisfied && \"Attempted to diagnose a satisfied constraint\"" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 658, __extension__ __PRETTY_FUNCTION__)) | |||
658 | "Attempted to diagnose a satisfied constraint")(static_cast <bool> (!Satisfaction.IsSatisfied && "Attempted to diagnose a satisfied constraint") ? void (0) : __assert_fail ("!Satisfaction.IsSatisfied && \"Attempted to diagnose a satisfied constraint\"" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 658, __extension__ __PRETTY_FUNCTION__)); | |||
659 | for (auto &Pair : Satisfaction) { | |||
660 | diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First); | |||
661 | First = false; | |||
662 | } | |||
663 | } | |||
664 | ||||
665 | const NormalizedConstraint * | |||
666 | Sema::getNormalizedAssociatedConstraints( | |||
667 | NamedDecl *ConstrainedDecl, ArrayRef<const Expr *> AssociatedConstraints) { | |||
668 | auto CacheEntry = NormalizationCache.find(ConstrainedDecl); | |||
669 | if (CacheEntry == NormalizationCache.end()) { | |||
670 | auto Normalized = | |||
671 | NormalizedConstraint::fromConstraintExprs(*this, ConstrainedDecl, | |||
672 | AssociatedConstraints); | |||
673 | CacheEntry = | |||
674 | NormalizationCache | |||
675 | .try_emplace(ConstrainedDecl, | |||
676 | Normalized | |||
677 | ? new (Context) NormalizedConstraint( | |||
678 | std::move(*Normalized)) | |||
679 | : nullptr) | |||
680 | .first; | |||
681 | } | |||
682 | return CacheEntry->second; | |||
683 | } | |||
684 | ||||
685 | static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N, | |||
686 | ConceptDecl *Concept, ArrayRef<TemplateArgument> TemplateArgs, | |||
687 | const ASTTemplateArgumentListInfo *ArgsAsWritten) { | |||
688 | if (!N.isAtomic()) { | |||
689 | if (substituteParameterMappings(S, N.getLHS(), Concept, TemplateArgs, | |||
690 | ArgsAsWritten)) | |||
691 | return true; | |||
692 | return substituteParameterMappings(S, N.getRHS(), Concept, TemplateArgs, | |||
693 | ArgsAsWritten); | |||
694 | } | |||
695 | TemplateParameterList *TemplateParams = Concept->getTemplateParameters(); | |||
696 | ||||
697 | AtomicConstraint &Atomic = *N.getAtomicConstraint(); | |||
698 | TemplateArgumentListInfo SubstArgs; | |||
699 | MultiLevelTemplateArgumentList MLTAL; | |||
700 | MLTAL.addOuterTemplateArguments(TemplateArgs); | |||
701 | if (!Atomic.ParameterMapping) { | |||
702 | llvm::SmallBitVector OccurringIndices(TemplateParams->size()); | |||
703 | S.MarkUsedTemplateParameters(Atomic.ConstraintExpr, /*OnlyDeduced=*/false, | |||
704 | /*Depth=*/0, OccurringIndices); | |||
705 | Atomic.ParameterMapping.emplace( | |||
706 | MutableArrayRef<TemplateArgumentLoc>( | |||
707 | new (S.Context) TemplateArgumentLoc[OccurringIndices.count()], | |||
708 | OccurringIndices.count())); | |||
709 | for (unsigned I = 0, J = 0, C = TemplateParams->size(); I != C; ++I) | |||
710 | if (OccurringIndices[I]) | |||
711 | new (&(*Atomic.ParameterMapping)[J++]) TemplateArgumentLoc( | |||
712 | S.getIdentityTemplateArgumentLoc(TemplateParams->begin()[I], | |||
713 | // Here we assume we do not support things like | |||
714 | // template<typename A, typename B> | |||
715 | // concept C = ...; | |||
716 | // | |||
717 | // template<typename... Ts> requires C<Ts...> | |||
718 | // struct S { }; | |||
719 | // The above currently yields a diagnostic. | |||
720 | // We still might have default arguments for concept parameters. | |||
721 | ArgsAsWritten->NumTemplateArgs > I ? | |||
722 | ArgsAsWritten->arguments()[I].getLocation() : | |||
723 | SourceLocation())); | |||
724 | } | |||
725 | Sema::InstantiatingTemplate Inst( | |||
726 | S, ArgsAsWritten->arguments().front().getSourceRange().getBegin(), | |||
727 | Sema::InstantiatingTemplate::ParameterMappingSubstitution{}, Concept, | |||
728 | SourceRange(ArgsAsWritten->arguments()[0].getSourceRange().getBegin(), | |||
729 | ArgsAsWritten->arguments().back().getSourceRange().getEnd())); | |||
730 | if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs)) | |||
731 | return true; | |||
732 | Atomic.ParameterMapping.emplace( | |||
733 | MutableArrayRef<TemplateArgumentLoc>( | |||
734 | new (S.Context) TemplateArgumentLoc[SubstArgs.size()], | |||
735 | SubstArgs.size())); | |||
736 | std::copy(SubstArgs.arguments().begin(), SubstArgs.arguments().end(), | |||
737 | N.getAtomicConstraint()->ParameterMapping->begin()); | |||
738 | return false; | |||
739 | } | |||
740 | ||||
741 | Optional<NormalizedConstraint> | |||
742 | NormalizedConstraint::fromConstraintExprs(Sema &S, NamedDecl *D, | |||
743 | ArrayRef<const Expr *> E) { | |||
744 | assert(E.size() != 0)(static_cast <bool> (E.size() != 0) ? void (0) : __assert_fail ("E.size() != 0", "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 744, __extension__ __PRETTY_FUNCTION__)); | |||
745 | auto First = fromConstraintExpr(S, D, E[0]); | |||
746 | if (E.size() == 1) | |||
747 | return First; | |||
748 | auto Second = fromConstraintExpr(S, D, E[1]); | |||
749 | if (!Second) | |||
750 | return None; | |||
751 | llvm::Optional<NormalizedConstraint> Conjunction; | |||
752 | Conjunction.emplace(S.Context, std::move(*First), std::move(*Second), | |||
753 | CCK_Conjunction); | |||
754 | for (unsigned I = 2; I < E.size(); ++I) { | |||
755 | auto Next = fromConstraintExpr(S, D, E[I]); | |||
756 | if (!Next) | |||
757 | return llvm::Optional<NormalizedConstraint>{}; | |||
758 | NormalizedConstraint NewConjunction(S.Context, std::move(*Conjunction), | |||
759 | std::move(*Next), CCK_Conjunction); | |||
760 | *Conjunction = std::move(NewConjunction); | |||
761 | } | |||
762 | return Conjunction; | |||
763 | } | |||
764 | ||||
765 | llvm::Optional<NormalizedConstraint> | |||
766 | NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) { | |||
767 | assert(E != nullptr)(static_cast <bool> (E != nullptr) ? void (0) : __assert_fail ("E != nullptr", "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 767, __extension__ __PRETTY_FUNCTION__)); | |||
768 | ||||
769 | // C++ [temp.constr.normal]p1.1 | |||
770 | // [...] | |||
771 | // - The normal form of an expression (E) is the normal form of E. | |||
772 | // [...] | |||
773 | E = E->IgnoreParenImpCasts(); | |||
774 | if (LogicalBinOp BO = E) { | |||
775 | auto LHS = fromConstraintExpr(S, D, BO.getLHS()); | |||
776 | if (!LHS) | |||
777 | return None; | |||
778 | auto RHS = fromConstraintExpr(S, D, BO.getRHS()); | |||
779 | if (!RHS) | |||
780 | return None; | |||
781 | ||||
782 | return NormalizedConstraint(S.Context, std::move(*LHS), std::move(*RHS), | |||
783 | BO.isAnd() ? CCK_Conjunction : CCK_Disjunction); | |||
784 | } else if (auto *CSE = dyn_cast<const ConceptSpecializationExpr>(E)) { | |||
785 | const NormalizedConstraint *SubNF; | |||
786 | { | |||
787 | Sema::InstantiatingTemplate Inst( | |||
788 | S, CSE->getExprLoc(), | |||
789 | Sema::InstantiatingTemplate::ConstraintNormalization{}, D, | |||
790 | CSE->getSourceRange()); | |||
791 | // C++ [temp.constr.normal]p1.1 | |||
792 | // [...] | |||
793 | // The normal form of an id-expression of the form C<A1, A2, ..., AN>, | |||
794 | // where C names a concept, is the normal form of the | |||
795 | // constraint-expression of C, after substituting A1, A2, ..., AN for C’s | |||
796 | // respective template parameters in the parameter mappings in each atomic | |||
797 | // constraint. If any such substitution results in an invalid type or | |||
798 | // expression, the program is ill-formed; no diagnostic is required. | |||
799 | // [...] | |||
800 | ConceptDecl *CD = CSE->getNamedConcept(); | |||
801 | SubNF = S.getNormalizedAssociatedConstraints(CD, | |||
802 | {CD->getConstraintExpr()}); | |||
803 | if (!SubNF) | |||
804 | return None; | |||
805 | } | |||
806 | ||||
807 | Optional<NormalizedConstraint> New; | |||
808 | New.emplace(S.Context, *SubNF); | |||
809 | ||||
810 | if (substituteParameterMappings( | |||
811 | S, *New, CSE->getNamedConcept(), | |||
812 | CSE->getTemplateArguments(), CSE->getTemplateArgsAsWritten())) | |||
813 | return None; | |||
814 | ||||
815 | return New; | |||
816 | } | |||
817 | return NormalizedConstraint{new (S.Context) AtomicConstraint(S, E)}; | |||
818 | } | |||
819 | ||||
820 | using NormalForm = | |||
821 | llvm::SmallVector<llvm::SmallVector<AtomicConstraint *, 2>, 4>; | |||
822 | ||||
823 | static NormalForm makeCNF(const NormalizedConstraint &Normalized) { | |||
824 | if (Normalized.isAtomic()) | |||
825 | return {{Normalized.getAtomicConstraint()}}; | |||
826 | ||||
827 | NormalForm LCNF = makeCNF(Normalized.getLHS()); | |||
828 | NormalForm RCNF = makeCNF(Normalized.getRHS()); | |||
829 | if (Normalized.getCompoundKind() == NormalizedConstraint::CCK_Conjunction) { | |||
830 | LCNF.reserve(LCNF.size() + RCNF.size()); | |||
831 | while (!RCNF.empty()) | |||
832 | LCNF.push_back(RCNF.pop_back_val()); | |||
833 | return LCNF; | |||
834 | } | |||
835 | ||||
836 | // Disjunction | |||
837 | NormalForm Res; | |||
838 | Res.reserve(LCNF.size() * RCNF.size()); | |||
839 | for (auto &LDisjunction : LCNF) | |||
840 | for (auto &RDisjunction : RCNF) { | |||
841 | NormalForm::value_type Combined; | |||
842 | Combined.reserve(LDisjunction.size() + RDisjunction.size()); | |||
843 | std::copy(LDisjunction.begin(), LDisjunction.end(), | |||
844 | std::back_inserter(Combined)); | |||
845 | std::copy(RDisjunction.begin(), RDisjunction.end(), | |||
846 | std::back_inserter(Combined)); | |||
847 | Res.emplace_back(Combined); | |||
848 | } | |||
849 | return Res; | |||
850 | } | |||
851 | ||||
852 | static NormalForm makeDNF(const NormalizedConstraint &Normalized) { | |||
853 | if (Normalized.isAtomic()) | |||
854 | return {{Normalized.getAtomicConstraint()}}; | |||
855 | ||||
856 | NormalForm LDNF = makeDNF(Normalized.getLHS()); | |||
857 | NormalForm RDNF = makeDNF(Normalized.getRHS()); | |||
858 | if (Normalized.getCompoundKind() == NormalizedConstraint::CCK_Disjunction) { | |||
859 | LDNF.reserve(LDNF.size() + RDNF.size()); | |||
860 | while (!RDNF.empty()) | |||
861 | LDNF.push_back(RDNF.pop_back_val()); | |||
862 | return LDNF; | |||
863 | } | |||
864 | ||||
865 | // Conjunction | |||
866 | NormalForm Res; | |||
867 | Res.reserve(LDNF.size() * RDNF.size()); | |||
868 | for (auto &LConjunction : LDNF) { | |||
869 | for (auto &RConjunction : RDNF) { | |||
870 | NormalForm::value_type Combined; | |||
871 | Combined.reserve(LConjunction.size() + RConjunction.size()); | |||
872 | std::copy(LConjunction.begin(), LConjunction.end(), | |||
873 | std::back_inserter(Combined)); | |||
874 | std::copy(RConjunction.begin(), RConjunction.end(), | |||
875 | std::back_inserter(Combined)); | |||
876 | Res.emplace_back(Combined); | |||
877 | } | |||
878 | } | |||
879 | return Res; | |||
880 | } | |||
881 | ||||
882 | template<typename AtomicSubsumptionEvaluator> | |||
883 | static bool subsumes(NormalForm PDNF, NormalForm QCNF, | |||
884 | AtomicSubsumptionEvaluator E) { | |||
885 | // C++ [temp.constr.order] p2 | |||
886 | // Then, P subsumes Q if and only if, for every disjunctive clause Pi in the | |||
887 | // disjunctive normal form of P, Pi subsumes every conjunctive clause Qj in | |||
888 | // the conjuctive normal form of Q, where [...] | |||
889 | for (const auto &Pi : PDNF) { | |||
890 | for (const auto &Qj : QCNF) { | |||
891 | // C++ [temp.constr.order] p2 | |||
892 | // - [...] a disjunctive clause Pi subsumes a conjunctive clause Qj if | |||
893 | // and only if there exists an atomic constraint Pia in Pi for which | |||
894 | // there exists an atomic constraint, Qjb, in Qj such that Pia | |||
895 | // subsumes Qjb. | |||
896 | bool Found = false; | |||
897 | for (const AtomicConstraint *Pia : Pi) { | |||
898 | for (const AtomicConstraint *Qjb : Qj) { | |||
899 | if (E(*Pia, *Qjb)) { | |||
900 | Found = true; | |||
901 | break; | |||
902 | } | |||
903 | } | |||
904 | if (Found) | |||
905 | break; | |||
906 | } | |||
907 | if (!Found) | |||
908 | return false; | |||
909 | } | |||
910 | } | |||
911 | return true; | |||
912 | } | |||
913 | ||||
914 | template<typename AtomicSubsumptionEvaluator> | |||
915 | static bool subsumes(Sema &S, NamedDecl *DP, ArrayRef<const Expr *> P, | |||
916 | NamedDecl *DQ, ArrayRef<const Expr *> Q, bool &Subsumes, | |||
917 | AtomicSubsumptionEvaluator E) { | |||
918 | // C++ [temp.constr.order] p2 | |||
919 | // In order to determine if a constraint P subsumes a constraint Q, P is | |||
920 | // transformed into disjunctive normal form, and Q is transformed into | |||
921 | // conjunctive normal form. [...] | |||
922 | auto *PNormalized = S.getNormalizedAssociatedConstraints(DP, P); | |||
923 | if (!PNormalized) | |||
924 | return true; | |||
925 | const NormalForm PDNF = makeDNF(*PNormalized); | |||
926 | ||||
927 | auto *QNormalized = S.getNormalizedAssociatedConstraints(DQ, Q); | |||
928 | if (!QNormalized) | |||
929 | return true; | |||
930 | const NormalForm QCNF = makeCNF(*QNormalized); | |||
931 | ||||
932 | Subsumes = subsumes(PDNF, QCNF, E); | |||
933 | return false; | |||
934 | } | |||
935 | ||||
936 | bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef<const Expr *> AC1, | |||
937 | NamedDecl *D2, ArrayRef<const Expr *> AC2, | |||
938 | bool &Result) { | |||
939 | if (AC1.empty()) { | |||
940 | Result = AC2.empty(); | |||
941 | return false; | |||
942 | } | |||
943 | if (AC2.empty()) { | |||
944 | // TD1 has associated constraints and TD2 does not. | |||
945 | Result = true; | |||
946 | return false; | |||
947 | } | |||
948 | ||||
949 | std::pair<NamedDecl *, NamedDecl *> Key{D1, D2}; | |||
950 | auto CacheEntry = SubsumptionCache.find(Key); | |||
951 | if (CacheEntry != SubsumptionCache.end()) { | |||
952 | Result = CacheEntry->second; | |||
953 | return false; | |||
954 | } | |||
955 | ||||
956 | if (subsumes(*this, D1, AC1, D2, AC2, Result, | |||
957 | [this] (const AtomicConstraint &A, const AtomicConstraint &B) { | |||
958 | return A.subsumes(Context, B); | |||
959 | })) | |||
960 | return true; | |||
961 | SubsumptionCache.try_emplace(Key, Result); | |||
962 | return false; | |||
963 | } | |||
964 | ||||
965 | bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1, | |||
966 | ArrayRef<const Expr *> AC1, NamedDecl *D2, ArrayRef<const Expr *> AC2) { | |||
967 | if (isSFINAEContext()) | |||
968 | // No need to work here because our notes would be discarded. | |||
969 | return false; | |||
970 | ||||
971 | if (AC1.empty() || AC2.empty()) | |||
972 | return false; | |||
973 | ||||
974 | auto NormalExprEvaluator = | |||
975 | [this] (const AtomicConstraint &A, const AtomicConstraint &B) { | |||
976 | return A.subsumes(Context, B); | |||
977 | }; | |||
978 | ||||
979 | const Expr *AmbiguousAtomic1 = nullptr, *AmbiguousAtomic2 = nullptr; | |||
980 | auto IdenticalExprEvaluator = | |||
981 | [&] (const AtomicConstraint &A, const AtomicConstraint &B) { | |||
982 | if (!A.hasMatchingParameterMapping(Context, B)) | |||
983 | return false; | |||
984 | const Expr *EA = A.ConstraintExpr, *EB = B.ConstraintExpr; | |||
985 | if (EA == EB) | |||
986 | return true; | |||
987 | ||||
988 | // Not the same source level expression - are the expressions | |||
989 | // identical? | |||
990 | llvm::FoldingSetNodeID IDA, IDB; | |||
991 | EA->Profile(IDA, Context, /*Cannonical=*/true); | |||
992 | EB->Profile(IDB, Context, /*Cannonical=*/true); | |||
993 | if (IDA != IDB) | |||
994 | return false; | |||
995 | ||||
996 | AmbiguousAtomic1 = EA; | |||
997 | AmbiguousAtomic2 = EB; | |||
998 | return true; | |||
999 | }; | |||
1000 | ||||
1001 | { | |||
1002 | // The subsumption checks might cause diagnostics | |||
1003 | SFINAETrap Trap(*this); | |||
1004 | auto *Normalized1 = getNormalizedAssociatedConstraints(D1, AC1); | |||
1005 | if (!Normalized1) | |||
1006 | return false; | |||
1007 | const NormalForm DNF1 = makeDNF(*Normalized1); | |||
1008 | const NormalForm CNF1 = makeCNF(*Normalized1); | |||
1009 | ||||
1010 | auto *Normalized2 = getNormalizedAssociatedConstraints(D2, AC2); | |||
1011 | if (!Normalized2) | |||
1012 | return false; | |||
1013 | const NormalForm DNF2 = makeDNF(*Normalized2); | |||
1014 | const NormalForm CNF2 = makeCNF(*Normalized2); | |||
1015 | ||||
1016 | bool Is1AtLeastAs2Normally = subsumes(DNF1, CNF2, NormalExprEvaluator); | |||
1017 | bool Is2AtLeastAs1Normally = subsumes(DNF2, CNF1, NormalExprEvaluator); | |||
1018 | bool Is1AtLeastAs2 = subsumes(DNF1, CNF2, IdenticalExprEvaluator); | |||
1019 | bool Is2AtLeastAs1 = subsumes(DNF2, CNF1, IdenticalExprEvaluator); | |||
1020 | if (Is1AtLeastAs2 == Is1AtLeastAs2Normally && | |||
1021 | Is2AtLeastAs1 == Is2AtLeastAs1Normally) | |||
1022 | // Same result - no ambiguity was caused by identical atomic expressions. | |||
1023 | return false; | |||
1024 | } | |||
1025 | ||||
1026 | // A different result! Some ambiguous atomic constraint(s) caused a difference | |||
1027 | assert(AmbiguousAtomic1 && AmbiguousAtomic2)(static_cast <bool> (AmbiguousAtomic1 && AmbiguousAtomic2 ) ? void (0) : __assert_fail ("AmbiguousAtomic1 && AmbiguousAtomic2" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 1027, __extension__ __PRETTY_FUNCTION__)); | |||
1028 | ||||
1029 | Diag(AmbiguousAtomic1->getBeginLoc(), diag::note_ambiguous_atomic_constraints) | |||
1030 | << AmbiguousAtomic1->getSourceRange(); | |||
1031 | Diag(AmbiguousAtomic2->getBeginLoc(), | |||
1032 | diag::note_ambiguous_atomic_constraints_similar_expression) | |||
1033 | << AmbiguousAtomic2->getSourceRange(); | |||
1034 | return true; | |||
1035 | } | |||
1036 | ||||
1037 | concepts::ExprRequirement::ExprRequirement( | |||
1038 | Expr *E, bool IsSimple, SourceLocation NoexceptLoc, | |||
1039 | ReturnTypeRequirement Req, SatisfactionStatus Status, | |||
1040 | ConceptSpecializationExpr *SubstitutedConstraintExpr) : | |||
1041 | Requirement(IsSimple ? RK_Simple : RK_Compound, Status == SS_Dependent, | |||
1042 | Status == SS_Dependent && | |||
1043 | (E->containsUnexpandedParameterPack() || | |||
1044 | Req.containsUnexpandedParameterPack()), | |||
1045 | Status == SS_Satisfied), Value(E), NoexceptLoc(NoexceptLoc), | |||
1046 | TypeReq(Req), SubstitutedConstraintExpr(SubstitutedConstraintExpr), | |||
1047 | Status(Status) { | |||
1048 | assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) &&(static_cast <bool> ((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) && "Simple requirement must not have a return type requirement or a " "noexcept specification") ? void (0) : __assert_fail ("(!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) && \"Simple requirement must not have a return type requirement or a \" \"noexcept specification\"" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 1050, __extension__ __PRETTY_FUNCTION__)) | |||
1049 | "Simple requirement must not have a return type requirement or a "(static_cast <bool> ((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) && "Simple requirement must not have a return type requirement or a " "noexcept specification") ? void (0) : __assert_fail ("(!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) && \"Simple requirement must not have a return type requirement or a \" \"noexcept specification\"" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 1050, __extension__ __PRETTY_FUNCTION__)) | |||
1050 | "noexcept specification")(static_cast <bool> ((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) && "Simple requirement must not have a return type requirement or a " "noexcept specification") ? void (0) : __assert_fail ("(!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) && \"Simple requirement must not have a return type requirement or a \" \"noexcept specification\"" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 1050, __extension__ __PRETTY_FUNCTION__)); | |||
1051 | assert((Status > SS_TypeRequirementSubstitutionFailure && Req.isTypeConstraint()) ==(static_cast <bool> ((Status > SS_TypeRequirementSubstitutionFailure && Req.isTypeConstraint()) == (SubstitutedConstraintExpr != nullptr)) ? void (0) : __assert_fail ("(Status > SS_TypeRequirementSubstitutionFailure && Req.isTypeConstraint()) == (SubstitutedConstraintExpr != nullptr)" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 1052, __extension__ __PRETTY_FUNCTION__)) | |||
1052 | (SubstitutedConstraintExpr != nullptr))(static_cast <bool> ((Status > SS_TypeRequirementSubstitutionFailure && Req.isTypeConstraint()) == (SubstitutedConstraintExpr != nullptr)) ? void (0) : __assert_fail ("(Status > SS_TypeRequirementSubstitutionFailure && Req.isTypeConstraint()) == (SubstitutedConstraintExpr != nullptr)" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 1052, __extension__ __PRETTY_FUNCTION__)); | |||
1053 | } | |||
1054 | ||||
1055 | concepts::ExprRequirement::ExprRequirement( | |||
1056 | SubstitutionDiagnostic *ExprSubstDiag, bool IsSimple, | |||
1057 | SourceLocation NoexceptLoc, ReturnTypeRequirement Req) : | |||
1058 | Requirement(IsSimple ? RK_Simple : RK_Compound, Req.isDependent(), | |||
1059 | Req.containsUnexpandedParameterPack(), /*IsSatisfied=*/false), | |||
1060 | Value(ExprSubstDiag), NoexceptLoc(NoexceptLoc), TypeReq(Req), | |||
1061 | Status(SS_ExprSubstitutionFailure) { | |||
1062 | assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) &&(static_cast <bool> ((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) && "Simple requirement must not have a return type requirement or a " "noexcept specification") ? void (0) : __assert_fail ("(!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) && \"Simple requirement must not have a return type requirement or a \" \"noexcept specification\"" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 1064, __extension__ __PRETTY_FUNCTION__)) | |||
1063 | "Simple requirement must not have a return type requirement or a "(static_cast <bool> ((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) && "Simple requirement must not have a return type requirement or a " "noexcept specification") ? void (0) : __assert_fail ("(!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) && \"Simple requirement must not have a return type requirement or a \" \"noexcept specification\"" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 1064, __extension__ __PRETTY_FUNCTION__)) | |||
1064 | "noexcept specification")(static_cast <bool> ((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) && "Simple requirement must not have a return type requirement or a " "noexcept specification") ? void (0) : __assert_fail ("(!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) && \"Simple requirement must not have a return type requirement or a \" \"noexcept specification\"" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 1064, __extension__ __PRETTY_FUNCTION__)); | |||
1065 | } | |||
1066 | ||||
1067 | concepts::ExprRequirement::ReturnTypeRequirement:: | |||
1068 | ReturnTypeRequirement(TemplateParameterList *TPL) : | |||
1069 | TypeConstraintInfo(TPL, 0) { | |||
1070 | assert(TPL->size() == 1)(static_cast <bool> (TPL->size() == 1) ? void (0) : __assert_fail ("TPL->size() == 1", "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 1070, __extension__ __PRETTY_FUNCTION__)); | |||
| ||||
1071 | const TypeConstraint *TC = | |||
1072 | cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint(); | |||
1073 | assert(TC &&(static_cast <bool> (TC && "TPL must have a template type parameter with a type constraint" ) ? void (0) : __assert_fail ("TC && \"TPL must have a template type parameter with a type constraint\"" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 1074, __extension__ __PRETTY_FUNCTION__)) | |||
1074 | "TPL must have a template type parameter with a type constraint")(static_cast <bool> (TC && "TPL must have a template type parameter with a type constraint" ) ? void (0) : __assert_fail ("TC && \"TPL must have a template type parameter with a type constraint\"" , "/build/llvm-toolchain-snapshot-13~++20210726100616+dead50d4427c/clang/lib/Sema/SemaConcept.cpp" , 1074, __extension__ __PRETTY_FUNCTION__)); | |||
1075 | auto *Constraint = | |||
1076 | cast_or_null<ConceptSpecializationExpr>( | |||
1077 | TC->getImmediatelyDeclaredConstraint()); | |||
1078 | bool Dependent = | |||
1079 | Constraint->getTemplateArgsAsWritten() && | |||
| ||||
1080 | TemplateSpecializationType::anyInstantiationDependentTemplateArguments( | |||
1081 | Constraint->getTemplateArgsAsWritten()->arguments().drop_front(1)); | |||
1082 | TypeConstraintInfo.setInt(Dependent ? 1 : 0); | |||
1083 | } | |||
1084 | ||||
1085 | concepts::TypeRequirement::TypeRequirement(TypeSourceInfo *T) : | |||
1086 | Requirement(RK_Type, T->getType()->isInstantiationDependentType(), | |||
1087 | T->getType()->containsUnexpandedParameterPack(), | |||
1088 | // We reach this ctor with either dependent types (in which | |||
1089 | // IsSatisfied doesn't matter) or with non-dependent type in | |||
1090 | // which the existence of the type indicates satisfaction. | |||
1091 | /*IsSatisfied=*/true), | |||
1092 | Value(T), | |||
1093 | Status(T->getType()->isInstantiationDependentType() ? SS_Dependent | |||
1094 | : SS_Satisfied) {} |