Bug 1255894: Allow capturing `this` in lambda expressions when marked safe. r?mystor draft
authorKris Maglione <maglione.k@gmail.com>
Sat, 08 Apr 2017 11:52:04 -0700
changeset 558951 6269de5619d3d781029130f6a5b1893931234364
parent 503931 45da67ddd151c81b665864957cb13d40f6fab055
child 558952 a4fb51b7c0d2027666f91a1bc1833801163b69a2
push id52994
push usermaglione.k@gmail.com
push dateSat, 08 Apr 2017 18:56:00 +0000
reviewersmystor
bugs1255894
milestone55.0a1
Bug 1255894: Allow capturing `this` in lambda expressions when marked safe. r?mystor MozReview-Commit-ID: E9suVDbOZKY
build/clang-plugin/CustomTypeAnnotation.cpp
build/clang-plugin/CustomTypeAnnotation.h
build/clang-plugin/RefCountedInsideLambdaChecker.cpp
mfbt/Attributes.h
--- a/build/clang-plugin/CustomTypeAnnotation.cpp
+++ b/build/clang-plugin/CustomTypeAnnotation.cpp
@@ -12,16 +12,18 @@ CustomTypeAnnotation GlobalClass =
 CustomTypeAnnotation NonHeapClass =
     CustomTypeAnnotation("moz_nonheap_class", "non-heap");
 CustomTypeAnnotation HeapClass =
     CustomTypeAnnotation("moz_heap_class", "heap");
 CustomTypeAnnotation NonTemporaryClass =
     CustomTypeAnnotation("moz_non_temporary_class", "non-temporary");
 CustomTypeAnnotation NonParam =
     CustomTypeAnnotation("moz_non_param", "non-param");
+CustomTypeAnnotation SafeForLambdaCapture =
+    CustomTypeAnnotation("moz_safe_for_lambda_capture", "lambda-safe");
 
 void CustomTypeAnnotation::dumpAnnotationReason(BaseCheck &Check,
                                                 QualType T,
                                                 SourceLocation Loc) {
   const char* Inherits =
       "%1 is a %0 type because it inherits from a %0 type %2";
   const char* Member =
       "%1 is a %0 type because member %2 is a %0 type %3";
--- a/build/clang-plugin/CustomTypeAnnotation.h
+++ b/build/clang-plugin/CustomTypeAnnotation.h
@@ -63,10 +63,11 @@ protected:
 };
 
 extern CustomTypeAnnotation StackClass;
 extern CustomTypeAnnotation GlobalClass;
 extern CustomTypeAnnotation NonHeapClass;
 extern CustomTypeAnnotation HeapClass;
 extern CustomTypeAnnotation NonTemporaryClass;
 extern CustomTypeAnnotation NonParam;
+extern CustomTypeAnnotation SafeForLambdaCapture;
 
 #endif
