| // RUN: %clang_analyze_cc1 -std=c++11 -fblocks -Wno-objc-root-class -analyzer-checker=core,deadcode,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s | 
 |  | 
 | int clang_analyzer_eval(int); | 
 |  | 
 | @interface Super | 
 | - (void)superMethod; | 
 | @end | 
 |  | 
 | @interface Sub : Super { | 
 |   int _ivar1; | 
 |   int _ivar2; | 
 | } | 
 | @end | 
 |  | 
 | @implementation Sub | 
 | - (void)callMethodOnSuperInCXXLambda; { | 
 |   // Explicit capture. | 
 |   [self]() { | 
 |     [super superMethod]; | 
 |   }(); | 
 |  | 
 |   // Implicit capture. | 
 |   [=]() { | 
 |     [super superMethod]; | 
 |   }(); | 
 | } | 
 |  | 
 | // Make sure to properly handle super-calls when a block captures | 
 | // a local variable named 'self'. | 
 | - (void)callMethodOnSuperInCXXLambdaWithRedefinedSelf; { | 
 |   /*__weak*/ Sub *weakSelf = self; | 
 |   // Implicit capture. (Sema outlaws explicit capture of a redefined self | 
 |   // and a call to super [which uses the original self]). | 
 |   [=]() { | 
 |     Sub *self = weakSelf; | 
 |     [=]() { | 
 |       [super superMethod]; | 
 |     }(); | 
 |   }(); | 
 | } | 
 |  | 
 | - (void)swapIvars { | 
 |   int tmp = _ivar1; | 
 |   _ivar1 = _ivar2; | 
 |   _ivar2 = tmp; | 
 | } | 
 |  | 
 | - (void)callMethodOnSelfInCXXLambda; { | 
 |   _ivar1 = 7; | 
 |   _ivar2 = 8; | 
 |   [self]() { | 
 |     [self swapIvars]; | 
 |   }(); | 
 |  | 
 |   clang_analyzer_eval(_ivar1 == 8); // expected-warning{{TRUE}} | 
 |   clang_analyzer_eval(_ivar2 == 7); // expected-warning{{TRUE}} | 
 | } | 
 |  | 
 | @end | 
 |  | 
 | int getValue(); | 
 | void useValue(int v); | 
 |  | 
 | void castToBlockNoDeadStore() { | 
 |   int v = getValue(); // no-warning | 
 |  | 
 |   (void)(void(^)())[v]() { // This capture should count as a use, so no dead store warning above. | 
 |   }; | 
 | } | 
 |  | 
 | void takesBlock(void(^block)()); | 
 |  | 
 | void passToFunctionTakingBlockNoDeadStore() { | 
 |   int v = 7; // no-warning | 
 |   int x = 8; // no-warning | 
 |   takesBlock([&v, x]() { | 
 |     (void)v; | 
 |   }); | 
 | } | 
 |  | 
 | void castToBlockAndInline() { | 
 |   int result = ((int(^)(int))[](int p) { | 
 |     return p; | 
 |   })(7); | 
 |  | 
 |   clang_analyzer_eval(result == 7); // expected-warning{{TRUE}} | 
 | } | 
 |  | 
 | void castToBlockWithCaptureAndInline() { | 
 |   int y = 7; | 
 |  | 
 |   auto lambda = [y]{ return y; }; | 
 |   int(^block)() = lambda; | 
 |  | 
 |   int result = block(); | 
 |   clang_analyzer_eval(result == 7); // expected-warning{{TRUE}} | 
 | } | 
 |  | 
 | void castMutableLambdaToBlock() { | 
 |   int x = 0; | 
 |  | 
 |   auto lambda = [x]() mutable { | 
 |     x = x + 1; | 
 |     return x; | 
 |    }; | 
 |  | 
 |   // The block should copy the lambda before capturing. | 
 |   int(^block)() = lambda; | 
 |  | 
 |   int r1 = block(); | 
 |   clang_analyzer_eval(r1 == 1); // expected-warning{{TRUE}} | 
 |  | 
 |   int r2 = block(); | 
 |   clang_analyzer_eval(r2 == 2); // expected-warning{{TRUE}} | 
 |  | 
 |   // Because block copied the lambda, r3 should be 1. | 
 |   int r3 = lambda(); | 
 |   clang_analyzer_eval(r3 == 1); // expected-warning{{TRUE}} | 
 |  | 
 |   // Aliasing the block shouldn't copy the lambda. | 
 |   int(^blockAlias)() = block; | 
 |  | 
 |   int r4 = blockAlias(); | 
 |   clang_analyzer_eval(r4 == 3); // expected-warning{{TRUE}} | 
 |  | 
 |   int r5 = block(); | 
 |   clang_analyzer_eval(r5 == 4); // expected-warning{{TRUE}} | 
 |  | 
 |   // Another copy of lambda | 
 |   int(^blockSecondCopy)() = lambda; | 
 |   int r6 = blockSecondCopy(); | 
 |   clang_analyzer_eval(r6 == 2); // expected-warning{{TRUE}} | 
 | } | 
 |  | 
 | void castLambdaInLocalBlock() { | 
 |   // Make sure we don't emit a spurious diagnostic about the address of a block | 
 |   // escaping in the implicit conversion operator method for lambda-to-block | 
 |   // conversions. | 
 |   auto lambda = []{ }; // no-warning | 
 |  | 
 |   void(^block)() = lambda; | 
 |   (void)block; | 
 | } |