Skip to content

Commit 1730bff

Browse files
authored
Merge pull request #4598 from jtbandes/swift-3.0-branch
[Swift 3] print `__attribute__((noescape))` in generated Obj-C headers
2 parents 181cf98 + 8764acb commit 1730bff

File tree

12 files changed

+219
-64
lines changed

12 files changed

+219
-64
lines changed

lib/ClangImporter/ImportType.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ namespace {
492492
// FIXME: If we were walking TypeLocs, we could actually get parameter
493493
// names. The probably doesn't matter outside of a FuncDecl, which
494494
// we'll have to special-case, but it's an interesting bit of data loss.
495+
// We also lose `noescape`. <https://bugs.swift.org/browse/SR-2529>
495496
params.push_back(swiftParamTy);
496497
}
497498

lib/PrintAsObjC/PrintAsObjC.cpp

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ namespace {
8181
Normal = false,
8282
CustomNamesOnly = true,
8383
};
84+
85+
/// Whether the type being printed is in function param position.
86+
enum IsFunctionParam_t : bool {
87+
IsFunctionParam = true,
88+
IsNotFunctionParam = false,
89+
};
8490
}
8591

8692
static StringRef getNameForObjC(const ValueDecl *VD,
@@ -361,7 +367,7 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
361367
(clangParam && isNSUInteger(clangParam->getType()))) {
362368
os << "NSUInteger";
363369
} else {
364-
print(param->getType(), OTK_None);
370+
print(param->getType(), OTK_None, Identifier(), IsFunctionParam);
365371
}
366372
os << ")";
367373

@@ -542,19 +548,6 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
542548

543549
os << ";\n";
544550
}
545-
546-
void printSingleFunctionParam(const ParamDecl *param) {
547-
// The type name may be multi-part.
548-
PrintMultiPartType multiPart(*this);
549-
visitPart(param->getType(), OTK_None);
550-
auto name = param->getName();
551-
if (name.empty())
552-
return;
553-
554-
os << ' ' << name;
555-
if (isClangKeyword(name))
556-
os << "_";
557-
}
558551

