@@ -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
0 commit comments