Skip to content

Commit 9cd2413

Browse files
committed
[clang] Add a new nullability annotation for swift async: _Nullable_result
_Nullable_result generally like _Nullable, except when being imported into a swift async method. rdar://70106409 Differential revision: https://reviews.llvm.org/D92495
1 parent 234d88a commit 9cd2413

25 files changed

+176
-11
lines changed

clang/include/clang-c/Index.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3861,7 +3861,15 @@ enum CXTypeNullabilityKind {
38613861
/**
38623862
* Nullability is not applicable to this type.
38633863
*/
3864-
CXTypeNullability_Invalid = 3
3864+
CXTypeNullability_Invalid = 3,
3865+
3866+
/**
3867+
* Generally behaves like Nullable, except when used in a block parameter that
3868+
* was imported into a swift async method. There, swift will assume that the
3869+
* parameter can get null even if no error occured. _Nullable parameters are
3870+
* assumed to only get null on error.
3871+
*/
3872+
CXTypeNullability_NullableResult = 4
38653873
};
38663874

38673875
/**

clang/include/clang/AST/Type.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4716,6 +4716,9 @@ class AttributedType : public Type, public llvm::FoldingSetNode {
47164716
case NullabilityKind::Nullable:
47174717
return attr::TypeNullable;
47184718

4719+
case NullabilityKind::NullableResult:
4720+
return attr::TypeNullableResult;
4721+
47194722
case NullabilityKind::Unspecified:
47204723
return attr::TypeNullUnspecified;
47214724
}

clang/include/clang/Basic/Attr.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1805,6 +1805,11 @@ def TypeNullable : TypeAttr {
18051805
let Documentation = [TypeNullableDocs];
18061806
}
18071807

1808+
def TypeNullableResult : TypeAttr {
1809+
let Spellings = [Keyword<"_Nullable_result">];
1810+
let Documentation = [TypeNullableResultDocs];
1811+
}
1812+
18081813
def TypeNullUnspecified : TypeAttr {
18091814
let Spellings = [Keyword<"_Null_unspecified">];
18101815
let Documentation = [TypeNullUnspecifiedDocs];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3508,6 +3508,29 @@ a caller of ``fetch_or_zero`` can provide null.
35083508
}];
35093509
}
35103510

3511+
def TypeNullableResultDocs : Documentation {
3512+
let Category = NullabilityDocs;
3513+
let Content = [{
3514+
The ``_Nullable_result`` nullability qualifier means that a value of the
3515+
``_Nullable_result`` pointer can be ``nil``, just like ``_Nullable``. Where this
3516+
attribute differs from ``_Nullable`` is when it's used on a parameter to a
3517+
completion handler in a Swift async method. For instance, here:
3518+
3519+
.. code-block:: objc
3520+
3521+
-(void)fetchSomeDataWithID:(int)identifier
3522+
completionHandler:(void (^)(Data *_Nullable_result result, NSError *error))completionHandler;
3523+
3524+
This method asynchronously calls ``completionHandler`` when the data is
3525+
available, or calls it with an error. ``_Nullable_result`` indicates to the
3526+
Swift importer that this is the uncommon case where ``result`` can get ``nil``
3527+
even if no error has occured, and will therefore import it as a Swift optional
3528+
type. Otherwise, if ``result`` was annotated with ``_Nullable``, the Swift
3529+
importer will assume that ``result`` will always be non-nil unless an error
3530+
occured.
3531+
}];
3532+
}
3533+
35113534
def TypeNullUnspecifiedDocs : Documentation {
35123535
let Category = NullabilityDocs;
35133536
let Content = [{

clang/include/clang/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ FEATURE(cxx_rtti, LangOpts.RTTI &&LangOpts.RTTIData)
8585
FEATURE(enumerator_attributes, true)
8686
FEATURE(nullability, true)
8787
FEATURE(nullability_on_arrays, true)
88+
FEATURE(nullability_nullable_result, true)
8889
FEATURE(memory_sanitizer,
8990
LangOpts.Sanitize.hasOneOf(SanitizerKind::Memory |
9091
SanitizerKind::KernelMemory))

clang/include/clang/Basic/Specifiers.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,12 @@ namespace clang {
309309
/// unspecified. This captures a (fairly rare) case where we
310310
/// can't conclude anything about the nullability of the type even
311311
/// though it has been considered.
312-
Unspecified
312+
Unspecified,
313+
// Generally behaves like Nullable, except when used in a block parameter
314+
// that was imported into a swift async method. There, swift will assume
315+
// that the parameter can get null even if no error occured. _Nullable
316+
// parameters are assumed to only get null on error.
317+
NullableResult,
313318
};
314319

315320
/// Return true if \p L has a weaker nullability annotation than \p R. The

clang/include/clang/Basic/TokenKinds.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,7 @@ ALIAS("__volatile__" , volatile , KEYALL)
650650
// Type nullability.
651651
KEYWORD(_Nonnull , KEYALL)
652652
KEYWORD(_Nullable , KEYALL)
653+
KEYWORD(_Nullable_result , KEYALL)
653654
KEYWORD(_Null_unspecified , KEYALL)
654655

655656
// Microsoft extensions which should be disabled in strict conformance mode

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12448,6 +12448,7 @@ class Sema final {
1244812448
/// Nullability type specifiers.
1244912449
IdentifierInfo *Ident__Nonnull = nullptr;
1245012450
IdentifierInfo *Ident__Nullable = nullptr;
12451+
IdentifierInfo *Ident__Nullable_result = nullptr;
1245112452
IdentifierInfo *Ident__Null_unspecified = nullptr;
1245212453

1245312454
IdentifierInfo *Ident_NSError = nullptr;

clang/lib/APINotes/APINotesYAMLCompiler.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ template <> struct ScalarEnumerationTraits<NullabilityKind> {
8989
IO.enumCase(NK, "Nonnull", NullabilityKind::NonNull);
9090
IO.enumCase(NK, "Optional", NullabilityKind::Nullable);
9191
IO.enumCase(NK, "Unspecified", NullabilityKind::Unspecified);
92+
IO.enumCase(NK, "NullableResult", NullabilityKind::NullableResult);
9293
// TODO: Mapping this to it's own value would allow for better cross
9394
// checking. Also the default should be Unknown.
9495
IO.enumCase(NK, "Scalar", NullabilityKind::Unspecified);

clang/lib/AST/Type.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3512,6 +3512,7 @@ bool AttributedType::isQualifier() const {
35123512
case attr::ObjCInertUnsafeUnretained:
35133513
case attr::TypeNonNull:
35143514
case attr::TypeNullable:
3515+
case attr::TypeNullableResult:
35153516
case attr::TypeNullUnspecified:
35163517
case attr::LifetimeBound:
35173518
case attr::AddressSpace:
@@ -4159,6 +4160,8 @@ AttributedType::getImmediateNullability() const {
41594160
return NullabilityKind::Nullable;
41604161
if (getAttrKind() == attr::TypeNullUnspecified)
41614162
return NullabilityKind::Unspecified;
4163+
if (getAttrKind() == attr::TypeNullableResult)
4164+
return NullabilityKind::NullableResult;
41624165
return None;
41634166
}
41644167

clang/lib/AST/TypePrinter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1579,6 +1579,8 @@ void TypePrinter::printAttributedBefore(const AttributedType *T,
15791579
OS << " _Nullable";
15801580
else if (T->getAttrKind() == attr::TypeNullUnspecified)
15811581
OS << " _Null_unspecified";
1582+
else if (T->getAttrKind() == attr::TypeNullableResult)
1583+
OS << " _Nullable_result";
15821584
else
15831585
llvm_unreachable("unhandled nullability");
15841586
spaceBeforePlaceHolder(OS);
@@ -1649,6 +1651,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
16491651
case attr::LifetimeBound:
16501652
case attr::TypeNonNull:
16511653
case attr::TypeNullable:
1654+
case attr::TypeNullableResult:
16521655
case attr::TypeNullUnspecified:
16531656
case attr::ObjCGC:
16541657
case attr::ObjCInertUnsafeUnretained:

clang/lib/Basic/Diagnostic.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB,
5555
case NullabilityKind::Unspecified:
5656
string = nullability.second ? "'null_unspecified'" : "'_Null_unspecified'";
5757
break;
58+
59+
case NullabilityKind::NullableResult:
60+
assert(!nullability.second &&
61+
"_Nullable_result isn't supported as context-sensitive keyword");
62+
string = "_Nullable_result";
63+
break;
5864
}
5965

6066
DB.AddString(string);

clang/lib/Basic/IdentifierTable.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,11 @@ StringRef clang::getNullabilitySpelling(NullabilityKind kind,
714714
case NullabilityKind::Nullable:
715715
return isContextSensitive ? "nullable" : "_Nullable";
716716

717+
case NullabilityKind::NullableResult:
718+
assert(!isContextSensitive &&
719+
"_Nullable_result isn't supported as context-sensitive keyword");
720+
return "_Nullable_result";
721+
717722
case NullabilityKind::Unspecified:
718723
return isContextSensitive ? "null_unspecified" : "_Null_unspecified";
719724
}

clang/lib/Parse/ParseDecl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,7 @@ void Parser::ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs) {
833833
switch (Tok.getKind()) {
834834
case tok::kw__Nonnull:
835835
case tok::kw__Nullable:
836+
case tok::kw__Nullable_result:
836837
case tok::kw__Null_unspecified: {
837838
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
838839
SourceLocation AttrNameLoc = ConsumeToken();
@@ -3536,6 +3537,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
35363537
// Nullability type specifiers.
35373538
case tok::kw__Nonnull:
35383539
case tok::kw__Nullable:
3540+
case tok::kw__Nullable_result:
35393541
case tok::kw__Null_unspecified:
35403542
ParseNullabilityTypeSpecifiers(DS.getAttributes());
35413543
continue;
@@ -5022,6 +5024,7 @@ bool Parser::isTypeSpecifierQualifier() {
50225024

50235025
case tok::kw__Nonnull:
50245026
case tok::kw__Nullable:
5027+
case tok::kw__Nullable_result:
50255028
case tok::kw__Null_unspecified:
50265029

50275030
case tok::kw___kindof:
@@ -5249,6 +5252,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
52495252

52505253
case tok::kw__Nonnull:
52515254
case tok::kw__Nullable:
5255+
case tok::kw__Nullable_result:
52525256
case tok::kw__Null_unspecified:
52535257

52545258
case tok::kw___kindof:
@@ -5524,6 +5528,7 @@ void Parser::ParseTypeQualifierListOpt(
55245528
// Nullability type specifiers.
55255529
case tok::kw__Nonnull:
55265530
case tok::kw__Nullable:
5531+
case tok::kw__Nullable_result:
55275532
case tok::kw__Null_unspecified:
55285533
ParseNullabilityTypeSpecifiers(DS.getAttributes());
55295534
continue;

clang/lib/Parse/ParseTentative.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -842,7 +842,8 @@ Parser::TPResult Parser::TryParsePtrOperatorSeq() {
842842

843843
while (Tok.isOneOf(tok::kw_const, tok::kw_volatile, tok::kw_restrict,
844844
tok::kw__Nonnull, tok::kw__Nullable,
845-
tok::kw__Null_unspecified, tok::kw__Atomic))
845+
tok::kw__Nullable_result, tok::kw__Null_unspecified,
846+
tok::kw__Atomic))
846847
ConsumeToken();
847848
} else {
848849
return TPResult::True;
@@ -1437,6 +1438,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
14371438
case tok::kw___unaligned:
14381439
case tok::kw__Nonnull:
14391440
case tok::kw__Nullable:
1441+
case tok::kw__Nullable_result:
14401442
case tok::kw__Null_unspecified:
14411443
case tok::kw___kindof:
14421444
return TPResult::True;

clang/lib/Sema/Sema.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,8 @@ void Sema::diagnoseNullableToNonnullConversion(QualType DstType,
503503
QualType SrcType,
504504
SourceLocation Loc) {
505505
Optional<NullabilityKind> ExprNullability = SrcType->getNullability(Context);
506-
if (!ExprNullability || *ExprNullability != NullabilityKind::Nullable)
506+
if (!ExprNullability || (*ExprNullability != NullabilityKind::Nullable &&
507+
*ExprNullability != NullabilityKind::NullableResult))
507508
return;
508509

509510
Optional<NullabilityKind> TypeNullability = DstType->getNullability(Context);

clang/lib/Sema/SemaCodeComplete.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2700,6 +2700,10 @@ static std::string formatObjCParamQualifiers(unsigned ObjCQuals,
27002700
case NullabilityKind::Unspecified:
27012701
Result += "null_unspecified ";
27022702
break;
2703+
2704+
case NullabilityKind::NullableResult:
2705+
llvm_unreachable("Not supported as a context-sensitive keyword!");
2706+
break;
27032707
}
27042708
}
27052709
}

clang/lib/Sema/SemaExpr.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8562,8 +8562,12 @@ static QualType computeConditionalNullability(QualType ResTy, bool IsBin,
85628562

85638563
auto GetNullability = [&Ctx](QualType Ty) {
85648564
Optional<NullabilityKind> Kind = Ty->getNullability(Ctx);
8565-
if (Kind)
8565+
if (Kind) {
8566+
// For our purposes, treat _Nullable_result as _Nullable.
8567+
if (*Kind == NullabilityKind::NullableResult)
8568+
return NullabilityKind::Nullable;
85668569
return *Kind;
8570+
}
85678571
return NullabilityKind::Unspecified;
85688572
};
85698573

clang/lib/Sema/SemaExprObjC.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,12 +1563,20 @@ QualType Sema::getMessageSendResultType(const Expr *Receiver,
15631563

15641564
// Map the nullability of the result into a table index.
15651565
unsigned receiverNullabilityIdx = 0;
1566-
if (auto nullability = ReceiverType->getNullability(Context))
1566+
if (Optional<NullabilityKind> nullability =
1567+
ReceiverType->getNullability(Context)) {
1568+
if (*nullability == NullabilityKind::NullableResult)
1569+
nullability = NullabilityKind::Nullable;
15671570
receiverNullabilityIdx = 1 + static_cast<unsigned>(*nullability);
1571+
}
15681572

15691573
unsigned resultNullabilityIdx = 0;
1570-
if (auto nullability = resultType->getNullability(Context))
1574+
if (Optional<NullabilityKind> nullability =
1575+
resultType->getNullability(Context)) {
1576+
if (*nullability == NullabilityKind::NullableResult)
1577+
nullability = NullabilityKind::Nullable;
15711578
resultNullabilityIdx = 1 + static_cast<unsigned>(*nullability);
1579+
}
15721580

15731581
// The table of nullability mappings, indexed by the receiver's nullability
15741582
// and then the result type's nullability.

clang/lib/Sema/SemaType.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr,
147147
#define NULLABILITY_TYPE_ATTRS_CASELIST \
148148
case ParsedAttr::AT_TypeNonNull: \
149149
case ParsedAttr::AT_TypeNullable: \
150+
case ParsedAttr::AT_TypeNullableResult: \
150151
case ParsedAttr::AT_TypeNullUnspecified
151152

152153
namespace {
@@ -3893,6 +3894,11 @@ IdentifierInfo *Sema::getNullabilityKeyword(NullabilityKind nullability) {
38933894
Ident__Nullable = PP.getIdentifierInfo("_Nullable");
38943895
return Ident__Nullable;
38953896

3897+
case NullabilityKind::NullableResult:
3898+
if (!Ident__Nullable_result)
3899+
Ident__Nullable_result = PP.getIdentifierInfo("_Nullable_result");
3900+
return Ident__Nullable_result;
3901+
38963902
case NullabilityKind::Unspecified:
38973903
if (!Ident__Null_unspecified)
38983904
Ident__Null_unspecified = PP.getIdentifierInfo("_Null_unspecified");
@@ -3915,6 +3921,7 @@ static bool hasNullabilityAttr(const ParsedAttributesView &attrs) {
39153921
for (const ParsedAttr &AL : attrs) {
39163922
if (AL.getKind() == ParsedAttr::AT_TypeNonNull ||
39173923
AL.getKind() == ParsedAttr::AT_TypeNullable ||
3924+
AL.getKind() == ParsedAttr::AT_TypeNullableResult ||
39183925
AL.getKind() == ParsedAttr::AT_TypeNullUnspecified)
39193926
return true;
39203927
}
@@ -4333,6 +4340,9 @@ static Attr *createNullabilityAttr(ASTContext &Ctx, ParsedAttr &Attr,
43334340
case NullabilityKind::Nullable:
43344341
return createSimpleAttr<TypeNullableAttr>(Ctx, Attr);
43354342

4343+
case NullabilityKind::NullableResult:
4344+
return createSimpleAttr<TypeNullableResultAttr>(Ctx, Attr);
4345+
43364346
case NullabilityKind::Unspecified:
43374347
return createSimpleAttr<TypeNullUnspecifiedAttr>(Ctx, Attr);
43384348
}
@@ -7008,6 +7018,9 @@ static NullabilityKind mapNullabilityAttrKind(ParsedAttr::Kind kind) {
70087018
case ParsedAttr::AT_TypeNullable:
70097019
return NullabilityKind::Nullable;
70107020

7021+
case ParsedAttr::AT_TypeNullableResult:
7022+
return NullabilityKind::NullableResult;
7023+
70117024
case ParsedAttr::AT_TypeNullUnspecified:
70127025
return NullabilityKind::Unspecified;
70137026

clang/test/Index/nullability.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ int *a;
22
int * _Nonnull b;
33
int * _Nullable c;
44
int * _Null_unspecified d;
5+
int * _Nullable_result e;
56

67
// RUN: env CINDEXTEST_INCLUDE_ATTRIBUTED_TYPES=1 c-index-test -test-print-type %s | FileCheck %s
78
// CHECK: VarDecl=a:1:6 [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
89
// CHECK: VarDecl=b:2:16 [type=int * _Nonnull] [typekind=Attributed] [nullability=nonnull] [canonicaltype=int *] [canonicaltypekind=Pointer] [modifiedtype=int *] [modifiedtypekind=Pointer] [isPOD=1]
910
// CHECK: VarDecl=c:3:17 [type=int * _Nullable] [typekind=Attributed] [nullability=nullable] [canonicaltype=int *] [canonicaltypekind=Pointer] [modifiedtype=int *] [modifiedtypekind=Pointer] [isPOD=1]
1011
// CHECK: VarDecl=d:4:25 [type=int * _Null_unspecified] [typekind=Attributed] [nullability=unspecified] [canonicaltype=int *] [canonicaltypekind=Pointer] [modifiedtype=int *] [modifiedtypekind=Pointer] [isPOD=1]
12+
// CHECK: VarDecl=e:5:24 [type=int * _Nullable_result] [typekind=Attributed] [nullability=nullable_result] [canonicaltype=int *] [canonicaltypekind=Pointer] [modifiedtype=int *] [modifiedtypekind=Pointer] [isPOD=1]

clang/test/SemaObjC/nullability.m

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,13 @@ - (id)returnsNone;
116116
- (nonnull id)returnsNonNull;
117117
- (nullable id)returnsNullable;
118118
- (null_unspecified id)returnsNullUnspecified;
119+
- (_Nullable_result id)returnsNullableResult;
119120
@end
120121

121122
void test_receiver_merge(NSMergeReceiver *none,
122123
_Nonnull NSMergeReceiver *nonnull,
123124
_Nullable NSMergeReceiver *nullable,
125+
_Nullable_result NSMergeReceiver *nullable_result,
124126
_Null_unspecified NSMergeReceiver *null_unspecified) {
125127
int *ptr;
126128

@@ -129,6 +131,12 @@ void test_receiver_merge(NSMergeReceiver *none,
129131
ptr = [nullable returnsNonNull]; // expected-warning{{'id _Nullable'}}
130132
ptr = [nullable returnsNone]; // expected-warning{{'id _Nullable'}}
131133

134+
ptr = [nullable_result returnsNullable]; // expected-warning{{'id _Nullable'}}
135+
ptr = [nullable_result returnsNullUnspecified]; // expected-warning{{'id _Nullable'}}
136+
ptr = [nullable_result returnsNonNull]; // expected-warning{{'id _Nullable'}}
137+
ptr = [nullable_result returnsNone]; // expected-warning{{'id _Nullable'}}
138+
ptr = [nullable_result returnsNullableResult]; // expected-warning{{'id _Nullable_result'}}
139+
132140
ptr = [null_unspecified returnsNullable]; // expected-warning{{'id _Nullable'}}
133141
ptr = [null_unspecified returnsNullUnspecified]; // expected-warning{{'id _Null_unspecified'}}
134142
ptr = [null_unspecified returnsNonNull]; // expected-warning{{'id _Null_unspecified'}}
@@ -237,6 +245,7 @@ void conditional_expr(int c) {
237245
NSFoo * _Nonnull nonnullP;
238246
NSFoo * _Nullable nullableP;
239247
NSFoo * _Null_unspecified unspecifiedP;
248+
NSFoo * _Nullable_result nullableResultP;
240249
NSFoo *noneP;
241250

242251
p = c ? nonnullP : nonnullP;
@@ -255,6 +264,10 @@ void conditional_expr(int c) {
255264
p = c ? noneP : nullableP; // expected-warning{{implicit conversion from nullable pointer 'NSFoo * _Nullable' to non-nullable pointer type 'NSFoo * _Nonnull'}}
256265
p = c ? noneP : unspecifiedP;
257266
p = c ? noneP : noneP;
267+
p = c ? noneP : nullableResultP; // expected-warning{{implicit conversion from nullable pointer 'NSFoo * _Nullable' to non-nullable pointer type 'NSFoo * _Nonnull'}}
268+
p = c ? nonnullP : nullableResultP; // expected-warning{{implicit conversion from nullable pointer 'NSFoo * _Nullable' to non-nullable pointer type 'NSFoo * _Nonnull'}}
269+
p = c ? nullableP : nullableResultP; // expected-warning{{implicit conversion from nullable pointer 'NSFoo * _Nullable' to non-nullable pointer type 'NSFoo * _Nonnull'}}
270+
p = c ? nullableResultP : nullableResultP; // expected-warning{{implicit conversion from nullable pointer 'NSFoo * _Nullable_result' to non-nullable pointer type 'NSFoo * _Nonnull'}}
258271
}
259272

260273
typedef int INTS[4];

0 commit comments

Comments
 (0)