forked from OSchip/llvm-project
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:
parent
eb6e64ca8f
commit
9960a8638d
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue