CF_RETURNS_[NOT_]RETAINED on a param makes the inner pointer __nullable.

That is,

  void cf2(CFTypeRef * __nullable p CF_RETURNS_NOT_RETAINED);

is equivalent to

  void cf2(CFTypeRef __nullable * __nullable p CF_RETURNS_NOT_RETAINED);

More rdar://problem/18742441

llvm-svn: 240186
This commit is contained in:
Douglas Gregor 2015-06-19 23:17:51 +00:00
parent eb6e64ca8f
commit 9960a8638d
3 changed files with 62 additions and 3 deletions

View File

@ -2614,6 +2614,8 @@ namespace {
SingleLevelPointer,
// Multi-level pointer (of any pointer kind).
MultiLevelPointer,
// CFFooRef*
MaybePointerToCFRef,
// CFErrorRef*
CFErrorRefPointer,
// NSError**
@ -2754,6 +2756,9 @@ static PointerDeclaratorKind classifyPointerDeclarator(Sema &S,
case 1:
return PointerDeclaratorKind::SingleLevelPointer;
case 2:
return PointerDeclaratorKind::MaybePointerToCFRef;
default:
return PointerDeclaratorKind::MultiLevelPointer;
}
@ -2894,6 +2899,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Determine whether we should infer __nonnull on pointer types.
Optional<NullabilityKind> inferNullability;
bool inferNullabilityCS = false;
bool inferNullabilityInnerOnly = false;
bool inferNullabilityInnerOnlyComplete = false;
// Are we in an assume-nonnull region?
bool inAssumeNonNullRegion = false;
@ -3007,6 +3014,31 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
if (isFunctionOrMethod && inAssumeNonNullRegion)
inferNullability = NullabilityKind::Nullable;
break;
case PointerDeclaratorKind::MaybePointerToCFRef:
if (isFunctionOrMethod) {
// On pointer-to-pointer parameters marked cf_returns_retained or
// cf_returns_not_retained, if the outer pointer is explicit then
// infer the inner pointer as __nullable.
auto hasCFReturnsAttr = [](const AttributeList *NextAttr) -> bool {
while (NextAttr) {
if (NextAttr->getKind() == AttributeList::AT_CFReturnsRetained ||
NextAttr->getKind() == AttributeList::AT_CFReturnsNotRetained)
return true;
NextAttr = NextAttr->getNext();
}
return false;
};
if (const auto *InnermostChunk = D.getInnermostNonParenChunk()) {
if (hasCFReturnsAttr(D.getAttributes()) ||
hasCFReturnsAttr(InnermostChunk->getAttrs()) ||
hasCFReturnsAttr(D.getDeclSpec().getAttributes().getList())) {
inferNullability = NullabilityKind::Nullable;
inferNullabilityInnerOnly = true;
}
}
}
break;
}
break;
@ -3047,9 +3079,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
return nullptr;
// If we're supposed to infer nullability, do so now.
if (inferNullability) {
auto syntax = inferNullabilityCS ? AttributeList::AS_ContextSensitiveKeyword
: AttributeList::AS_Keyword;
if (inferNullability && !inferNullabilityInnerOnlyComplete) {
AttributeList::Syntax syntax
= inferNullabilityCS ? AttributeList::AS_ContextSensitiveKeyword
: AttributeList::AS_Keyword;
AttributeList *nullabilityAttr = state.getDeclarator().getAttributePool()
.create(
S.getNullabilityKeyword(
@ -3059,6 +3092,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
nullptr, 0, syntax);
spliceAttrIntoList(*nullabilityAttr, attrs);
if (inferNullabilityInnerOnly)
inferNullabilityInnerOnlyComplete = true;
return nullabilityAttr;
}

View File

@ -2164,6 +2164,13 @@ void testCFReturnsNotRetained() {
CFRelease(obj); // // expected-warning {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
}
void testCFReturnsNotRetainedAnnotated() {
extern void getViaParam2(CFTypeRef * __nonnull CF_RETURNS_NOT_RETAINED outObj);
CFTypeRef obj;
getViaParam2(&obj);
CFRelease(obj); // // expected-warning {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
}
void testCFReturnsRetained() {
extern int copyViaParam(CFTypeRef * CF_RETURNS_RETAINED outObj);
CFTypeRef obj;

View File

@ -9,3 +9,19 @@ void func2(mynonnull i);
void func3(int *); // expected-warning{{pointer is missing a nullability type specifier}}
#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
typedef void *CFTypeRef;
void cf1(CFTypeRef * p CF_RETURNS_NOT_RETAINED); // expected-warning {{pointer is missing a nullability type specifier}}
void cf2(CFTypeRef * __nullable p CF_RETURNS_NOT_RETAINED);
void cf3(CFTypeRef * __nonnull p CF_RETURNS_NOT_RETAINED);
void cf4(CFTypeRef __nullable * __nullable p CF_RETURNS_NOT_RETAINED);
void cf5(CFTypeRef __nonnull * __nullable p CF_RETURNS_NOT_RETAINED);
void cf6(CFTypeRef * __nullable CF_RETURNS_NOT_RETAINED p);
void cf7(CF_RETURNS_NOT_RETAINED CFTypeRef * __nonnull p);
typedef CFTypeRef __nullable *CFTypeRefPtr;
void cfp1(CFTypeRefPtr p CF_RETURNS_NOT_RETAINED); // expected-warning {{pointer is missing a nullability type specifier}}
void cfp2(CFTypeRefPtr __nonnull p CF_RETURNS_NOT_RETAINED);