Bug Summary

File:build/source/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp
Warning:line 421, column 9
1st function call argument is an uninitialized value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name SignalHandlerCheck.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-17/lib/clang/17 -D CLANG_REPOSITORY_STRING="++20230510111145+7df43bdb42ae-1~exp1~20230510111303.1288" -D _DEBUG -D _GLIBCXX_ASSERTIONS -D _GNU_SOURCE -D _LIBCPP_ENABLE_ASSERTIONS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/clang/tools/extra/clang-tidy/bugprone -I /build/source/clang-tools-extra/clang-tidy/bugprone -I tools/clang/tools/extra/clang-tidy -I /build/source/clang/include -I tools/clang/include -I include -I /build/source/llvm/include -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-17/lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/source/= -fcoverage-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/source/= -source-date-epoch 1683717183 -O2 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-misleading-indentation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2023-05-10-133810-16478-1 -x c++ /build/source/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp

/build/source/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp

1//===--- SignalHandlerCheck.cpp - clang-tidy ------------------------------===//
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#include "SignalHandlerCheck.h"
10#include "clang/ASTMatchers/ASTMatchFinder.h"
11#include "llvm/ADT/DepthFirstIterator.h"
12#include "llvm/ADT/STLExtras.h"
13
14// This is the minimal set of safe functions.
15// https://wiki.sei.cmu.edu/confluence/display/c/SIG30-C.+Call+only+asynchronous-safe+functions+within+signal+handlers
16constexpr llvm::StringLiteral MinimalConformingFunctions[] = {
17 "signal", "abort", "_Exit", "quick_exit"};
18
19// The POSIX-defined set of safe functions.
20// https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03
21// 'quick_exit' is added to the set additionally because it looks like the
22// mentioned POSIX specification was not updated after 'quick_exit' appeared
23// in the C11 standard.
24// Also, we want to keep the "minimal set" a subset of the "POSIX set".
25// The list is repeated in bugprone-signal-handler.rst and should be kept up to date.
26constexpr llvm::StringLiteral POSIXConformingFunctions[] = {
27 "_Exit",
28 "_exit",
29 "abort",
30 "accept",
31 "access",
32 "aio_error",
33 "aio_return",
34 "aio_suspend",
35 "alarm",
36 "bind",
37 "cfgetispeed",
38 "cfgetospeed",
39 "cfsetispeed",
40 "cfsetospeed",
41 "chdir",
42 "chmod",
43 "chown",
44 "clock_gettime",
45 "close",
46 "connect",
47 "creat",
48 "dup",
49 "dup2",
50 "execl",
51 "execle",
52 "execv",
53 "execve",
54 "faccessat",
55 "fchdir",
56 "fchmod",
57 "fchmodat",
58 "fchown",
59 "fchownat",
60 "fcntl",
61 "fdatasync",
62 "fexecve",
63 "ffs",
64 "fork",
65 "fstat",
66 "fstatat",
67 "fsync",
68 "ftruncate",
69 "futimens",
70 "getegid",
71 "geteuid",
72 "getgid",
73 "getgroups",
74 "getpeername",
75 "getpgrp",
76 "getpid",
77 "getppid",
78 "getsockname",
79 "getsockopt",
80 "getuid",
81 "htonl",
82 "htons",
83 "kill",
84 "link",
85 "linkat",
86 "listen",
87 "longjmp",
88 "lseek",
89 "lstat",
90 "memccpy",
91 "memchr",
92 "memcmp",
93 "memcpy",
94 "memmove",
95 "memset",
96 "mkdir",
97 "mkdirat",
98 "mkfifo",
99 "mkfifoat",
100 "mknod",
101 "mknodat",
102 "ntohl",
103 "ntohs",
104 "open",
105 "openat",
106 "pause",
107 "pipe",
108 "poll",
109 "posix_trace_event",
110 "pselect",
111 "pthread_kill",
112 "pthread_self",
113 "pthread_sigmask",
114 "quick_exit",
115 "raise",
116 "read",
117 "readlink",
118 "readlinkat",
119 "recv",
120 "recvfrom",
121 "recvmsg",
122 "rename",
123 "renameat",
124 "rmdir",
125 "select",
126 "sem_post",
127 "send",
128 "sendmsg",
129 "sendto",
130 "setgid",
131 "setpgid",
132 "setsid",
133 "setsockopt",
134 "setuid",
135 "shutdown",
136 "sigaction",
137 "sigaddset",
138 "sigdelset",
139 "sigemptyset",
140 "sigfillset",
141 "sigismember",
142 "siglongjmp",
143 "signal",
144 "sigpause",
145 "sigpending",
146 "sigprocmask",
147 "sigqueue",
148 "sigset",
149 "sigsuspend",
150 "sleep",
151 "sockatmark",
152 "socket",
153 "socketpair",
154 "stat",
155 "stpcpy",
156 "stpncpy",
157 "strcat",
158 "strchr",
159 "strcmp",
160 "strcpy",
161 "strcspn",
162 "strlen",
163 "strncat",
164 "strncmp",
165 "strncpy",
166 "strnlen",
167 "strpbrk",
168 "strrchr",
169 "strspn",
170 "strstr",
171 "strtok_r",
172 "symlink",
173 "symlinkat",
174 "tcdrain",
175 "tcflow",
176 "tcflush",
177 "tcgetattr",
178 "tcgetpgrp",
179 "tcsendbreak",
180 "tcsetattr",
181 "tcsetpgrp",
182 "time",
183 "timer_getoverrun",
184 "timer_gettime",
185 "timer_settime",
186 "times",
187 "umask",
188 "uname",
189 "unlink",
190 "unlinkat",
191 "utime",
192 "utimensat",
193 "utimes",
194 "wait",
195 "waitpid",
196 "wcpcpy",
197 "wcpncpy",
198 "wcscat",
199 "wcschr",
200 "wcscmp",
201 "wcscpy",
202 "wcscspn",
203 "wcslen",
204 "wcsncat",
205 "wcsncmp",
206 "wcsncpy",
207 "wcsnlen",
208 "wcspbrk",
209 "wcsrchr",
210 "wcsspn",
211 "wcsstr",
212 "wcstok",
213 "wmemchr",
214 "wmemcmp",
215 "wmemcpy",
216 "wmemmove",
217 "wmemset",
218 "write"};
219
220using namespace clang::ast_matchers;
221
222namespace clang::tidy {
223
224template <>
225struct OptionEnumMapping<
226 bugprone::SignalHandlerCheck::AsyncSafeFunctionSetKind> {
227 static llvm::ArrayRef<std::pair<
228 bugprone::SignalHandlerCheck::AsyncSafeFunctionSetKind, StringRef>>
229 getEnumMapping() {
230 static constexpr std::pair<
231 bugprone::SignalHandlerCheck::AsyncSafeFunctionSetKind, StringRef>
232 Mapping[] = {
233 {bugprone::SignalHandlerCheck::AsyncSafeFunctionSetKind::Minimal,
234 "minimal"},
235 {bugprone::SignalHandlerCheck::AsyncSafeFunctionSetKind::POSIX,
236 "POSIX"},
237 };
238 return ArrayRef(Mapping);
239 }
240};
241
242namespace bugprone {
243
244namespace {
245
246/// Returns if a function is declared inside a system header.
247/// These functions are considered to be "standard" (system-provided) library
248/// functions.
249bool isStandardFunction(const FunctionDecl *FD) {
250 // Find a possible redeclaration in system header.
251 // FIXME: Looking at the canonical declaration is not the most exact way
252 // to do this.
253
254 // Most common case will be inclusion directly from a header.
255 // This works fine by using canonical declaration.
256 // a.c
257 // #include <sysheader.h>
258
259 // Next most common case will be extern declaration.
260 // Can't catch this with either approach.
261 // b.c
262 // extern void sysfunc(void);
263
264 // Canonical declaration is the first found declaration, so this works.
265 // c.c
266 // #include <sysheader.h>
267 // extern void sysfunc(void); // redecl won't matter
268
269 // This does not work with canonical declaration.
270 // Probably this is not a frequently used case but may happen (the first
271 // declaration can be in a non-system header for example).
272 // d.c
273 // extern void sysfunc(void); // Canonical declaration, not in system header.
274 // #include <sysheader.h>
275
276 return FD->getASTContext().getSourceManager().isInSystemHeader(
277 FD->getCanonicalDecl()->getLocation());
278}
279
280/// Check if a statement is "C++-only".
281/// This includes all statements that have a class name with "CXX" prefix
282/// and every other statement that is declared in file ExprCXX.h.
283bool isCXXOnlyStmt(const Stmt *S) {
284 StringRef Name = S->getStmtClassName();
285 if (Name.startswith("CXX"))
286 return true;
287 // Check for all other class names in ExprCXX.h that have no 'CXX' prefix.
288 return isa<ArrayTypeTraitExpr, BuiltinBitCastExpr, CUDAKernelCallExpr,
289 CoawaitExpr, CoreturnStmt, CoroutineBodyStmt, CoroutineSuspendExpr,
290 CoyieldExpr, DependentCoawaitExpr, DependentScopeDeclRefExpr,
291 ExprWithCleanups, ExpressionTraitExpr, FunctionParmPackExpr,
292 LambdaExpr, MSDependentExistsStmt, MSPropertyRefExpr,
293 MSPropertySubscriptExpr, MaterializeTemporaryExpr, OverloadExpr,
294 PackExpansionExpr, SizeOfPackExpr, SubstNonTypeTemplateParmExpr,
295 SubstNonTypeTemplateParmPackExpr, TypeTraitExpr,
296 UserDefinedLiteral>(S);
297}
298
299/// Given a call graph node of a \p Caller function and a \p Callee that is
300/// called from \p Caller, get a \c CallExpr of the corresponding function call.
301/// It is unspecified which call is found if multiple calls exist, but the order
302/// should be deterministic (depend only on the AST).
303Expr *findCallExpr(const CallGraphNode *Caller, const CallGraphNode *Callee) {
304 auto FoundCallee = llvm::find_if(
305 Caller->callees(), [Callee](const CallGraphNode::CallRecord &Call) {
306 return Call.Callee == Callee;
307 });
308 assert(FoundCallee != Caller->end() &&(static_cast <bool> (FoundCallee != Caller->end() &&
"Callee should be called from the caller function here.") ? void
(0) : __assert_fail ("FoundCallee != Caller->end() && \"Callee should be called from the caller function here.\""
, "clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp"
, 309, __extension__ __PRETTY_FUNCTION__))
309 "Callee should be called from the caller function here.")(static_cast <bool> (FoundCallee != Caller->end() &&
"Callee should be called from the caller function here.") ? void
(0) : __assert_fail ("FoundCallee != Caller->end() && \"Callee should be called from the caller function here.\""
, "clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp"
, 309, __extension__ __PRETTY_FUNCTION__))
;
310 return FoundCallee->CallExpr;
311}
312
313SourceRange getSourceRangeOfStmt(const Stmt *S, ASTContext &Ctx) {
314 ParentMapContext &PM = Ctx.getParentMapContext();
315 DynTypedNode P = DynTypedNode::create(*S);
316 while (P.getSourceRange().isInvalid()) {
317 DynTypedNodeList PL = PM.getParents(P);
318 if (PL.size() != 1)
319 return {};
320 P = PL[0];
321 }
322 return P.getSourceRange();
323}
324
325} // namespace
326
327AST_MATCHER(FunctionDecl, isStandardFunction)namespace internal { class matcher_isStandardFunctionMatcher :
public ::clang::ast_matchers::internal::MatcherInterface<
FunctionDecl> { public: explicit matcher_isStandardFunctionMatcher
() = default; bool matches(const FunctionDecl &Node, ::clang
::ast_matchers::internal::ASTMatchFinder *Finder, ::clang::ast_matchers
::internal::BoundNodesTreeBuilder *Builder) const override; }
; } inline ::clang::ast_matchers::internal::Matcher<FunctionDecl
> isStandardFunction() { return ::clang::ast_matchers::internal
::makeMatcher( new internal::matcher_isStandardFunctionMatcher
()); } inline bool internal::matcher_isStandardFunctionMatcher
::matches( const FunctionDecl &Node, ::clang::ast_matchers
::internal::ASTMatchFinder *Finder, ::clang::ast_matchers::internal
::BoundNodesTreeBuilder *Builder) const
{
328 return isStandardFunction(&Node);
329}
330
331SignalHandlerCheck::SignalHandlerCheck(StringRef Name,
332 ClangTidyContext *Context)
333 : ClangTidyCheck(Name, Context),
334 AsyncSafeFunctionSet(Options.get("AsyncSafeFunctionSet",
335 AsyncSafeFunctionSetKind::POSIX)) {
336 if (AsyncSafeFunctionSet == AsyncSafeFunctionSetKind::Minimal) {
337 for (StringRef v : MinimalConformingFunctions)
338 ConformingFunctions.insert(v);
339 } else {
340 for (StringRef v : POSIXConformingFunctions)
341 ConformingFunctions.insert(v);
342 }
343}
344
345void SignalHandlerCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
346 Options.store(Opts, "AsyncSafeFunctionSet", AsyncSafeFunctionSet);
347}
348
349bool SignalHandlerCheck::isLanguageVersionSupported(
350 const LangOptions &LangOpts) const {
351 return !LangOpts.CPlusPlus17;
352}
353
354void SignalHandlerCheck::registerMatchers(MatchFinder *Finder) {
355 auto SignalFunction = functionDecl(hasAnyName("::signal", "::std::signal"),
356 parameterCountIs(2), isStandardFunction());
357 auto HandlerExpr =
358 declRefExpr(hasDeclaration(functionDecl().bind("handler_decl")),
359 unless(isExpandedFromMacro("SIG_IGN")),
360 unless(isExpandedFromMacro("SIG_DFL")))
361 .bind("handler_expr");
362 auto HandlerLambda = cxxMemberCallExpr(
363 on(expr(ignoringParenImpCasts(lambdaExpr().bind("handler_lambda")))));
364 Finder->addMatcher(callExpr(callee(SignalFunction),
365 hasArgument(1, anyOf(HandlerExpr, HandlerLambda)))
366 .bind("register_call"),
367 this);
368}
369
370void SignalHandlerCheck::check(const MatchFinder::MatchResult &Result) {
371 if (const auto *HandlerLambda
0.1
'HandlerLambda' is null
0.1
'HandlerLambda' is null
0.1
'HandlerLambda' is null
=
1
Taking false branch
372 Result.Nodes.getNodeAs<LambdaExpr>("handler_lambda")) {
373 diag(HandlerLambda->getBeginLoc(),
374 "lambda function is not allowed as signal handler (until C++17)")
375 << HandlerLambda->getSourceRange();
376 return;
377 }
378
379 const auto *HandlerDecl =
380 Result.Nodes.getNodeAs<FunctionDecl>("handler_decl");
381 const auto *HandlerExpr = Result.Nodes.getNodeAs<DeclRefExpr>("handler_expr");
382 assert(Result.Nodes.getNodeAs<CallExpr>("register_call") && HandlerDecl &&(static_cast <bool> (Result.Nodes.getNodeAs<CallExpr
>("register_call") && HandlerDecl && HandlerExpr
&& "All of these should exist in a match here.") ? void
(0) : __assert_fail ("Result.Nodes.getNodeAs<CallExpr>(\"register_call\") && HandlerDecl && HandlerExpr && \"All of these should exist in a match here.\""
, "clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp"
, 383, __extension__ __PRETTY_FUNCTION__))
2
'?' condition is true
383 HandlerExpr && "All of these should exist in a match here.")(static_cast <bool> (Result.Nodes.getNodeAs<CallExpr
>("register_call") && HandlerDecl && HandlerExpr
&& "All of these should exist in a match here.") ? void
(0) : __assert_fail ("Result.Nodes.getNodeAs<CallExpr>(\"register_call\") && HandlerDecl && HandlerExpr && \"All of these should exist in a match here.\""
, "clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp"
, 383, __extension__ __PRETTY_FUNCTION__))
;
384
385 if (CG.size() <= 1) {
3
Assuming the condition is false
4
Taking false branch
386 // Call graph must be populated with the entire TU at the beginning.
387 // (It is possible to add a single function but the functions called from it
388 // are not analysed in this case.)
389 CG.addToCallGraph(const_cast<TranslationUnitDecl *>(
390 HandlerDecl->getTranslationUnitDecl()));
391 assert(CG.size() > 1 &&(static_cast <bool> (CG.size() > 1 && "There should be at least one function added to call graph."
) ? void (0) : __assert_fail ("CG.size() > 1 && \"There should be at least one function added to call graph.\""
, "clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp"
, 392, __extension__ __PRETTY_FUNCTION__))
392 "There should be at least one function added to call graph.")(static_cast <bool> (CG.size() > 1 && "There should be at least one function added to call graph."
) ? void (0) : __assert_fail ("CG.size() > 1 && \"There should be at least one function added to call graph.\""
, "clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp"
, 392, __extension__ __PRETTY_FUNCTION__))
;
393 }
394
395 if (!HandlerDecl->hasBody()) {
5
Assuming the condition is false
6
Taking false branch
396 // Check the handler function.
397 // The warning is placed to the signal handler registration.
398 // No need to display a call chain and no need for more checks.
399 (void)checkFunction(HandlerDecl, HandlerExpr, {});
400 return;
401 }
402
403 // FIXME: Update CallGraph::getNode to use canonical decl?
404 CallGraphNode *HandlerNode = CG.getNode(HandlerDecl->getCanonicalDecl());
405 assert(HandlerNode &&(static_cast <bool> (HandlerNode && "Handler with body should be present in the call graph."
) ? void (0) : __assert_fail ("HandlerNode && \"Handler with body should be present in the call graph.\""
, "clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp"
, 406, __extension__ __PRETTY_FUNCTION__))
7
Assuming 'HandlerNode' is non-null
8
'?' condition is true
406 "Handler with body should be present in the call graph.")(static_cast <bool> (HandlerNode && "Handler with body should be present in the call graph."
) ? void (0) : __assert_fail ("HandlerNode && \"Handler with body should be present in the call graph.\""
, "clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp"
, 406, __extension__ __PRETTY_FUNCTION__))
;
407 // Start from signal handler and visit every function call.
408 auto Itr = llvm::df_begin(HandlerNode), ItrE = llvm::df_end(HandlerNode);
409 while (Itr != ItrE) {
9
Loop condition is true. Entering loop body
410 const auto *CallF = dyn_cast<FunctionDecl>((*Itr)->getDecl());
10
Assuming the object is a 'CastReturnType'
411 unsigned int PathL = Itr.getPathLength();
412 if (CallF
10.1
'CallF' is non-null
10.1
'CallF' is non-null
10.1
'CallF' is non-null
) {
413 // A signal handler or a function transitively reachable from the signal
414 // handler was found to be unsafe.
415 // Generate notes for the whole call chain (including the signal handler
416 // registration).
417 const Expr *CallOrRef = (PathL > 1)
11
Assuming 'PathL' is <= 1
12
'?' condition is false
418 ? findCallExpr(Itr.getPath(PathL - 2), *Itr)
419 : HandlerExpr;
420 auto ChainReporter = [this, &Itr, HandlerExpr](bool SkipPathEnd) {
421 reportHandlerChain(Itr, HandlerExpr, SkipPathEnd);
31
1st function call argument is an uninitialized value
422 };
423 // If problems were found in a function (`CallF`), skip the analysis of
424 // functions that are called from it.
425 if (checkFunction(CallF, CallOrRef, ChainReporter))
13
Calling 'SignalHandlerCheck::checkFunction'
426 Itr.skipChildren();
427 else
428 ++Itr;
429 } else {
430 ++Itr;
431 }
432 }
433}
434
435bool SignalHandlerCheck::checkFunction(
436 const FunctionDecl *FD, const Expr *CallOrRef,
437 std::function<void(bool)> ChainReporter) {
438 bool FunctionIsCalled = isa<CallExpr>(CallOrRef);
14
Assuming 'CallOrRef' is not a 'CallExpr'
439
440 if (isStandardFunction(FD)) {
15
Taking false branch
441 if (!isStandardFunctionAsyncSafe(FD)) {
442 diag(CallOrRef->getBeginLoc(), "standard function %0 may not be "
443 "asynchronous-safe; "
444 "%select{using it as|calling it from}1 "
445 "a signal handler may be dangerous")
446 << FD << FunctionIsCalled << CallOrRef->getSourceRange();
447 if (ChainReporter)
448 ChainReporter(/*SkipPathEnd=*/true);
449 return true;
450 }
451 return false;
452 }
453
454 if (!FD->hasBody()) {
16
Assuming the condition is false
17
Taking false branch
455 diag(CallOrRef->getBeginLoc(), "cannot verify that external function %0 is "
456 "asynchronous-safe; "
457 "%select{using it as|calling it from}1 "
458 "a signal handler may be dangerous")
459 << FD << FunctionIsCalled << CallOrRef->getSourceRange();
460 if (ChainReporter)
461 ChainReporter(/*SkipPathEnd=*/true);
462 return true;
463 }
464
465 if (getLangOpts().CPlusPlus)
18
Assuming field 'CPlusPlus' is not equal to 0
19
Taking true branch
466 return checkFunctionCPP14(FD, CallOrRef, ChainReporter);
20
Calling 'SignalHandlerCheck::checkFunctionCPP14'
467
468 return false;
469}
470
471bool SignalHandlerCheck::checkFunctionCPP14(
472 const FunctionDecl *FD, const Expr *CallOrRef,
473 std::function<void(bool)> ChainReporter) {
474 if (!FD->isExternC()) {
21
Assuming the condition is true
22
Taking true branch
475 diag(CallOrRef->getBeginLoc(),
476 "functions without C linkage are not allowed as signal "
477 "handler (until C++17)");
478 if (ChainReporter)
23
Taking true branch
479 ChainReporter(/*SkipPathEnd=*/true);
24
Calling 'function::operator()'
480 return true;
481 }
482
483 const FunctionDecl *FBody;
484 const Stmt *BodyS = FD->getBody(FBody);
485 if (!BodyS)
486 return false;
487
488 bool StmtProblemsFound = false;
489 ASTContext &Ctx = FBody->getASTContext();
490 auto Matches =
491 match(decl(forEachDescendant(stmt().bind("stmt"))), *FBody, Ctx);
492 for (const auto &Match : Matches) {
493 const auto *FoundS = Match.getNodeAs<Stmt>("stmt");
494 if (isCXXOnlyStmt(FoundS)) {
495 SourceRange R = getSourceRangeOfStmt(FoundS, Ctx);
496 if (R.isInvalid())
497 continue;
498 diag(R.getBegin(),
499 "C++-only construct is not allowed in signal handler (until C++17)")
500 << R;
501 diag(R.getBegin(), "internally, the statement is parsed as a '%0'",
502 DiagnosticIDs::Remark)
503 << FoundS->getStmtClassName();
504 if (ChainReporter)
505 ChainReporter(/*SkipPathEnd=*/false);
506 StmtProblemsFound = true;
507 }
508 }
509
510 return StmtProblemsFound;
511}
512
513bool SignalHandlerCheck::isStandardFunctionAsyncSafe(
514 const FunctionDecl *FD) const {
515 assert(isStandardFunction(FD))(static_cast <bool> (isStandardFunction(FD)) ? void (0)
: __assert_fail ("isStandardFunction(FD)", "clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp"
, 515, __extension__ __PRETTY_FUNCTION__))
;
516
517 const IdentifierInfo *II = FD->getIdentifier();
518 // Unnamed functions are not explicitly allowed.
519 // C++ std operators may be unsafe and not within the
520 // "common subset of C and C++".
521 if (!II)
522 return false;
523
524 if (!FD->isInStdNamespace() && !FD->isGlobal())
525 return false;
526
527 if (ConformingFunctions.count(II->getName()))
528 return true;
529
530 return false;
531}
532
533void SignalHandlerCheck::reportHandlerChain(
534 const llvm::df_iterator<clang::CallGraphNode *> &Itr,
535 const DeclRefExpr *HandlerRef, bool SkipPathEnd) {
536 int CallLevel = Itr.getPathLength() - 2;
537 assert(CallLevel >= -1 && "Empty iterator?")(static_cast <bool> (CallLevel >= -1 && "Empty iterator?"
) ? void (0) : __assert_fail ("CallLevel >= -1 && \"Empty iterator?\""
, "clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp"
, 537, __extension__ __PRETTY_FUNCTION__))
;
538
539 const CallGraphNode *Caller = Itr.getPath(CallLevel + 1), *Callee = nullptr;
540 while (CallLevel >= 0) {
541 Callee = Caller;
542 Caller = Itr.getPath(CallLevel);
543 const Expr *CE = findCallExpr(Caller, Callee);
544 if (SkipPathEnd)
545 SkipPathEnd = false;
546 else
547 diag(CE->getBeginLoc(), "function %0 called here from %1",
548 DiagnosticIDs::Note)
549 << cast<FunctionDecl>(Callee->getDecl())
550 << cast<FunctionDecl>(Caller->getDecl());
551 --CallLevel;
552 }
553
554 if (!SkipPathEnd)
555 diag(HandlerRef->getBeginLoc(),
556 "function %0 registered here as signal handler", DiagnosticIDs::Note)
557 << cast<FunctionDecl>(Caller->getDecl())
558 << HandlerRef->getSourceRange();
559}
560
561} // namespace bugprone
562} // namespace clang::tidy

/usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.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
47namespace 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),
27
Calling '__invoke_r<void, (lambda at /build/source/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp:420:28) &, bool>'
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())
25
Taking false branch
621 __throw_bad_function_call();
622 return _M_invoker(_M_functor, std::forward<_ArgTypes>(__args)...);
26
Calling '_Function_handler::_M_invoke'
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

/usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h

1// Implementation of INVOKE -*- C++ -*-
2
3// Copyright (C) 2016-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/invoke.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_INVOKE_H1
31#define _GLIBCXX_INVOKE_H1 1
32
33#pragma GCC system_header
34
35#if __cplusplus201703L < 201103L
36# include <bits/c++0x_warning.h>
37#else
38
39#include <type_traits>
40
41namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default")))
42{
43_GLIBCXX_BEGIN_NAMESPACE_VERSION
44
45 /**
46 * @addtogroup utilities
47 * @{
48 */
49
50 // Used by __invoke_impl instead of std::forward<_Tp> so that a
51 // reference_wrapper is converted to an lvalue-reference.
52 template<typename _Tp, typename _Up = typename __inv_unwrap<_Tp>::type>
53 constexpr _Up&&
54 __invfwd(typename remove_reference<_Tp>::type& __t) noexcept
55 { return static_cast<_Up&&>(__t); }
56
57 template<typename _Res, typename _Fn, typename... _Args>
58 constexpr _Res
59 __invoke_impl(__invoke_other, _Fn&& __f, _Args&&... __args)
60 { return std::forward<_Fn>(__f)(std::forward<_Args>(__args)...); }
30
Calling 'operator()'
61
62 template<typename _Res, typename _MemFun, typename _Tp, typename... _Args>
63 constexpr _Res
64 __invoke_impl(__invoke_memfun_ref, _MemFun&& __f, _Tp&& __t,
65 _Args&&... __args)
66 { return (__invfwd<_Tp>(__t).*__f)(std::forward<_Args>(__args)...); }
67
68 template<typename _Res, typename _MemFun, typename _Tp, typename... _Args>
69 constexpr _Res
70 __invoke_impl(__invoke_memfun_deref, _MemFun&& __f, _Tp&& __t,
71 _Args&&... __args)
72 {
73 return ((*std::forward<_Tp>(__t)).*__f)(std::forward<_Args>(__args)...);
74 }
75
76 template<typename _Res, typename _MemPtr, typename _Tp>
77 constexpr _Res
78 __invoke_impl(__invoke_memobj_ref, _MemPtr&& __f, _Tp&& __t)
79 { return __invfwd<_Tp>(__t).*__f; }
80
81 template<typename _Res, typename _MemPtr, typename _Tp>
82 constexpr _Res
83 __invoke_impl(__invoke_memobj_deref, _MemPtr&& __f, _Tp&& __t)
84 { return (*std::forward<_Tp>(__t)).*__f; }
85
86 /// Invoke a callable object.
87 template<typename _Callable, typename... _Args>
88 constexpr typename __invoke_result<_Callable, _Args...>::type
89 __invoke(_Callable&& __fn, _Args&&... __args)
90 noexcept(__is_nothrow_invocable<_Callable, _Args...>::value)
91 {
92 using __result = __invoke_result<_Callable, _Args...>;
93 using __type = typename __result::type;
94 using __tag = typename __result::__invoke_type;
95 return std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn),
96 std::forward<_Args>(__args)...);
97 }
98
99#if __cplusplus201703L >= 201703L
100 // INVOKE<R>: Invoke a callable object and convert the result to R.
101 template<typename _Res, typename _Callable, typename... _Args>
102 constexpr enable_if_t<is_invocable_r_v<_Res, _Callable, _Args...>, _Res>
103 __invoke_r(_Callable&& __fn, _Args&&... __args)
104 noexcept(is_nothrow_invocable_r_v<_Res, _Callable, _Args...>)
105 {
106 using __result = __invoke_result<_Callable, _Args...>;
107 using __type = typename __result::type;
108 using __tag = typename __result::__invoke_type;
109 if constexpr (is_void_v<_Res>
27.1
'is_void_v' is true
27.1
'is_void_v' is true
27.1
'is_void_v' is true
)
28
Taking true branch
110 std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn),
29
Calling '__invoke_impl<void, (lambda at /build/source/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp:420:28) &, bool>'
111 std::forward<_Args>(__args)...);
112 else
113 return std::__invoke_impl<__type>(__tag{},
114 std::forward<_Callable>(__fn),
115 std::forward<_Args>(__args)...);
116 }
117#else // C++11
118 template<typename _Res, typename _Callable, typename... _Args>
119 using __can_invoke_as_void = __enable_if_t<
120 __and_<is_void<_Res>, __is_invocable<_Callable, _Args...>>::value,
121 _Res
122 >;
123
124 template<typename _Res, typename _Callable, typename... _Args>
125 using __can_invoke_as_nonvoid = __enable_if_t<
126 __and_<__not_<is_void<_Res>>,
127 is_convertible<typename __invoke_result<_Callable, _Args...>::type,
128 _Res>
129 >::value,
130 _Res
131 >;
132
133 // INVOKE<R>: Invoke a callable object and convert the result to R.
134 template<typename _Res, typename _Callable, typename... _Args>
135 constexpr __can_invoke_as_nonvoid<_Res, _Callable, _Args...>
136 __invoke_r(_Callable&& __fn, _Args&&... __args)
137 {
138 using __result = __invoke_result<_Callable, _Args...>;
139 using __type = typename __result::type;
140 using __tag = typename __result::__invoke_type;
141 return std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn),
142 std::forward<_Args>(__args)...);
143 }
144
145 // INVOKE<R> when R is cv void
146 template<typename _Res, typename _Callable, typename... _Args>
147 _GLIBCXX14_CONSTEXPRconstexpr __can_invoke_as_void<_Res, _Callable, _Args...>
148 __invoke_r(_Callable&& __fn, _Args&&... __args)
149 {
150 using __result = __invoke_result<_Callable, _Args...>;
151 using __type = typename __result::type;
152 using __tag = typename __result::__invoke_type;
153 std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn),
154 std::forward<_Args>(__args)...);
155 }
156#endif // C++11
157
158_GLIBCXX_END_NAMESPACE_VERSION
159} // namespace std
160
161#endif // C++11
162
163#endif // _GLIBCXX_INVOKE_H