@finally is still not implemented.
With this, clang can emit -Wreturn-type warnings for functions containing
@try/@catch (but not yet @finally), and -Wunreachable-code also works for those
functions.
The implementation is similar to D36914.
Part of PR46693.
Differential Revision: https://reviews.llvm.org/D112287
`[[clang::fallthrough]]` has meaning for the CFG, but all other
StmtAttrs we currently have don't. So omit them, as AttributedStatements
with children cause several issues and there's no benefit in including
them.
Fixes PR52103 and PR49454. See PR52103 for details.
Differential Revision: https://reviews.llvm.org/D111568
Modify the IfStmt node to suppoort constant evaluated expressions.
Add a new ExpressionEvaluationContext::ImmediateFunctionContext to
keep track of immediate function contexts.
This proved easier/better/probably more efficient than walking the AST
backward as it allows diagnosing nested if consteval statements.
Previous changes like D101202 and D104261 have eliminated the special
status that break and continue once had, since now we're making
decisions purely based on the structure of the CFG without regard for
the underlying source code constructs.
This means we don't gain anything from defering handling for these
blocks. Dropping it moves some diagnostics, though arguably into a
better place. We're working around a "quirk" in the CFG that perhaps
wasn't visible before: while loops have an empty "transition block"
where continue statements and the regular loop exit meet, before
continuing to the loop entry. To get a source location for that, we
slightly extend our handling for empty blocks. The source location for
the transition ends up to be the loop entry then, but formally this
isn't a back edge. We pretend it is anyway. (This is safe: we can always
treat edges as back edges, it just means we allow less and don't modify
the lock set. The other way around it wouldn't be safe.)
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D106715
Previously in D104261 we warned about dropping locks from back edges,
this is the corresponding change for exclusive/shared joins. If we're
entering the loop with an exclusive change, which is then relaxed to a
shared lock before we loop back, we have already analyzed the loop body
with the stronger exclusive lock and thus might have false positives.
There is a minor non-observable change: we modify the exit lock set of a
function, but since that isn't used further it doesn't change anything.
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D106713
The `-analyzer-display-progress` displayed the function name of the
currently analyzed function. It differs in C and C++. In C++, it
prints the argument types as well in a comma-separated list.
While in C, only the function name is displayed, without the brackets.
E.g.:
C++: foo(), foo(int, float)
C: foo
In crash traces, the analyzer dumps the location contexts, but the
string is not enough for `-analyze-function` in C++ mode.
This patch addresses the issue by dumping the proper function names
even in stack traces.
Reviewed By: NoQ
Differential Revision: https://reviews.llvm.org/D105708
C++23 will make these conversions ambiguous - so fix them to make the
codebase forward-compatible with C++23 (& a follow-up change I've made
will make this ambiguous/invalid even in <C++23 so we don't regress
this & it generally improves the code anyway)
In D104261 we made the parameters' meaning slightly more specific, this
changes their names accordingly. In all uses we're building a new lock
set by intersecting existing locksets. The first (modifiable) argument
is the new lock set being built, the second (non-modifiable) argument is
the exit set of a preceding block.
Reviewed By: aaron.ballman, delesley
Differential Revision: https://reviews.llvm.org/D104649
We allow branches to join where one holds a managed lock but the other
doesn't, but we can't do so for back edges: because there we can't drop
them from the lockset, as we have already analyzed the loop with the
larger lockset. So we can't allow dropping managed locks on back edges.
We move the managed() check from handleRemovalFromIntersection up to
intersectAndWarn, where we additionally check if we're on a back edge if
we're removing from the first lock set (the entry set of the next block)
but not if we're removing from the second lock set (the exit set of the
previous block). Now that the order of arguments matters, I had to swap
them in one invocation, which also causes some minor differences in the
tests.
Reviewed By: delesley
Differential Revision: https://reviews.llvm.org/D104261
This is mostly a mechanical change, but a testcase that contains
parts of the StringRef class (clang/test/Analysis/llvm-conventions.cpp)
isn't touched.
<string> is currently the highest impact header in a clang+llvm build:
https://commondatastorage.googleapis.com/chromium-browser-clang/llvm-include-analysis.html
One of the most common places this is being included is the APInt.h header, which needs it for an old toString() implementation that returns std::string - an inefficient method compared to the SmallString versions that it actually wraps.
This patch replaces these APInt/APSInt methods with a pair of llvm::toString() helpers inside StringExtras.h, adjusts users accordingly and removes the <string> from APInt.h - I was hoping that more of these users could be converted to use the SmallString methods, but it appears that most end up creating a std::string anyhow. I avoided trying to use the raw_ostream << operators as well as I didn't want to lose having the integer radix explicit in the code.
Differential Revision: https://reviews.llvm.org/D103888
This renames the expression value categories from rvalue to prvalue,
keeping nomenclature consistent with C++11 onwards.
C++ has the most complicated taxonomy here, and every other language
only uses a subset of it, so it's less confusing to use the C++ names
consistently, and mentally remap to the C names when working on that
context (prvalue -> rvalue, no xvalues, etc).
Renames:
* VK_RValue -> VK_PRValue
* Expr::isRValue -> Expr::isPRValue
* SK_QualificationConversionRValue -> SK_QualificationConversionPRValue
* JSON AST Dumper Expression nodes value category: "rvalue" -> "prvalue"
Signed-off-by: Matheus Izvekov <mizvekov@gmail.com>
Reviewed By: rsmith
Differential Revision: https://reviews.llvm.org/D103720
It is a reference-counted class but it uses different methods for that
and the checker doesn't understand them yet.
Differential Revision: https://reviews.llvm.org/D103081
Similar to how we allow managed and asserted locks to be held and not
held in joining branches, we also allow them to be held shared and
exclusive. The scoped lock should restore the original state at the end
of the scope in any event, and asserted locks need not be released.
We should probably only allow asserted locks to be subsumed by managed,
not by (directly) acquired locks, but that's for another change.
Reviewed By: delesley
Differential Revision: https://reviews.llvm.org/D102026
It's going to become a bit more complicated, so let's have it separate.
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D102025
Previously, information about `ConstructionContextLayer` was not
propagated thru causing the expression like:
Var c = (createVar());
To produce unrelated temporary for the `createVar()` result and conjure
a new symbol for the value of `c` in C++17 mode.
Reviewed By: steakhal
Patch By: tomasz-kaminski-sonarsource!
Differential Revision: https://reviews.llvm.org/D102835
Non-comprehensive list of cases:
* Dumping template arguments;
* Corresponding parameter contains a deduced type;
* Template arguments are for a DeclRefExpr that hadMultipleCandidates()
Type information is added in the form of prefixes (u8, u, U, L),
suffixes (U, L, UL, LL, ULL) or explicit casts to printed integral template
argument, if MSVC codeview mode is disabled.
Differential revision: https://reviews.llvm.org/D77598
We were modifying precisely when intersecting the lock sets of multiple
predecessors without back edge. That's no coincidence: we can't modify
on back edges, it doesn't make sense to modify at the end of a function,
and otherwise we always want to intersect on forward edges, because we
can build a new lock set for those.
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D101755
We weren't modifying the lock set when intersecting with one coming
from a break-terminated block. This is inconsistent, since break isn't a
back edge, and it leads to false negatives with scoped locks. We usually
don't warn for those when joining locksets aren't the same, we just
silently remove locks that are not in the intersection. But not warning
and not removing them isn't right.
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D101202
The motivation here is to make it available in the base class whether a
fact is managed or not. That would have meant three flags on the base
class, so I had a look whether we really have 8 possible combinations.
It turns out we don't: asserted and declared are obviously mutually
exclusive. Managed facts are only created when we acquire a capability
through a scoped capability. Adopting an asserted or declared lock will
not (in fact can not, because Facts are immutable) make them managed.
We probably don't want to allow adopting an asserted lock (because then
the function should probably have a release attribute, and then the
assertion is pointless), but we might at some point decide to replace a
declared fact on adoption.
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D100801
Instead of conditionally overwriting a nullptr and then branching on its
nullness, just branch directly on the original condition. Then we can
make both pointers (non-null) references instead.
When property is declared in a superclass (or in a protocol),
it still can be of CXXRecord type and Sema could've already
generated a body for us. This patch joins two branches and
two ways of acquiring IVar in order to reuse the existing code.
And prevent us from generating l-value to r-value casts for
C++ types.
rdar://67416721
Differential Revision: https://reviews.llvm.org/D99194
We already did so for scoped locks acquired in the constructor, this
change extends the treatment to deferred locks and scoped unlocking, so
locks acquired outside of the constructor. Obviously this makes things
more consistent.
Originally I thought this was a bad idea, because obviously it
introduces false negatives when it comes to double locking, but these
are typically easily found in tests, and the primary goal of the Thread
safety analysis is not to find double locks but race conditions.
Since the scoped lock will release the mutex anyway when the scope ends,
the inconsistent state is just temporary and probably fine.
Reviewed By: delesley
Differential Revision: https://reviews.llvm.org/D98747
Currently we want to allow calling non-const methods even when only a
shared lock is held, because -Wthread-safety-reference is already quite
sensitive and not all code is const-correct. Even if it is, this might
require users to add std::as_const around the implicit object argument.
See D52395 for a discussion.
Fixes PR46963.
Cleanup attribute allows users to attach a destructor-like functions
to variable declarations to be called whenever they leave the scope.
The logic of such functions is not supported by the Clang's CFG and
is too hard to be reasoned about. In order to avoid false positives
in this situation, we assume that we didn't see ALL of the executtion
paths of the function and, thus, can warn only about multiple call
violation.
rdar://74441906
Differential Revision: https://reviews.llvm.org/D98694
This patch introduces a very simple inter-procedural analysis
between blocks and enclosing functions.
We always analyze blocks first (analysis is done as part of semantic
analysis that goes side-by-side with the parsing process), and at the
moment of reporting we don't know how that block will be actually
used.
This patch introduces new logic delaying reports of the "never called"
warnings on blocks. If we are not sure that the block will be called
exactly once, we shouldn't warn our users about that. Double calls,
however, don't require such delays. While analyzing the enclosing
function, we can actually decide what we should do with those
warnings.
Additionally, as a side effect, we can be more confident about blocks
in such context and can treat them not as escapes, but as direct
calls.
rdar://74090107
Differential Revision: https://reviews.llvm.org/D98688
This commit makes escapes symmetrical, meaning that having escape
before and after the branching, where parameter is not called on
one of the paths, will have the same effect.
Differential Revision: https://reviews.llvm.org/D98622
There is no syntax like {@code ...} in Doxygen, @code is a block command
that ends with @endcode, and generally these are not enclosed in braces.
The correct syntax for inline code snippets is @c <code>.
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D98665
Introduce `MacroExpansionContext` to track what and how macros in a translation
unit expand. This is the first element of the patch-stack in this direction.
The main goal is to substitute the current macro expansion generator in the
`PlistsDiagnostics`, but all the other `DiagnosticsConsumer` could benefit from
this.
`getExpandedText` and `getOriginalText` are the primary functions of this class.
The former can provide you the text that was the result of the macro expansion
chain starting from a `SourceLocation`.
While the latter will tell you **what text** was in the original source code
replaced by the macro expansion chain from that location.
Here is an example:
void bar();
#define retArg(x) x
#define retArgUnclosed retArg(bar()
#define BB CC
#define applyInt BB(int)
#define CC(x) retArgUnclosed
void unbalancedMacros() {
applyInt );
//^~~~~~~~~~^ is the substituted range
// Original text is "applyInt )"
// Expanded text is "bar()"
}
#define expandArgUnclosedCommaExpr(x) (x, bar(), 1
#define f expandArgUnclosedCommaExpr
void unbalancedMacros2() {
int x = f(f(1)) )); // Look at the parenthesis!
// ^~~~~~^ is the substituted range
// Original text is "f(f(1))"
// Expanded text is "((1,bar(),1,bar(),1"
}
Might worth investigating how to provide a reusable component, which could be
used for example by a standalone tool eg. expanding all macros to their
definitions.
I borrowed the main idea from the `PrintPreprocessedOutput.cpp` Frontend
component, providing a `PPCallbacks` instance hooking the preprocessor events.
I'm using that for calculating the source range where tokens will be expanded
to. I'm also using the `Preprocessor`'s `OnToken` callback, via the
`Preprocessor::setTokenWatcher` to reconstruct the expanded text.
Unfortunately, I concatenate the token's string representation without any
whitespaces except if the token is an identifier when I emit an extra space
to produce valid code for `int var` token sequences.
This could be improved later if needed.
Patch-stack:
1) D93222 (this one) Introduces the MacroExpansionContext class and unittests
2) D93223 Create MacroExpansionContext member in AnalysisConsumer and pass
down to the diagnostics consumers
3) D93224 Use the MacroExpansionContext for macro expansions in plists
It replaces the 'old' macro expansion mechanism.
4) D94673 API for CTU macro expansions
You should be able to get a `MacroExpansionContext` for each imported TU.
Right now it will just return `llvm::None` as this is not implemented yet.
5) FIXME: Implement macro expansion tracking for imported TUs as well.
It would also relieve us from bugs like:
- [fixed] D86135
- [confirmed] The `__VA_ARGS__` and other macro nitty-gritty, such as how to
stringify macro parameters, where to put or swallow commas, etc. are not
handled correctly.
- [confirmed] Unbalanced parenthesis are not well handled - resulting in
incorrect expansions or even crashes.
- [confirmed][crashing] https://bugs.llvm.org/show_bug.cgi?id=48358
Reviewed By: martong, Szelethus
Differential Revision: https://reviews.llvm.org/D93222
Suppose you stumble across a DeclRefExpr in the AST, that references a VarDecl.
How would you know that that variable is written in the containing statement, or
not? One trick would be to ascend the AST through Stmt::getParent, and see
whether the variable appears on the left hand side of the assignment.
Liveness does something similar, but instead of ascending the AST, it descends
into it with a StmtVisitor, and after finding an assignment, it notes that the
LHS appears in the context of an assignemnt. However, as [1] demonstrates, the
analysis isn't ran on the AST of an entire function, but rather on CFG, where
the order of the statements, visited in order, would make it impossible to know
this information by descending.
void f() {
int i;
i = 5;
}
`-FunctionDecl 0x55a6e1b070b8 <test.cpp:1:1, line:5:1> line:1:6 f 'void ()'
`-CompoundStmt 0x55a6e1b07298 <col:10, line:5:1>
|-DeclStmt 0x55a6e1b07220 <line:2:3, col:8>
| `-VarDecl 0x55a6e1b071b8 <col:3, col:7> col:7 used i 'int'
`-BinaryOperator 0x55a6e1b07278 <line:4:3, col:7> 'int' lvalue '='
|-DeclRefExpr 0x55a6e1b07238 <col:3> 'int' lvalue Var 0x55a6e1b071b8 'i' 'int'
`-IntegerLiteral 0x55a6e1b07258 <col:7> 'int' 5
void f()
[B2 (ENTRY)]
Succs (1): B1
[B1]
1: int i;
2: 5
3: i
4: [B1.3] = [B1.2]
Preds (1): B2
Succs (1): B0
[B0 (EXIT)]
Preds (1): B1
You can see that the arguments (rightfully so, they need to be evaluated first)
precede the assignment operator. For this reason, Liveness implemented a pass to
scan the CFG and note which variables appear in an assignment.
BUT.
This problem only exists if we traverse a CFGBlock in order. And Liveness in
fact does it reverse order. So a distinct pass is indeed unnecessary, we can
note the appearance of the assignment by the time we reach the variable.
[1] http://lists.llvm.org/pipermail/cfe-dev/2020-July/066330.html
Differential Revision: https://reviews.llvm.org/D87518
This reverts commit 3500cc8d89.
This old commit was made over a completely false premise. OSSymbols
aren't different from other OSObjects and we shouldn't treat them
differently for the purposes of static analysis.
It is very common to check callbacks and completion handlers for null.
This patch supports such checks using built-in functions:
* __builtin_expect
* __builtin_expect_with_probablity
* __builtin_unpredictable
rdar://73455388
Differential Revision: https://reviews.llvm.org/D96268