diff options
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 12 | ||||
| -rw-r--r-- | clang/test/CodeGenCXX/blocks.cpp | 25 | 
2 files changed, 37 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index bc422db8b91..a5b766ad73b 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -8615,6 +8615,10 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) {      PushDeclContext(CurScope, Block);    else      CurContext = Block; + +  // Enter a new evaluation context to insulate the block from any +  // cleanups from the enclosing full-expression. +  PushExpressionEvaluationContext(PotentiallyEvaluated);    }  void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { @@ -8742,6 +8746,10 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {  /// ActOnBlockError - If there is an error parsing a block, this callback  /// is invoked to pop the information about the block from the action impl.  void Sema::ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) { +  // Leave the expression-evaluation context. +  DiscardCleanupsInEvaluationContext(); +  PopExpressionEvaluationContext(); +    // Pop off CurBlock, handle nested blocks.    PopDeclContext();    PopFunctionOrBlockScope(); @@ -8755,6 +8763,10 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,    if (!LangOpts.Blocks)      Diag(CaretLoc, diag::err_blocks_disable); +  // Leave the expression-evaluation context. +  assert(!ExprNeedsCleanups && "cleanups within block not correctly bound!"); +  PopExpressionEvaluationContext(); +    BlockScopeInfo *BSI = cast<BlockScopeInfo>(FunctionScopes.back());    PopDeclContext(); diff --git a/clang/test/CodeGenCXX/blocks.cpp b/clang/test/CodeGenCXX/blocks.cpp index 40faf1bf235..921d94a138a 100644 --- a/clang/test/CodeGenCXX/blocks.cpp +++ b/clang/test/CodeGenCXX/blocks.cpp @@ -178,3 +178,28 @@ namespace test5 {    // CHECK:      call void @_ZN5test51AD1Ev([[A]]* [[X]])    // CHECK-NEXT: ret void  } + +namespace test6 { +  struct A { +    A(); +    ~A(); +  }; + +  void foo(const A &, void (^)()); +  void bar(); + +  void test() { +    // Make sure that the temporary cleanup isn't somehow captured +    // within the block. +    foo(A(), ^{ bar(); }); +    bar(); +  } + +  // CHECK:    define void @_ZN5test64testEv() +  // CHECK:      [[TEMP:%.*]] = alloca [[A:%.*]], align 1 +  // CHECK-NEXT: call void @_ZN5test61AC1Ev([[A]]* [[TEMP]]) +  // CHECK-NEXT: call void @_ZN5test63fooERKNS_1AEU13block_pointerFvvE( +  // CHECK-NEXT: call void @_ZN5test61AD1Ev([[A]]* [[TEMP]]) +  // CHECK-NEXT: call void @_ZN5test63barEv() +  // CHECK-NEXT: ret void +}  | 

