[cfe-commits] r136364 - in /cfe/trunk: docs/LanguageExtensions.html include/clang/Basic/Attr.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h lib/Sema/AttributeList.cpp lib/Sema/SemaDeclAttr.cpp test/SemaCXX/warn-thread-safety.cpp
Caitlin Sadowski
supertri at google.com
Thu Jul 28 10:21:07 PDT 2011
Author: supertri
Date: Thu Jul 28 12:21:07 2011
New Revision: 136364
URL: http://llvm.org/viewvc/llvm-project?rev=136364&view=rev
Log:
Added parsing for guarded_var, pt_guarded_var, lockable,
scoped_lockable, and no_thread_safety_analysis attributes, all for thread safety analysis
Added:
cfe/trunk/test/SemaCXX/warn-thread-safety.cpp
Modified:
cfe/trunk/docs/LanguageExtensions.html
cfe/trunk/include/clang/Basic/Attr.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/AttributeList.h
cfe/trunk/lib/Sema/AttributeList.cpp
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
Modified: cfe/trunk/docs/LanguageExtensions.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LanguageExtensions.html?rev=136364&r1=136363&r2=136364&view=diff
==============================================================================
--- cfe/trunk/docs/LanguageExtensions.html (original)
+++ cfe/trunk/docs/LanguageExtensions.html Thu Jul 28 12:21:07 2011
@@ -87,6 +87,14 @@
</ul>
</li>
<li><a href="#analyzerspecific">Static Analysis-Specific Extensions</a></li>
+<li><a href="#threadsafety">Thread Safety Annotation Checking</a></li>
+ <ul>
+ <li><a href="#ts_guardedvar"><tt>guarded_var</tt></a></li>
+ <li><a href="#ts_ptguardedvar"><tt>pt_guarded_var</tt></a></li>
+ <li><a href="#ts_lockable"><tt>lockable</tt></a></li>
+ <li><a href="#ts_scopedlockable"><tt>scoped_lockable</tt></a></li>
+ <li><a href="#ts_noanal"><tt>no_thread_safety_analysis</tt></a></li>
+ </ul>
</ul>
<!-- ======================================================================= -->
@@ -1088,6 +1096,50 @@
<p>Query for these features with <tt>__has_attribute(ns_consumed)</tt>,
<tt>__has_attribute(ns_returns_retained)</tt>, etc.</p>
+
+<!-- ======================================================================= -->
+<h2 id="analyzerspecific">Thread-Safety Annotation Checking</h2>
+<!-- ======================================================================= -->
+
+<p>Clang supports additional attributes for checking basic locking policies in
+multithreaded programs.
+Clang currently parses the following list of attributes, although
+<b>the implementation for these annotations is currently in development.</b>
+For more details, see the
+<a href="http://gcc.gnu.org/wiki/ThreadSafetyAnnotation">GCC implementation</a>.
+</p>
+
+<h4 id="ts_guardedvar">guarded_var</h4>
+
+<p>Use <tt>__attribute__((guarded_var))</tt> on a variable declaration to
+specify that the variable must be accessed while holding some lock.</p>
+
+<h4 id="ts_ptguardedvar">pt_guarded_var</h4>
+
+<p>Use <tt>__attribute__((pt_guarded_var))</tt> on a pointer declaration to
+specify that the pointer must be dereferenced while holding some lock.</p>
+
+<h4 id="ts_lockable">lockable</h4>
+
+<p>Use <tt>__attribute__((lockable))</tt> on a class definition to specify
+that it has a lockable type (e.g. a Mutex class). This annotation is primarily
+used to check consistency.</p>
+
+<h4 id="ts_scopedlockable">scoped_lockable</h4>
+
+<p>Use <tt>__attribute__((scoped_lockable))</tt> on a class definition to
+specify that it has a "scoped" lockable type. Objects of this type will acquire
+the lock upon construction and release it upon going out of scope.
+ This annotation is primarily used to check
+consistency.</p>
+
+<h4 id="ts_noanal">no_thread_safety_analysis</h4>
+
+<p>Use <tt>__attribute__((no_thread_safety_analysis))</tt> on a function
+declaration to specify that the thread safety analysis should not be run on that
+function. This attribute provides an escape hatch (e.g. for situations when it
+is difficult to annotate the locking policy). </p>
+
</div>
</body>
</html>
Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=136364&r1=136363&r2=136364&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Thu Jul 28 12:21:07 2011
@@ -538,3 +538,26 @@
def X86ForceAlignArgPointer : InheritableAttr {
let Spellings = [];
}
+
+
+// C/C++ Thread safety attributes (e.g. for deadlock, data race checking)
+
+def GuardedVar : InheritableAttr {
+ let Spellings = ["guarded_var"];
+}
+
+def PtGuardedVar : InheritableAttr {
+ let Spellings = ["pt_guarded_var"];
+}
+
+def Lockable : InheritableAttr {
+ let Spellings = ["lockable"];
+}
+
+def ScopedLockable : InheritableAttr {
+ let Spellings = ["scoped_lockable"];
+}
+
+def NoThreadSafetyAnalysis : InheritableAttr {
+ let Spellings = ["no_thread_safety_analysis"];
+}
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=136364&r1=136363&r2=136364&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jul 28 12:21:07 2011
@@ -1249,7 +1249,7 @@
"parameters and methods|functions, methods and blocks|"
"classes and virtual methods|functions, methods, and parameters|"
"classes|virtual methods|class members|variables|methods|"
- "variables, functions and labels}1">;
+ "variables, functions and labels|fields and global variables}1">;
def err_attribute_wrong_decl_type : Error<
"%0 attribute only applies to %select{functions|unions|"
"variables and functions|functions and methods|parameters|"
@@ -1287,6 +1287,9 @@
def warn_label_attribute_not_unused : Warning<
"The only valid attribute for labels is 'unused'">;
def err_invalid_pcs : Error<"Invalid PCS type">;
+def err_attribute_can_be_applied_only_to_value_decl : Error<
+ "%0 attribute can only be applied to value declarations">;
+
// Availability attribute
def warn_availability_unknown_platform : Warning<
Modified: cfe/trunk/include/clang/Sema/AttributeList.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?rev=136364&r1=136363&r2=136364&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/AttributeList.h (original)
+++ cfe/trunk/include/clang/Sema/AttributeList.h Thu Jul 28 12:21:07 2011
@@ -184,12 +184,14 @@
AT_format_arg,
AT_global,
AT_gnu_inline,
+ AT_guarded_var,
AT_host,
AT_IBAction, // Clang-specific.
AT_IBOutlet, // Clang-specific.
AT_IBOutletCollection, // Clang-specific.
AT_init_priority,
AT_launch_bounds,
+ AT_lockable,
AT_malloc,
AT_may_alias,
AT_mode,
@@ -198,6 +200,7 @@
AT_neon_polyvector_type, // Clang-specific.
AT_neon_vector_type, // Clang-specific.
AT_no_instrument_function,
+ AT_no_thread_safety_analysis,
AT_nocommon,
AT_nodebug,
AT_noinline,
@@ -225,9 +228,11 @@
AT_packed,
AT_pascal,
AT_pcs, // ARM specific
+ AT_pt_guarded_var,
AT_pure,
AT_regparm,
AT_reqd_wg_size,
+ AT_scoped_lockable,
AT_section,
AT_sentinel,
AT_shared,
Modified: cfe/trunk/lib/Sema/AttributeList.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AttributeList.cpp?rev=136364&r1=136363&r2=136364&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AttributeList.cpp (original)
+++ cfe/trunk/lib/Sema/AttributeList.cpp Thu Jul 28 12:21:07 2011
@@ -210,5 +210,10 @@
.Case("uuid", AT_uuid)
.Case("pcs", AT_pcs)
.Case("ms_struct", AT_MsStruct)
+ .Case("guarded_var", AT_guarded_var)
+ .Case("pt_guarded_var", AT_pt_guarded_var)
+ .Case("scoped_lockable", AT_scoped_lockable)
+ .Case("lockable", AT_lockable)
+ .Case("no_thread_safety_analysis", AT_no_thread_safety_analysis)
.Default(UnknownAttribute);
}
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=136364&r1=136363&r2=136364&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Thu Jul 28 12:21:07 2011
@@ -204,6 +204,39 @@
return true;
}
+///
+/// \brief Check if passed in Decl is a field or potentially shared global var
+/// \return true if the Decl is a field or potentially shared global variable
+///
+static bool mayBeSharedVariable(Decl *D) {
+ if (isa<FieldDecl>(D))
+ return true;
+ if(VarDecl *vd = dyn_cast<VarDecl>(D))
+ return (vd->hasGlobalStorage() && !(vd->isThreadSpecified()));
+
+ return false;
+}
+
+///
+/// \brief Check if passed in Decl is a pointer type.
+/// Note that this function may produce an error message.
+/// \return true if the Decl is a pointer type; false otherwise
+///
+bool checkIsPointer(Sema & S, Decl * D, const AttributeList & Attr) {
+ if(ValueDecl * vd = dyn_cast <ValueDecl>(D)) {
+ QualType QT = vd->getType();
+ if(QT->isAnyPointerType()){
+ return true;
+ }
+ S.Diag(Attr.getLoc(), diag::warn_pointer_attribute_wrong_type)
+ << Attr.getName()->getName() << QT;
+ } else {
+ S.Diag(Attr.getLoc(), diag::err_attribute_can_be_applied_only_to_value_decl)
+ << Attr.getName();
+ }
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Attribute Implementations
//===----------------------------------------------------------------------===//
@@ -212,6 +245,65 @@
// least add some helper functions to check most argument patterns (#
// and types of args).
+static void handleGuardedVarAttr(Sema &S, Decl *D, const AttributeList &Attr,
+ bool pointer = false) {
+ assert(!Attr.isInvalid());
+
+ if (!checkAttributeNumArgs(S, Attr, 0))
+ return;
+
+ // D must be either a member field or global (potentially shared) variable.
+ if (!mayBeSharedVariable(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 15; /*fields and global vars*/;
+ return;
+ }
+
+ if (pointer && !checkIsPointer(S, D, Attr))
+ return;
+
+ if (pointer)
+ D->addAttr(::new (S.Context) PtGuardedVarAttr(Attr.getLoc(), S.Context));
+ else
+ D->addAttr(::new (S.Context) GuardedVarAttr(Attr.getLoc(), S.Context));
+}
+
+static void handleLockableAttr(Sema &S, Decl *D, const AttributeList &Attr,
+ bool scoped = false) {
+ assert(!Attr.isInvalid());
+
+ if (!checkAttributeNumArgs(S, Attr, 0))
+ return;
+
+ if (!isa<CXXRecordDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedClass;
+ return;
+ }
+
+ if (scoped)
+ D->addAttr(::new (S.Context) ScopedLockableAttr(Attr.getLoc(), S.Context));
+ else
+ D->addAttr(::new (S.Context) LockableAttr(Attr.getLoc(), S.Context));
+}
+
+static void handleNoThreadSafetyAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ assert(!Attr.isInvalid());
+
+ if (!checkAttributeNumArgs(S, Attr, 0))
+ return;
+
+ if (!isFunction(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunctionOrMethod;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) NoThreadSafetyAnalysisAttr(Attr.getLoc(),
+ S.Context));
+}
+
static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D,
const AttributeList &Attr) {
TypedefNameDecl *tDecl = dyn_cast<TypedefNameDecl>(D);
@@ -3071,6 +3163,24 @@
case AttributeList::AT_uuid:
handleUuidAttr(S, D, Attr);
break;
+
+ // Thread safety attributes:
+ case AttributeList::AT_guarded_var:
+ handleGuardedVarAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_pt_guarded_var:
+ handleGuardedVarAttr(S, D, Attr, /*pointer = */true);
+ break;
+ case AttributeList::AT_scoped_lockable:
+ handleLockableAttr(S, D, Attr, /*scoped = */true);
+ break;
+ case AttributeList::AT_no_thread_safety_analysis:
+ handleNoThreadSafetyAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_lockable:
+ handleLockableAttr(S, D, Attr);
+ break;
+
default:
// Ask target about the attribute.
const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema();
Added: cfe/trunk/test/SemaCXX/warn-thread-safety.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-thread-safety.cpp?rev=136364&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-thread-safety.cpp (added)
+++ cfe/trunk/test/SemaCXX/warn-thread-safety.cpp Thu Jul 28 12:21:07 2011
@@ -0,0 +1,204 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+/***********************************
+ * No Thread Safety Analysis (noanal)
+ ***********************************/
+
+// FIXME: Right now we cannot parse attributes put on function definitions
+// We would like to patch this at some point.
+
+#if !__has_attribute(no_thread_safety_analysis)
+#error "Should support no_thread_safety_analysis attribute"
+#endif
+
+void noanal_function() __attribute__((no_thread_safety_analysis));
+
+void noanal_function() __attribute__((no_thread_safety_analysis(1))); // \
+ expected-error {{attribute takes no arguments}}
+
+int noanal_testfn(int y) __attribute__((no_thread_safety_analysis));
+
+int noanal_testfn(int y) {
+ int x __attribute__((no_thread_safety_analysis)) = y; // \
+ expected-warning {{'no_thread_safety_analysis' attribute only applies to functions and methods}}
+ return x;
+};
+
+int noanal_test_var __attribute__((no_thread_safety_analysis)); // \
+ expected-warning {{'no_thread_safety_analysis' attribute only applies to functions and methods}}
+
+class NoanalFoo {
+ private:
+ int test_field __attribute__((no_thread_safety_analysis)); // \
+ expected-warning {{'no_thread_safety_analysis' attribute only applies to functions and methods}}
+ void test_method() __attribute__((no_thread_safety_analysis));
+};
+
+class __attribute__((no_thread_safety_analysis)) NoanalTestClass { // \
+ expected-warning {{'no_thread_safety_analysis' attribute only applies to functions and methods}}
+};
+
+void noanal_fun_params(int lvar __attribute__((no_thread_safety_analysis))); // \
+ expected-warning {{'no_thread_safety_analysis' attribute only applies to functions and methods}}
+
+
+/***********************************
+ * Guarded Var Attribute (gv)
+ ***********************************/
+
+#if !__has_attribute(guarded_var)
+#error "Should support guarded_var attribute"
+#endif
+
+int gv_var_noargs __attribute__((guarded_var));
+
+int gv_var_args __attribute__((guarded_var(1))); // \
+ expected-error {{attribute takes no arguments}}
+
+class GVFoo {
+ private:
+ int gv_field_noargs __attribute__((guarded_var));
+ int gv_field_args __attribute__((guarded_var(1))); // \
+ expected-error {{attribute takes no arguments}}
+};
+
+class __attribute__((guarded_var)) GV { // \
+ expected-warning {{'guarded_var' attribute only applies to fields and global variables}}
+};
+
+void gv_function() __attribute__((guarded_var)); // \
+ expected-warning {{'guarded_var' attribute only applies to fields and global variables}}
+
+void gv_function_params(int gv_lvar __attribute__((guarded_var))); // \
+ expected-warning {{'guarded_var' attribute only applies to fields and global variables}}
+
+int gv_testfn(int y){
+ int x __attribute__((guarded_var)) = y; // \
+ expected-warning {{'guarded_var' attribute only applies to fields and global variables}}
+ return x;
+}
+
+/***********************************
+ * Pt Guarded Var Attribute (pgv)
+ ***********************************/
+
+//FIXME: add support for boost::scoped_ptr<int> fancyptr and references
+
+#if !__has_attribute(pt_guarded_var)
+#error "Should support pt_guarded_var attribute"
+#endif
+
+int *pgv_pt_var_noargs __attribute__((pt_guarded_var));
+
+int pgv_var_noargs __attribute__((pt_guarded_var)); // \
+ expected-warning {{'pt_guarded_var' only applies to pointer types; type here is 'int'}}
+
+class PGVFoo {
+ private:
+ int *pt_field_noargs __attribute__((pt_guarded_var));
+ int field_noargs __attribute__((pt_guarded_var)); // \
+ expected-warning {{'pt_guarded_var' only applies to pointer types; type here is 'int'}}
+ int *gv_field_args __attribute__((pt_guarded_var(1))); // \
+ expected-error {{attribute takes no arguments}}
+};
+
+class __attribute__((pt_guarded_var)) PGV { // \
+ expected-warning {{'pt_guarded_var' attribute only applies to fields and global variables}}
+};
+
+int *pgv_var_args __attribute__((pt_guarded_var(1))); // \
+ expected-error {{attribute takes no arguments}}
+
+
+void pgv_function() __attribute__((pt_guarded_var)); // \
+ expected-warning {{'pt_guarded_var' attribute only applies to fields and global variables}}
+
+void pgv_function_params(int *gv_lvar __attribute__((pt_guarded_var))); // \
+ expected-warning {{'pt_guarded_var' attribute only applies to fields and global variables}}
+
+void pgv_testfn(int y){
+ int *x __attribute__((pt_guarded_var)) = new int(0); // \
+ expected-warning {{'pt_guarded_var' attribute only applies to fields and global variables}}
+ delete x;
+}
+
+/***********************************
+ * Lockable Attribute (l)
+ ***********************************/
+
+//FIXME: In future we may want to add support for structs, ObjC classes, etc.
+
+#if !__has_attribute(lockable)
+#error "Should support lockable attribute"
+#endif
+
+class __attribute__((lockable)) LTestClass {
+};
+
+class __attribute__((lockable (1))) LTestClass_args { // \
+ expected-error {{attribute takes no arguments}}
+};
+
+void l_test_function() __attribute__((lockable)); // \
+ expected-warning {{'lockable' attribute only applies to classes}}
+
+int l_testfn(int y) {
+ int x __attribute__((lockable)) = y; // \
+ expected-warning {{'lockable' attribute only applies to classes}}
+ return x;
+}
+
+int l_test_var __attribute__((lockable)); // \
+ expected-warning {{'lockable' attribute only applies to classes}}
+
+class LFoo {
+ private:
+ int test_field __attribute__((lockable)); // \
+ expected-warning {{'lockable' attribute only applies to classes}}
+ void test_method() __attribute__((lockable)); // \
+ expected-warning {{'lockable' attribute only applies to classes}}
+};
+
+
+void l_function_params(int lvar __attribute__((lockable))); // \
+ expected-warning {{'lockable' attribute only applies to classes}}
+
+
+/***********************************
+ * Scoped Lockable Attribute (sl)
+ ***********************************/
+
+#if !__has_attribute(scoped_lockable)
+#error "Should support scoped_lockable attribute"
+#endif
+
+class __attribute__((scoped_lockable)) SLTestClass {
+};
+
+class __attribute__((scoped_lockable (1))) SLTestClass_args { // \
+ expected-error {{attribute takes no arguments}}
+};
+
+void sl_test_function() __attribute__((scoped_lockable)); // \
+ expected-warning {{'scoped_lockable' attribute only applies to classes}}
+
+int sl_testfn(int y) {
+ int x __attribute__((scoped_lockable)) = y; // \
+ expected-warning {{'scoped_lockable' attribute only applies to classes}}
+ return x;
+}
+
+int sl_test_var __attribute__((scoped_lockable)); // \
+ expected-warning {{'scoped_lockable' attribute only applies to classes}}
+
+class SLFoo {
+ private:
+ int test_field __attribute__((scoped_lockable)); // \
+ expected-warning {{'scoped_lockable' attribute only applies to classes}}
+ void test_method() __attribute__((scoped_lockable)); // \
+ expected-warning {{'scoped_lockable' attribute only applies to classes}}
+};
+
+
+void sl_function_params(int lvar __attribute__((scoped_lockable))); // \
+ expected-warning {{'scoped_lockable' attribute only applies to classes}}
More information about the cfe-commits
mailing list