559552
void printAbstractFunctionAsFunction(FuncDecl *FD) {
560553
printDocumentationComment(FD);
@@ -578,7 +571,8 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
578571
auto params = FD->getParameterLists().back();
579572
interleave(*params,
580573
[&](const ParamDecl *param) {
581-
printSingleFunctionParam(param);
574+
print(param->getType(), OTK_None, param->getName(),
575+
IsFunctionParam);
582576
},
583577
[&]{ os << ", "; });
584578

@@ -1437,12 +1431,13 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
14371431
} else {
14381432
interleave(tupleTy->getElements(),
14391433
[this](TupleTypeElt elt) {
1440-
print(elt.getType(), OTK_None, elt.getName());
1434+
print(elt.getType(), OTK_None, elt.getName(),
1435+
IsFunctionParam);
14411436
},
14421437
[this] { os << ", "; });
14431438
}
14441439
} else {
1445-
print(paramsTy, OTK_None);
1440+
print(paramsTy, OTK_None, Identifier(), IsFunctionParam);
14461441
}
14471442
os << ")";
14481443
}
@@ -1516,9 +1511,16 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
15161511
/// visitPart().
15171512
public:
15181513
void print(Type ty, Optional<OptionalTypeKind> optionalKind,
1519-
Identifier name = Identifier()) {
1514+
Identifier name = Identifier(),
1515+
IsFunctionParam_t isFuncParam = IsNotFunctionParam) {
15201516
PrettyStackTraceType trace(M.getASTContext(), "printing", ty);
15211517

1518+
if (isFuncParam)
1519+
if (auto fnTy = ty->lookThroughAllAnyOptionalTypes()
1520+
->getAs<AnyFunctionType>())
1521+
if (fnTy->isNoEscape())
1522+
os << "SWIFT_NOESCAPE ";
1523+
15221524
PrintMultiPartType multiPart(*this);
15231525
visitPart(ty, optionalKind);
15241526
if (!name.empty()) {
@@ -2080,6 +2082,11 @@ class ModuleWriter {
20802082
"#else\n"
20812083
"# define SWIFT_METHOD_FAMILY(X)\n"
20822084
"#endif\n"
2085+
"#if defined(__has_attribute) && __has_attribute(noescape)\n"
2086+
"# define SWIFT_NOESCAPE __attribute__((noescape))\n"
2087+
"#else\n"
2088+
"# define SWIFT_NOESCAPE\n"
2089+
"#endif\n"
20832090
"#if !defined(SWIFT_CLASS_EXTRA)\n"
20842091
"# define SWIFT_CLASS_EXTRA\n"
20852092
"#endif\n"

lib/Sema/TypeCheckType.cpp

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1410,9 +1410,9 @@ static bool isDefaultNoEscapeContext(const DeclContext *DC) {
14101410
}
14111411

14121412
// Hack to apply context-specific @escaping to an AST function type.
1413-
static Type adjustFunctionExtInfo(DeclContext *DC,
1414-
Type ty,
1415-
TypeResolutionOptions options) {
1413+
static Type applyNonEscapingFromContext(DeclContext *DC,
1414+
Type ty,
1415+
TypeResolutionOptions options) {
14161416
// Remember whether this is a function parameter.
14171417
bool isFunctionParam =
14181418
options.contains(TR_FunctionInput) ||
@@ -1426,7 +1426,12 @@ static Type adjustFunctionExtInfo(DeclContext *DC,
14261426
if (defaultNoEscape && !extInfo.isNoEscape()) {
14271427
extInfo = extInfo.withNoEscape();
14281428

1429-
// We lost the sugar to flip the isNoEscape bit
1429+
// We lost the sugar to flip the isNoEscape bit.
1430+
//
1431+
// FIXME: It would be better to add a new AttributedType sugared type,
1432+
// which would wrap the NameAliasType or ParenType, and apply the
1433+
// isNoEscape bit when de-sugaring.
1434+
// <https://bugs.swift.org/browse/SR-2520>
14301435
return FunctionType::get(funcTy->getInput(), funcTy->getResult(), extInfo);
14311436
}
14321437

@@ -1467,7 +1472,7 @@ Type TypeChecker::resolveIdentifierType(
14671472
// Hack to apply context-specific @escaping to a typealias with an underlying
14681473
// function type.
14691474
if (result->is<FunctionType>())
1470-
result = adjustFunctionExtInfo(DC, result, options);
1475+
result = applyNonEscapingFromContext(DC, result, options);
14711476

14721477
// We allow a type to conform to a protocol that is less available than
14731478
// the type itself. This enables a type to retroactively model or directly
@@ -1716,7 +1721,7 @@ Type TypeResolver::resolveType(TypeRepr *repr, TypeResolutionOptions options) {
17161721
// Default non-escaping for closure parameters
17171722
auto result = resolveASTFunctionType(cast<FunctionTypeRepr>(repr), options);
17181723
if (result && result->is<FunctionType>())
1719-
return adjustFunctionExtInfo(DC, result, options);
1724+
return applyNonEscapingFromContext(DC, result, options);
17201725
return result;
17211726
}
17221727
return resolveSILFunctionType(cast<FunctionTypeRepr>(repr), options);
@@ -1973,10 +1978,6 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
19731978
.fixItReplace(resultRange, "Never");
19741979
}
19751980

1976-
if (attrs.has(TAK_noescape)) {
1977-
// FIXME: diagnostic to tell user this is redundant and drop it
1978-
}
1979-
19801981
// Resolve the function type directly with these attributes.
19811982
FunctionType::ExtInfo extInfo(rep,
19821983
attrs.has(TAK_autoclosure),
@@ -2016,7 +2017,7 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
20162017
attrs.clearAttribute(TAK_escaping);
20172018
} else {
20182019
// No attribute; set the isNoEscape bit if we're in parameter context.
2019-
ty = adjustFunctionExtInfo(DC, ty, options);
2020+
ty = applyNonEscapingFromContext(DC, ty, options);
20202021
}
20212022
}
20222023

@@ -2034,6 +2035,7 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
20342035
}
20352036
}
20362037
} else if (hasFunctionAttr && fnRepr) {
2038+
// Remove the function attributes from the set so that we don't diagnose.
20372039
for (auto i : FunctionAttrs)
20382040
attrs.clearAttribute(i);
20392041
attrs.convention = None;
@@ -2484,6 +2486,11 @@ Type TypeResolver::resolveTupleType(TupleTypeRepr *repr,
24842486

24852487
// If this is the top level of a function input list, peel off the
24862488
// ImmediateFunctionInput marker and install a FunctionInput one instead.
2489+
//
2490+
// If we have a single ParenType though, don't clear these bits; we
2491+
// still want to parse the type contained therein as if it were in
2492+
// parameter position, meaning function types are not @escaping by
2493+
// default.
24872494
auto elementOptions = options;
24882495
if (!repr->isParenType()) {
24892496
elementOptions = withoutContext(elementOptions);

test/ClangModules/blocks_parse.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ func testNoEscape(f: @convention(block) () -> Void, nsStr: NSString,
1919
fStr: (String!) -> Void) {
2020
accepts_noescape_block(f)
2121
accepts_noescape_block(f)
22+
23+
// Please see related tests in PrintAsObjC/imported-block-typedefs.swift.
2224

2325
// rdar://problem/19818617
2426
nsStr.enumerateLines(fStr) // okay due to @noescape

test/Inputs/clang-importer-sdk/usr/include/blocks.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,5 @@ my_block_t __nullable blockWithNullable();
1919
void accepts_block(my_block_t) __attribute__((nonnull));
2020
void accepts_noescape_block(__attribute__((noescape)) my_block_t) __attribute__((nonnull));
2121

22+
// Please see related tests in PrintAsObjC/imported-block-typedefs.swift.
23+

test/PrintAsObjC/Inputs/comments-expected-output.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ SWIFT_CLASS("_TtC8comments16ClosureContainer")
127127
\a combine error: Nothing.
128128
129129
*/
130-
- (void)closureParameterExplodedExplodedWithA:(NSInteger)a combine:(NSInteger (^ _Nonnull)(NSInteger, NSInteger))combine;
130+
- (void)closureParameterExplodedExplodedWithA:(NSInteger)a combine:(SWIFT_NOESCAPE NSInteger (^ _Nonnull)(NSInteger, NSInteger))combine;
131131
/**
132132
Partially applies a binary operator.
133133
\param a The left-hand side to partially apply.
@@ -150,7 +150,7 @@ SWIFT_CLASS("_TtC8comments16ClosureContainer")
150150
\a combine error: Nothing.
151151
152152
*/
153-
- (void)closureParameterOutlineExplodedWithA:(NSInteger)a combine:(NSInteger (^ _Nonnull)(NSInteger, NSInteger))combine;
153+
- (void)closureParameterOutlineExplodedWithA:(NSInteger)a combine:(SWIFT_NOESCAPE NSInteger (^ _Nonnull)(NSInteger, NSInteger))combine;
154154
/**
155155
Partially applies a binary operator.
156156
\param a The left-hand side to partially apply.
@@ -173,7 +173,7 @@ SWIFT_CLASS("_TtC8comments16ClosureContainer")
173173
\a combine error: Nothing.
174174
175175
*/
176-
- (void)closureParameterOutlineOutlineWithA:(NSInteger)a combine:(NSInteger (^ _Nonnull)(NSInteger, NSInteger))combine;
176+
- (void)closureParameterOutlineOutlineWithA:(NSInteger)a combine:(SWIFT_NOESCAPE NSInteger (^ _Nonnull)(NSInteger, NSInteger))combine;
177177
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
178178
@end
179179

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
typedef void (^PlainBlock)(void);
2+
typedef void (^BlockWithEscapingParam)(PlainBlock);
3+
typedef void (^BlockWithNoescapeParam)(__attribute__((noescape)) PlainBlock);
4+
typedef BlockWithEscapingParam (^BlockReturningBlockWithEscapingParam)(void);
5+
typedef BlockWithNoescapeParam (^BlockReturningBlockWithNoescapeParam)(void);

0 commit comments

Comments
 (0)