Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit c99daf4

Browse files
authored
Merge pull request #24 from apple/api-notes-noescape
[API Notes] Add support for parameters, 'noescape' attribute <rdar://problem/27256643>
2 parents 436c6fc + f115f82 commit c99daf4

File tree

10 files changed

+173
-19
lines changed

10 files changed

+173
-19
lines changed

include/clang/APINotes/Types.h

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,6 @@ class VariableInfo : public CommonEntityInfo {
268268
Nullable = static_cast<unsigned>(kind);
269269
}
270270

271-
272271
friend bool operator==(const VariableInfo &lhs, const VariableInfo &rhs) {
273272
return static_cast<const CommonEntityInfo &>(lhs) == rhs &&
274273
lhs.NullabilityAudited == rhs.NullabilityAudited &&
@@ -279,6 +278,13 @@ class VariableInfo : public CommonEntityInfo {
279278
return !(lhs == rhs);
280279
}
281280

281+
friend VariableInfo &operator|=(VariableInfo &lhs,
282+
const VariableInfo &rhs) {
283+
static_cast<CommonEntityInfo &>(lhs) |= rhs;
284+
if (!lhs.NullabilityAudited && rhs.NullabilityAudited)
285+
lhs.setNullabilityAudited(*rhs.getNullability());
286+
return lhs;
287+
}
282288
};
283289

284290
/// Describes API notes data for an Objective-C property.
@@ -300,6 +306,34 @@ class ObjCPropertyInfo : public VariableInfo {
300306
}
301307
};
302308