--- a/build/clang-plugin/RefCountedInsideLambdaChecker.cpp
+++ b/build/clang-plugin/RefCountedInsideLambdaChecker.cpp
@@ -103,17 +103,17 @@ void RefCountedInsideLambdaChecker::chec
     }
   }
 
   // Now we can go through and produce errors for any captured variables or this pointers.
   for (const LambdaCapture& Capture : Lambda->captures()) {
     if (Capture.capturesVariable()) {
       QualType Pointee = Capture.getCapturedVar()->getType()->getPointeeType();
 
-      if (!Pointee.isNull() && isClassRefCounted(Pointee)) {
+      if (!Pointee.isNull() && isClassRefCounted(Pointee) && !SafeForLambdaCapture.hasEffectiveAnnotation(Pointee)) {
         emitDiagnostics(Capture.getLocation(), Capture.getCapturedVar()->getName(), Pointee);
         return;
       }
     }
 
     // The situation with captures of `this` is more complex. All captures of
     // `this` look the same-ish (they are LCK_This). We want to complain about
     // captures of `this` where `this` is a refcounted type, and the capture is
@@ -135,15 +135,15 @@ void RefCountedInsideLambdaChecker::chec
         return;
       }
     }
   }
 }
 
 bool RefCountedInsideLambdaChecker::ThisVisitor::VisitCXXThisExpr(CXXThisExpr *This) {
   QualType Pointee = This->getType()->getPointeeType();
-  if (!Pointee.isNull() && isClassRefCounted(Pointee)) {
+  if (!Pointee.isNull() && isClassRefCounted(Pointee) && !SafeForLambdaCapture.hasEffectiveAnnotation(Pointee)) {
     Checker.emitDiagnostics(This->getLocStart(), "this", Pointee);
     return false;
   }
 
   return true;
 }
--- a/mfbt/Attributes.h
+++ b/mfbt/Attributes.h
@@ -462,16 +462,19 @@
  *
  *   Examples include an nsIAtom* member which is known at compile time to point to a
  *   static atom which is valid throughout the lifetime of the program, or an API which
  *   stores a pointer, but doesn't take ownership over it, instead requiring the API
  *   consumer to correctly null the value before it becomes invalid.
  *
  *   Use of this annotation is discouraged when a strong reference or one of the above
  *   two annotations can be used instead.
+ * MOZ_SAFE_FOR_LAMBDA_CAPTURE: Applies to class declarations. Allows `this` to
+ *   be captured by value in lambda expressions, for classes which ensure that a
+ *   reference is kept alive for the lifetime of all such lambdas.
  * MOZ_NO_ADDREF_RELEASE_ON_RETURN: Applies to function declarations.  Makes it
  *   a compile time error to call AddRef or Release on the return value of a
  *   function.  This is intended to be used with operator->() of our smart
  *   pointer classes to ensure that the refcount of an object wrapped in a
  *   smart pointer is not manipulated directly.
  * MOZ_MUST_USE_TYPE: Applies to type declarations.  Makes it a compile time
  *   error to not use the return value of a function which has this type.  This
  *   is intended to be used with types which it is an error to not use.
@@ -537,16 +540,17 @@
 #    define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class"))) \
             MOZ_TRIVIAL_CTOR_DTOR
 #  endif
 #  define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
 #  define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT __attribute__((annotate("moz_no_arith_expr_in_arg")))
 #  define MOZ_OWNING_REF __attribute__((annotate("moz_strong_ref")))
 #  define MOZ_NON_OWNING_REF __attribute__((annotate("moz_weak_ref")))
 #  define MOZ_UNSAFE_REF(reason) __attribute__((annotate("moz_weak_ref")))
+#  define MOZ_SAFE_FOR_LAMBDA_CAPTURE __attribute__((annotate("moz_safe_for_lambda_capture")))
 #  define MOZ_NO_ADDREF_RELEASE_ON_RETURN __attribute__((annotate("moz_no_addref_release_on_return")))
 #  define MOZ_MUST_USE_TYPE __attribute__((annotate("moz_must_use_type")))
 #  define MOZ_NEEDS_NO_VTABLE_TYPE __attribute__((annotate("moz_needs_no_vtable_type")))
 #  define MOZ_NON_MEMMOVABLE __attribute__((annotate("moz_non_memmovable")))
 #  define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type")))
 #  define MOZ_NEEDS_MEMMOVABLE_MEMBERS __attribute__((annotate("moz_needs_memmovable_members")))
 #  define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS \
     __attribute__((annotate("moz_inherit_type_annotations_from_template_args")))
@@ -582,16 +586,17 @@
 #  define MOZ_TRIVIAL_CTOR_DTOR /* nothing */
 #  define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS /* nothing */
 #  define MOZ_IMPLICIT /* nothing */
 #  define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT /* nothing */
 #  define MOZ_HEAP_ALLOCATOR /* nothing */
 #  define MOZ_OWNING_REF /* nothing */
 #  define MOZ_NON_OWNING_REF /* nothing */
 #  define MOZ_UNSAFE_REF(reason) /* nothing */
+#  define MOZ_SAFE_FOR_LAMBDA_CAPTURE /* nothing */
 #  define MOZ_NO_ADDREF_RELEASE_ON_RETURN /* nothing */
 #  define MOZ_MUST_USE_TYPE /* nothing */
 #  define MOZ_NEEDS_NO_VTABLE_TYPE /* nothing */
 #  define MOZ_NON_MEMMOVABLE /* nothing */
 #  define MOZ_NEEDS_MEMMOVABLE_TYPE /* nothing */
 #  define MOZ_NEEDS_MEMMOVABLE_MEMBERS /* nothing */
 #  define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS /* nothing */
 #  define MOZ_INIT_OUTSIDE_CTOR /* nothing */