From d40851784c38246462105689e66db48448817cb7 Mon Sep 17 00:00:00 2001 From: DeLesley Hutchins Date: Thu, 3 Sep 2015 21:14:22 +0000 Subject: [PATCH] Thread safety analysis: the NO_THREAD_SAFETY_ANALYSIS attribute will now disable checking of arguments to the function, which is done by -Wthread-safety-reference. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@246806 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Analysis/ThreadSafety.cpp | 58 +++++++++++--------- test/SemaCXX/warn-thread-safety-analysis.cpp | 55 +++++++++++++++++++ 2 files changed, 88 insertions(+), 25 deletions(-) diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp index e2c6ab5d94..922b157a2a 100644 --- a/lib/Analysis/ThreadSafety.cpp +++ b/lib/Analysis/ThreadSafety.cpp @@ -1926,34 +1926,42 @@ void BuildLockset::VisitCallExpr(CallExpr *Exp) { } } - if (ExamineArgs) { if (FunctionDecl *FD = Exp->getDirectCallee()) { - unsigned Fn = FD->getNumParams(); - unsigned Cn = Exp->getNumArgs(); - unsigned Skip = 0; - - unsigned i = 0; - if (OperatorFun) { - if (isa(FD)) { - // First arg in operator call is implicit self argument, - // and doesn't appear in the FunctionDecl. - Skip = 1; - Cn--; - } else { - // Ignore the first argument of operators; it's been checked above. - i = 1; + + // NO_THREAD_SAFETY_ANALYSIS does double duty here. Normally it + // only turns off checking within the body of a function, but we also + // use it to turn off checking in arguments to the function. This + // could result in some false negatives, but the alternative is to + // create yet another attribute. + // + if (!FD->hasAttr()) { + unsigned Fn = FD->getNumParams(); + unsigned Cn = Exp->getNumArgs(); + unsigned Skip = 0; + + unsigned i = 0; + if (OperatorFun) { + if (isa(FD)) { + // First arg in operator call is implicit self argument, + // and doesn't appear in the FunctionDecl. + Skip = 1; + Cn--; + } else { + // Ignore the first argument of operators; it's been checked above. + i = 1; + } + } + // Ignore default arguments + unsigned n = (Fn < Cn) ? Fn : Cn; + + for (; i < n; ++i) { + ParmVarDecl* Pvd = FD->getParamDecl(i); + Expr* Arg = Exp->getArg(i+Skip); + QualType Qt = Pvd->getType(); + if (Qt->isReferenceType()) + checkAccess(Arg, AK_Read, POK_PassByRef); } - } - // Ignore default arguments - unsigned n = (Fn < Cn) ? Fn : Cn; - - for (; i < n; ++i) { - ParmVarDecl* Pvd = FD->getParamDecl(i); - Expr* Arg = Exp->getArg(i+Skip); - QualType Qt = Pvd->getType(); - if (Qt->isReferenceType()) - checkAccess(Arg, AK_Read, POK_PassByRef); } } } diff --git a/test/SemaCXX/warn-thread-safety-analysis.cpp b/test/SemaCXX/warn-thread-safety-analysis.cpp index 4f31d406b5..cdbef700a1 100644 --- a/test/SemaCXX/warn-thread-safety-analysis.cpp +++ b/test/SemaCXX/warn-thread-safety-analysis.cpp @@ -5091,3 +5091,58 @@ class Foo { } // end namespace ScopedAdoptTest + +namespace TestReferenceNoThreadSafetyAnalysis { + +#define TS_UNCHECKED_READ(x) ts_unchecked_read(x) + +// Takes a reference to a guarded data member, and returns an unguarded +// reference. +template +inline const T& ts_unchecked_read(const T& v) NO_THREAD_SAFETY_ANALYSIS { + return v; +} + +template +inline T& ts_unchecked_read(T& v) NO_THREAD_SAFETY_ANALYSIS { + return v; +} + + +class Foo { +public: + Foo(): a(0) { } + + int a; +}; + + +class Bar { +public: + Bar() : a(0) { } + + Mutex mu; + int a GUARDED_BY(mu); + Foo foo GUARDED_BY(mu); +}; + + +void test() { + Bar bar; + const Bar cbar; + + int a = TS_UNCHECKED_READ(bar.a); // nowarn + TS_UNCHECKED_READ(bar.a) = 1; // nowarn + + int b = TS_UNCHECKED_READ(bar.foo).a; // nowarn + TS_UNCHECKED_READ(bar.foo).a = 1; // nowarn + + int c = TS_UNCHECKED_READ(cbar.a); // nowarn +} + +#undef TS_UNCHECKED_READ + +} // end namespace TestReferenceNoThreadSafetyAnalysis + + + -- 2.40.0