summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/lib/Sema/SemaType.cpp42
-rw-r--r--clang/test/Analysis/retain-release.m7
-rw-r--r--clang/test/SemaObjCXX/Inputs/nullability-consistency-8.h16
3 files changed, 62 insertions, 3 deletions
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index d3b773e5350..d950d329b4e 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -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;
}
diff --git a/clang/test/Analysis/retain-release.m b/clang/test/Analysis/retain-release.m
index e3ad4090373..1dbcda507c1 100644
--- a/clang/test/Analysis/retain-release.m
+++ b/clang/test/Analysis/retain-release.m
@@ -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;
diff --git a/clang/test/SemaObjCXX/Inputs/nullability-consistency-8.h b/clang/test/SemaObjCXX/Inputs/nullability-consistency-8.h
index e7cf4b3ee8a..890bb4db546 100644
--- a/clang/test/SemaObjCXX/Inputs/nullability-consistency-8.h
+++ b/clang/test/SemaObjCXX/Inputs/nullability-consistency-8.h
@@ -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);
OpenPOWER on IntegriCloud