1*67e74705SXin Li// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fblocks -Wno-objc-root-class -analyze -analyzer-checker=core,deadcode,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s 2*67e74705SXin Li 3*67e74705SXin Liint clang_analyzer_eval(int); 4*67e74705SXin Li 5*67e74705SXin Li@interface Super 6*67e74705SXin Li- (void)superMethod; 7*67e74705SXin Li@end 8*67e74705SXin Li 9*67e74705SXin Li@interface Sub : Super { 10*67e74705SXin Li int _ivar1; 11*67e74705SXin Li int _ivar2; 12*67e74705SXin Li} 13*67e74705SXin Li@end 14*67e74705SXin Li 15*67e74705SXin Li@implementation Sub 16*67e74705SXin Li- (void)callMethodOnSuperInCXXLambda; { 17*67e74705SXin Li // Explicit capture. 18*67e74705SXin Li [self]() { 19*67e74705SXin Li [super superMethod]; 20*67e74705SXin Li }(); 21*67e74705SXin Li 22*67e74705SXin Li // Implicit capture. 23*67e74705SXin Li [=]() { 24*67e74705SXin Li [super superMethod]; 25*67e74705SXin Li }(); 26*67e74705SXin Li} 27*67e74705SXin Li 28*67e74705SXin Li// Make sure to properly handle super-calls when a block captures 29*67e74705SXin Li// a local variable named 'self'. 30*67e74705SXin Li- (void)callMethodOnSuperInCXXLambdaWithRedefinedSelf; { 31*67e74705SXin Li /*__weak*/ Sub *weakSelf = self; 32*67e74705SXin Li // Implicit capture. (Sema outlaws explicit capture of a redefined self 33*67e74705SXin Li // and a call to super [which uses the original self]). 34*67e74705SXin Li [=]() { 35*67e74705SXin Li Sub *self = weakSelf; 36*67e74705SXin Li [=]() { 37*67e74705SXin Li [super superMethod]; 38*67e74705SXin Li }(); 39*67e74705SXin Li }(); 40*67e74705SXin Li} 41*67e74705SXin Li 42*67e74705SXin Li- (void)swapIvars { 43*67e74705SXin Li int tmp = _ivar1; 44*67e74705SXin Li _ivar1 = _ivar2; 45*67e74705SXin Li _ivar2 = tmp; 46*67e74705SXin Li} 47*67e74705SXin Li 48*67e74705SXin Li- (void)callMethodOnSelfInCXXLambda; { 49*67e74705SXin Li _ivar1 = 7; 50*67e74705SXin Li _ivar2 = 8; 51*67e74705SXin Li [self]() { 52*67e74705SXin Li [self swapIvars]; 53*67e74705SXin Li }(); 54*67e74705SXin Li 55*67e74705SXin Li clang_analyzer_eval(_ivar1 == 8); // expected-warning{{TRUE}} 56*67e74705SXin Li clang_analyzer_eval(_ivar2 == 7); // expected-warning{{TRUE}} 57*67e74705SXin Li} 58*67e74705SXin Li 59*67e74705SXin Li@end 60*67e74705SXin Li 61*67e74705SXin Liint getValue(); 62*67e74705SXin Livoid useValue(int v); 63*67e74705SXin Li 64*67e74705SXin Livoid castToBlockNoDeadStore() { 65*67e74705SXin Li int v = getValue(); // no-warning 66*67e74705SXin Li 67*67e74705SXin Li (void)(void(^)())[v]() { // This capture should count as a use, so no dead store warning above. 68*67e74705SXin Li }; 69*67e74705SXin Li} 70*67e74705SXin Li 71*67e74705SXin Livoid takesBlock(void(^block)()); 72*67e74705SXin Li 73*67e74705SXin Livoid passToFunctionTakingBlockNoDeadStore() { 74*67e74705SXin Li int v = 7; // no-warning 75*67e74705SXin Li int x = 8; // no-warning 76*67e74705SXin Li takesBlock([&v, x]() { 77*67e74705SXin Li (void)v; 78*67e74705SXin Li }); 79*67e74705SXin Li} 80*67e74705SXin Li 81*67e74705SXin Livoid castToBlockAndInline() { 82*67e74705SXin Li int result = ((int(^)(int))[](int p) { 83*67e74705SXin Li return p; 84*67e74705SXin Li })(7); 85*67e74705SXin Li 86*67e74705SXin Li clang_analyzer_eval(result == 7); // expected-warning{{TRUE}} 87*67e74705SXin Li} 88*67e74705SXin Li 89*67e74705SXin Livoid castToBlockWithCaptureAndInline() { 90*67e74705SXin Li int y = 7; 91*67e74705SXin Li 92*67e74705SXin Li auto lambda = [y]{ return y; }; 93*67e74705SXin Li int(^block)() = lambda; 94*67e74705SXin Li 95*67e74705SXin Li int result = block(); 96*67e74705SXin Li clang_analyzer_eval(result == 7); // expected-warning{{TRUE}} 97*67e74705SXin Li} 98*67e74705SXin Li 99*67e74705SXin Livoid castMutableLambdaToBlock() { 100*67e74705SXin Li int x = 0; 101*67e74705SXin Li 102*67e74705SXin Li auto lambda = [x]() mutable { 103*67e74705SXin Li x = x + 1; 104*67e74705SXin Li return x; 105*67e74705SXin Li }; 106*67e74705SXin Li 107*67e74705SXin Li // The block should copy the lambda before capturing. 108*67e74705SXin Li int(^block)() = lambda; 109*67e74705SXin Li 110*67e74705SXin Li int r1 = block(); 111*67e74705SXin Li clang_analyzer_eval(r1 == 1); // expected-warning{{TRUE}} 112*67e74705SXin Li 113*67e74705SXin Li int r2 = block(); 114*67e74705SXin Li clang_analyzer_eval(r2 == 2); // expected-warning{{TRUE}} 115*67e74705SXin Li 116*67e74705SXin Li // Because block copied the lambda, r3 should be 1. 117*67e74705SXin Li int r3 = lambda(); 118*67e74705SXin Li clang_analyzer_eval(r3 == 1); // expected-warning{{TRUE}} 119*67e74705SXin Li 120*67e74705SXin Li // Aliasing the block shouldn't copy the lambda. 121*67e74705SXin Li int(^blockAlias)() = block; 122*67e74705SXin Li 123*67e74705SXin Li int r4 = blockAlias(); 124*67e74705SXin Li clang_analyzer_eval(r4 == 3); // expected-warning{{TRUE}} 125*67e74705SXin Li 126*67e74705SXin Li int r5 = block(); 127*67e74705SXin Li clang_analyzer_eval(r5 == 4); // expected-warning{{TRUE}} 128*67e74705SXin Li 129*67e74705SXin Li // Another copy of lambda 130*67e74705SXin Li int(^blockSecondCopy)() = lambda; 131*67e74705SXin Li int r6 = blockSecondCopy(); 132*67e74705SXin Li clang_analyzer_eval(r6 == 2); // expected-warning{{TRUE}} 133*67e74705SXin Li} 134*67e74705SXin Li 135*67e74705SXin Livoid castLambdaInLocalBlock() { 136*67e74705SXin Li // Make sure we don't emit a spurious diagnostic about the address of a block 137*67e74705SXin Li // escaping in the implicit conversion operator method for lambda-to-block 138*67e74705SXin Li // conversions. 139*67e74705SXin Li auto lambda = []{ }; // no-warning 140*67e74705SXin Li 141*67e74705SXin Li void(^block)() = lambda; 142*67e74705SXin Li (void)block; 143*67e74705SXin Li} 144