Skip to content

Commit f585cf3

Browse files
committed
[Swiftify] Do not swiftify non-Swift-like counted_by exprs
__counted_by (and __sized_by) expressions can have arbitrary C syntax in them, such as: void foo(int * __counted_by(*len) p, int *len); When @_SwififyImport tries to generate Swift code for this, the expression `*len` leads to a syntax error, since it isn't valid Swift. This patch adds a check to ensure we only attach the Swiftify macro to __counted_by expressions that are also syntactically valid in Swift. rdar://150956352
1 parent 6069462 commit f585cf3

File tree

4 files changed

+115
-3
lines changed

4 files changed

+115
-3
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@
6060
#include "clang/AST/Decl.h"
6161
#include "clang/AST/DeclCXX.h"
6262
#include "clang/AST/DeclObjCCommon.h"
63+
#include "clang/AST/Expr.h"
6364
#include "clang/AST/PrettyPrinter.h"
65+
#include "clang/AST/StmtVisitor.h"
6466
#include "clang/AST/RecordLayout.h"
6567
#include "clang/AST/Type.h"
6668
#include "clang/Basic/Specifiers.h"
@@ -9139,6 +9141,46 @@ class SwiftifyInfoPrinter {
91399141
};
91409142
} // namespace
91419143

9144+
namespace {
9145+
/// Look for any side effects within a Stmt.
9146+
struct CATExprValidator : clang::ConstStmtVisitor<CATExprValidator, bool> {
9147+
bool VisitDeclRefExpr(const clang::DeclRefExpr *e) { return true; }
9148+
bool VisitIntegerLiteral(const clang::IntegerLiteral *) { return true; }
9149+
bool VisitImplicitCastExpr(const clang::ImplicitCastExpr *c) { return this->Visit(c->getSubExpr()); }
9150+
9151+
#define SUPPORTED_UNOP(UNOP) \
9152+
bool VisitUnary ## UNOP(const clang::UnaryOperator *unop) { \
9153+
return this->Visit(unop->getSubExpr()); \
9154+
}
9155+
SUPPORTED_UNOP(Plus)
9156+
SUPPORTED_UNOP(Minus)
9157+
SUPPORTED_UNOP(Not)
9158+
#undef SUPPORTED_UNOP
9159+
9160+
#define SUPPORTED_BINOP(BINOP) \
9161+
bool VisitBin ## BINOP(const clang::BinaryOperator *binop) { \
9162+
return this->Visit(binop->getLHS()) && this->Visit(binop->getRHS()); \
9163+
}
9164+
SUPPORTED_BINOP(Add)
9165+
SUPPORTED_BINOP(Sub)
9166+
SUPPORTED_BINOP(Div)
9167+
SUPPORTED_BINOP(Mul)
9168+
SUPPORTED_BINOP(Rem)
9169+
SUPPORTED_BINOP(Shl)
9170+
SUPPORTED_BINOP(Shr)
9171+
SUPPORTED_BINOP(And)
9172+
SUPPORTED_BINOP(Xor)
9173+
SUPPORTED_BINOP(Or)
9174+
#undef SUPPORTED_BINOP
9175+
9176+
bool VisitStmt(const clang::Stmt *) { return false; }
9177+
};
9178+
} // namespace
9179+
9180+
static bool SwiftifiableCAT(const clang::CountAttributedType *CAT) {
9181+
return CAT && CATExprValidator().Visit(CAT->getCountExpr());
9182+
}
9183+
91429184
void ClangImporter::Implementation::swiftify(FuncDecl *MappedDecl) {
91439185
if (!SwiftContext.LangOpts.hasFeature(Feature::SafeInteropWrappers))
91449186
return;
@@ -9174,8 +9216,8 @@ void ClangImporter::Implementation::swiftify(FuncDecl *MappedDecl) {
91749216
SwiftifyInfoPrinter printer(getClangASTContext(), SwiftContext, out);
91759217
bool returnIsStdSpan = registerStdSpanTypeMapping(
91769218
MappedDecl->getResultInterfaceType(), ClangDecl->getReturnType());
9177-
if (auto CAT =
9178-
ClangDecl->getReturnType()->getAs<clang::CountAttributedType>()) {
9219+
auto *CAT = ClangDecl->getReturnType()->getAs<clang::CountAttributedType>();
9220+
if (SwiftifiableCAT(CAT)) {
91799221
printer.printCountedBy(CAT, SwiftifyInfoPrinter::RETURN_VALUE_INDEX);
91809222
attachMacro = true;
91819223
}
@@ -9190,7 +9232,8 @@ void ClangImporter::Implementation::swiftify(FuncDecl *MappedDecl) {
91909232
auto clangParamTy = clangParam->getType();
91919233
auto swiftParam = MappedDecl->getParameters()->get(index);
91929234
bool paramHasBoundsInfo = false;
9193-
if (auto CAT = clangParamTy->getAs<clang::CountAttributedType>()) {
9235+
auto *CAT = clangParamTy->getAs<clang::CountAttributedType>();
9236+
if (SwiftifiableCAT(CAT)) {
91949237
printer.printCountedBy(CAT, index);
91959238
attachMacro = paramHasBoundsInfo = true;
91969239
}

test/Interop/C/swiftify-import/Inputs/counted-by.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
void simple(int len, int * __counted_by(len) p);
66

7+
void simpleFlipped(int * __counted_by(len) p, int len);
8+
79
void swiftAttr(int len, int *p) __attribute__((
810
swift_attr("@_SwiftifyImport(.countedBy(pointer: .param(2), count: \"len\"))")));
911

@@ -18,3 +20,29 @@ void nonnull(int len, int * __counted_by(len) _Nonnull p);
1820
void nullable(int len, int * __counted_by(len) _Nullable p);
1921

2022
int * __counted_by(len) returnPointer(int len);
23+
24+
void offByOne(int len, int * __counted_by(len + 1) p);
25+
26+
void scalar(int n, int m, int * __counted_by(m * n) p);
27+
28+
void constInt(int * __counted_by(42 * 10) p);
29+
30+
void constFloatCastedToInt(int * __counted_by((int) (4.2 / 12)) p);
31+
32+
void sizeofType(int * __counted_by(sizeof(int *)) p);
33+
34+
void sizeofParam(int * __counted_by(sizeof(p)) p);
35+
36+
void derefLen(int * len, int * __counted_by(*len) p);
37+
38+
void lNot(int len, int * __counted_by(!len) p);
39+
40+
void lAnd(int len, int * __counted_by(len && len) p);
41+
42+
void lOr(int len, int * __counted_by(len && len) p);
43+
44+
void floatCastToInt(float meters, int * __counted_by((int) meters) p);
45+
46+
void pointerCastToInt(int *square, int * __counted_by((int) square) p);
47+
48+
void nanAsInt(int * __counted_by((int) (0 / 0)) p);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %target-swift-ide-test -print-module -module-to-print=CountedByClang -plugin-path %swift-plugin-dir -I %S/Inputs -source-filename=x -enable-experimental-feature SafeInteropWrappers | %FileCheck %s
2+
3+
// REQUIRES: swift_feature_SafeInteropWrappers
4+
5+
// These functions use __counted_by annotations that are not syntactically valid
6+
// in Swift, so they should not be Swiftified
7+
8+
// CHECK-NOT: @_alwaysEmitIntoClient {{.*}} derefLen
9+
// CHECK-NOT: @_alwaysEmitIntoClient {{.*}} lNot
10+
// CHECK-NOT: @_alwaysEmitIntoClient {{.*}} lAnd
11+
// CHECK-NOT: @_alwaysEmitIntoClient {{.*}} lOr
12+
// CHECK-NOT: @_alwaysEmitIntoClient {{.*}} floatCastToInt
13+
// CHECK-NOT: @_alwaysEmitIntoClient {{.*}} pointerCastToInt
14+
// CHECK-NOT: @_alwaysEmitIntoClient {{.*}} nanAsInt

test/Interop/C/swiftify-import/counted-by.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,31 @@
1111
import CountedByClang
1212

1313
// CHECK: @_alwaysEmitIntoClient public func complexExpr(_ len: Int{{.*}}, _ offset: Int{{.*}}, _ p: UnsafeMutableBufferPointer<Int{{.*}}>)
14+
// CHECK-NEXT: @_alwaysEmitIntoClient public func constFloatCastedToInt(_ p: UnsafeMutableBufferPointer<Int32>)
15+
// CHECK-NEXT: @_alwaysEmitIntoClient public func constInt(_ p: UnsafeMutableBufferPointer<Int32>)
1416
// CHECK-NEXT: @_alwaysEmitIntoClient public func nonnull(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
1517
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
1618
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullable(_ p: UnsafeMutableBufferPointer<Int{{.*}}>?)
19+
// CHECK-NEXT: @_alwaysEmitIntoClient public func offByOne(_ len: Int32, _ p: UnsafeMutableBufferPointer<Int32>)
1720
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func returnPointer(_ len: Int{{.*}}) -> UnsafeMutableBufferPointer<Int{{.*}}>
21+
// CHECK-NEXT: @_alwaysEmitIntoClient public func scalar(_ n: Int32, _ m: Int32, _ p: UnsafeMutableBufferPointer<Int32>)
1822
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int{{.*}}, _ p1: UnsafeMutableBufferPointer<Int{{.*}}>, _ p2: UnsafeMutableBufferPointer<Int{{.*}}>)
1923
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
24+
// CHECK-NEXT: @_alwaysEmitIntoClient public func simpleFlipped(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
25+
// CHECK-NEXT: @_alwaysEmitIntoClient public func sizeofParam(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
26+
// CHECK-NEXT: @_alwaysEmitIntoClient public func sizeofType(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
2027
// CHECK-NEXT: @_alwaysEmitIntoClient public func swiftAttr(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
2128

2229
@inlinable
2330
public func callComplexExpr(_ p: UnsafeMutableBufferPointer<CInt>) {
2431
complexExpr(CInt(p.count), 1, p)
2532
}
2633

34+
@inlinable
35+
public func callConstInt(_ p: UnsafeMutableBufferPointer<CInt>) {
36+
constInt(p)
37+
}
38+
2739
@inlinable
2840
public func callNonnull(_ p: UnsafeMutableBufferPointer<CInt>) {
2941
nonnull(p)
@@ -39,12 +51,22 @@ public func callNullable(_ p: UnsafeMutableBufferPointer<CInt>?) {
3951
nullable(p)
4052
}
4153

54+
@inlinable
55+
public func callOffByOne(_ p: UnsafeMutableBufferPointer<CInt>) {
56+
offByOne(0, p)
57+
}
58+
4259
@inlinable
4360
public func callReturnPointer() {
4461
let a: UnsafeMutableBufferPointer<CInt>? = returnPointer(4) // call wrapper
4562
let b: UnsafeMutablePointer<CInt>? = returnPointer(4) // call unsafe interop
4663
}
4764

65+
@inlinable
66+
public func callScalar(_ p: UnsafeMutableBufferPointer<CInt>) {
67+
scalar(4, 2, p)
68+
}
69+
4870
@inlinable
4971
public func callShared(_ p: UnsafeMutableBufferPointer<CInt>, _ p2: UnsafeMutableBufferPointer<CInt>) {
5072
shared(CInt(p.count), p, p2)
@@ -55,6 +77,11 @@ public func callSimple(_ p: UnsafeMutableBufferPointer<CInt>) {
5577
simple(p)
5678
}
5779

80+
@inlinable
81+
public func callSimpleFlipped(_ p: UnsafeMutableBufferPointer<CInt>) {
82+
simpleFlipped(p)
83+
}
84+
5885
@inlinable
5986
public func callSwiftAttr(_ p: UnsafeMutableBufferPointer<CInt>) {
6087
swiftAttr(p)

0 commit comments

Comments
 (0)