pmeerw's blog
May 2020
CSS library that turns your HTML document
into a website that looks like a LaTeX document.
Write semantic HTML, add <link rel="stylesheet" href="https://latex.now.sh/style.css"> to the <head> and...
posted at: 00:18 | path: /fun | permanent link
A seemingly simple problem: check C/C++ code statically for unused return values, but surprisingly here is no easily available tooling. Let's look at some options:
[[nodiscard]], e.g. the following code (unused-return.cpp)
int foo() {
return 42;
}
[[nodiscard]]
int bar() {
return 23;
}
int main() {
foo();
bar();
}
when compiled with g++-8 unused-return.cpp, will result in
unused-return.cpp: In function ‘int main()’:
unused-return.cpp:12:6: warning: ignoring return value of ‘int bar()’, declared with attribute nodiscard [-Wunused-result]
bar();
~~~^~
unused-return.cpp:6:5: note: declared here
int bar() {
^~~
(tested with GCC 8.4 / Ubuntu)
No warning will printed (foo()), unless [[nodiscard]] is annotated (bar()).
unused-return.c:
__attribute__ ((warn_unused_result))
int bar() {
return 23;
}
resulting in a warning
unused-return.c: In function ‘main’: unused-return.c:12:3: warning: ignoring return value of ‘bar’, declared with attribute warn_unused_result [-Wunused-result] bar(); ^~~~~when compiled with
gcc unused-return.c (GCC 8.4/Ubuntu).
It doesn't help to enable warnings to get a similar warning for function foo().
splint unused-return.c, but the output is quite verbose and doesn't cover C++:
Splint 3.1.2 --- 20 Feb 2018 unused-return.c: (in function main) unused-return.c:11:3: Return value (type int) ignored: foo() Result returned by function call is not used. If this is intended, can cast result to (void) to eliminate message. (Use -retvalint to inhibit warning) unused-return.c:12:3: Return value (type int) ignored: bar() Finished checking --- 2 code warnings
clang-query tool can be used to moreless interactively query the AST of the program. This is expored in more detail below...
Stackoverflow provides all the basics: a clang-query script which matches call expressions
in the abstract syntax tree (AST) of the program, then restricting to 'intersting cases'.
For a nice intro to clang-query, see this devblog article.
I've added the -w switch to suppress clang warnings
when processing the input program, and some bind trickery
to make the output a bit nicer.
#!/bin/sh
# unused-return.sh: Run clang-query to report unused return values.
# When --dump, print the AST of matching syntax.
if [ "x$1" = "x--dump" ]; then
dump="set output dump"
shift
fi
query='m
callExpr(
isExpansionInMainFile(),
hasParent(anyOf(
compoundStmt(),
ifStmt(hasCondition(expr().bind("cond"))),
whileStmt(hasCondition(expr().bind("cond"))),
doStmt(hasCondition(expr().bind("cond")))
)),
unless(hasType(voidType())),
unless(isTypeDependent()),
unless(cxxOperatorCallExpr()),
unless(callee(namedDecl(anyOf(
hasName("memset"),
hasName("setlength"),
hasName("flags"),
hasName("width"),
hasName("__builtin_memcpy")
)))),
unless(equalsBoundNode("cond"))).bind("unused-return")'
clang-query-9 -extra-arg="-w" -c="set bind-root false" -c="$dump" -c="$query" "$@" --
The output should look like
Match #1: unused-return.c:11:3: note: "unused-return" binds here foo(); ^~~~~ Match #2: unused-return.c:12:3: note: "unused-return" binds here bar(); ^~~~~ 2 matches.A recent clang version is needed, tested with clang 9 / Ubuntu; clang 6 did not work.
All files for download: unused-return.zip.
Update (2020-05-05): MSVC has _Check_return_ and _Must_inspect_result_, for good measure.
Update (2020-05-06): clang-tidy has bugprone-unused-return-value to check for missing return values of certain configured functions, such as std::async(), std::unique_ptr::release(), std::remove()
Update (2020-05-06): see reddit
posted at: 01:30 | path: /programming | permanent link