Skip to content

Commit c6f184e

Browse files
committed
Warn on RequiresCapability attribute mismatch
1 parent c727b48 commit c6f184e

File tree

5 files changed

+46
-6
lines changed

5 files changed

+46
-6
lines changed

clang/include/clang/Analysis/Analyses/ThreadSafety.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,9 @@ class ThreadSafetyHandler {
230230
/// Warn that there is a cycle in acquired_before/after dependencies.
231231
virtual void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) {}
232232

233+
virtual void handleAttributeMismatch(const NamedDecl *D1,
234+
const NamedDecl *D2) {}
235+
233236
/// Called by the analysis when starting analysis of a function.
234237
/// Used to issue suggestions for changes to annotations.
235238
virtual void enterFunction(const FunctionDecl *FD) {}

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4054,7 +4054,9 @@ def warn_acquired_before : Warning<
40544054
def warn_acquired_before_after_cycle : Warning<
40554055
"cycle in acquired_before/after dependencies, starting with '%0'">,
40564056
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
4057-
4057+
def warn_attribute_mismatch : Warning<
4058+
"attribute mismatch between function declarations of %0">,
4059+
InGroup<ThreadSafetyAttributes>, DefaultIgnore;
40584060

40594061
// Thread safety warnings negative capabilities
40604062
def warn_acquire_requires_negative_cap : Warning<

clang/lib/Analysis/ThreadSafety.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,8 @@ class ThreadSafetyAnalyzer {
10731073
ProtectedOperationKind POK);
10741074
void checkPtAccess(const FactSet &FSet, const Expr *Exp, AccessKind AK,
10751075
ProtectedOperationKind POK);
1076+
1077+
void checkMismatchedFunctionAttrs(const NamedDecl *ND);
10761078
};
10771079

10781080
} // namespace
@@ -2263,6 +2265,27 @@ static bool neverReturns(const CFGBlock *B) {
22632265
return false;
22642266
}
22652267

2268+
void ThreadSafetyAnalyzer::checkMismatchedFunctionAttrs(const NamedDecl *ND) {
2269+
auto collectCapabilities = [&](const Decl *D) {
2270+
CapExprSet Caps;
2271+
for (const auto *A : D->specific_attrs<RequiresCapabilityAttr>()) {
2272+
for (const Expr *E : A->args())
2273+
Caps.push_back_nodup(SxBuilder.translateAttrExpr(E, nullptr));
2274+
}
2275+
return Caps;
2276+
};
2277+
2278+
auto NDArgs = collectCapabilities(ND);
2279+
for (const Decl *D = ND->getPreviousDecl(); D; D = D->getPreviousDecl()) {
2280+
auto DArgs = collectCapabilities(D);
2281+
2282+
for (const auto &[A, B] : zip_longest(NDArgs, DArgs)) {
2283+
if (!A || !B || !A->equals(*B))
2284+
Handler.handleAttributeMismatch(ND, cast<NamedDecl>(D));
2285+
}
2286+
}
2287+
}
2288+
22662289
/// Check a function's CFG for thread-safety violations.
22672290
///
22682291
/// We traverse the blocks in the CFG, compute the set of mutexes that are held
@@ -2282,6 +2305,8 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
22822305
const NamedDecl *D = walker.getDecl();
22832306
CurrentFunction = dyn_cast<FunctionDecl>(D);
22842307

2308+
checkMismatchedFunctionAttrs(D);
2309+
22852310
if (D->hasAttr<NoThreadSafetyAnalysisAttr>())
22862311
return;
22872312

clang/lib/Sema/AnalysisBasedWarnings.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2065,6 +2065,16 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
20652065
Warnings.emplace_back(std::move(Warning), getNotes());
20662066
}
20672067

2068+
void handleAttributeMismatch(const NamedDecl *ThisDecl,
2069+
const NamedDecl *PrevDecl) override {
2070+
PartialDiagnosticAt Warning(ThisDecl->getLocation(),
2071+
S.PDiag(diag::warn_attribute_mismatch)
2072+
<< ThisDecl);
2073+
PartialDiagnosticAt Note(PrevDecl->getLocation(),
2074+
S.PDiag(diag::note_previous_decl) << PrevDecl);
2075+
Warnings.emplace_back(std::move(Warning), getNotes(Note));
2076+
}
2077+
20682078
void enterFunction(const FunctionDecl* FD) override {
20692079
CurrentFunction = FD;
20702080
}

clang/test/SemaCXX/warn-thread-safety-analysis.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2198,8 +2198,8 @@ namespace FunctionDefinitionTest {
21982198
class Foo {
21992199
public:
22002200
void foo1();
2201-
void foo2();
2202-
void foo3(Foo *other);
2201+
void foo2() EXCLUSIVE_LOCKS_REQUIRED(mu_);
2202+
void foo3(Foo *other) EXCLUSIVE_LOCKS_REQUIRED(other->mu_);
22032203

22042204
template<class T>
22052205
void fooT1(const T& dummy1);
@@ -2249,8 +2249,8 @@ void fooF1(Foo *f) EXCLUSIVE_LOCKS_REQUIRED(f->mu_) {
22492249
f->a = 1;
22502250
}
22512251

2252-
void fooF2(Foo *f);
2253-
void fooF2(Foo *f) EXCLUSIVE_LOCKS_REQUIRED(f->mu_) {
2252+
void fooF2(Foo *f); // expected-note {{declared here}}
2253+
void fooF2(Foo *f) EXCLUSIVE_LOCKS_REQUIRED(f->mu_) { // expected-warning {{attribute mismatch between function declarations of 'fooF2'}}
22542254
f->a = 2;
22552255
}
22562256

@@ -2269,7 +2269,7 @@ void test() {
22692269
Foo myFoo;
22702270

22712271
myFoo.foo2(); // \
2272-
// expected-warning {{calling function 'foo2' requires holding mutex 'myFoo.mu_' exclusively}}
2272+
// expected-warning 2{{calling function 'foo2' requires holding mutex 'myFoo.mu_' exclusively}}
22732273
myFoo.foo3(&myFoo); // \
22742274
// expected-warning {{calling function 'foo3' requires holding mutex 'myFoo.mu_' exclusively}}
22752275
myFoo.fooT1(dummy); // \

0 commit comments

Comments
 (0)