aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Analysis/ThreadSafety.cpp
AgeCommit message (Collapse)AuthorFilesLines
8 daysThread Safety Analysis: Fix recursive capability alias resolution (#159921)Marco Elver1-21/+24
Fix a false positive in thread safety alias analysis caused by incorrect late resolution of aliases. The analysis previously failed to distinguish between an alias and its defining expression; reassigning a variable within that expression (e.g., `ptr` in `alias = ptr->field`) would incorrectly change the dependent alias as well. The fix is to properly use LocalVariableMap::lookupExpr's updated context in a recursive lookup. Reported-by: Christoph Hellwig <hch@lst.de> Link: https://lkml.kernel.org/r/20250919140803.GA23745@lst.de
2025-09-11Thread Safety Analysis: Basic capability alias-analysis (#142955)Marco Elver1-25/+122
Add basic alias analysis for capabilities by reusing LocalVariableMap, which tracks currently valid definitions of variables. Aliases created through complex control flow are not tracked. This implementation would satisfy the basic needs of addressing the concerns for Linux kernel application [1]. For example, the analysis will no longer generate false positives for cases such as (and many others): void testNestedAccess(Container *c) { Foo *ptr = &c->foo; ptr->mu.Lock(); c->foo.data = 42; // OK - no false positive ptr->mu.Unlock(); } void testNestedAcquire(Container *c) EXCLUSIVE_LOCK_FUNCTION(&c->foo.mu) { Foo *buf = &c->foo; buf->mu.Lock(); // OK - no false positive } Given the analysis is now able to identify potentially unsafe patterns it was not able to identify previously (see added FIXME test case for an example), mark alias resolution as a "beta" feature behind the flag `-Wthread-safety-beta`. **Fixing LocalVariableMap:** It was found that LocalVariableMap was not properly tracking loop-invariant aliases: the old implementation failed because the merge logic compared raw VarDefinition IDs. The algorithm for handling back-edges (in createReferenceContext()) generates new 'reference' definitions for loop-scoped variables. Later ID comparison caused alias invalidation at back-edge merges (in intersectBackEdge()) and at subsequent forward-merges with non-loop paths (in intersectContexts()). Fix LocalVariableMap by adding the getCanonicalDefinitionID() helper that resolves any definition ID down to its non-reference base. As a result, a variable's definition is preserved across control-flow merges as long as its underlying canonical definition remains the same. Link: https://lore.kernel.org/all/CANpmjNPquO=W1JAh1FNQb8pMQjgeZAKCPQUAd7qUg=5pjJ6x=Q@mail.gmail.com/ [1]
2025-08-27[clang] NFC: reintroduce clang/include/clang/AST/Type.h (#155050)Matheus Izvekov1-1/+1
This reintroduces `Type.h`, having earlier been renamed to `TypeBase.h`, as a redirection to `TypeBase.h`, and redirects most users to include the former instead. This is a preparatory patch for being able to provide inline definitions for `Type` methods which would otherwise cause a circular dependency with `Decl{,CXX}.h`. Doing these operations into their own NFC patch helps the git rename detection logic work, preserving the history. This patch makes clang just a little slower to build (~0.17%), just because it makes more code indirectly include `DeclCXX.h`.
2025-08-27[clang] NFC: rename clang/include/clang/AST/Type.h to TypeBase.h (#155049)Matheus Izvekov1-1/+1
This is a preparatory patch, to be able to provide inline definitions for `Type` functions which depend on `Decl{,CXX}.h`. As the latter also depends on `Type.h`, this would not be possible without some reorganizing. Splitting this rename into its own patch allows git to track this as a rename, and preserve all git history, and not force any code reformatting. A later NFC patch will reintroduce `Type.h` as redirection to `TypeBase.h`, rewriting most places back to directly including `Type.h` instead of `TypeBase.h`, leaving only a handful of places where this is necessary. Then yet a later patch will exploit this by making more stuff inline.
2025-08-20Thread Safety Analysis: Graduate ACQUIRED_BEFORE() and ACQUIRED_AFTER() from ↵Marco Elver1-2/+1
beta features (#152853) Both these attributes were introduced in ab1dc2d54db5 ("Thread Safety Analysis: add support for before/after annotations on mutexes") back in 2015 as "beta" features. Anecdotally, we've been using `-Wthread-safety-beta` for years without problems. Furthermore, this feature requires the user to explicitly use these attributes in the first place. After 10 years, let's graduate the feature to the stable feature set, and reserve `-Wthread-safety-beta` for new upcoming features.
2025-08-09[clang] Improve nested name specifier AST representation (#147835)Matheus Izvekov1-1/+3
This is a major change on how we represent nested name qualifications in the AST. * The nested name specifier itself and how it's stored is changed. The prefixes for types are handled within the type hierarchy, which makes canonicalization for them super cheap, no memory allocation required. Also translating a type into nested name specifier form becomes a no-op. An identifier is stored as a DependentNameType. The nested name specifier gains a lightweight handle class, to be used instead of passing around pointers, which is similar to what is implemented for TemplateName. There is still one free bit available, and this handle can be used within a PointerUnion and PointerIntPair, which should keep bit-packing aficionados happy. * The ElaboratedType node is removed, all type nodes in which it could previously apply to can now store the elaborated keyword and name qualifier, tail allocating when present. * TagTypes can now point to the exact declaration found when producing these, as opposed to the previous situation of there only existing one TagType per entity. This increases the amount of type sugar retained, and can have several applications, for example in tracking module ownership, and other tools which care about source file origins, such as IWYU. These TagTypes are lazily allocated, in order to limit the increase in AST size. This patch offers a great performance benefit. It greatly improves compilation time for [stdexec](https://github.com/NVIDIA/stdexec). For one datapoint, for `test_on2.cpp` in that project, which is the slowest compiling test, this patch improves `-c` compilation time by about 7.2%, with the `-fsyntax-only` improvement being at ~12%. This has great results on compile-time-tracker as well: ![image](https://github.com/user-attachments/assets/700dce98-2cab-4aa8-97d1-b038c0bee831) This patch also further enables other optimziations in the future, and will reduce the performance impact of template specialization resugaring when that lands. It has some other miscelaneous drive-by fixes. About the review: Yes the patch is huge, sorry about that. Part of the reason is that I started by the nested name specifier part, before the ElaboratedType part, but that had a huge performance downside, as ElaboratedType is a big performance hog. I didn't have the steam to go back and change the patch after the fact. There is also a lot of internal API changes, and it made sense to remove ElaboratedType in one go, versus removing it from one type at a time, as that would present much more churn to the users. Also, the nested name specifier having a different API avoids missing changes related to how prefixes work now, which could make existing code compile but not work. How to review: The important changes are all in `clang/include/clang/AST` and `clang/lib/AST`, with also important changes in `clang/lib/Sema/TreeTransform.h`. The rest and bulk of the changes are mostly consequences of the changes in API. PS: TagType::getDecl is renamed to `getOriginalDecl` in this patch, just for easier to rebasing. I plan to rename it back after this lands. Fixes #136624 Fixes https://github.com/llvm/llvm-project/issues/43179 Fixes https://github.com/llvm/llvm-project/issues/68670 Fixes https://github.com/llvm/llvm-project/issues/92757
2025-08-04Thread safety analysis: Allocate FactEntrys with BumpPtrAllocator (#149660)Aaron Puchert1-87/+145
The FactManager managing the FactEntrys stays alive for the analysis of a single function. We are already using that by allocating TIL S-expressions via BumpPtrAllocator. We can do the same with FactEntrys. If we allocate the facts in an arena, we won't get destructor calls for them, and they better be trivially destructible. This required replacing the SmallVector member of ScopedLockableFactEntry with TrailingObjects. FactEntrys are now passed around by plain pointer. However, to hide the allocation of TrailingObjects from users, we introduce `create` methods, and this allows us to make the constructors private.
2025-08-03Thread safety analysis: Don't warn on acquiring reentrant capability (#150857)Aaron Puchert1-1/+1
The point of reentrant capabilities is that they can be acquired multiple times, so they should probably be excluded from requiring a negative capability on acquisition via -Wthread-safety-negative. However, we still propagate explicit negative requirements.
2025-06-05Thread Safety Analysis: Use replaceLock instead of removeLock+addLock (#141500)Marco Elver1-3/+3
In ScopedLockableFactEntry::unlock(), we can avoid a second search, pop_back(), and push_back() if we use the already obtained iterator into the FactSet to replace the old FactEntry and take its position in the vector.
2025-05-31[Analysis] Remove unused includes (NFC) (#142255)Kazu Hirata1-5/+0
These are identified by misc-include-cleaner. I've filtered out those that break builds. Also, I'm staying away from llvm-config.h, config.h, and Compiler.h, which likely cause platform- or compiler-specific build failures.
2025-05-26Thread Safety Analysis: Support reentrant capabilities (#137133)Marco Elver1-25/+108
Introduce the `reentrant_capability` attribute, which may be specified alongside the `capability(..)` attribute to denote that the defined capability type is reentrant. Marking a capability as reentrant means that acquiring the same capability multiple times is safe, and does not produce warnings on attempted re-acquisition. The most significant changes required are plumbing to propagate if the attribute is present to a CapabilityExpr, and introducing ReentrancyDepth to the LockableFactEntry class.
2025-05-21[clang] Use llvm::find_if (NFC) (#140983)Kazu Hirata1-13/+9
2025-05-20[clang][analysis] Thread Safety Analysis: Handle parenthesis (#140656)Prabhu Rajasekaran1-1/+1
2025-04-30Thread Safety Analysis: Fix styleMarco Elver1-3/+3
Comment fix and apply new clang-format style in ScopedLockableFactEntry::unlock(). Factored out from https://github.com/llvm/llvm-project/pull/137133 NFC.
2025-04-27[Analysis] Remove has_arg_iterator_range (NFC) (#137568)Kazu Hirata1-19/+0
The last use was removed by: commit f8afb8fdedae04ad2670857c97925c439d47d862 Author: Aaron Puchert <aaron.puchert@sap.com> Date: Fri Apr 29 22:12:21 2022 +0200
2025-04-15Merge similar Clang Thread Safety attributes (#135561)Aaron Puchert1-55/+5
Some of the old lock-based and new capability-based spellings behave basically in the same way, so merging them simplifies the code significantly. There are two minor functional changes: we only warn (instead of an error) when the try_acquire_capability attribute is used on something else than a function. The alternative would have been to produce an error for the old spelling, but we seem to only warn for all function attributes, so this is arguably more consistent. The second change is that we also check the first argument (which is the value returned for a successful try-acquire) for `this`. But from what I can tell, this code is defunct anyway at the moment (see #31414).
2025-02-26Thread Safety Analysis: Support warning on passing/returning pointers to ↵Marco Elver1-5/+25
guarded variables Introduce `-Wthread-safety-pointer` to warn when passing or returning pointers to guarded variables or guarded data. This is is analogous to `-Wthread-safety-reference`, which performs similar checks for C++ references. Adding checks for pointer passing is required to avoid false negatives in large C codebases, where data structures are typically implemented through helpers that take pointers to instances of a data structure. The feature is planned to be enabled by default under `-Wthread-safety` in the next release cycle. This gives time for early adopters to address new findings. Pull Request: https://github.com/llvm/llvm-project/pull/127396
2025-02-26Thread Safety Analysis: Handle address-of followed by dereferenceMarco Elver1-0/+11
Correctly analyze expressions where the address of a guarded variable is taken and immediately dereferenced, such as (*(type-specifier *)&x). Previously, such patterns would result in false negatives. Pull Request: https://github.com/llvm/llvm-project/pull/127396
2024-12-20Thread Safety Analysis: Support passing scoped locks between functions with ↵Malek Ben Slimane1-10/+165
appropriate annotations (#110523) This is helpful when multiple functions operate on the same capabilities, but we still want to use scoped lockable types for readability and exception safety. - Introduce support for thread safety annotations on function parameters marked with the 'scoped_lockable' attribute. - Add semantic checks for annotated function parameters, ensuring correct usage. - Enhance the analysis to recognize and handle parameters annotated for thread safety, extending the scope of analysis to track these across function boundries. - Verify that the underlying mutexes of function arguments match the expectations set by the annotations. Limitation: This does not work when the attribute arguments are class members, because attributes on function parameters are parsed differently from attributes on functions.
2024-09-05[Analysis] Avoid repeated hash lookups (NFC) (#107357)Kazu Hirata1-2/+1
2024-09-04Thread Safety Analysis: Differentiate between lock sets at real join points ↵Malek Ben Slimane1-2/+6
and expected/actual sets at function end (#105526) This fixes false positives related to returning a scoped lockable object. At the end of a function, we check managed locks instead of scoped locks. At real join points, we skip checking managed locks because we assume that the scope keeps track of its underlying mutexes and will release them at its destruction. So, checking for the scopes is sufficient. However, at the end of a function, we aim at comparing the expected and the actual lock sets. There, we skip checking scoped locks to prevent to get duplicate warnings for the same lock.
2024-07-01[clang][ThreadSafety] Revert stricter typing on trylock attributes (#97293)Dan McArdle1-46/+36
This PR reverts #95290 and the one-liner followup PR #96494. I received some substantial feedback on #95290, which I plan to address in a future PR. I've also received feedback that because the change emits errors where they were not emitted before, we should at least have a flag to disable the stricter warnings.
2024-06-24[clang][ThreadSafety] Check trylock function success and return types (#95290)Dan McArdle1-36/+46
With this change, Clang will generate errors when trylock functions have improper return types. Today, it silently fails to apply the trylock attribute to these functions which may incorrectly lead users to believe they have correctly acquired locks before accessing guarded data. As a side effect of explicitly checking the success argument type, I seem to have fixed a false negative in the analysis that could occur when a trylock's success argument is an enumerator. I've added a regression test to warn-thread-safety-analysis.cpp named `TrylockSuccessEnumFalseNegative`. This change also improves the documentation with descriptions of of the subtle gotchas that arise from the analysis interpreting the success arg as a boolean. Issue #92408
2023-12-08Thread safety analysis: Fix a bug in handling temporary constructors (#74020)Ziqing Luo1-13/+13
Extends the lifetime of the map `ConstructedObjects` to be of the whole CFG so that the map can connect temporary Ctor and Dtor in different CFG blocks.
2023-10-19Reapply "[clang analysis][thread-safety] Handle return-by-reference..… ↵Clement Courbet1-25/+53
(#68572) …… (#68394)" The new warnings are now under a separate flag `-Wthread-safety-reference-return`, which is on by default under `-Wthread-safety-reference`. - People can opt out via `-Wthread-safety-reference -Wnothread-safety-reference-return`. This reverts commit 859f2d032386632562521a99db20923217d98988.
2023-10-06Revert "Reapply "[clang analysis][thread-safety] Handle ↵Caroline Tice1-54/+26
return-by-reference..… (#68394)" This reverts commit cd184c866e0aad1f957910b8c7a94f98a2b21ceb.
2023-10-06Reapply "[clang analysis][thread-safety] Handle return-by-reference..… ↵Clement Courbet1-26/+54
(#68394) …. (#67776)" Now that `scudo` issues have been fixed (#68273). This reverts commit 462bdd5bf0861a27f451f7917802a954e2046bc7.
2023-09-29Revert "[clang analysis][thread-safety] Handle return-by-reference...… ↵Clement Courbet1-54/+26
(#67795) … (#67776)" This detects issues in `scudo`. Reverting until these are fixed. ``` /b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/tsd.h:74:12: error: returning variable 'QuarantineCache' by reference requires holding mutex 'Mutex' exclusively [-Werror,-Wthread-safety-reference] 74 | return QuarantineCache; | ^ /b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/combined.h:248:28: note: in instantiation of member function 'scudo::TSD<scudo::Allocator<scudo::DefaultConfig, &malloc_postinit>>::getQuarantineCache' requested here 248 | Quarantine.drain(&TSD->getQuarantineCache(), | ^ /b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/tsd.h:57:15: note: in instantiation of member function 'scudo::Allocator<scudo::DefaultConfig, &malloc_postinit>::commitBack' requested here 57 | Instance->commitBack(this); | ^ /b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/tsd_exclusive.h:172:27: note: in instantiation of member function 'scudo::TSD<scudo::Allocator<scudo::DefaultConfig, &malloc_postinit>>::commitBack' requested here 172 | TSDRegistryT::ThreadTSD.commitBack(Instance); | ^ /b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/tsd_exclusive.h:33:46: note: in instantiation of function template specialization 'scudo::teardownThread<scudo::Allocator<scudo::DefaultConfig, &malloc_postinit>>' requested here 33 | CHECK_EQ(pthread_key_create(&PThreadKey, teardownThread<Allocator>), 0); | ^ /b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/tsd_exclusive.h:42:5: note: in instantiation of member function 'scudo::TSDRegistryExT<scudo::Allocator<scudo::DefaultConfig, &malloc_postinit>>::init' requested here 42 | init(Instance); // Sets Initialized. | ^ /b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/tsd_exclusive.h:130:5: note: in instantiation of member function 'scudo::TSDRegistryExT<scudo::Allocator<scudo::DefaultConfig, &malloc_postinit>>::initOnceMaybe' requested here 130 | initOnceMaybe(Instance); | ^ /b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/tsd_exclusive.h:74:5: note: in instantiation of member function 'scudo::TSDRegistryExT<scudo::Allocator<scudo::DefaultConfig, &malloc_postinit>>::initThread' requested here 74 | initThread(Instance, MinimalInit); | ^ /b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/combined.h:221:17: note: in instantiation of member function 'scudo::TSDRegistryExT<scudo::Allocator<scudo::DefaultConfig, &malloc_postinit>>::initThreadMaybe' requested here 221 | TSDRegistry.initThreadMaybe(this, MinimalInit); | ^ /b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/combined.h:790:5: note: in instantiation of member function 'scudo::Allocator<scudo::DefaultConfig, &malloc_postinit>::initThreadMaybe' requested here 790 | initThreadMaybe(); | ^ /b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/wrappers_c.inc:36:25: note: in instantiation of member function 'scudo::Allocator<scudo::DefaultConfig, &malloc_postinit>::canReturnNull' requested here 36 | if (SCUDO_ALLOCATOR.canReturnNull()) { ``` This reverts commit 6dd96d6e80e9b3679a6161c590c60e0e99549b89.
2023-09-29[clang analysis][thread-safety] Handle return-by-reference... (#67776)Clement Courbet1-26/+54
...of guarded variables, when the function is not marked as requiring locks: ``` class Return { Mutex mu; Foo foo GUARDED_BY(mu); Foo &returns_ref_locked() { MutexLock lock(&mu); return foo; // BAD } Foo &returns_ref_locks_required() SHARED_LOCKS_REQUIRED(mu) { return foo; // OK } }; ``` Review on Phabricator: https://reviews.llvm.org/D153131
2023-09-29Reland "[clang analysis][NFCI] Preparatory work for D153131. (#67420)… ↵Clement Courbet1-59/+70
(#67775) …" (#67523) Discussion in https://reviews.llvm.org/D153132. This reverts commit f70377471c990aa567584ae429e77adc9a55491b.
2023-09-27Revert "[clang analysis][NFCI] Preparatory work for D153131. (#67420)" (#67523)Clement Courbet1-72/+61
There was a misunderstanding as to whether we wanted those base NFC changes or not. This reverts commit 166074eff2e9a5f79b791f1cc9b641a4e2968616.
2023-09-26[clang analysis][NFCI] Preparatory work for D153131. (#67420)Clement Courbet1-61/+72
This was ported over from phabricator. Review https://reviews.llvm.org/D153131.
2023-09-19[clang][TSA] Thread safety cleanup functionsTimm Bäder1-1/+11
Consider cleanup functions in thread safety analysis. Differential Revision: https://reviews.llvm.org/D152504
2023-09-19[NFC] Preparatory work for D153131 (#66750)Clement Courbet1-9/+9
2023-08-25[NFC] Initialize member pointer and avoid potential null dereferenceSindhu Chittireddy1-1/+1
Differential Revision: https://reviews.llvm.org/D158775
2023-06-27Revert "[clang][CFG][NFC] A few smaller cleanups"Timm Bäder1-13/+13
This reverts commit 173df3dd5f9a812b07f9866965f4e92a982a3fca. Looks like this wasn't as innocent as it seemed: https://lab.llvm.org/buildbot#builders/38/builds/12982
2023-06-27[clang][CFG][NFC] A few smaller cleanupsTimm Bäder1-13/+13
Use dyn_cast_if_present instead of _or_null, use decomposition decls, and a few other minor things.
2023-06-22[CLANG] Fix potential null pointer dereference bugsManna, Soumi1-2/+1
This patch uses castAs instead of getAs which will assert if the type doesn't match and adds nullptr check if needed. Also this patch improves the codes and passes I.getData() instead of doing a lookup in dumpVarDefinitionName() since we're iterating over the same map in LocalVariableMap::dumpContex(). Reviewed By: aaron.ballman, aaronpuchert Differential Revision: https://reviews.llvm.org/D153033
2023-06-06[clang][ThreadSafety][NFC] Make isReference() constTimm Bäder1-1/+1
2023-03-14[clang] Use *{Set,Map}::contains (NFC)Kazu Hirata1-1/+1
2023-01-14[clang] Remove remaining uses of llvm::Optional (NFC)Kazu Hirata1-1/+0
This patch removes several "using" declarations and #include "llvm/ADT/Optional.h". This is part of an effort to migrate from llvm::Optional to std::optional: https://discourse.llvm.org/t/deprecating-llvm-optional-x-hasvalue-getvalue-getvalueor/63716
2023-01-14[clang] Use std::optional instead of llvm::Optional (NFC)Kazu Hirata1-3/+3
This patch replaces (llvm::|)Optional< with std::optional<. I'll post a separate patch to remove #include "llvm/ADT/Optional.h". This is part of an effort to migrate from llvm::Optional to std::optional: https://discourse.llvm.org/t/deprecating-llvm-optional-x-hasvalue-getvalue-getvalueor/63716
2023-01-14[clang] Add #include <optional> (NFC)Kazu Hirata1-0/+1
This patch adds #include <optional> to those files containing llvm::Optional<...> or Optional<...>. I'll post a separate patch to actually replace llvm::Optional with std::optional. This is part of an effort to migrate from llvm::Optional to std::optional: https://discourse.llvm.org/t/deprecating-llvm-optional-x-hasvalue-getvalue-getvalueor/63716
2022-10-13Thread safety analysis: Support copy-elided production of scoped ↵Aaron Puchert1-98/+104
capabilities through arbitrary calls When support for copy elision was initially added in e97654b2f2807, it was taking attributes from a constructor call, although that constructor call is actually not involved. It seems more natural to use attributes on the function returning the scoped capability, which is where it's actually coming from. This would also support a number of interesting use cases, like producing different scope kinds without the need for tag types, or producing scopes from a private mutex. Changing the behavior was surprisingly difficult: we were not handling CXXConstructorExpr calls like regular calls but instead handled them through the DeclStmt they're contained in. This was based on the assumption that constructors are basically only called in variable declarations (not true because of temporaries), and that variable declarations necessitate constructors (not true with C++17 anymore). Untangling this required separating construction from assigning a variable name. When a call produces an object, we use a placeholder til::LiteralPtr for `this`, and we collect the call expression and placeholder in a map. Later when going through a DeclStmt, we look up the call expression and set the placeholder to the new VarDecl. The change has a couple of nice side effects: * We don't miss constructor calls not contained in DeclStmts anymore, allowing patterns like MutexLock{&mu}, requiresMutex(); The scoped lock temporary will be destructed at the end of the full statement, so it protects the following call without the need for a scope, but with the ability to unlock in case of an exception. * We support lifetime extension of temporaries. While unusual, one can now write const MutexLock &scope = MutexLock(&mu); and have it behave as expected. * Destructors used to be handled in a weird way: since there is no expression in the AST for implicit destructor calls, we instead provided a made-up DeclRefExpr to the variable being destructed, and passed that instead of a CallExpr. Then later in translateAttrExpr there was special code that knew that destructor expressions worked a bit different. * We were producing dummy DeclRefExprs in a number of places, this has been eliminated. We now use til::SExprs instead. Technically this could break existing code, but the current handling seems unexpected enough to justify this change. Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D129755
2022-10-07Revert "Thread safety analysis: Support copy-elided production of scoped ↵Hans Wennborg1-94/+93
capabilities through arbitrary calls" This caused false positives, see comment on the code review. > When support for copy elision was initially added in e97654b2f2807, it > was taking attributes from a constructor call, although that constructor > call is actually not involved. It seems more natural to use attributes > on the function returning the scoped capability, which is where it's > actually coming from. This would also support a number of interesting > use cases, like producing different scope kinds without the need for tag > types, or producing scopes from a private mutex. > > Changing the behavior was surprisingly difficult: we were not handling > CXXConstructorExpr calls like regular calls but instead handled them > through the DeclStmt they're contained in. This was based on the > assumption that constructors are basically only called in variable > declarations (not true because of temporaries), and that variable > declarations necessitate constructors (not true with C++17 anymore). > > Untangling this required separating construction from assigning a > variable name. When a call produces an object, we use a placeholder > til::LiteralPtr for `this`, and we collect the call expression and > placeholder in a map. Later when going through a DeclStmt, we look up > the call expression and set the placeholder to the new VarDecl. > > The change has a couple of nice side effects: > * We don't miss constructor calls not contained in DeclStmts anymore, > allowing patterns like > MutexLock{&mu}, requiresMutex(); > The scoped lock temporary will be destructed at the end of the full > statement, so it protects the following call without the need for a > scope, but with the ability to unlock in case of an exception. > * We support lifetime extension of temporaries. While unusual, one can > now write > const MutexLock &scope = MutexLock(&mu); > and have it behave as expected. > * Destructors used to be handled in a weird way: since there is no > expression in the AST for implicit destructor calls, we instead > provided a made-up DeclRefExpr to the variable being destructed, and > passed that instead of a CallExpr. Then later in translateAttrExpr > there was special code that knew that destructor expressions worked a > bit different. > * We were producing dummy DeclRefExprs in a number of places, this has > been eliminated. We now use til::SExprs instead. > > Technically this could break existing code, but the current handling > seems unexpected enough to justify this change. > > Reviewed By: aaron.ballman > > Differential Revision: https://reviews.llvm.org/D129755 This reverts commit 0041a69495f828f6732803cfb0f1e3fddd7fbf2a and the follow-up warning fix in 83d93d3c11ac9727bf3d4c5c956de44233cc7f87.
2022-10-06[clang] Fix a warningKazu Hirata1-0/+1
This patch fixes: clang/lib/Analysis/ThreadSafety.cpp:1788:12: error: unused variable 'inserted' [-Werror,-Wunused-variable]
2022-10-06Thread safety analysis: Support copy-elided production of scoped ↵Aaron Puchert1-93/+93
capabilities through arbitrary calls When support for copy elision was initially added in e97654b2f2807, it was taking attributes from a constructor call, although that constructor call is actually not involved. It seems more natural to use attributes on the function returning the scoped capability, which is where it's actually coming from. This would also support a number of interesting use cases, like producing different scope kinds without the need for tag types, or producing scopes from a private mutex. Changing the behavior was surprisingly difficult: we were not handling CXXConstructorExpr calls like regular calls but instead handled them through the DeclStmt they're contained in. This was based on the assumption that constructors are basically only called in variable declarations (not true because of temporaries), and that variable declarations necessitate constructors (not true with C++17 anymore). Untangling this required separating construction from assigning a variable name. When a call produces an object, we use a placeholder til::LiteralPtr for `this`, and we collect the call expression and placeholder in a map. Later when going through a DeclStmt, we look up the call expression and set the placeholder to the new VarDecl. The change has a couple of nice side effects: * We don't miss constructor calls not contained in DeclStmts anymore, allowing patterns like MutexLock{&mu}, requiresMutex(); The scoped lock temporary will be destructed at the end of the full statement, so it protects the following call without the need for a scope, but with the ability to unlock in case of an exception. * We support lifetime extension of temporaries. While unusual, one can now write const MutexLock &scope = MutexLock(&mu); and have it behave as expected. * Destructors used to be handled in a weird way: since there is no expression in the AST for implicit destructor calls, we instead provided a made-up DeclRefExpr to the variable being destructed, and passed that instead of a CallExpr. Then later in translateAttrExpr there was special code that knew that destructor expressions worked a bit different. * We were producing dummy DeclRefExprs in a number of places, this has been eliminated. We now use til::SExprs instead. Technically this could break existing code, but the current handling seems unexpected enough to justify this change. Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D129755
2022-10-06Thread safety analysis: Handle additional cast in scoped capability constructionAaron Puchert1-7/+14
We might have a CK_NoOp cast and a further CK_ConstructorConversion. As an optimization, drop some IgnoreParens calls: inside of the CK_{Constructor,UserDefined}Conversion should be no more parentheses, and inside the CXXBindTemporaryExpr should also be none. Lastly, we factor out the unpacking so that we can reuse it for MaterializeTemporaryExprs later on. Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D129752
2022-08-08[clang] LLVM_FALLTHROUGH => [[fallthrough]]. NFCFangrui Song1-2/+2
With C++17 there is no Clang pedantic warning or MSVC C5051. Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D131346
2022-07-14Thread safety analysis: Support builtin pointer-to-member operatorsAaron Puchert1-0/+11
We consider an access to x.*pm as access of the same kind into x, and an access to px->*pm as access of the same kind into *px. Previously we missed reads and writes in the .* case, and operations to the pointed-to data for ->* (we didn't miss accesses to the pointer itself, because that requires an LValueToRValue cast that we treat independently). We added support for overloaded operator->* in D124966. Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D129514