diff --git a/clang/lib/Analysis/CalledOnceCheck.cpp b/clang/lib/Analysis/CalledOnceCheck.cpp --- a/clang/lib/Analysis/CalledOnceCheck.cpp +++ b/clang/lib/Analysis/CalledOnceCheck.cpp @@ -867,16 +867,14 @@ // Let's check if any of the call arguments is a point of interest. for (const auto &Argument : llvm::enumerate(Arguments)) { if (auto Index = getIndexOfExpression(Argument.value())) { - ParameterStatus &CurrentParamStatus = CurrentState.getStatusFor(*Index); - if (shouldBeCalledOnce(CallOrMessage, Argument.index())) { // If the corresponding parameter is marked as 'called_once' we should // consider it as a call. processCallFor(*Index, CallOrMessage); - } else if (CurrentParamStatus.getKind() == ParameterStatus::NotCalled) { + } else { // Otherwise, we mark this parameter as escaped, which can be // interpreted both as called or not called depending on the context. - CurrentParamStatus = ParameterStatus::Escaped; + processEscapeFor(*Index); } // Otherwise, let's keep the state as it is. } @@ -910,6 +908,16 @@ } } + /// Process escape of the parameter with the given index + void processEscapeFor(unsigned Index) { + ParameterStatus &CurrentParamStatus = CurrentState.getStatusFor(Index); + + // Escape overrides whatever error we think happened. + if (CurrentParamStatus.isErrorStatus()) { + CurrentParamStatus = ParameterStatus::Escaped; + } + } + void findAndReportNotCalledBranches(const CFGBlock *Parent, unsigned Index, bool IsEscape = false) { for (const CFGBlock *Succ : Parent->succs()) { @@ -1365,11 +1373,7 @@ /// Check given parameter that was discovered to escape. void checkEscapee(const ParmVarDecl &Parameter) { if (auto Index = getIndex(Parameter)) { - ParameterStatus &CurrentParamStatus = CurrentState.getStatusFor(*Index); - - if (CurrentParamStatus.getKind() == ParameterStatus::NotCalled) { - CurrentParamStatus = ParameterStatus::Escaped; - } + processEscapeFor(*Index); } } diff --git a/clang/test/SemaObjC/warn-called-once.m b/clang/test/SemaObjC/warn-called-once.m --- a/clang/test/SemaObjC/warn-called-once.m +++ b/clang/test/SemaObjC/warn-called-once.m @@ -1130,4 +1130,32 @@ } } +- (void)test_escape_before_branch:(int)cond + withCompletion:(void (^)(void))handler { + if (cond) { + filler(); + } + + void (^copiedHandler)(void) = ^{ + handler(); + }; + + if (cond) { + // no-warning + handler(); + } else { + copiedHandler(); + } +} + +- (void)test_escape_after_branch:(int)cond + withCompletion:(void (^)(void))handler { + if (cond) { + // no-warning + handler(); + } + + escape(handler); +} + @end