309+
/// Describes a function or method parameter.
310+
class ParamInfo : public VariableInfo {
311+
/// Whether the this parameter has the 'noescape' attribute.
312+
unsigned NoEscape : 1;
313+
314+
public:
315+
ParamInfo() : VariableInfo(), NoEscape(false) { }
316+
317+
bool isNoEscape() const { return NoEscape; }
318+
void setNoEscape(bool noescape) { NoEscape = noescape; }
319+
320+
friend ParamInfo &operator|=(ParamInfo &lhs, const ParamInfo &rhs) {
321+
static_cast<VariableInfo &>(lhs) |= rhs;
322+
if (!lhs.NoEscape && rhs.NoEscape)
323+
lhs.NoEscape = true;
324+
return lhs;
325+
}
326+
327+
friend bool operator==(const ParamInfo &lhs, const ParamInfo &rhs) {
328+
return static_cast<const VariableInfo &>(lhs) == rhs &&
329+
lhs.NoEscape == rhs.NoEscape;
330+
}
331+
332+
friend bool operator!=(const ParamInfo &lhs, const ParamInfo &rhs) {
333+
return !(lhs == rhs);
334+
}
335+
};
336+
303337
/// A temporary reference to an Objective-C selector, suitable for
304338
/// referencing selector data on the stack.
305339
///
@@ -333,6 +367,9 @@ class FunctionInfo : public CommonEntityInfo {
333367
// of the parameters.
334368
uint64_t NullabilityPayload = 0;
335369

370+
/// The function parameters.
371+
std::vector<ParamInfo> Params;
372+
336373
FunctionInfo()
337374
: CommonEntityInfo(),
338375
NullabilityAudited(false),

lib/APINotes/APINotesFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const uint16_t VERSION_MAJOR = 0;
3535
/// API notes file minor version number.
3636
///
3737
/// When the format changes IN ANY WAY, this number should be incremented.
38-
const uint16_t VERSION_MINOR = 12; // SwiftPrivate
38+
const uint16_t VERSION_MINOR = 13; // Function/method parameters
3939

4040
using IdentifierID = Fixnum<31>;
4141
using IdentifierIDField = BCVBR<16>;

lib/APINotes/APINotesReader.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,22 @@ namespace {
228228
= endian::readNext<uint8_t, little, unaligned>(data);
229229
info.NullabilityPayload
230230
= endian::readNext<uint64_t, little, unaligned>(data);
231+
232+
unsigned numParams = endian::readNext<uint16_t, little, unaligned>(data);
233+
while (numParams > 0) {
234+
uint8_t payload = endian::readNext<uint8_t, little, unaligned>(data);
235+
236+
ParamInfo pi;
237+
uint8_t nullabilityValue = payload & 0x3; payload >>= 2;
238+
if (payload & 0x01)
239+
pi.setNullabilityAudited(static_cast<NullabilityKind>(nullabilityValue));
240+
payload >>= 1;
241+
pi.setNoEscape(payload & 0x01);
242+
payload >>= 1; assert(payload == 0 && "Bad API notes");
243+
244+
info.Params.push_back(pi);
245+
--numParams;
246+
}
231247
}
232248

233249
/// Used to deserialize the on-disk Objective-C method table.

lib/APINotes/APINotesWriter.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,8 @@ namespace {
494494
/// Retrieve the serialized size of the given FunctionInfo, for use in
495495
/// on-disk hash tables.
496496
static unsigned getFunctionInfoSize(const FunctionInfo &info) {
497-
return 2 + sizeof(uint64_t) + getCommonEntityInfoSize(info);
497+
return 2 + sizeof(uint64_t) + getCommonEntityInfoSize(info) +
498+
2 + info.Params.size() * 1;
498499
}
499500

500501
/// Emit a serialized representation of the function information.
@@ -505,6 +506,20 @@ namespace {
505506
writer.write<uint8_t>(info.NullabilityAudited);
506507
writer.write<uint8_t>(info.NumAdjustedNullable);
507508
writer.write<uint64_t>(info.NullabilityPayload);
509+
510+
// Parameters.
511+
writer.write<uint16_t>(info.Params.size());
512+
for (const auto &pi : info.Params) {
513+
uint8_t payload = pi.isNoEscape();
514+
515+
auto nullability = pi.getNullability();
516+
payload = (payload << 1) | nullability.hasValue();
517+
518+
payload = payload << 2;
519+
if (nullability)
520+
payload |= static_cast<uint8_t>(*nullability);
521+
writer.write<uint8_t>(payload);
522+
}
508523
}
509524

510525
/// Used to serialize the on-disk Objective-C method table.

lib/APINotes/APINotesYAMLCompiler.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,17 @@ namespace {
166166
NullabilityKind::NonNull;
167167
typedef std::vector<clang::NullabilityKind> NullabilitySeq;
168168

169+
struct Param {
170+
unsigned Position;
171+
bool NoEscape = false;
172+
llvm::Optional<NullabilityKind> Nullability;
173+
};
174+
typedef std::vector<Param> ParamsSeq;
175+
169176
struct Method {
170177
StringRef Selector;
171178
MethodKind Kind;
179+
ParamsSeq Params;
172180
NullabilitySeq Nullability;
173181
llvm::Optional<NullabilityKind> NullabilityOfRet;
174182
AvailabilityItem Availability;
@@ -205,6 +213,7 @@ namespace {
205213

206214
struct Function {
207215
StringRef Name;
216+
ParamsSeq Params;
208217
NullabilitySeq Nullability;
209218
llvm::Optional<NullabilityKind> NullabilityOfRet;
210219
AvailabilityItem Availability;
@@ -272,6 +281,7 @@ namespace {
272281
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(clang::NullabilityKind)
273282
LLVM_YAML_IS_SEQUENCE_VECTOR(Method)
274283
LLVM_YAML_IS_SEQUENCE_VECTOR(Property)
284+
LLVM_YAML_IS_SEQUENCE_VECTOR(Param)
275285
LLVM_YAML_IS_SEQUENCE_VECTOR(Class)
276286
LLVM_YAML_IS_SEQUENCE_VECTOR(Function)
277287
LLVM_YAML_IS_SEQUENCE_VECTOR(GlobalVariable)
@@ -322,6 +332,16 @@ namespace llvm {
322332
}
323333
};
324334

335+
template <>
336+
struct MappingTraits<Param> {
337+
static void mapping(IO &io, Param& p) {
338+
io.mapRequired("Position", p.Position);
339+
io.mapOptional("Nullability", p.Nullability,
340+
AbsentNullability);
341+
io.mapOptional("NoEscape", p.NoEscape);
342+
}
343+
};
344+
325345
template <>
326346
struct MappingTraits<Property> {
327347
static void mapping(IO &io, Property& p) {
@@ -340,6 +360,7 @@ namespace llvm {
340360
static void mapping(IO &io, Method& m) {
341361
io.mapRequired("Selector", m.Selector);
342362
io.mapRequired("MethodKind", m.Kind);
363+
io.mapOptional("Parameters", m.Params);
343364
io.mapOptional("Nullability", m.Nullability);
344365
io.mapOptional("NullabilityOfRet", m.NullabilityOfRet,
345366
AbsentNullability);
@@ -374,6 +395,7 @@ namespace llvm {
374395
struct MappingTraits<Function> {
375396
static void mapping(IO &io, Function& f) {
376397
io.mapRequired("Name", f.Name);
398+
io.mapOptional("Parameters", f.Params);
377399
io.mapOptional("Nullability", f.Nullability);
378400
io.mapOptional("NullabilityOfRet", f.NullabilityOfRet,
379401
AbsentNullability);
@@ -527,6 +549,20 @@ namespace {
527549
return false;
528550
}
529551

552+
void convertParams(const ParamsSeq &params, FunctionInfo &outInfo) {
553+
for (const auto &p : params) {
554+
ParamInfo pi;
555+
if (p.Nullability)
556+
pi.setNullabilityAudited(*p.Nullability);
557+
pi.setNoEscape(p.NoEscape);
558+
559+
while (outInfo.Params.size() <= p.Position) {
560+
outInfo.Params.push_back(ParamInfo());
561+
}
562+
outInfo.Params[p.Position] |= pi;
563+
}
564+
}
565+
530566
void convertNullability(const NullabilitySeq &nullability,
531567
Optional<NullabilityKind> nullabilityOfRet,
532568
FunctionInfo &outInfo,
@@ -610,6 +646,9 @@ namespace {
610646
if (meth.FactoryAsInit != FactoryAsInitKind::Infer)
611647
mInfo.setFactoryAsInitKind(meth.FactoryAsInit);
612648

649+
// Translate parameter information.
650+
convertParams(meth.Params, mInfo);
651+
613652
// Translate nullability info.
614653
convertNullability(meth.Nullability, meth.NullabilityOfRet,
615654
mInfo, meth.Selector);
@@ -744,6 +783,7 @@ namespace {
744783
convertAvailability(function.Availability, info, function.Name);
745784
info.SwiftPrivate = function.SwiftPrivate;
746785
info.SwiftName = function.SwiftName;
786+
convertParams(function.Params, info);
747787
convertNullability(function.Nullability,
748788
function.NullabilityOfRet,
749789
info, function.Name);
@@ -924,6 +964,19 @@ namespace {
924964
}
925965
}
926966

967+
/// Map parameter information for a function.
968+
void handleParameters(ParamsSeq &params,
969+
const FunctionInfo &info) {
970+
unsigned position = 0;
971+
for (const auto &pi: info.Params) {
972+
Param p;
973+
p.Position = position++;
974+
p.Nullability = pi.getNullability();
975+
p.NoEscape = pi.isNoEscape();
976+
params.push_back(p);
977+
}
978+
}
979+
927980
/// Map nullability information for a function.
928981
void handleNullability(NullabilitySeq &nullability,
929982
llvm::Optional<NullabilityKind> &nullabilityOfRet,
@@ -967,6 +1020,7 @@ namespace {
9671020
method.Kind = isInstanceMethod ? MethodKind::Instance : MethodKind::Class;
9681021

9691022
handleCommon(method, info);
1023+
handleParameters(method.Params, info);
9701024
handleNullability(method.Nullability, method.NullabilityOfRet, info,
9711025
selector.count(':'));
9721026
method.FactoryAsInit = info.getFactoryAsInitKind();
@@ -1003,6 +1057,7 @@ namespace {
10031057
Function function;
10041058
function.Name = name;
10051059
handleCommon(function, info);
1060+
handleParameters(function.Params, info);
10061061
if (info.NumAdjustedNullable > 0)
10071062
handleNullability(function.Nullability, function.NullabilityOfRet,
10081063
info, info.NumAdjustedNullable-1);

lib/Sema/SemaAPINotes.cpp

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -175,18 +175,27 @@ static void ProcessAPINotes(Sema &S, Decl *D,
175175
ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info));
176176
}
177177

178+
/// Process API notes for a parameter.
179+
static void ProcessAPINotes(Sema &S, ParmVarDecl *D,
180+
const api_notes::ParamInfo &Info) {
181+
// noescape
182+
if (Info.isNoEscape() && !D->getAttr<NoEscapeAttr>())
183+
D->addAttr(NoEscapeAttr::CreateImplicit(S.Context));
184+
185+
// Handle common entity information.
186+
ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info));
187+
}
188+
178189
/// Process API notes for a global variable.
179190
static void ProcessAPINotes(Sema &S, VarDecl *D,
180191
const api_notes::GlobalVariableInfo &Info) {
181-
182192
// Handle common entity information.
183193
ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info));
184194
}
185195

186196
/// Process API notes for an Objective-C property.
187197
static void ProcessAPINotes(Sema &S, ObjCPropertyDecl *D,
188198
const api_notes::ObjCPropertyInfo &Info) {
189-
190199
// Handle common entity information.
191200
ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info));
192201
}
@@ -207,26 +216,31 @@ static void ProcessAPINotes(Sema &S, FunctionOrMethod AnyFunc,
207216
D = MD;
208217
}
209218

210-
// Nullability.
219+
// Nullability of return type.
211220
if (Info.NullabilityAudited) {
212-
// Return type.
213221
applyNullability(S, D, Info.getReturnTypeInfo());
222+
}
214223

215-
// Parameters.
216-
unsigned NumParams;
224+
// Parameters.
225+
unsigned NumParams;
226+
if (FD)
227+
NumParams = FD->getNumParams();
228+
else
229+
NumParams = MD->param_size();
230+
231+
for (unsigned I = 0; I != NumParams; ++I) {
232+
ParmVarDecl *Param;
217233
if (FD)
218-
NumParams = FD->getNumParams();
234+
Param = FD->getParamDecl(I);
219235
else
220-
NumParams = MD->param_size();
221-
222-
for (unsigned I = 0; I != NumParams; ++I) {
223-
ParmVarDecl *Param;
224-
if (FD)
225-
Param = FD->getParamDecl(I);
226-
else
227-
Param = MD->param_begin()[I];
228-
236+
Param = MD->param_begin()[I];
237+
238+
// Nullability.
239+
if (Info.NullabilityAudited)
229240
applyNullability(S, Param, Info.getParamTypeInfo(I));
241+
242+
if (I < Info.Params.size()) {
243+
ProcessAPINotes(S, Param, Info.Params[I]);
230244
}
231245
}
232246

test/APINotes/Inputs/APINotes/HeaderLib.apinotes

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ Functions:
99
- Name: do_something_with_pointers
1010
NullabilityOfRet: O
1111
Nullability: [ N, O ]
12+
- Name: take_pointer_and_int
13+
Parameters:
14+
- Position: 0
15+
Nullability: N
16+
NoEscape: true
17+
- Position: 1
18+
NoEscape: true
1219

1320
Globals:
1421
- Name: global_int

test/APINotes/Inputs/Headers/HeaderLib.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,6 @@ void do_something_with_pointers(int *ptr1, int *ptr2);
1313
typedef int unavailable_typedef;
1414
struct unavailable_struct { int x, y, z; };
1515

16+
void take_pointer_and_int(int *ptr1, int value);
17+
1618
#endif

test/APINotes/Inputs/roundtrip.apinotes

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ Classes:
6767
SwiftName: ''
6868
- Selector: 'addSubview:positioned:relativeTo:'
6969
MethodKind: Instance
70+
Parameters:
71+
- Position: 0
72+
NoEscape: false
73+
- Position: 1
74+
NoEscape: false
75+
- Position: 2
76+
NoEscape: true
7077
Nullability: [ N, N, O ]
7178
NullabilityOfRet: N
7279
Availability: available

test/APINotes/nullability.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ int main() {
88
int i = 0;
99
do_something_with_pointers(&i, 0);
1010
do_something_with_pointers(0, &i); // expected-warning{{null passed to a callee that requires a non-null argument}}
11+
take_pointer_and_int(0, 0); // expected-warning{{null passed to a callee that requires a non-null argument}}
1112

1213
float *fp = global_int; // expected-warning{{incompatible pointer types initializing 'float *' with an expression of type 'int * _Nonnull'}}
1314
return 0;

0 commit comments

Comments
 (0)