Skip to content

Commit e1bd863

Browse files
committed
merge main into amd-staging
2 parents 47bcc02 + 90a14d2 commit e1bd863

File tree

155 files changed

+15447
-2777
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

155 files changed

+15447
-2777
lines changed

clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp

Lines changed: 50 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "../utils/ExprSequence.h"
2121
#include "../utils/Matchers.h"
22+
#include "../utils/OptionsUtils.h"
2223
#include <optional>
2324

2425
using namespace clang::ast_matchers;
@@ -48,7 +49,8 @@ struct UseAfterMove {
4849
/// various internal helper functions).
4950
class UseAfterMoveFinder {
5051
public:
51-
UseAfterMoveFinder(ASTContext *TheContext);
52+
UseAfterMoveFinder(ASTContext *TheContext,
53+
llvm::ArrayRef<StringRef> InvalidationFunctions);
5254

5355
// Within the given code block, finds the first use of 'MovedVariable' that
5456
// occurs after 'MovingCall' (the expression that performs the move). If a
@@ -71,13 +73,19 @@ class UseAfterMoveFinder {
7173
llvm::SmallPtrSetImpl<const DeclRefExpr *> *DeclRefs);
7274

7375
ASTContext *Context;
76+
llvm::ArrayRef<StringRef> InvalidationFunctions;
7477
std::unique_ptr<ExprSequence> Sequence;
7578
std::unique_ptr<StmtToBlockMap> BlockMap;
7679
llvm::SmallPtrSet<const CFGBlock *, 8> Visited;
7780
};
7881

7982
} // namespace
8083

84+
static auto getNameMatcher(llvm::ArrayRef<StringRef> InvalidationFunctions) {
85+
return anyOf(hasAnyName("::std::move", "::std::forward"),
86+
matchers::matchesAnyListedName(InvalidationFunctions));
87+
}
88+
8189
// Matches nodes that are
8290
// - Part of a decltype argument or class template argument (we check this by
8391
// seeing if they are children of a TypeLoc), or
@@ -92,8 +100,9 @@ static StatementMatcher inDecltypeOrTemplateArg() {
92100
hasAncestor(expr(hasUnevaluatedContext())));
93101
}
94102

95-
UseAfterMoveFinder::UseAfterMoveFinder(ASTContext *TheContext)
96-
: Context(TheContext) {}
103+
UseAfterMoveFinder::UseAfterMoveFinder(
104+
ASTContext *TheContext, llvm::ArrayRef<StringRef> InvalidationFunctions)
105+
: Context(TheContext), InvalidationFunctions(InvalidationFunctions) {}
97106

98107
std::optional<UseAfterMove>
99108
UseAfterMoveFinder::find(Stmt *CodeBlock, const Expr *MovingCall,
@@ -359,7 +368,7 @@ void UseAfterMoveFinder::getReinits(
359368
unless(parmVarDecl(hasType(
360369
references(qualType(isConstQualified())))))),
361370
unless(callee(functionDecl(
362-
hasAnyName("::std::move", "::std::forward")))))))
371+
getNameMatcher(InvalidationFunctions)))))))
363372
.bind("reinit");
364373

365374
Stmts->clear();
@@ -388,18 +397,21 @@ void UseAfterMoveFinder::getReinits(
388397
}
389398
}
390399

