File: | build/source/clang/include/clang/Analysis/FlowSensitive/CFGMatchSwitch.h |
Warning: | line 71, column 12 Potential memory leak |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- UncheckedOptionalAccessModel.cpp ------------------------*- C++ -*-===// | |||
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 defines a dataflow analysis that detects unsafe uses of optional | |||
10 | // values. | |||
11 | // | |||
12 | //===----------------------------------------------------------------------===// | |||
13 | ||||
14 | #include "clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h" | |||
15 | #include "clang/AST/ASTContext.h" | |||
16 | #include "clang/AST/DeclCXX.h" | |||
17 | #include "clang/AST/Expr.h" | |||
18 | #include "clang/AST/ExprCXX.h" | |||
19 | #include "clang/AST/Stmt.h" | |||
20 | #include "clang/ASTMatchers/ASTMatchers.h" | |||
21 | #include "clang/Analysis/CFG.h" | |||
22 | #include "clang/Analysis/FlowSensitive/CFGMatchSwitch.h" | |||
23 | #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" | |||
24 | #include "clang/Analysis/FlowSensitive/NoopLattice.h" | |||
25 | #include "clang/Analysis/FlowSensitive/StorageLocation.h" | |||
26 | #include "clang/Analysis/FlowSensitive/Value.h" | |||
27 | #include "clang/Basic/SourceLocation.h" | |||
28 | #include "llvm/ADT/StringRef.h" | |||
29 | #include "llvm/Support/Casting.h" | |||
30 | #include "llvm/Support/ErrorHandling.h" | |||
31 | #include <cassert> | |||
32 | #include <memory> | |||
33 | #include <optional> | |||
34 | #include <utility> | |||
35 | #include <vector> | |||
36 | ||||
37 | namespace clang { | |||
38 | namespace dataflow { | |||
39 | namespace { | |||
40 | ||||
41 | using namespace ::clang::ast_matchers; | |||
42 | using LatticeTransferState = TransferState<NoopLattice>; | |||
43 | ||||
44 | DeclarationMatcher optionalClass() { | |||
45 | return classTemplateSpecializationDecl( | |||
46 | anyOf(hasName("std::optional"), hasName("std::__optional_storage_base"), | |||
47 | hasName("__optional_destruct_base"), hasName("absl::optional"), | |||
48 | hasName("base::Optional")), | |||
49 | hasTemplateArgument(0, refersToType(type().bind("T")))); | |||
50 | } | |||
51 | ||||
52 | auto optionalOrAliasType() { | |||
53 | return hasUnqualifiedDesugaredType( | |||
54 | recordType(hasDeclaration(optionalClass()))); | |||
55 | } | |||
56 | ||||
57 | /// Matches any of the spellings of the optional types and sugar, aliases, etc. | |||
58 | auto hasOptionalType() { return hasType(optionalOrAliasType()); } | |||
59 | ||||
60 | auto isOptionalMemberCallWithName( | |||
61 | llvm::StringRef MemberName, | |||
62 | const std::optional<StatementMatcher> &Ignorable = std::nullopt) { | |||
63 | auto Exception = unless(Ignorable ? expr(anyOf(*Ignorable, cxxThisExpr())) | |||
64 | : cxxThisExpr()); | |||
65 | return cxxMemberCallExpr( | |||
66 | on(expr(Exception)), | |||
67 | callee(cxxMethodDecl(hasName(MemberName), ofClass(optionalClass())))); | |||
68 | } | |||
69 | ||||
70 | auto isOptionalOperatorCallWithName( | |||
71 | llvm::StringRef operator_name, | |||
72 | const std::optional<StatementMatcher> &Ignorable = std::nullopt) { | |||
73 | return cxxOperatorCallExpr( | |||
74 | hasOverloadedOperatorName(operator_name), | |||
75 | callee(cxxMethodDecl(ofClass(optionalClass()))), | |||
76 | Ignorable ? callExpr(unless(hasArgument(0, *Ignorable))) : callExpr()); | |||
77 | } | |||
78 | ||||
79 | auto isMakeOptionalCall() { | |||
80 | return callExpr( | |||
81 | callee(functionDecl(hasAnyName( | |||
82 | "std::make_optional", "base::make_optional", "absl::make_optional"))), | |||
83 | hasOptionalType()); | |||
84 | } | |||
85 | ||||
86 | auto nulloptTypeDecl() { | |||
87 | return namedDecl( | |||
88 | hasAnyName("std::nullopt_t", "absl::nullopt_t", "base::nullopt_t")); | |||
89 | } | |||
90 | ||||
91 | auto hasNulloptType() { return hasType(nulloptTypeDecl()); } | |||
92 | ||||
93 | // `optional` or `nullopt_t` | |||
94 | auto hasAnyOptionalType() { | |||
95 | return hasType(hasUnqualifiedDesugaredType( | |||
96 | recordType(hasDeclaration(anyOf(nulloptTypeDecl(), optionalClass()))))); | |||
97 | } | |||
98 | ||||
99 | ||||
100 | auto inPlaceClass() { | |||
101 | return recordDecl( | |||
102 | hasAnyName("std::in_place_t", "absl::in_place_t", "base::in_place_t")); | |||
103 | } | |||
104 | ||||
105 | auto isOptionalNulloptConstructor() { | |||
106 | return cxxConstructExpr( | |||
107 | hasOptionalType(), | |||
108 | hasDeclaration(cxxConstructorDecl(parameterCountIs(1), | |||
109 | hasParameter(0, hasNulloptType())))); | |||
110 | } | |||
111 | ||||
112 | auto isOptionalInPlaceConstructor() { | |||
113 | return cxxConstructExpr(hasOptionalType(), | |||
114 | hasArgument(0, hasType(inPlaceClass()))); | |||
115 | } | |||
116 | ||||
117 | auto isOptionalValueOrConversionConstructor() { | |||
118 | return cxxConstructExpr( | |||
119 | hasOptionalType(), | |||
120 | unless(hasDeclaration( | |||
121 | cxxConstructorDecl(anyOf(isCopyConstructor(), isMoveConstructor())))), | |||
122 | argumentCountIs(1), hasArgument(0, unless(hasNulloptType()))); | |||
123 | } | |||
124 | ||||
125 | auto isOptionalValueOrConversionAssignment() { | |||
126 | return cxxOperatorCallExpr( | |||
127 | hasOverloadedOperatorName("="), | |||
128 | callee(cxxMethodDecl(ofClass(optionalClass()))), | |||
129 | unless(hasDeclaration(cxxMethodDecl( | |||
130 | anyOf(isCopyAssignmentOperator(), isMoveAssignmentOperator())))), | |||
131 | argumentCountIs(2), hasArgument(1, unless(hasNulloptType()))); | |||
132 | } | |||
133 | ||||
134 | auto isNulloptConstructor() { | |||
135 | return cxxConstructExpr(hasNulloptType(), argumentCountIs(1), | |||
136 | hasArgument(0, hasNulloptType())); | |||
137 | } | |||
138 | ||||
139 | auto isOptionalNulloptAssignment() { | |||
140 | return cxxOperatorCallExpr(hasOverloadedOperatorName("="), | |||
141 | callee(cxxMethodDecl(ofClass(optionalClass()))), | |||
142 | argumentCountIs(2), | |||
143 | hasArgument(1, hasNulloptType())); | |||
144 | } | |||
145 | ||||
146 | auto isStdSwapCall() { | |||
147 | return callExpr(callee(functionDecl(hasName("std::swap"))), | |||
148 | argumentCountIs(2), hasArgument(0, hasOptionalType()), | |||
149 | hasArgument(1, hasOptionalType())); | |||
150 | } | |||
151 | ||||
152 | constexpr llvm::StringLiteral ValueOrCallID = "ValueOrCall"; | |||
153 | ||||
154 | auto isValueOrStringEmptyCall() { | |||
155 | // `opt.value_or("").empty()` | |||
156 | return cxxMemberCallExpr( | |||
157 | callee(cxxMethodDecl(hasName("empty"))), | |||
158 | onImplicitObjectArgument(ignoringImplicit( | |||
159 | cxxMemberCallExpr(on(expr(unless(cxxThisExpr()))), | |||
160 | callee(cxxMethodDecl(hasName("value_or"), | |||
161 | ofClass(optionalClass()))), | |||
162 | hasArgument(0, stringLiteral(hasSize(0)))) | |||
163 | .bind(ValueOrCallID)))); | |||
164 | } | |||
165 | ||||
166 | auto isValueOrNotEqX() { | |||
167 | auto ComparesToSame = [](ast_matchers::internal::Matcher<Stmt> Arg) { | |||
168 | return hasOperands( | |||
169 | ignoringImplicit( | |||
170 | cxxMemberCallExpr(on(expr(unless(cxxThisExpr()))), | |||
171 | callee(cxxMethodDecl(hasName("value_or"), | |||
172 | ofClass(optionalClass()))), | |||
173 | hasArgument(0, Arg)) | |||
174 | .bind(ValueOrCallID)), | |||
175 | ignoringImplicit(Arg)); | |||
176 | }; | |||
177 | ||||
178 | // `opt.value_or(X) != X`, for X is `nullptr`, `""`, or `0`. Ideally, we'd | |||
179 | // support this pattern for any expression, but the AST does not have a | |||
180 | // generic expression comparison facility, so we specialize to common cases | |||
181 | // seen in practice. FIXME: define a matcher that compares values across | |||
182 | // nodes, which would let us generalize this to any `X`. | |||
183 | return binaryOperation(hasOperatorName("!="), | |||
184 | anyOf(ComparesToSame(cxxNullPtrLiteralExpr()), | |||
185 | ComparesToSame(stringLiteral(hasSize(0))), | |||
186 | ComparesToSame(integerLiteral(equals(0))))); | |||
187 | } | |||
188 | ||||
189 | auto isCallReturningOptional() { | |||
190 | return callExpr(hasType(qualType(anyOf( | |||
191 | optionalOrAliasType(), referenceType(pointee(optionalOrAliasType())))))); | |||
192 | } | |||
193 | ||||
194 | template <typename L, typename R> | |||
195 | auto isComparisonOperatorCall(L lhs_arg_matcher, R rhs_arg_matcher) { | |||
196 | return cxxOperatorCallExpr( | |||
197 | anyOf(hasOverloadedOperatorName("=="), hasOverloadedOperatorName("!=")), | |||
198 | argumentCountIs(2), hasArgument(0, lhs_arg_matcher), | |||
199 | hasArgument(1, rhs_arg_matcher)); | |||
200 | } | |||
201 | ||||
202 | // Ensures that `Expr` is mapped to a `BoolValue` and returns it. | |||
203 | BoolValue &forceBoolValue(Environment &Env, const Expr &Expr) { | |||
204 | auto *Value = cast_or_null<BoolValue>(Env.getValue(Expr, SkipPast::None)); | |||
205 | if (Value != nullptr) | |||
206 | return *Value; | |||
207 | ||||
208 | auto &Loc = Env.createStorageLocation(Expr); | |||
209 | Value = &Env.makeAtomicBoolValue(); | |||
210 | Env.setValue(Loc, *Value); | |||
211 | Env.setStorageLocation(Expr, Loc); | |||
212 | return *Value; | |||
213 | } | |||
214 | ||||
215 | /// Sets `HasValueVal` as the symbolic value that represents the "has_value" | |||
216 | /// property of the optional value `OptionalVal`. | |||
217 | void setHasValue(Value &OptionalVal, BoolValue &HasValueVal) { | |||
218 | OptionalVal.setProperty("has_value", HasValueVal); | |||
219 | } | |||
220 | ||||
221 | /// Creates a symbolic value for an `optional` value using `HasValueVal` as the | |||
222 | /// symbolic value of its "has_value" property. | |||
223 | StructValue &createOptionalValue(Environment &Env, BoolValue &HasValueVal) { | |||
224 | auto OptionalVal = std::make_unique<StructValue>(); | |||
225 | setHasValue(*OptionalVal, HasValueVal); | |||
226 | return Env.takeOwnership(std::move(OptionalVal)); | |||
227 | } | |||
228 | ||||
229 | /// Returns the symbolic value that represents the "has_value" property of the | |||
230 | /// optional value `OptionalVal`. Returns null if `OptionalVal` is null. | |||
231 | BoolValue *getHasValue(Environment &Env, Value *OptionalVal) { | |||
232 | if (OptionalVal != nullptr) { | |||
233 | auto *HasValueVal = | |||
234 | cast_or_null<BoolValue>(OptionalVal->getProperty("has_value")); | |||
235 | if (HasValueVal == nullptr) { | |||
236 | HasValueVal = &Env.makeAtomicBoolValue(); | |||
237 | OptionalVal->setProperty("has_value", *HasValueVal); | |||
238 | } | |||
239 | return HasValueVal; | |||
240 | } | |||
241 | return nullptr; | |||
242 | } | |||
243 | ||||
244 | /// If `Type` is a reference type, returns the type of its pointee. Otherwise, | |||
245 | /// returns `Type` itself. | |||
246 | QualType stripReference(QualType Type) { | |||
247 | return Type->isReferenceType() ? Type->getPointeeType() : Type; | |||
248 | } | |||
249 | ||||
250 | /// Returns true if and only if `Type` is an optional type. | |||
251 | bool isOptionalType(QualType Type) { | |||
252 | if (!Type->isRecordType()) | |||
253 | return false; | |||
254 | // FIXME: Optimize this by avoiding the `getQualifiedNameAsString` call. | |||
255 | auto TypeName = Type->getAsCXXRecordDecl()->getQualifiedNameAsString(); | |||
256 | return TypeName == "std::optional" || TypeName == "absl::optional" || | |||
257 | TypeName == "base::Optional"; | |||
258 | } | |||
259 | ||||
260 | /// Returns the number of optional wrappers in `Type`. | |||
261 | /// | |||
262 | /// For example, if `Type` is `optional<optional<int>>`, the result of this | |||
263 | /// function will be 2. | |||
264 | int countOptionalWrappers(const ASTContext &ASTCtx, QualType Type) { | |||
265 | if (!isOptionalType(Type)) | |||
266 | return 0; | |||
267 | return 1 + countOptionalWrappers( | |||
268 | ASTCtx, | |||
269 | cast<ClassTemplateSpecializationDecl>(Type->getAsRecordDecl()) | |||
270 | ->getTemplateArgs() | |||
271 | .get(0) | |||
272 | .getAsType() | |||
273 | .getDesugaredType(ASTCtx)); | |||
274 | } | |||
275 | ||||
276 | /// Tries to initialize the `optional`'s value (that is, contents), and return | |||
277 | /// its location. Returns nullptr if the value can't be represented. | |||
278 | StorageLocation *maybeInitializeOptionalValueMember(QualType Q, | |||
279 | Value &OptionalVal, | |||
280 | Environment &Env) { | |||
281 | // The "value" property represents a synthetic field. As such, it needs | |||
282 | // `StorageLocation`, like normal fields (and other variables). So, we model | |||
283 | // it with a `ReferenceValue`, since that includes a storage location. Once | |||
284 | // the property is set, it will be shared by all environments that access the | |||
285 | // `Value` representing the optional (here, `OptionalVal`). | |||
286 | if (auto *ValueProp = OptionalVal.getProperty("value")) { | |||
287 | auto *ValueRef = clang::cast<ReferenceValue>(ValueProp); | |||
288 | auto &ValueLoc = ValueRef->getReferentLoc(); | |||
289 | if (Env.getValue(ValueLoc) == nullptr) { | |||
290 | // The property was previously set, but the value has been lost. This can | |||
291 | // happen, for example, because of an environment merge (where the two | |||
292 | // environments mapped the property to different values, which resulted in | |||
293 | // them both being discarded), or when two blocks in the CFG, with neither | |||
294 | // a dominator of the other, visit the same optional value, or even when a | |||
295 | // block is revisited during testing to collect per-statement state. | |||
296 | // FIXME: This situation means that the optional contents are not shared | |||
297 | // between branches and the like. Practically, this lack of sharing | |||
298 | // reduces the precision of the model when the contents are relevant to | |||
299 | // the check, like another optional or a boolean that influences control | |||
300 | // flow. | |||
301 | auto *ValueVal = Env.createValue(ValueLoc.getType()); | |||
302 | if (ValueVal == nullptr) | |||
303 | return nullptr; | |||
304 | Env.setValue(ValueLoc, *ValueVal); | |||
305 | } | |||
306 | return &ValueLoc; | |||
307 | } | |||
308 | ||||
309 | auto Ty = stripReference(Q); | |||
310 | auto *ValueVal = Env.createValue(Ty); | |||
311 | if (ValueVal == nullptr) | |||
312 | return nullptr; | |||
313 | auto &ValueLoc = Env.createStorageLocation(Ty); | |||
314 | Env.setValue(ValueLoc, *ValueVal); | |||
315 | auto ValueRef = std::make_unique<ReferenceValue>(ValueLoc); | |||
316 | OptionalVal.setProperty("value", Env.takeOwnership(std::move(ValueRef))); | |||
317 | return &ValueLoc; | |||
318 | } | |||
319 | ||||
320 | void initializeOptionalReference(const Expr *OptionalExpr, | |||
321 | const MatchFinder::MatchResult &, | |||
322 | LatticeTransferState &State) { | |||
323 | if (auto *OptionalVal = | |||
324 | State.Env.getValue(*OptionalExpr, SkipPast::Reference)) { | |||
325 | if (OptionalVal->getProperty("has_value") == nullptr) { | |||
326 | setHasValue(*OptionalVal, State.Env.makeAtomicBoolValue()); | |||
327 | } | |||
328 | } | |||
329 | } | |||
330 | ||||
331 | /// Returns true if and only if `OptionalVal` is initialized and known to be | |||
332 | /// empty in `Env. | |||
333 | bool isEmptyOptional(const Value &OptionalVal, const Environment &Env) { | |||
334 | auto *HasValueVal = | |||
335 | cast_or_null<BoolValue>(OptionalVal.getProperty("has_value")); | |||
336 | return HasValueVal != nullptr && | |||
337 | Env.flowConditionImplies(Env.makeNot(*HasValueVal)); | |||
338 | } | |||
339 | ||||
340 | /// Returns true if and only if `OptionalVal` is initialized and known to be | |||
341 | /// non-empty in `Env. | |||
342 | bool isNonEmptyOptional(const Value &OptionalVal, const Environment &Env) { | |||
343 | auto *HasValueVal = | |||
344 | cast_or_null<BoolValue>(OptionalVal.getProperty("has_value")); | |||
345 | return HasValueVal != nullptr && Env.flowConditionImplies(*HasValueVal); | |||
346 | } | |||
347 | ||||
348 | void transferUnwrapCall(const Expr *UnwrapExpr, const Expr *ObjectExpr, | |||
349 | LatticeTransferState &State) { | |||
350 | if (auto *OptionalVal = | |||
351 | State.Env.getValue(*ObjectExpr, SkipPast::ReferenceThenPointer)) { | |||
352 | if (State.Env.getStorageLocation(*UnwrapExpr, SkipPast::None) == nullptr) | |||
353 | if (auto *Loc = maybeInitializeOptionalValueMember( | |||
354 | UnwrapExpr->getType(), *OptionalVal, State.Env)) | |||
355 | State.Env.setStorageLocation(*UnwrapExpr, *Loc); | |||
356 | } | |||
357 | } | |||
358 | ||||
359 | void transferMakeOptionalCall(const CallExpr *E, | |||
360 | const MatchFinder::MatchResult &, | |||
361 | LatticeTransferState &State) { | |||
362 | auto &Loc = State.Env.createStorageLocation(*E); | |||
363 | State.Env.setStorageLocation(*E, Loc); | |||
364 | State.Env.setValue( | |||
365 | Loc, createOptionalValue(State.Env, State.Env.getBoolLiteralValue(true))); | |||
366 | } | |||
367 | ||||
368 | void transferOptionalHasValueCall(const CXXMemberCallExpr *CallExpr, | |||
369 | const MatchFinder::MatchResult &, | |||
370 | LatticeTransferState &State) { | |||
371 | if (auto *HasValueVal = getHasValue( | |||
372 | State.Env, State.Env.getValue(*CallExpr->getImplicitObjectArgument(), | |||
373 | SkipPast::ReferenceThenPointer))) { | |||
374 | auto &CallExprLoc = State.Env.createStorageLocation(*CallExpr); | |||
375 | State.Env.setValue(CallExprLoc, *HasValueVal); | |||
376 | State.Env.setStorageLocation(*CallExpr, CallExprLoc); | |||
377 | } | |||
378 | } | |||
379 | ||||
380 | /// `ModelPred` builds a logical formula relating the predicate in | |||
381 | /// `ValueOrPredExpr` to the optional's `has_value` property. | |||
382 | void transferValueOrImpl(const clang::Expr *ValueOrPredExpr, | |||
383 | const MatchFinder::MatchResult &Result, | |||
384 | LatticeTransferState &State, | |||
385 | BoolValue &(*ModelPred)(Environment &Env, | |||
386 | BoolValue &ExprVal, | |||
387 | BoolValue &HasValueVal)) { | |||
388 | auto &Env = State.Env; | |||
389 | ||||
390 | const auto *ObjectArgumentExpr = | |||
391 | Result.Nodes.getNodeAs<clang::CXXMemberCallExpr>(ValueOrCallID) | |||
392 | ->getImplicitObjectArgument(); | |||
393 | ||||
394 | auto *HasValueVal = getHasValue( | |||
395 | State.Env, | |||
396 | State.Env.getValue(*ObjectArgumentExpr, SkipPast::ReferenceThenPointer)); | |||
397 | if (HasValueVal == nullptr) | |||
398 | return; | |||
399 | ||||
400 | Env.addToFlowCondition( | |||
401 | ModelPred(Env, forceBoolValue(Env, *ValueOrPredExpr), *HasValueVal)); | |||
402 | } | |||
403 | ||||
404 | void transferValueOrStringEmptyCall(const clang::Expr *ComparisonExpr, | |||
405 | const MatchFinder::MatchResult &Result, | |||
406 | LatticeTransferState &State) { | |||
407 | return transferValueOrImpl(ComparisonExpr, Result, State, | |||
408 | [](Environment &Env, BoolValue &ExprVal, | |||
409 | BoolValue &HasValueVal) -> BoolValue & { | |||
410 | // If the result is *not* empty, then we know the | |||
411 | // optional must have been holding a value. If | |||
412 | // `ExprVal` is true, though, we don't learn | |||
413 | // anything definite about `has_value`, so we | |||
414 | // don't add any corresponding implications to | |||
415 | // the flow condition. | |||
416 | return Env.makeImplication(Env.makeNot(ExprVal), | |||
417 | HasValueVal); | |||
418 | }); | |||
419 | } | |||
420 | ||||
421 | void transferValueOrNotEqX(const Expr *ComparisonExpr, | |||
422 | const MatchFinder::MatchResult &Result, | |||
423 | LatticeTransferState &State) { | |||
424 | transferValueOrImpl(ComparisonExpr, Result, State, | |||
425 | [](Environment &Env, BoolValue &ExprVal, | |||
426 | BoolValue &HasValueVal) -> BoolValue & { | |||
427 | // We know that if `(opt.value_or(X) != X)` then | |||
428 | // `opt.hasValue()`, even without knowing further | |||
429 | // details about the contents of `opt`. | |||
430 | return Env.makeImplication(ExprVal, HasValueVal); | |||
431 | }); | |||
432 | } | |||
433 | ||||
434 | void transferCallReturningOptional(const CallExpr *E, | |||
435 | const MatchFinder::MatchResult &Result, | |||
436 | LatticeTransferState &State) { | |||
437 | if (State.Env.getStorageLocation(*E, SkipPast::None) != nullptr) | |||
438 | return; | |||
439 | ||||
440 | auto &Loc = State.Env.createStorageLocation(*E); | |||
441 | State.Env.setStorageLocation(*E, Loc); | |||
442 | State.Env.setValue( | |||
443 | Loc, createOptionalValue(State.Env, State.Env.makeAtomicBoolValue())); | |||
444 | } | |||
445 | ||||
446 | void assignOptionalValue(const Expr &E, Environment &Env, | |||
447 | BoolValue &HasValueVal) { | |||
448 | if (auto *OptionalLoc = | |||
449 | Env.getStorageLocation(E, SkipPast::ReferenceThenPointer)) { | |||
450 | Env.setValue(*OptionalLoc, createOptionalValue(Env, HasValueVal)); | |||
451 | } | |||
452 | } | |||
453 | ||||
454 | /// Returns a symbolic value for the "has_value" property of an `optional<T>` | |||
455 | /// value that is constructed/assigned from a value of type `U` or `optional<U>` | |||
456 | /// where `T` is constructible from `U`. | |||
457 | BoolValue &valueOrConversionHasValue(const FunctionDecl &F, const Expr &E, | |||
458 | const MatchFinder::MatchResult &MatchRes, | |||
459 | LatticeTransferState &State) { | |||
460 | assert(F.getTemplateSpecializationArgs() != nullptr)(static_cast <bool> (F.getTemplateSpecializationArgs() != nullptr) ? void (0) : __assert_fail ("F.getTemplateSpecializationArgs() != nullptr" , "clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp" , 460, __extension__ __PRETTY_FUNCTION__)); | |||
461 | assert(F.getTemplateSpecializationArgs()->size() > 0)(static_cast <bool> (F.getTemplateSpecializationArgs()-> size() > 0) ? void (0) : __assert_fail ("F.getTemplateSpecializationArgs()->size() > 0" , "clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp" , 461, __extension__ __PRETTY_FUNCTION__)); | |||
462 | ||||
463 | const int TemplateParamOptionalWrappersCount = countOptionalWrappers( | |||
464 | *MatchRes.Context, | |||
465 | stripReference(F.getTemplateSpecializationArgs()->get(0).getAsType())); | |||
466 | const int ArgTypeOptionalWrappersCount = | |||
467 | countOptionalWrappers(*MatchRes.Context, stripReference(E.getType())); | |||
468 | ||||
469 | // Check if this is a constructor/assignment call for `optional<T>` with | |||
470 | // argument of type `U` such that `T` is constructible from `U`. | |||
471 | if (TemplateParamOptionalWrappersCount == ArgTypeOptionalWrappersCount) | |||
472 | return State.Env.getBoolLiteralValue(true); | |||
473 | ||||
474 | // This is a constructor/assignment call for `optional<T>` with argument of | |||
475 | // type `optional<U>` such that `T` is constructible from `U`. | |||
476 | if (auto *HasValueVal = | |||
477 | getHasValue(State.Env, State.Env.getValue(E, SkipPast::Reference))) | |||
478 | return *HasValueVal; | |||
479 | return State.Env.makeAtomicBoolValue(); | |||
480 | } | |||
481 | ||||
482 | void transferValueOrConversionConstructor( | |||
483 | const CXXConstructExpr *E, const MatchFinder::MatchResult &MatchRes, | |||
484 | LatticeTransferState &State) { | |||
485 | assert(E->getNumArgs() > 0)(static_cast <bool> (E->getNumArgs() > 0) ? void ( 0) : __assert_fail ("E->getNumArgs() > 0", "clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp" , 485, __extension__ __PRETTY_FUNCTION__)); | |||
486 | ||||
487 | assignOptionalValue(*E, State.Env, | |||
488 | valueOrConversionHasValue(*E->getConstructor(), | |||
489 | *E->getArg(0), MatchRes, | |||
490 | State)); | |||
491 | } | |||
492 | ||||
493 | void transferAssignment(const CXXOperatorCallExpr *E, BoolValue &HasValueVal, | |||
494 | LatticeTransferState &State) { | |||
495 | assert(E->getNumArgs() > 0)(static_cast <bool> (E->getNumArgs() > 0) ? void ( 0) : __assert_fail ("E->getNumArgs() > 0", "clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp" , 495, __extension__ __PRETTY_FUNCTION__)); | |||
496 | ||||
497 | auto *OptionalLoc = | |||
498 | State.Env.getStorageLocation(*E->getArg(0), SkipPast::Reference); | |||
499 | if (OptionalLoc == nullptr) | |||
500 | return; | |||
501 | ||||
502 | State.Env.setValue(*OptionalLoc, createOptionalValue(State.Env, HasValueVal)); | |||
503 | ||||
504 | // Assign a storage location for the whole expression. | |||
505 | State.Env.setStorageLocation(*E, *OptionalLoc); | |||
506 | } | |||
507 | ||||
508 | void transferValueOrConversionAssignment( | |||
509 | const CXXOperatorCallExpr *E, const MatchFinder::MatchResult &MatchRes, | |||
510 | LatticeTransferState &State) { | |||
511 | assert(E->getNumArgs() > 1)(static_cast <bool> (E->getNumArgs() > 1) ? void ( 0) : __assert_fail ("E->getNumArgs() > 1", "clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp" , 511, __extension__ __PRETTY_FUNCTION__)); | |||
512 | transferAssignment(E, | |||
513 | valueOrConversionHasValue(*E->getDirectCallee(), | |||
514 | *E->getArg(1), MatchRes, State), | |||
515 | State); | |||
516 | } | |||
517 | ||||
518 | void transferNulloptAssignment(const CXXOperatorCallExpr *E, | |||
519 | const MatchFinder::MatchResult &, | |||
520 | LatticeTransferState &State) { | |||
521 | transferAssignment(E, State.Env.getBoolLiteralValue(false), State); | |||
522 | } | |||
523 | ||||
524 | void transferSwap(const Expr &E1, SkipPast E1Skip, const Expr &E2, | |||
525 | Environment &Env) { | |||
526 | // We account for cases where one or both of the optionals are not modeled, | |||
527 | // either lacking associated storage locations, or lacking values associated | |||
528 | // to such storage locations. | |||
529 | auto *Loc1 = Env.getStorageLocation(E1, E1Skip); | |||
530 | auto *Loc2 = Env.getStorageLocation(E2, SkipPast::Reference); | |||
531 | ||||
532 | if (Loc1 == nullptr) { | |||
533 | if (Loc2 != nullptr) | |||
534 | Env.setValue(*Loc2, createOptionalValue(Env, Env.makeAtomicBoolValue())); | |||
535 | return; | |||
536 | } | |||
537 | if (Loc2 == nullptr) { | |||
538 | Env.setValue(*Loc1, createOptionalValue(Env, Env.makeAtomicBoolValue())); | |||
539 | return; | |||
540 | } | |||
541 | ||||
542 | // Both expressions have locations, though they may not have corresponding | |||
543 | // values. In that case, we create a fresh value at this point. Note that if | |||
544 | // two branches both do this, they will not share the value, but it at least | |||
545 | // allows for local reasoning about the value. To avoid the above, we would | |||
546 | // need *lazy* value allocation. | |||
547 | // FIXME: allocate values lazily, instead of just creating a fresh value. | |||
548 | auto *Val1 = Env.getValue(*Loc1); | |||
549 | if (Val1 == nullptr) | |||
550 | Val1 = &createOptionalValue(Env, Env.makeAtomicBoolValue()); | |||
551 | ||||
552 | auto *Val2 = Env.getValue(*Loc2); | |||
553 | if (Val2 == nullptr) | |||
554 | Val2 = &createOptionalValue(Env, Env.makeAtomicBoolValue()); | |||
555 | ||||
556 | Env.setValue(*Loc1, *Val2); | |||
557 | Env.setValue(*Loc2, *Val1); | |||
558 | } | |||
559 | ||||
560 | void transferSwapCall(const CXXMemberCallExpr *E, | |||
561 | const MatchFinder::MatchResult &, | |||
562 | LatticeTransferState &State) { | |||
563 | assert(E->getNumArgs() == 1)(static_cast <bool> (E->getNumArgs() == 1) ? void (0 ) : __assert_fail ("E->getNumArgs() == 1", "clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp" , 563, __extension__ __PRETTY_FUNCTION__)); | |||
564 | transferSwap(*E->getImplicitObjectArgument(), SkipPast::ReferenceThenPointer, | |||
565 | *E->getArg(0), State.Env); | |||
566 | } | |||
567 | ||||
568 | void transferStdSwapCall(const CallExpr *E, const MatchFinder::MatchResult &, | |||
569 | LatticeTransferState &State) { | |||
570 | assert(E->getNumArgs() == 2)(static_cast <bool> (E->getNumArgs() == 2) ? void (0 ) : __assert_fail ("E->getNumArgs() == 2", "clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp" , 570, __extension__ __PRETTY_FUNCTION__)); | |||
571 | transferSwap(*E->getArg(0), SkipPast::Reference, *E->getArg(1), State.Env); | |||
572 | } | |||
573 | ||||
574 | BoolValue &evaluateEquality(Environment &Env, BoolValue &EqVal, BoolValue &LHS, | |||
575 | BoolValue &RHS) { | |||
576 | // Logically, an optional<T> object is composed of two values - a `has_value` | |||
577 | // bit and a value of type T. Equality of optional objects compares both | |||
578 | // values. Therefore, merely comparing the `has_value` bits isn't sufficient: | |||
579 | // when two optional objects are engaged, the equality of their respective | |||
580 | // values of type T matters. Since we only track the `has_value` bits, we | |||
581 | // can't make any conclusions about equality when we know that two optional | |||
582 | // objects are engaged. | |||
583 | // | |||
584 | // We express this as two facts about the equality: | |||
585 | // a) EqVal => (LHS & RHS) v (!RHS & !LHS) | |||
586 | // If they are equal, then either both are set or both are unset. | |||
587 | // b) (!LHS & !RHS) => EqVal | |||
588 | // If neither is set, then they are equal. | |||
589 | // We rewrite b) as !EqVal => (LHS v RHS), for a more compact formula. | |||
590 | return Env.makeAnd( | |||
591 | Env.makeImplication( | |||
592 | EqVal, Env.makeOr(Env.makeAnd(LHS, RHS), | |||
593 | Env.makeAnd(Env.makeNot(LHS), Env.makeNot(RHS)))), | |||
594 | Env.makeImplication(Env.makeNot(EqVal), Env.makeOr(LHS, RHS))); | |||
595 | } | |||
596 | ||||
597 | void transferOptionalAndOptionalCmp(const clang::CXXOperatorCallExpr *CmpExpr, | |||
598 | const MatchFinder::MatchResult &, | |||
599 | LatticeTransferState &State) { | |||
600 | Environment &Env = State.Env; | |||
601 | auto *CmpValue = &forceBoolValue(Env, *CmpExpr); | |||
602 | if (auto *LHasVal = getHasValue( | |||
603 | Env, Env.getValue(*CmpExpr->getArg(0), SkipPast::Reference))) | |||
604 | if (auto *RHasVal = getHasValue( | |||
605 | Env, Env.getValue(*CmpExpr->getArg(1), SkipPast::Reference))) { | |||
606 | if (CmpExpr->getOperator() == clang::OO_ExclaimEqual) | |||
607 | CmpValue = &State.Env.makeNot(*CmpValue); | |||
608 | Env.addToFlowCondition( | |||
609 | evaluateEquality(Env, *CmpValue, *LHasVal, *RHasVal)); | |||
610 | } | |||
611 | } | |||
612 | ||||
613 | void transferOptionalAndValueCmp(const clang::CXXOperatorCallExpr *CmpExpr, | |||
614 | const clang::Expr *E, Environment &Env) { | |||
615 | auto *CmpValue = &forceBoolValue(Env, *CmpExpr); | |||
616 | if (auto *HasVal = getHasValue(Env, Env.getValue(*E, SkipPast::Reference))) { | |||
617 | if (CmpExpr->getOperator() == clang::OO_ExclaimEqual) | |||
618 | CmpValue = &Env.makeNot(*CmpValue); | |||
619 | Env.addToFlowCondition(evaluateEquality(Env, *CmpValue, *HasVal, | |||
620 | Env.getBoolLiteralValue(true))); | |||
621 | } | |||
622 | } | |||
623 | ||||
624 | std::optional<StatementMatcher> | |||
625 | ignorableOptional(const UncheckedOptionalAccessModelOptions &Options) { | |||
626 | if (Options.IgnoreSmartPointerDereference) { | |||
627 | auto SmartPtrUse = expr(ignoringParenImpCasts(cxxOperatorCallExpr( | |||
628 | anyOf(hasOverloadedOperatorName("->"), hasOverloadedOperatorName("*")), | |||
629 | unless(hasArgument(0, expr(hasOptionalType())))))); | |||
630 | return expr( | |||
631 | anyOf(SmartPtrUse, memberExpr(hasObjectExpression(SmartPtrUse)))); | |||
632 | } | |||
633 | return std::nullopt; | |||
634 | } | |||
635 | ||||
636 | StatementMatcher | |||
637 | valueCall(const std::optional<StatementMatcher> &IgnorableOptional) { | |||
638 | return isOptionalMemberCallWithName("value", IgnorableOptional); | |||
639 | } | |||
640 | ||||
641 | StatementMatcher | |||
642 | valueOperatorCall(const std::optional<StatementMatcher> &IgnorableOptional) { | |||
643 | return expr(anyOf(isOptionalOperatorCallWithName("*", IgnorableOptional), | |||
644 | isOptionalOperatorCallWithName("->", IgnorableOptional))); | |||
645 | } | |||
646 | ||||
647 | auto buildTransferMatchSwitch() { | |||
648 | // FIXME: Evaluate the efficiency of matchers. If using matchers results in a | |||
649 | // lot of duplicated work (e.g. string comparisons), consider providing APIs | |||
650 | // that avoid it through memoization. | |||
651 | return CFGMatchSwitchBuilder<LatticeTransferState>() | |||
652 | // Attach a symbolic "has_value" state to optional values that we see for | |||
653 | // the first time. | |||
654 | .CaseOfCFGStmt<Expr>( | |||
655 | expr(anyOf(declRefExpr(), memberExpr()), hasOptionalType()), | |||
656 | initializeOptionalReference) | |||
657 | ||||
658 | // make_optional | |||
659 | .CaseOfCFGStmt<CallExpr>(isMakeOptionalCall(), transferMakeOptionalCall) | |||
660 | ||||
661 | // optional::optional (in place) | |||
662 | .CaseOfCFGStmt<CXXConstructExpr>( | |||
663 | isOptionalInPlaceConstructor(), | |||
664 | [](const CXXConstructExpr *E, const MatchFinder::MatchResult &, | |||
665 | LatticeTransferState &State) { | |||
666 | assignOptionalValue(*E, State.Env, | |||
667 | State.Env.getBoolLiteralValue(true)); | |||
668 | }) | |||
669 | // nullopt_t::nullopt_t | |||
670 | .CaseOfCFGStmt<CXXConstructExpr>( | |||
671 | isNulloptConstructor(), | |||
672 | [](const CXXConstructExpr *E, const MatchFinder::MatchResult &, | |||
673 | LatticeTransferState &State) { | |||
674 | assignOptionalValue(*E, State.Env, | |||
675 | State.Env.getBoolLiteralValue(false)); | |||
676 | }) | |||
677 | // optional::optional(nullopt_t) | |||
678 | .CaseOfCFGStmt<CXXConstructExpr>( | |||
679 | isOptionalNulloptConstructor(), | |||
680 | [](const CXXConstructExpr *E, const MatchFinder::MatchResult &, | |||
681 | LatticeTransferState &State) { | |||
682 | assignOptionalValue(*E, State.Env, | |||
683 | State.Env.getBoolLiteralValue(false)); | |||
684 | }) | |||
685 | // optional::optional (value/conversion) | |||
686 | .CaseOfCFGStmt<CXXConstructExpr>(isOptionalValueOrConversionConstructor(), | |||
687 | transferValueOrConversionConstructor) | |||
688 | ||||
689 | ||||
690 | // optional::operator= | |||
691 | .CaseOfCFGStmt<CXXOperatorCallExpr>( | |||
692 | isOptionalValueOrConversionAssignment(), | |||
693 | transferValueOrConversionAssignment) | |||
694 | .CaseOfCFGStmt<CXXOperatorCallExpr>(isOptionalNulloptAssignment(), | |||
695 | transferNulloptAssignment) | |||
696 | ||||
697 | // optional::value | |||
698 | .CaseOfCFGStmt<CXXMemberCallExpr>( | |||
699 | valueCall(std::nullopt), | |||
700 | [](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &, | |||
701 | LatticeTransferState &State) { | |||
702 | transferUnwrapCall(E, E->getImplicitObjectArgument(), State); | |||
703 | }) | |||
704 | ||||
705 | // optional::operator*, optional::operator-> | |||
706 | .CaseOfCFGStmt<CallExpr>(valueOperatorCall(std::nullopt), | |||
707 | [](const CallExpr *E, | |||
708 | const MatchFinder::MatchResult &, | |||
709 | LatticeTransferState &State) { | |||
710 | transferUnwrapCall(E, E->getArg(0), State); | |||
711 | }) | |||
712 | ||||
713 | // optional::has_value | |||
714 | .CaseOfCFGStmt<CXXMemberCallExpr>( | |||
715 | isOptionalMemberCallWithName("has_value"), | |||
716 | transferOptionalHasValueCall) | |||
717 | ||||
718 | // optional::operator bool | |||
719 | .CaseOfCFGStmt<CXXMemberCallExpr>( | |||
720 | isOptionalMemberCallWithName("operator bool"), | |||
721 | transferOptionalHasValueCall) | |||
722 | ||||
723 | // optional::emplace | |||
724 | .CaseOfCFGStmt<CXXMemberCallExpr>( | |||
725 | isOptionalMemberCallWithName("emplace"), | |||
726 | [](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &, | |||
727 | LatticeTransferState &State) { | |||
728 | assignOptionalValue(*E->getImplicitObjectArgument(), State.Env, | |||
729 | State.Env.getBoolLiteralValue(true)); | |||
730 | }) | |||
731 | ||||
732 | // optional::reset | |||
733 | .CaseOfCFGStmt<CXXMemberCallExpr>( | |||
734 | isOptionalMemberCallWithName("reset"), | |||
735 | [](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &, | |||
736 | LatticeTransferState &State) { | |||
737 | assignOptionalValue(*E->getImplicitObjectArgument(), State.Env, | |||
738 | State.Env.getBoolLiteralValue(false)); | |||
739 | }) | |||
740 | ||||
741 | // optional::swap | |||
742 | .CaseOfCFGStmt<CXXMemberCallExpr>(isOptionalMemberCallWithName("swap"), | |||
743 | transferSwapCall) | |||
744 | ||||
745 | // std::swap | |||
746 | .CaseOfCFGStmt<CallExpr>(isStdSwapCall(), transferStdSwapCall) | |||
747 | ||||
748 | // opt.value_or("").empty() | |||
749 | .CaseOfCFGStmt<Expr>(isValueOrStringEmptyCall(), | |||
750 | transferValueOrStringEmptyCall) | |||
751 | ||||
752 | // opt.value_or(X) != X | |||
753 | .CaseOfCFGStmt<Expr>(isValueOrNotEqX(), transferValueOrNotEqX) | |||
754 | ||||
755 | // Comparisons (==, !=): | |||
756 | .CaseOfCFGStmt<CXXOperatorCallExpr>( | |||
757 | isComparisonOperatorCall(hasAnyOptionalType(), hasAnyOptionalType()), | |||
758 | transferOptionalAndOptionalCmp) | |||
759 | .CaseOfCFGStmt<CXXOperatorCallExpr>( | |||
760 | isComparisonOperatorCall(hasOptionalType(), | |||
761 | unless(hasAnyOptionalType())), | |||
762 | [](const clang::CXXOperatorCallExpr *Cmp, | |||
763 | const MatchFinder::MatchResult &, LatticeTransferState &State) { | |||
764 | transferOptionalAndValueCmp(Cmp, Cmp->getArg(0), State.Env); | |||
765 | }) | |||
766 | .CaseOfCFGStmt<CXXOperatorCallExpr>( | |||
767 | isComparisonOperatorCall(unless(hasAnyOptionalType()), | |||
768 | hasOptionalType()), | |||
769 | [](const clang::CXXOperatorCallExpr *Cmp, | |||
770 | const MatchFinder::MatchResult &, LatticeTransferState &State) { | |||
771 | transferOptionalAndValueCmp(Cmp, Cmp->getArg(1), State.Env); | |||
772 | }) | |||
773 | ||||
774 | // returns optional | |||
775 | .CaseOfCFGStmt<CallExpr>(isCallReturningOptional(), | |||
776 | transferCallReturningOptional) | |||
777 | ||||
778 | .Build(); | |||
779 | } | |||
780 | ||||
781 | std::vector<SourceLocation> diagnoseUnwrapCall(const Expr *UnwrapExpr, | |||
782 | const Expr *ObjectExpr, | |||
783 | const Environment &Env) { | |||
784 | if (auto *OptionalVal = | |||
785 | Env.getValue(*ObjectExpr, SkipPast::ReferenceThenPointer)) { | |||
786 | auto *Prop = OptionalVal->getProperty("has_value"); | |||
787 | if (auto *HasValueVal = cast_or_null<BoolValue>(Prop)) { | |||
788 | if (Env.flowConditionImplies(*HasValueVal)) | |||
789 | return {}; | |||
790 | } | |||
791 | } | |||
792 | ||||
793 | // Record that this unwrap is *not* provably safe. | |||
794 | // FIXME: include either the name of the optional (if applicable) or a source | |||
795 | // range of the access for easier interpretation of the result. | |||
796 | return {ObjectExpr->getBeginLoc()}; | |||
797 | } | |||
798 | ||||
799 | auto buildDiagnoseMatchSwitch( | |||
800 | const UncheckedOptionalAccessModelOptions &Options) { | |||
801 | // FIXME: Evaluate the efficiency of matchers. If using matchers results in a | |||
802 | // lot of duplicated work (e.g. string comparisons), consider providing APIs | |||
803 | // that avoid it through memoization. | |||
804 | auto IgnorableOptional = ignorableOptional(Options); | |||
805 | return CFGMatchSwitchBuilder<const Environment, std::vector<SourceLocation>>() | |||
806 | // optional::value | |||
807 | .CaseOfCFGStmt<CXXMemberCallExpr>( | |||
808 | valueCall(IgnorableOptional), | |||
809 | [](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &, | |||
810 | const Environment &Env) { | |||
811 | return diagnoseUnwrapCall(E, E->getImplicitObjectArgument(), Env); | |||
812 | }) | |||
813 | ||||
814 | // optional::operator*, optional::operator-> | |||
815 | .CaseOfCFGStmt<CallExpr>( | |||
816 | valueOperatorCall(IgnorableOptional), | |||
817 | [](const CallExpr *E, const MatchFinder::MatchResult &, | |||
818 | const Environment &Env) { | |||
819 | return diagnoseUnwrapCall(E, E->getArg(0), Env); | |||
820 | }) | |||
821 | .Build(); | |||
822 | } | |||
823 | ||||
824 | } // namespace | |||
825 | ||||
826 | ast_matchers::DeclarationMatcher | |||
827 | UncheckedOptionalAccessModel::optionalClassDecl() { | |||
828 | return optionalClass(); | |||
829 | } | |||
830 | ||||
831 | UncheckedOptionalAccessModel::UncheckedOptionalAccessModel(ASTContext &Ctx) | |||
832 | : DataflowAnalysis<UncheckedOptionalAccessModel, NoopLattice>(Ctx), | |||
833 | TransferMatchSwitch(buildTransferMatchSwitch()) {} | |||
834 | ||||
835 | void UncheckedOptionalAccessModel::transfer(const CFGElement &Elt, | |||
836 | NoopLattice &L, Environment &Env) { | |||
837 | LatticeTransferState State(L, Env); | |||
838 | TransferMatchSwitch(Elt, getASTContext(), State); | |||
839 | } | |||
840 | ||||
841 | ComparisonResult UncheckedOptionalAccessModel::compare( | |||
842 | QualType Type, const Value &Val1, const Environment &Env1, | |||
843 | const Value &Val2, const Environment &Env2) { | |||
844 | if (!isOptionalType(Type)) | |||
845 | return ComparisonResult::Unknown; | |||
846 | bool MustNonEmpty1 = isNonEmptyOptional(Val1, Env1); | |||
847 | bool MustNonEmpty2 = isNonEmptyOptional(Val2, Env2); | |||
848 | if (MustNonEmpty1 && MustNonEmpty2) return ComparisonResult::Same; | |||
849 | // If exactly one is true, then they're different, no reason to check whether | |||
850 | // they're definitely empty. | |||
851 | if (MustNonEmpty1 || MustNonEmpty2) return ComparisonResult::Different; | |||
852 | // Check if they're both definitely empty. | |||
853 | return (isEmptyOptional(Val1, Env1) && isEmptyOptional(Val2, Env2)) | |||
854 | ? ComparisonResult::Same | |||
855 | : ComparisonResult::Different; | |||
856 | } | |||
857 | ||||
858 | bool UncheckedOptionalAccessModel::merge(QualType Type, const Value &Val1, | |||
859 | const Environment &Env1, | |||
860 | const Value &Val2, | |||
861 | const Environment &Env2, | |||
862 | Value &MergedVal, | |||
863 | Environment &MergedEnv) { | |||
864 | if (!isOptionalType(Type)) | |||
865 | return true; | |||
866 | // FIXME: uses same approach as join for `BoolValues`. Requires non-const | |||
867 | // values, though, so will require updating the interface. | |||
868 | auto &HasValueVal = MergedEnv.makeAtomicBoolValue(); | |||
869 | bool MustNonEmpty1 = isNonEmptyOptional(Val1, Env1); | |||
870 | bool MustNonEmpty2 = isNonEmptyOptional(Val2, Env2); | |||
871 | if (MustNonEmpty1 && MustNonEmpty2) | |||
872 | MergedEnv.addToFlowCondition(HasValueVal); | |||
873 | else if ( | |||
874 | // Only make the costly calls to `isEmptyOptional` if we got "unknown" | |||
875 | // (false) for both calls to `isNonEmptyOptional`. | |||
876 | !MustNonEmpty1 && !MustNonEmpty2 && isEmptyOptional(Val1, Env1) && | |||
877 | isEmptyOptional(Val2, Env2)) | |||
878 | MergedEnv.addToFlowCondition(MergedEnv.makeNot(HasValueVal)); | |||
879 | setHasValue(MergedVal, HasValueVal); | |||
880 | return true; | |||
881 | } | |||
882 | ||||
883 | Value *UncheckedOptionalAccessModel::widen(QualType Type, Value &Prev, | |||
884 | const Environment &PrevEnv, | |||
885 | Value &Current, | |||
886 | Environment &CurrentEnv) { | |||
887 | switch (compare(Type, Prev, PrevEnv, Current, CurrentEnv)) { | |||
888 | case ComparisonResult::Same: | |||
889 | return &Prev; | |||
890 | case ComparisonResult::Different: | |||
891 | if (auto *PrevHasVal = | |||
892 | cast_or_null<BoolValue>(Prev.getProperty("has_value"))) { | |||
893 | if (isa<TopBoolValue>(PrevHasVal)) | |||
894 | return &Prev; | |||
895 | } | |||
896 | if (auto *CurrentHasVal = | |||
897 | cast_or_null<BoolValue>(Current.getProperty("has_value"))) { | |||
898 | if (isa<TopBoolValue>(CurrentHasVal)) | |||
899 | return &Current; | |||
900 | } | |||
901 | return &createOptionalValue(CurrentEnv, CurrentEnv.makeTopBoolValue()); | |||
902 | case ComparisonResult::Unknown: | |||
903 | return nullptr; | |||
904 | } | |||
905 | llvm_unreachable("all cases covered in switch")::llvm::llvm_unreachable_internal("all cases covered in switch" , "clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp" , 905); | |||
906 | } | |||
907 | ||||
908 | UncheckedOptionalAccessDiagnoser::UncheckedOptionalAccessDiagnoser( | |||
909 | UncheckedOptionalAccessModelOptions Options) | |||
910 | : DiagnoseMatchSwitch(buildDiagnoseMatchSwitch(Options)) {} | |||
| ||||
911 | ||||
912 | std::vector<SourceLocation> UncheckedOptionalAccessDiagnoser::diagnose( | |||
913 | ASTContext &Ctx, const CFGElement *Elt, const Environment &Env) { | |||
914 | return DiagnoseMatchSwitch(*Elt, Ctx, Env); | |||
915 | } | |||
916 | ||||
917 | } // namespace dataflow | |||
918 | } // namespace clang |
1 | //===---- CFGMatchSwitch.h --------------------------------------*- C++ -*-===// | |||
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 defines the `CFGMatchSwitch` abstraction for building a "switch" | |||
10 | // statement for control flow graph elements. Each case of the switch is | |||
11 | // defined by an ASTMatcher which is applied on the AST node contained in the | |||
12 | // input `CFGElement`. | |||
13 | // | |||
14 | // Currently, the `CFGMatchSwitch` only handles `CFGElement`s of | |||
15 | // `Kind::Statement` and `Kind::Initializer`. | |||
16 | // | |||
17 | //===----------------------------------------------------------------------===// | |||
18 | ||||
19 | #ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CFGMATCHSWITCH_H_ | |||
20 | #define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CFGMATCHSWITCH_H_ | |||
21 | ||||
22 | #include "clang/AST/ASTContext.h" | |||
23 | #include "clang/AST/Stmt.h" | |||
24 | #include "clang/Analysis/CFG.h" | |||
25 | #include "clang/Analysis/FlowSensitive/MatchSwitch.h" | |||
26 | #include <functional> | |||
27 | #include <utility> | |||
28 | ||||
29 | namespace clang { | |||
30 | namespace dataflow { | |||
31 | ||||
32 | template <typename State, typename Result = void> | |||
33 | using CFGMatchSwitch = | |||
34 | std::function<Result(const CFGElement &, ASTContext &, State &)>; | |||
35 | ||||
36 | /// Collects cases of a "match switch": a collection of matchers paired with | |||
37 | /// callbacks, which together define a switch that can be applied to an AST node | |||
38 | /// contained in a CFG element. | |||
39 | template <typename State, typename Result = void> class CFGMatchSwitchBuilder { | |||
40 | public: | |||
41 | /// Registers an action `A` for `CFGStmt`s that will be triggered by the match | |||
42 | /// of the pattern `M` against the `Stmt` contained in the input `CFGStmt`. | |||
43 | /// | |||
44 | /// Requirements: | |||
45 | /// | |||
46 | /// `NodeT` should be derived from `Stmt`. | |||
47 | template <typename NodeT> | |||
48 | CFGMatchSwitchBuilder && | |||
49 | CaseOfCFGStmt(MatchSwitchMatcher<Stmt> M, | |||
50 | MatchSwitchAction<NodeT, State, Result> A) && { | |||
51 | std::move(StmtBuilder).template CaseOf<NodeT>(M, A); | |||
52 | return std::move(*this); | |||
53 | } | |||
54 | ||||
55 | /// Registers an action `A` for `CFGInitializer`s that will be triggered by | |||
56 | /// the match of the pattern `M` against the `CXXCtorInitializer` contained in | |||
57 | /// the input `CFGInitializer`. | |||
58 | /// | |||
59 | /// Requirements: | |||
60 | /// | |||
61 | /// `NodeT` should be derived from `CXXCtorInitializer`. | |||
62 | template <typename NodeT> | |||
63 | CFGMatchSwitchBuilder && | |||
64 | CaseOfCFGInit(MatchSwitchMatcher<CXXCtorInitializer> M, | |||
65 | MatchSwitchAction<NodeT, State, Result> A) && { | |||
66 | std::move(InitBuilder).template CaseOf<NodeT>(M, A); | |||
67 | return std::move(*this); | |||
68 | } | |||
69 | ||||
70 | CFGMatchSwitch<State, Result> Build() && { | |||
71 | return [StmtMS = std::move(StmtBuilder).Build(), | |||
| ||||
72 | InitMS = std::move(InitBuilder).Build()](const CFGElement &Element, | |||
73 | ASTContext &Context, | |||
74 | State &S) -> Result { | |||
75 | switch (Element.getKind()) { | |||
76 | case CFGElement::Initializer: | |||
77 | return InitMS(*Element.castAs<CFGInitializer>().getInitializer(), | |||
78 | Context, S); | |||
79 | case CFGElement::Statement: | |||
80 | case CFGElement::Constructor: | |||
81 | case CFGElement::CXXRecordTypedCall: | |||
82 | return StmtMS(*Element.castAs<CFGStmt>().getStmt(), Context, S); | |||
83 | default: | |||
84 | // FIXME: Handle other kinds of CFGElement. | |||
85 | return Result(); | |||
86 | } | |||
87 | }; | |||
88 | } | |||
89 | ||||
90 | private: | |||
91 | ASTMatchSwitchBuilder<Stmt, State, Result> StmtBuilder; | |||
92 | ASTMatchSwitchBuilder<CXXCtorInitializer, State, Result> InitBuilder; | |||
93 | }; | |||
94 | ||||
95 | } // namespace dataflow | |||
96 | } // namespace clang | |||
97 | ||||
98 | #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CFGMATCHSWITCH_H_ |
1 | //===---- MatchSwitch.h -----------------------------------------*- C++ -*-===// |
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 defines the `ASTMatchSwitch` abstraction for building a "switch" |
10 | // statement, where each case of the switch is defined by an AST matcher. The |
11 | // cases are considered in order, like pattern matching in functional |
12 | // languages. |
13 | // |
14 | // Currently, the design is catered towards simplifying the implementation of |
15 | // `DataflowAnalysis` transfer functions. Based on experience here, this |
16 | // library may be generalized and moved to ASTMatchers. |
17 | // |
18 | //===----------------------------------------------------------------------===// |
19 | // |
20 | // FIXME: Rename to ASTMatchSwitch.h |
21 | |
22 | #ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_MATCHSWITCH_H_ |
23 | #define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_MATCHSWITCH_H_ |
24 | |
25 | #include "clang/AST/ASTContext.h" |
26 | #include "clang/AST/Stmt.h" |
27 | #include "clang/ASTMatchers/ASTMatchFinder.h" |
28 | #include "clang/ASTMatchers/ASTMatchers.h" |
29 | #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" |
30 | #include "llvm/ADT/StringRef.h" |
31 | #include <functional> |
32 | #include <string> |
33 | #include <type_traits> |
34 | #include <utility> |
35 | #include <vector> |
36 | |
37 | namespace clang { |
38 | namespace dataflow { |
39 | |
40 | /// A common form of state shared between the cases of a transfer function. |
41 | template <typename LatticeT> struct TransferState { |
42 | TransferState(LatticeT &Lattice, Environment &Env) |
43 | : Lattice(Lattice), Env(Env) {} |
44 | |
45 | /// Current lattice element. |
46 | LatticeT &Lattice; |
47 | Environment &Env; |
48 | }; |
49 | |
50 | /// A read-only version of TransferState. |
51 | template <typename LatticeT> struct TransferStateForDiagnostics { |
52 | TransferStateForDiagnostics(const LatticeT &Lattice, const Environment &Env) |
53 | : Lattice(Lattice), Env(Env) {} |
54 | |
55 | /// Current lattice element. |
56 | const LatticeT &Lattice; |
57 | const Environment &Env; |
58 | }; |
59 | |
60 | template <typename T> |
61 | using MatchSwitchMatcher = ast_matchers::internal::Matcher<T>; |
62 | |
63 | template <typename T, typename State, typename Result = void> |
64 | using MatchSwitchAction = std::function<Result( |
65 | const T *, const ast_matchers::MatchFinder::MatchResult &, State &)>; |
66 | |
67 | template <typename BaseT, typename State, typename Result = void> |
68 | using ASTMatchSwitch = |
69 | std::function<Result(const BaseT &, ASTContext &, State &)>; |
70 | |
71 | /// Collects cases of a "match switch": a collection of matchers paired with |
72 | /// callbacks, which together define a switch that can be applied to a node |
73 | /// whose type derives from `BaseT`. This structure can simplify the definition |
74 | /// of `transfer` functions that rely on pattern-matching. |
75 | /// |
76 | /// For example, consider an analysis that handles particular function calls. It |
77 | /// can define the `ASTMatchSwitch` once, in the constructor of the analysis, |
78 | /// and then reuse it each time that `transfer` is called, with a fresh state |
79 | /// value. |
80 | /// |
81 | /// \code |
82 | /// ASTMatchSwitch<Stmt, TransferState<MyLattice> BuildSwitch() { |
83 | /// return ASTMatchSwitchBuilder<TransferState<MyLattice>>() |
84 | /// .CaseOf(callExpr(callee(functionDecl(hasName("foo")))), TransferFooCall) |
85 | /// .CaseOf(callExpr(argumentCountIs(2), |
86 | /// callee(functionDecl(hasName("bar")))), |
87 | /// TransferBarCall) |
88 | /// .Build(); |
89 | /// } |
90 | /// \endcode |
91 | template <typename BaseT, typename State, typename Result = void> |
92 | class ASTMatchSwitchBuilder { |
93 | public: |
94 | /// Registers an action that will be triggered by the match of a pattern |
95 | /// against the input statement. |
96 | /// |
97 | /// Requirements: |
98 | /// |
99 | /// `NodeT` should be derived from `BaseT`. |
100 | template <typename NodeT> |
101 | ASTMatchSwitchBuilder &&CaseOf(MatchSwitchMatcher<BaseT> M, |
102 | MatchSwitchAction<NodeT, State, Result> A) && { |
103 | static_assert(std::is_base_of<BaseT, NodeT>::value, |
104 | "NodeT must be derived from BaseT."); |
105 | Matchers.push_back(std::move(M)); |
106 | Actions.push_back( |
107 | [A = std::move(A)](const BaseT *Node, |
108 | const ast_matchers::MatchFinder::MatchResult &R, |
109 | State &S) { return A(cast<NodeT>(Node), R, S); }); |
110 | return std::move(*this); |
111 | } |
112 | |
113 | ASTMatchSwitch<BaseT, State, Result> Build() && { |
114 | return [Matcher = BuildMatcher(), Actions = std::move(Actions)]( |
115 | const BaseT &Node, ASTContext &Context, State &S) -> Result { |
116 | auto Results = ast_matchers::matchDynamic(Matcher, Node, Context); |
117 | if (Results.empty()) { |
118 | return Result(); |
119 | } |
120 | // Look through the map for the first binding of the form "TagN..." use |
121 | // that to select the action. |
122 | for (const auto &Element : Results[0].getMap()) { |
123 | llvm::StringRef ID(Element.first); |
124 | size_t Index = 0; |
125 | if (ID.consume_front("Tag") && !ID.getAsInteger(10, Index) && |
126 | Index < Actions.size()) { |
127 | return Actions[Index]( |
128 | &Node, |
129 | ast_matchers::MatchFinder::MatchResult(Results[0], &Context), S); |
130 | } |
131 | } |
132 | return Result(); |
133 | }; |
134 | } |
135 | |
136 | private: |
137 | ast_matchers::internal::DynTypedMatcher BuildMatcher() { |
138 | using ast_matchers::anything; |
139 | using ast_matchers::stmt; |
140 | using ast_matchers::unless; |
141 | using ast_matchers::internal::DynTypedMatcher; |
142 | if (Matchers.empty()) |
143 | return stmt(unless(anything())); |
144 | for (int I = 0, N = Matchers.size(); I < N; ++I) { |
145 | std::string Tag = ("Tag" + llvm::Twine(I)).str(); |
146 | // Many matchers are not bindable, so ensure that tryBind will work. |
147 | Matchers[I].setAllowBind(true); |
148 | auto M = *Matchers[I].tryBind(Tag); |
149 | // Each anyOf explicitly controls the traversal kind. The anyOf itself is |
150 | // set to `TK_AsIs` to ensure no nodes are skipped, thereby deferring to |
151 | // the kind of the branches. Then, each branch is either left as is, if |
152 | // the kind is already set, or explicitly set to `TK_AsIs`. We choose this |
153 | // setting because it is the default interpretation of matchers. |
154 | Matchers[I] = |
155 | !M.getTraversalKind() ? M.withTraversalKind(TK_AsIs) : std::move(M); |
156 | } |
157 | // The matcher type on the cases ensures that `Expr` kind is compatible with |
158 | // all of the matchers. |
159 | return DynTypedMatcher::constructVariadic( |
160 | DynTypedMatcher::VO_AnyOf, ASTNodeKind::getFromNodeKind<BaseT>(), |
161 | std::move(Matchers)); |
162 | } |
163 | |
164 | std::vector<ast_matchers::internal::DynTypedMatcher> Matchers; |
165 | std::vector<MatchSwitchAction<BaseT, State, Result>> Actions; |
166 | }; |
167 | |
168 | } // namespace dataflow |
169 | } // namespace clang |
170 | #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_MATCHSWITCH_H_ |
1 | // Implementation of std::function -*- C++ -*- |
2 | |
3 | // Copyright (C) 2004-2020 Free Software Foundation, Inc. |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free |
6 | // software; you can redistribute it and/or modify it under the |
7 | // terms of the GNU General Public License as published by the |
8 | // Free Software Foundation; either version 3, or (at your option) |
9 | // any later version. |
10 | |
11 | // This library is distributed in the hope that it will be useful, |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | // GNU General Public License for more details. |
15 | |
16 | // Under Section 7 of GPL version 3, you are granted additional |
17 | // permissions described in the GCC Runtime Library Exception, version |
18 | // 3.1, as published by the Free Software Foundation. |
19 | |
20 | // You should have received a copy of the GNU General Public License and |
21 | // a copy of the GCC Runtime Library Exception along with this program; |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
23 | // <http://www.gnu.org/licenses/>. |
24 | |
25 | /** @file include/bits/std_function.h |
26 | * This is an internal header file, included by other library headers. |
27 | * Do not attempt to use it directly. @headername{functional} |
28 | */ |
29 | |
30 | #ifndef _GLIBCXX_STD_FUNCTION_H1 |
31 | #define _GLIBCXX_STD_FUNCTION_H1 1 |
32 | |
33 | #pragma GCC system_header |
34 | |
35 | #if __cplusplus201703L < 201103L |
36 | # include <bits/c++0x_warning.h> |
37 | #else |
38 | |
39 | #if __cpp_rtti199711L |
40 | # include <typeinfo> |
41 | #endif |
42 | #include <bits/stl_function.h> |
43 | #include <bits/invoke.h> |
44 | #include <bits/refwrap.h> |
45 | #include <bits/functexcept.h> |
46 | |
47 | namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) |
48 | { |
49 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
50 | |
51 | /** |
52 | * @brief Exception class thrown when class template function's |
53 | * operator() is called with an empty target. |
54 | * @ingroup exceptions |
55 | */ |
56 | class bad_function_call : public std::exception |
57 | { |
58 | public: |
59 | virtual ~bad_function_call() noexcept; |
60 | |
61 | const char* what() const noexcept; |
62 | }; |
63 | |
64 | /** |
65 | * Trait identifying "location-invariant" types, meaning that the |
66 | * address of the object (or any of its members) will not escape. |
67 | * Trivially copyable types are location-invariant and users can |
68 | * specialize this trait for other types. |
69 | */ |
70 | template<typename _Tp> |
71 | struct __is_location_invariant |
72 | : is_trivially_copyable<_Tp>::type |
73 | { }; |
74 | |
75 | class _Undefined_class; |
76 | |
77 | union _Nocopy_types |
78 | { |
79 | void* _M_object; |
80 | const void* _M_const_object; |
81 | void (*_M_function_pointer)(); |
82 | void (_Undefined_class::*_M_member_pointer)(); |
83 | }; |
84 | |
85 | union [[gnu::may_alias]] _Any_data |
86 | { |
87 | void* _M_access() { return &_M_pod_data[0]; } |
88 | const void* _M_access() const { return &_M_pod_data[0]; } |
89 | |
90 | template<typename _Tp> |
91 | _Tp& |
92 | _M_access() |
93 | { return *static_cast<_Tp*>(_M_access()); } |
94 | |
95 | template<typename _Tp> |
96 | const _Tp& |
97 | _M_access() const |
98 | { return *static_cast<const _Tp*>(_M_access()); } |
99 | |
100 | _Nocopy_types _M_unused; |
101 | char _M_pod_data[sizeof(_Nocopy_types)]; |
102 | }; |
103 | |
104 | enum _Manager_operation |
105 | { |
106 | __get_type_info, |
107 | __get_functor_ptr, |
108 | __clone_functor, |
109 | __destroy_functor |
110 | }; |
111 | |
112 | template<typename _Signature> |
113 | class function; |
114 | |
115 | /// Base class of all polymorphic function object wrappers. |
116 | class _Function_base |
117 | { |
118 | public: |
119 | static const size_t _M_max_size = sizeof(_Nocopy_types); |
120 | static const size_t _M_max_align = __alignof__(_Nocopy_types); |
121 | |
122 | template<typename _Functor> |
123 | class _Base_manager |
124 | { |
125 | protected: |
126 | static const bool __stored_locally = |
127 | (__is_location_invariant<_Functor>::value |
128 | && sizeof(_Functor) <= _M_max_size |
129 | && __alignof__(_Functor) <= _M_max_align |
130 | && (_M_max_align % __alignof__(_Functor) == 0)); |
131 | |
132 | typedef integral_constant<bool, __stored_locally> _Local_storage; |
133 | |
134 | // Retrieve a pointer to the function object |
135 | static _Functor* |
136 | _M_get_pointer(const _Any_data& __source) |
137 | { |
138 | if _GLIBCXX17_CONSTEXPRconstexpr (__stored_locally) |
139 | { |
140 | const _Functor& __f = __source._M_access<_Functor>(); |
141 | return const_cast<_Functor*>(std::__addressof(__f)); |
142 | } |
143 | else // have stored a pointer |
144 | return __source._M_access<_Functor*>(); |
145 | } |
146 | |
147 | // Clone a location-invariant function object that fits within |
148 | // an _Any_data structure. |
149 | static void |
150 | _M_clone(_Any_data& __dest, const _Any_data& __source, true_type) |
151 | { |
152 | ::new (__dest._M_access()) _Functor(__source._M_access<_Functor>()); |
153 | } |
154 | |
155 | // Clone a function object that is not location-invariant or |
156 | // that cannot fit into an _Any_data structure. |
157 | static void |
158 | _M_clone(_Any_data& __dest, const _Any_data& __source, false_type) |
159 | { |
160 | __dest._M_access<_Functor*>() = |
161 | new _Functor(*__source._M_access<const _Functor*>()); |
162 | } |
163 | |
164 | // Destroying a location-invariant object may still require |
165 | // destruction. |
166 | static void |
167 | _M_destroy(_Any_data& __victim, true_type) |
168 | { |
169 | __victim._M_access<_Functor>().~_Functor(); |
170 | } |
171 | |
172 | // Destroying an object located on the heap. |
173 | static void |
174 | _M_destroy(_Any_data& __victim, false_type) |
175 | { |
176 | delete __victim._M_access<_Functor*>(); |
177 | } |
178 | |
179 | public: |
180 | static bool |
181 | _M_manager(_Any_data& __dest, const _Any_data& __source, |
182 | _Manager_operation __op) |
183 | { |
184 | switch (__op) |
185 | { |
186 | #if __cpp_rtti199711L |
187 | case __get_type_info: |
188 | __dest._M_access<const type_info*>() = &typeid(_Functor); |
189 | break; |
190 | #endif |
191 | case __get_functor_ptr: |
192 | __dest._M_access<_Functor*>() = _M_get_pointer(__source); |
193 | break; |
194 | |
195 | case __clone_functor: |
196 | _M_clone(__dest, __source, _Local_storage()); |
197 | break; |
198 | |
199 | case __destroy_functor: |
200 | _M_destroy(__dest, _Local_storage()); |
201 | break; |
202 | } |
203 | return false; |
204 | } |
205 | |
206 | static void |
207 | _M_init_functor(_Any_data& __functor, _Functor&& __f) |
208 | { _M_init_functor(__functor, std::move(__f), _Local_storage()); } |
209 | |
210 | template<typename _Signature> |
211 | static bool |
212 | _M_not_empty_function(const function<_Signature>& __f) |
213 | { return static_cast<bool>(__f); } |
214 | |
215 | template<typename _Tp> |
216 | static bool |
217 | _M_not_empty_function(_Tp* __fp) |
218 | { return __fp != nullptr; } |
219 | |
220 | template<typename _Class, typename _Tp> |
221 | static bool |
222 | _M_not_empty_function(_Tp _Class::* __mp) |
223 | { return __mp != nullptr; } |
224 | |
225 | template<typename _Tp> |
226 | static bool |
227 | _M_not_empty_function(const _Tp&) |
228 | { return true; } |
229 | |
230 | private: |
231 | static void |
232 | _M_init_functor(_Any_data& __functor, _Functor&& __f, true_type) |
233 | { ::new (__functor._M_access()) _Functor(std::move(__f)); } |
234 | |
235 | static void |
236 | _M_init_functor(_Any_data& __functor, _Functor&& __f, false_type) |
237 | { __functor._M_access<_Functor*>() = new _Functor(std::move(__f)); } |
238 | }; |
239 | |
240 | _Function_base() : _M_manager(nullptr) { } |
241 | |
242 | ~_Function_base() |
243 | { |
244 | if (_M_manager) |
245 | _M_manager(_M_functor, _M_functor, __destroy_functor); |
246 | } |
247 | |
248 | bool _M_empty() const { return !_M_manager; } |
249 | |
250 | typedef bool (*_Manager_type)(_Any_data&, const _Any_data&, |
251 | _Manager_operation); |
252 | |
253 | _Any_data _M_functor; |
254 | _Manager_type _M_manager; |
255 | }; |
256 | |
257 | template<typename _Signature, typename _Functor> |
258 | class _Function_handler; |
259 | |
260 | template<typename _Res, typename _Functor, typename... _ArgTypes> |
261 | class _Function_handler<_Res(_ArgTypes...), _Functor> |
262 | : public _Function_base::_Base_manager<_Functor> |
263 | { |
264 | typedef _Function_base::_Base_manager<_Functor> _Base; |
265 | |
266 | public: |
267 | static bool |
268 | _M_manager(_Any_data& __dest, const _Any_data& __source, |
269 | _Manager_operation __op) |
270 | { |
271 | switch (__op) |
272 | { |
273 | #if __cpp_rtti199711L |
274 | case __get_type_info: |
275 | __dest._M_access<const type_info*>() = &typeid(_Functor); |
276 | break; |
277 | #endif |
278 | case __get_functor_ptr: |
279 | __dest._M_access<_Functor*>() = _Base::_M_get_pointer(__source); |
280 | break; |
281 | |
282 | default: |
283 | _Base::_M_manager(__dest, __source, __op); |
284 | } |
285 | return false; |
286 | } |
287 | |
288 | static _Res |
289 | _M_invoke(const _Any_data& __functor, _ArgTypes&&... __args) |
290 | { |
291 | return std::__invoke_r<_Res>(*_Base::_M_get_pointer(__functor), |
292 | std::forward<_ArgTypes>(__args)...); |
293 | } |
294 | }; |
295 | |
296 | /** |
297 | * @brief Primary class template for std::function. |
298 | * @ingroup functors |
299 | * |
300 | * Polymorphic function wrapper. |
301 | */ |
302 | template<typename _Res, typename... _ArgTypes> |
303 | class function<_Res(_ArgTypes...)> |
304 | : public _Maybe_unary_or_binary_function<_Res, _ArgTypes...>, |
305 | private _Function_base |
306 | { |
307 | template<typename _Func, |
308 | typename _Res2 = __invoke_result<_Func&, _ArgTypes...>> |
309 | struct _Callable |
310 | : __is_invocable_impl<_Res2, _Res>::type |
311 | { }; |
312 | |
313 | // Used so the return type convertibility checks aren't done when |
314 | // performing overload resolution for copy construction/assignment. |
315 | template<typename _Tp> |
316 | struct _Callable<function, _Tp> : false_type { }; |
317 | |
318 | template<typename _Cond, typename _Tp> |
319 | using _Requires = typename enable_if<_Cond::value, _Tp>::type; |
320 | |
321 | public: |
322 | typedef _Res result_type; |
323 | |
324 | // [3.7.2.1] construct/copy/destroy |
325 | |
326 | /** |
327 | * @brief Default construct creates an empty function call wrapper. |
328 | * @post @c !(bool)*this |
329 | */ |
330 | function() noexcept |
331 | : _Function_base() { } |
332 | |
333 | /** |
334 | * @brief Creates an empty function call wrapper. |
335 | * @post @c !(bool)*this |
336 | */ |
337 | function(nullptr_t) noexcept |
338 | : _Function_base() { } |
339 | |
340 | /** |
341 | * @brief %Function copy constructor. |
342 | * @param __x A %function object with identical call signature. |
343 | * @post @c bool(*this) == bool(__x) |
344 | * |
345 | * The newly-created %function contains a copy of the target of @a |
346 | * __x (if it has one). |
347 | */ |
348 | function(const function& __x); |
349 | |
350 | /** |
351 | * @brief %Function move constructor. |
352 | * @param __x A %function object rvalue with identical call signature. |
353 | * |
354 | * The newly-created %function contains the target of @a __x |
355 | * (if it has one). |
356 | */ |
357 | function(function&& __x) noexcept : _Function_base() |
358 | { |
359 | __x.swap(*this); |
360 | } |
361 | |
362 | /** |
363 | * @brief Builds a %function that targets a copy of the incoming |
364 | * function object. |
365 | * @param __f A %function object that is callable with parameters of |
366 | * type @c T1, @c T2, ..., @c TN and returns a value convertible |
367 | * to @c Res. |
368 | * |
369 | * The newly-created %function object will target a copy of |
370 | * @a __f. If @a __f is @c reference_wrapper<F>, then this function |
371 | * object will contain a reference to the function object @c |
372 | * __f.get(). If @a __f is a NULL function pointer or NULL |
373 | * pointer-to-member, the newly-created object will be empty. |
374 | * |
375 | * If @a __f is a non-NULL function pointer or an object of type @c |
376 | * reference_wrapper<F>, this function will not throw. |
377 | */ |
378 | template<typename _Functor, |
379 | typename = _Requires<__not_<is_same<_Functor, function>>, void>, |
380 | typename = _Requires<_Callable<_Functor>, void>> |
381 | function(_Functor); |
382 | |
383 | /** |
384 | * @brief %Function assignment operator. |
385 | * @param __x A %function with identical call signature. |
386 | * @post @c (bool)*this == (bool)x |
387 | * @returns @c *this |
388 | * |
389 | * The target of @a __x is copied to @c *this. If @a __x has no |
390 | * target, then @c *this will be empty. |
391 | * |
392 | * If @a __x targets a function pointer or a reference to a function |
393 | * object, then this operation will not throw an %exception. |
394 | */ |
395 | function& |
396 | operator=(const function& __x) |
397 | { |
398 | function(__x).swap(*this); |
399 | return *this; |
400 | } |
401 | |
402 | /** |
403 | * @brief %Function move-assignment operator. |
404 | * @param __x A %function rvalue with identical call signature. |
405 | * @returns @c *this |
406 | * |
407 | * The target of @a __x is moved to @c *this. If @a __x has no |
408 | * target, then @c *this will be empty. |
409 | * |
410 | * If @a __x targets a function pointer or a reference to a function |
411 | * object, then this operation will not throw an %exception. |
412 | */ |
413 | function& |
414 | operator=(function&& __x) noexcept |
415 | { |
416 | function(std::move(__x)).swap(*this); |
417 | return *this; |
418 | } |
419 | |
420 | /** |
421 | * @brief %Function assignment to zero. |
422 | * @post @c !(bool)*this |
423 | * @returns @c *this |
424 | * |
425 | * The target of @c *this is deallocated, leaving it empty. |
426 | */ |
427 | function& |
428 | operator=(nullptr_t) noexcept |
429 | { |
430 | if (_M_manager) |
431 | { |
432 | _M_manager(_M_functor, _M_functor, __destroy_functor); |
433 | _M_manager = nullptr; |
434 | _M_invoker = nullptr; |
435 | } |
436 | return *this; |
437 | } |
438 | |
439 | /** |
440 | * @brief %Function assignment to a new target. |
441 | * @param __f A %function object that is callable with parameters of |
442 | * type @c T1, @c T2, ..., @c TN and returns a value convertible |
443 | * to @c Res. |
444 | * @return @c *this |
445 | * |
446 | * This %function object wrapper will target a copy of @a |
447 | * __f. If @a __f is @c reference_wrapper<F>, then this function |
448 | * object will contain a reference to the function object @c |
449 | * __f.get(). If @a __f is a NULL function pointer or NULL |
450 | * pointer-to-member, @c this object will be empty. |
451 | * |
452 | * If @a __f is a non-NULL function pointer or an object of type @c |
453 | * reference_wrapper<F>, this function will not throw. |
454 | */ |
455 | template<typename _Functor> |
456 | _Requires<_Callable<typename decay<_Functor>::type>, function&> |
457 | operator=(_Functor&& __f) |
458 | { |
459 | function(std::forward<_Functor>(__f)).swap(*this); |
460 | return *this; |
461 | } |
462 | |
463 | /// @overload |
464 | template<typename _Functor> |
465 | function& |
466 | operator=(reference_wrapper<_Functor> __f) noexcept |
467 | { |
468 | function(__f).swap(*this); |
469 | return *this; |
470 | } |
471 | |
472 | // [3.7.2.2] function modifiers |
473 | |
474 | /** |
475 | * @brief Swap the targets of two %function objects. |
476 | * @param __x A %function with identical call signature. |
477 | * |
478 | * Swap the targets of @c this function object and @a __f. This |
479 | * function will not throw an %exception. |
480 | */ |
481 | void swap(function& __x) noexcept |
482 | { |
483 | std::swap(_M_functor, __x._M_functor); |
484 | std::swap(_M_manager, __x._M_manager); |
485 | std::swap(_M_invoker, __x._M_invoker); |
486 | } |
487 | |
488 | // [3.7.2.3] function capacity |
489 | |
490 | /** |
491 | * @brief Determine if the %function wrapper has a target. |
492 | * |
493 | * @return @c true when this %function object contains a target, |
494 | * or @c false when it is empty. |
495 | * |
496 | * This function will not throw an %exception. |
497 | */ |
498 | explicit operator bool() const noexcept |
499 | { return !_M_empty(); } |
500 | |
501 | // [3.7.2.4] function invocation |
502 | |
503 | /** |
504 | * @brief Invokes the function targeted by @c *this. |
505 | * @returns the result of the target. |
506 | * @throws bad_function_call when @c !(bool)*this |
507 | * |
508 | * The function call operator invokes the target function object |
509 | * stored by @c this. |
510 | */ |
511 | _Res operator()(_ArgTypes... __args) const; |
512 | |
513 | #if __cpp_rtti199711L |
514 | // [3.7.2.5] function target access |
515 | /** |
516 | * @brief Determine the type of the target of this function object |
517 | * wrapper. |
518 | * |
519 | * @returns the type identifier of the target function object, or |
520 | * @c typeid(void) if @c !(bool)*this. |
521 | * |
522 | * This function will not throw an %exception. |
523 | */ |
524 | const type_info& target_type() const noexcept; |
525 | |
526 | /** |
527 | * @brief Access the stored target function object. |
528 | * |
529 | * @return Returns a pointer to the stored target function object, |
530 | * if @c typeid(_Functor).equals(target_type()); otherwise, a NULL |
531 | * pointer. |
532 | * |
533 | * This function does not throw exceptions. |
534 | * |
535 | * @{ |
536 | */ |
537 | template<typename _Functor> _Functor* target() noexcept; |
538 | |
539 | template<typename _Functor> const _Functor* target() const noexcept; |
540 | // @} |
541 | #endif |
542 | |
543 | private: |
544 | using _Invoker_type = _Res (*)(const _Any_data&, _ArgTypes&&...); |
545 | _Invoker_type _M_invoker; |
546 | }; |
547 | |
548 | #if __cpp_deduction_guides201703L >= 201606 |
549 | template<typename> |
550 | struct __function_guide_helper |
551 | { }; |
552 | |
553 | template<typename _Res, typename _Tp, bool _Nx, typename... _Args> |
554 | struct __function_guide_helper< |
555 | _Res (_Tp::*) (_Args...) noexcept(_Nx) |
556 | > |
557 | { using type = _Res(_Args...); }; |
558 | |
559 | template<typename _Res, typename _Tp, bool _Nx, typename... _Args> |
560 | struct __function_guide_helper< |
561 | _Res (_Tp::*) (_Args...) & noexcept(_Nx) |
562 | > |
563 | { using type = _Res(_Args...); }; |
564 | |
565 | template<typename _Res, typename _Tp, bool _Nx, typename... _Args> |
566 | struct __function_guide_helper< |
567 | _Res (_Tp::*) (_Args...) const noexcept(_Nx) |
568 | > |
569 | { using type = _Res(_Args...); }; |
570 | |
571 | template<typename _Res, typename _Tp, bool _Nx, typename... _Args> |
572 | struct __function_guide_helper< |
573 | _Res (_Tp::*) (_Args...) const & noexcept(_Nx) |
574 | > |
575 | { using type = _Res(_Args...); }; |
576 | |
577 | template<typename _Res, typename... _ArgTypes> |
578 | function(_Res(*)(_ArgTypes...)) -> function<_Res(_ArgTypes...)>; |
579 | |
580 | template<typename _Functor, typename _Signature = typename |
581 | __function_guide_helper<decltype(&_Functor::operator())>::type> |
582 | function(_Functor) -> function<_Signature>; |
583 | #endif |
584 | |
585 | // Out-of-line member definitions. |
586 | template<typename _Res, typename... _ArgTypes> |
587 | function<_Res(_ArgTypes...)>:: |
588 | function(const function& __x) |
589 | : _Function_base() |
590 | { |
591 | if (static_cast<bool>(__x)) |
592 | { |
593 | __x._M_manager(_M_functor, __x._M_functor, __clone_functor); |
594 | _M_invoker = __x._M_invoker; |
595 | _M_manager = __x._M_manager; |
596 | } |
597 | } |
598 | |
599 | template<typename _Res, typename... _ArgTypes> |
600 | template<typename _Functor, typename, typename> |
601 | function<_Res(_ArgTypes...)>:: |
602 | function(_Functor __f) |
603 | : _Function_base() |
604 | { |
605 | typedef _Function_handler<_Res(_ArgTypes...), _Functor> _My_handler; |
606 | |
607 | if (_My_handler::_M_not_empty_function(__f)) |
608 | { |
609 | _My_handler::_M_init_functor(_M_functor, std::move(__f)); |
610 | _M_invoker = &_My_handler::_M_invoke; |
611 | _M_manager = &_My_handler::_M_manager; |
612 | } |
613 | } |
614 | |
615 | template<typename _Res, typename... _ArgTypes> |
616 | _Res |
617 | function<_Res(_ArgTypes...)>:: |
618 | operator()(_ArgTypes... __args) const |
619 | { |
620 | if (_M_empty()) |
621 | __throw_bad_function_call(); |
622 | return _M_invoker(_M_functor, std::forward<_ArgTypes>(__args)...); |
623 | } |
624 | |
625 | #if __cpp_rtti199711L |
626 | template<typename _Res, typename... _ArgTypes> |
627 | const type_info& |
628 | function<_Res(_ArgTypes...)>:: |
629 | target_type() const noexcept |
630 | { |
631 | if (_M_manager) |
632 | { |
633 | _Any_data __typeinfo_result; |
634 | _M_manager(__typeinfo_result, _M_functor, __get_type_info); |
635 | return *__typeinfo_result._M_access<const type_info*>(); |
636 | } |
637 | else |
638 | return typeid(void); |
639 | } |
640 | |
641 | template<typename _Res, typename... _ArgTypes> |
642 | template<typename _Functor> |
643 | _Functor* |
644 | function<_Res(_ArgTypes...)>:: |
645 | target() noexcept |
646 | { |
647 | const function* __const_this = this; |
648 | const _Functor* __func = __const_this->template target<_Functor>(); |
649 | return const_cast<_Functor*>(__func); |
650 | } |
651 | |
652 | template<typename _Res, typename... _ArgTypes> |
653 | template<typename _Functor> |
654 | const _Functor* |
655 | function<_Res(_ArgTypes...)>:: |
656 | target() const noexcept |
657 | { |
658 | if (typeid(_Functor) == target_type() && _M_manager) |
659 | { |
660 | _Any_data __ptr; |
661 | _M_manager(__ptr, _M_functor, __get_functor_ptr); |
662 | return __ptr._M_access<const _Functor*>(); |
663 | } |
664 | else |
665 | return nullptr; |
666 | } |
667 | #endif |
668 | |
669 | // [20.7.15.2.6] null pointer comparisons |
670 | |
671 | /** |
672 | * @brief Compares a polymorphic function object wrapper against 0 |
673 | * (the NULL pointer). |
674 | * @returns @c true if the wrapper has no target, @c false otherwise |
675 | * |
676 | * This function will not throw an %exception. |
677 | */ |
678 | template<typename _Res, typename... _Args> |
679 | inline bool |
680 | operator==(const function<_Res(_Args...)>& __f, nullptr_t) noexcept |
681 | { return !static_cast<bool>(__f); } |
682 | |
683 | #if __cpp_impl_three_way_comparison < 201907L |
684 | /// @overload |
685 | template<typename _Res, typename... _Args> |
686 | inline bool |
687 | operator==(nullptr_t, const function<_Res(_Args...)>& __f) noexcept |
688 | { return !static_cast<bool>(__f); } |
689 | |
690 | /** |
691 | * @brief Compares a polymorphic function object wrapper against 0 |
692 | * (the NULL pointer). |
693 | * @returns @c false if the wrapper has no target, @c true otherwise |
694 | * |
695 | * This function will not throw an %exception. |
696 | */ |
697 | template<typename _Res, typename... _Args> |
698 | inline bool |
699 | operator!=(const function<_Res(_Args...)>& __f, nullptr_t) noexcept |
700 | { return static_cast<bool>(__f); } |
701 | |
702 | /// @overload |
703 | template<typename _Res, typename... _Args> |
704 | inline bool |
705 | operator!=(nullptr_t, const function<_Res(_Args...)>& __f) noexcept |
706 | { return static_cast<bool>(__f); } |
707 | #endif |
708 | |
709 | // [20.7.15.2.7] specialized algorithms |
710 | |
711 | /** |
712 | * @brief Swap the targets of two polymorphic function object wrappers. |
713 | * |
714 | * This function will not throw an %exception. |
715 | */ |
716 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
717 | // 2062. Effect contradictions w/o no-throw guarantee of std::function swaps |
718 | template<typename _Res, typename... _Args> |
719 | inline void |
720 | swap(function<_Res(_Args...)>& __x, function<_Res(_Args...)>& __y) noexcept |
721 | { __x.swap(__y); } |
722 | |
723 | #if __cplusplus201703L >= 201703L |
724 | namespace __detail::__variant |
725 | { |
726 | template<typename> struct _Never_valueless_alt; // see <variant> |
727 | |
728 | // Provide the strong exception-safety guarantee when emplacing a |
729 | // function into a variant. |
730 | template<typename _Signature> |
731 | struct _Never_valueless_alt<std::function<_Signature>> |
732 | : std::true_type |
733 | { }; |
734 | } // namespace __detail::__variant |
735 | #endif // C++17 |
736 | |
737 | _GLIBCXX_END_NAMESPACE_VERSION |
738 | } // namespace std |
739 | |
740 | #endif // C++11 |
741 | #endif // _GLIBCXX_STD_FUNCTION_H |