391-
enum class MoveType {
392-
Move, // std::move
393-
Forward, // std::forward
400+
enum MoveType {
401+
Forward = 0, // std::forward
402+
Move = 1, // std::move
403+
Invalidation = 2, // other
394404
};
395405

396406
static MoveType determineMoveType(const FunctionDecl *FuncDecl) {
397-
if (FuncDecl->getName() == "move")
398-
return MoveType::Move;
399-
if (FuncDecl->getName() == "forward")
400-
return MoveType::Forward;
407+
if (FuncDecl->isInStdNamespace()) {
408+
if (FuncDecl->getName() == "move")
409+
return MoveType::Move;
410+
if (FuncDecl->getName() == "forward")
411+
return MoveType::Forward;
412+
}
401413

402-
llvm_unreachable("Invalid move type");
414+
return MoveType::Invalidation;
403415
}
404416

405417
static void emitDiagnostic(const Expr *MovingCall, const DeclRefExpr *MoveArg,
@@ -408,41 +420,53 @@ static void emitDiagnostic(const Expr *MovingCall, const DeclRefExpr *MoveArg,
408420
const SourceLocation UseLoc = Use.DeclRef->getExprLoc();
409421
const SourceLocation MoveLoc = MovingCall->getExprLoc();
410422

411-
const bool IsMove = (Type == MoveType::Move);
412-
413-
Check->diag(UseLoc, "'%0' used after it was %select{forwarded|moved}1")
414-
<< MoveArg->getDecl()->getName() << IsMove;
415-
Check->diag(MoveLoc, "%select{forward|move}0 occurred here",
423+
Check->diag(UseLoc,
424+
"'%0' used after it was %select{forwarded|moved|invalidated}1")
425+
<< MoveArg->getDecl()->getName() << Type;
426+
Check->diag(MoveLoc, "%select{forward|move|invalidation}0 occurred here",
416427
DiagnosticIDs::Note)
417-
<< IsMove;
428+
<< Type;
418429
if (Use.EvaluationOrderUndefined) {
419430
Check->diag(
420431
UseLoc,
421-
"the use and %select{forward|move}0 are unsequenced, i.e. "
432+
"the use and %select{forward|move|invalidation}0 are unsequenced, i.e. "
422433
"there is no guarantee about the order in which they are evaluated",
423434
DiagnosticIDs::Note)
424-
<< IsMove;
435+
<< Type;
425436
} else if (Use.UseHappensInLaterLoopIteration) {
426437
Check->diag(UseLoc,
427438
"the use happens in a later loop iteration than the "
428-
"%select{forward|move}0",
439+
"%select{forward|move|invalidation}0",
429440
DiagnosticIDs::Note)
430-
<< IsMove;
441+
<< Type;
431442
}
432443
}
433444

445+
UseAfterMoveCheck::UseAfterMoveCheck(StringRef Name, ClangTidyContext *Context)
446+
: ClangTidyCheck(Name, Context),
447+
InvalidationFunctions(utils::options::parseStringList(
448+
Options.get("InvalidationFunctions", ""))) {}
449+
450+
void UseAfterMoveCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
451+
Options.store(Opts, "InvalidationFunctions",
452+
utils::options::serializeStringList(InvalidationFunctions));
453+
}
454+
434455
void UseAfterMoveCheck::registerMatchers(MatchFinder *Finder) {
435456
// try_emplace is a common maybe-moving function that returns a
436457
// bool to tell callers whether it moved. Ignore std::move inside
437458
// try_emplace to avoid false positives as we don't track uses of
438459
// the bool.
439460
auto TryEmplaceMatcher =
440461
cxxMemberCallExpr(callee(cxxMethodDecl(hasName("try_emplace"))));
462+
auto Arg = declRefExpr().bind("arg");
463+
auto IsMemberCallee = callee(functionDecl(unless(isStaticStorageClass())));
441464
auto CallMoveMatcher =
442-
callExpr(argumentCountIs(1),
443-
callee(functionDecl(hasAnyName("::std::move", "::std::forward"))
465+
callExpr(callee(functionDecl(getNameMatcher(InvalidationFunctions))
444466
.bind("move-decl")),
445-
hasArgument(0, declRefExpr().bind("arg")),
467+
anyOf(cxxMemberCallExpr(IsMemberCallee, on(Arg)),
468+
callExpr(unless(cxxMemberCallExpr(IsMemberCallee)),
469+
hasArgument(0, Arg))),
446470
unless(inDecltypeOrTemplateArg()),
447471
unless(hasParent(TryEmplaceMatcher)), expr().bind("call-move"),
448472
anyOf(hasAncestor(compoundStmt(
@@ -521,7 +545,7 @@ void UseAfterMoveCheck::check(const MatchFinder::MatchResult &Result) {
521545
}
522546

523547
for (Stmt *CodeBlock : CodeBlocks) {
524-
UseAfterMoveFinder Finder(Result.Context);
548+
UseAfterMoveFinder Finder(Result.Context, InvalidationFunctions);
525549
if (auto Use = Finder.find(CodeBlock, MovingCall, Arg))
526550
emitDiagnostic(MovingCall, Arg, *Use, this, Result.Context,
527551
determineMoveType(MoveDecl));

clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@ namespace clang::tidy::bugprone {
2020
/// https://clang.llvm.org/extra/clang-tidy/checks/bugprone/use-after-move.html
2121
class UseAfterMoveCheck : public ClangTidyCheck {
2222
public:
23-
UseAfterMoveCheck(StringRef Name, ClangTidyContext *Context)
24-
: ClangTidyCheck(Name, Context) {}
23+
UseAfterMoveCheck(StringRef Name, ClangTidyContext *Context);
24+
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
2525
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
2626
return LangOpts.CPlusPlus11;
2727
}
2828
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
2929
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
30+
31+
private:
32+
std::vector<StringRef> InvalidationFunctions;
3033
};
3134

3235
} // namespace clang::tidy::bugprone

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,10 @@ Changes in existing checks
408408
suffix when the reason starts with the character `>` in the `CustomFunctions`
409409
option.
410410

411+
- Improved :doc:`bugprone-use-after-move
412+
<clang-tidy/checks/bugprone/use-after-move>` check by adding
413+
`InvalidationFunctions` option to support custom invalidation functions.
414+
411415
- Improved :doc:`cppcoreguidelines-avoid-non-const-global-variables
412416
<clang-tidy/checks/cppcoreguidelines/avoid-non-const-global-variables>` check
413417
by adding a new option `AllowThreadLocal` that suppresses warnings on

clang-tools-extra/docs/clang-tidy/checks/bugprone/use-after-move.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,3 +253,13 @@ For example, if an additional member variable is added to ``S``, it is easy to
253253
forget to add the reinitialization for this additional member. Instead, it is
254254
safer to assign to the entire struct in one go, and this will also avoid the
255255
use-after-move warning.
256+
257+
Options
258+
-------
259+
260+
.. option:: InvalidationFunctions
261+
262+
A semicolon-separated list of names of functions that cause their first
263+
arguments to be invalidated (e.g., closing a handle).
264+
For member functions, the first argument is considered to be the implicit
265+
object argument (``this``). Default value is an empty string.

clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1-
// RUN: %check_clang_tidy -std=c++11 -check-suffixes=,CXX11 %s bugprone-use-after-move %t -- -- -fno-delayed-template-parsing
2-
// RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-use-after-move %t -- -- -fno-delayed-template-parsing
1+
// RUN: %check_clang_tidy -std=c++11 -check-suffixes=,CXX11 %s bugprone-use-after-move %t -- \
2+
// RUN: -config='{CheckOptions: { \
3+
// RUN: bugprone-use-after-move.InvalidationFunctions: "::Database<>::StaticCloseConnection;Database<>::CloseConnection;FriendCloseConnection" \
4+
// RUN: }}' -- \
5+
// RUN: -fno-delayed-template-parsing
6+
// RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-use-after-move %t -- \
7+
// RUN: -config='{CheckOptions: { \
8+
// RUN: bugprone-use-after-move.InvalidationFunctions: "::Database<>::StaticCloseConnection;Database<>::CloseConnection;FriendCloseConnection" \
9+
// RUN: }}' -- \
10+
// RUN: -fno-delayed-template-parsing
311

412
typedef decltype(nullptr) nullptr_t;
513

@@ -1645,3 +1653,53 @@ void create() {
16451653
}
16461654

16471655
} // namespace issue82023
1656+
1657+
namespace custom_invalidation
1658+
{
1659+
1660+
template<class T = int>
1661+
struct Database {
1662+
template<class...>
1663+
void CloseConnection(T = T()) {}
1664+
template<class...>
1665+
static void StaticCloseConnection(Database&, T = T()) {}
1666+
template<class...>
1667+
friend void FriendCloseConnection(Database&, T = T()) {}
1668+
void Query();
1669+
};
1670+
1671+
void Run() {
1672+
using DB = Database<>;
1673+
1674+
DB db1;
1675+
db1.CloseConnection();
1676+
db1.Query();
1677+
// CHECK-NOTES: [[@LINE-1]]:3: warning: 'db1' used after it was invalidated
1678+
// CHECK-NOTES: [[@LINE-3]]:7: note: invalidation occurred here
1679+
1680+
DB db2;
1681+
DB::StaticCloseConnection(db2);
1682+
db2.Query();
1683+
// CHECK-NOTES: [[@LINE-1]]:3: warning: 'db2' used after it was invalidated
1684+
// CHECK-NOTES: [[@LINE-3]]:3: note: invalidation occurred here
1685+
1686+
DB db3;
1687+
DB().StaticCloseConnection(db3);
1688+
db3.Query();
1689+
// CHECK-NOTES: [[@LINE-1]]:3: warning: 'db3' used after it was invalidated
1690+
// CHECK-NOTES: [[@LINE-3]]:3: note: invalidation occurred here
1691+
1692+
DB db4;
1693+
FriendCloseConnection(db4);
1694+
db4.Query();
1695+
// CHECK-NOTES: [[@LINE-1]]:3: warning: 'db4' used after it was invalidated
1696+
// CHECK-NOTES: [[@LINE-3]]:3: note: invalidation occurred here
1697+
1698+
DB db5;
1699+
FriendCloseConnection(db5, /*disconnect timeout*/ 5);
1700+
db5.Query();
1701+
// CHECK-NOTES: [[@LINE-1]]:3: warning: 'db5' used after it was invalidated
1702+
// CHECK-NOTES: [[@LINE-3]]:3: note: invalidation occurred here
1703+
}
1704+
1705+
} // namespace custom_invalidation

clang/docs/LanguageExtensions.rst

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4307,9 +4307,9 @@ as ``unsigned __int128`` and C23 ``unsigned _BitInt(N)``.
43074307
``__builtin_counted_by_ref`` returns a pointer to the count field from the
43084308
``counted_by`` attribute.
43094309
4310-
The argument must be a flexible array member. If the argument isn't a flexible
4311-
array member or doesn't have the ``counted_by`` attribute, the builtin returns
4312-
``(void *)0``.
4310+
The argument must be a flexible array member or a pointer with the ``counted_by``
4311+
attribute. If the argument doesn't have the ``counted_by`` attribute, the builtin
4312+
returns ``(void *)0``.
43134313
43144314
**Syntax**:
43154315
@@ -4340,9 +4340,9 @@ array member or doesn't have the ``counted_by`` attribute, the builtin returns
43404340
The ``__builtin_counted_by_ref`` builtin allows the programmer to prevent a
43414341
common error associated with the ``counted_by`` attribute. When using the
43424342
``counted_by`` attribute, the ``count`` field **must** be set before the
4343-
flexible array member can be accessed. Otherwise, the sanitizers may view such
4344-
accesses as false positives. For instance, it's not uncommon for programmers to
4345-
initialize the flexible array before setting the ``count`` field:
4343+
flexible array member or pointer can be accessed. Otherwise, the sanitizers may
4344+
view such accesses as false positives. For instance, it's not uncommon for
4345+
programmers to initialize the flexible array before setting the ``count`` field:
43464346
43474347
.. code-block:: c
43484348
@@ -4360,10 +4360,9 @@ initialize the flexible array before setting the ``count`` field:
43604360
ptr->count = COUNT;
43614361
43624362
Enforcing the rule that ``ptr->count = COUNT;`` must occur after every
4363-
allocation of a struct with a flexible array member with the ``counted_by``
4364-
attribute is prone to failure in large code bases. This builtin mitigates this
4365-
for allocators (like in Linux) that are implemented in a way where the counter
4366-
assignment can happen automatically.
4363+
allocation of a struct with a ``counted_by`` member is prone to failure in large
4364+
code bases. This builtin mitigates this for allocators (like in Linux) that are
4365+
implemented in a way where the counter assignment can happen automatically.
43674366
43684367
**Note:** The value returned by ``__builtin_counted_by_ref`` cannot be assigned
43694368
to a variable, have its address taken, or passed into or returned from a

clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ class FactsGenerator : public ConstStmtVisitor<FactsGenerator> {
9191

9292
void markUseAsWrite(const DeclRefExpr *DRE);
9393

94+
llvm::SmallVector<Fact *> issuePlaceholderLoans();
9495
FactManager &FactMgr;
9596
AnalysisDeclContext &AC;
9697
llvm::SmallVector<Fact *> CurrentBlockFacts;

clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ class LifetimeSafetyReporter {
4747
const Expr *EscapeExpr,
4848
SourceLocation ExpiryLoc,
4949
Confidence Confidence) {}
50+
51+
// Suggests lifetime bound annotations for function paramters
52+
virtual void suggestAnnotation(const ParmVarDecl *PVD,
53+
const Expr *EscapeExpr) {}
5054
};
5155

5256
/// The main entry point for the analysis.

0 commit comments

Comments
 (0)