Skip to content

Commit 8be78da

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 (cherry picked from commit e5b1f4a)
1 parent 3ffc1f9 commit 8be78da

File tree

4 files changed

+126
-4
lines changed

4 files changed

+126
-4
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 47 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"
@@ -9094,6 +9096,47 @@ class SwiftifyInfoPrinter {
90949096
};
90959097
} // namespace
90969098

9099+
namespace {
9100+
/// Look for any side effects within a Stmt.
9101+
struct CATExprValidator : clang::ConstStmtVisitor<CATExprValidator, bool> {
9102+
bool VisitDeclRefExpr(const clang::DeclRefExpr *e) { return true; }
9103+
bool VisitIntegerLiteral(const clang::IntegerLiteral *) { return true; }
9104+
bool VisitImplicitCastExpr(const clang::ImplicitCastExpr *c) { return this->Visit(c->getSubExpr()); }
9105+
bool VisitParenExpr(const clang::ParenExpr *p) { return this->Visit(p->getSubExpr()); }
9106+
9107+
#define SUPPORTED_UNOP(UNOP) \
9108+
bool VisitUnary ## UNOP(const clang::UnaryOperator *unop) { \
9109+
return this->Visit(unop->getSubExpr()); \
9110+
}
9111+
SUPPORTED_UNOP(Plus)
9112+
SUPPORTED_UNOP(Minus)
9113+
SUPPORTED_UNOP(Not)
9114+
#undef SUPPORTED_UNOP
9115+
9116+
#define SUPPORTED_BINOP(BINOP) \
9117+
bool VisitBin ## BINOP(const clang::BinaryOperator *binop) { \
9118+
return this->Visit(binop->getLHS()) && this->Visit(binop->getRHS()); \
9119+
}
9120+
SUPPORTED_BINOP(Add)
9121+
SUPPORTED_BINOP(Sub)
9122+
SUPPORTED_BINOP(Div)
9123+
SUPPORTED_BINOP(Mul)
9124+
SUPPORTED_BINOP(Rem)
9125+
SUPPORTED_BINOP(Shl)
9126+
SUPPORTED_BINOP(Shr)
9127+
SUPPORTED_BINOP(And)
9128+
SUPPORTED_BINOP(Xor)
9129+
SUPPORTED_BINOP(Or)
9130+
#undef SUPPORTED_BINOP
9131+
9132+
bool VisitStmt(const clang::Stmt *) { return false; }
9133+
};
9134+
} // namespace
9135+
9136+
static bool SwiftifiableCAT(const clang::CountAttributedType *CAT) {
9137+
return CAT && CATExprValidator().Visit(CAT->getCountExpr());
9138+
}
9139+
90979140
void ClangImporter::Implementation::swiftify(FuncDecl *MappedDecl) {
90989141
if (!SwiftContext.LangOpts.hasFeature(Feature::SafeInteropWrappers))
90999142
return;
@@ -9131,8 +9174,8 @@ void ClangImporter::Implementation::swiftify(FuncDecl *MappedDecl) {
91319174
SwiftifyInfoPrinter printer(getClangASTContext(), out);
91329175
bool returnIsStdSpan = registerStdSpanTypeMapping(
91339176
MappedDecl->getResultInterfaceType(), ClangDecl->getReturnType());
9134-
if (auto CAT =
9135-
ClangDecl->getReturnType()->getAs<clang::CountAttributedType>()) {
9177+
auto *CAT = ClangDecl->getReturnType()->getAs<clang::CountAttributedType>();
9178+
if (SwiftifiableCAT(CAT)) {
91369179
printer.printCountedBy(CAT, SwiftifyInfoPrinter::RETURN_VALUE_INDEX);
91379180
attachMacro = true;
91389181
}
@@ -9147,7 +9190,8 @@ void ClangImporter::Implementation::swiftify(FuncDecl *MappedDecl) {
91479190
auto clangParamTy = clangParam->getType();
91489191
auto swiftParam = MappedDecl->getParameters()->get(index);
91499192
bool paramHasBoundsInfo = false;
9150-
if (auto CAT = clangParamTy->getAs<clang::CountAttributedType>()) {
9193+
auto *CAT = clangParamTy->getAs<clang::CountAttributedType>();
9194+
if (SwiftifiableCAT(CAT)) {
91519195
printer.printCountedBy(CAT, index);
91529196
attachMacro = paramHasBoundsInfo = true;
91539197
}

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

Lines changed: 34 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,35 @@ 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 offBySome(int len, int offset, int * __counted_by(len + (1 + offset)) p);
27+
28+
void scalar(int m, int n, int * __counted_by(m * n) p);
29+
30+
void bitwise(int m, int n, int o, int * __counted_by(m & n | ~o) p);
31+
32+
void bitshift(int m, int n, int o, int * __counted_by(m << (n >> o)) p);
33+
34+
void constInt(int * __counted_by(42 * 10) p);
35+
36+
void constFloatCastedToInt(int * __counted_by((int) (4.2 / 12)) p);
37+
38+
void sizeofType(int * __counted_by(sizeof(int *)) p);
39+
40+
void sizeofParam(int * __counted_by(sizeof(p)) p);
41+
42+
void derefLen(int * len, int * __counted_by(*len) p);
43+
44+
void lNot(int len, int * __counted_by(!len) p);
45+
46+
void lAnd(int len, int * __counted_by(len && len) p);
47+
48+
void lOr(int len, int * __counted_by(len || len) p);
49+
50+
void floatCastToInt(float meters, int * __counted_by((int) meters) p);
51+
52+
void pointerCastToInt(int *square, int * __counted_by((int) square) p);
53+
54+
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: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,35 @@
1010

1111
import CountedByClang
1212

13-
// CHECK: @_alwaysEmitIntoClient public func complexExpr(_ len: Int{{.*}}, _ offset: Int{{.*}}, _ p: UnsafeMutableBufferPointer<Int{{.*}}>)
13+
// CHECK: @_alwaysEmitIntoClient public func bitshift(_ m: Int32, _ n: Int32, _ o: Int32, _ p: UnsafeMutableBufferPointer<Int32>)
14+
// CHECK-NEXT: @_alwaysEmitIntoClient public func bitwise(_ m: Int32, _ n: Int32, _ o: Int32, _ p: UnsafeMutableBufferPointer<Int32>)
15+
// CHECK-NEXT: @_alwaysEmitIntoClient public func complexExpr(_ len: Int{{.*}}, _ offset: Int{{.*}}, _ p: UnsafeMutableBufferPointer<Int{{.*}}>)
16+
// CHECK-NEXT: @_alwaysEmitIntoClient public func constFloatCastedToInt(_ p: UnsafeMutableBufferPointer<Int32>)
17+
// CHECK-NEXT: @_alwaysEmitIntoClient public func constInt(_ p: UnsafeMutableBufferPointer<Int32>)
1418
// CHECK-NEXT: @_alwaysEmitIntoClient public func nonnull(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
1519
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
1620
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullable(_ p: UnsafeMutableBufferPointer<Int{{.*}}>?)
21+
// CHECK-NEXT: @_alwaysEmitIntoClient public func offByOne(_ len: Int32, _ p: UnsafeMutableBufferPointer<Int32>)
22+
// CHECK-NEXT: @_alwaysEmitIntoClient public func offBySome(_ len: Int32, _ offset: Int32, _ p: UnsafeMutableBufferPointer<Int32>)
1723
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func returnPointer(_ len: Int{{.*}}) -> UnsafeMutableBufferPointer<Int{{.*}}>
24+
// CHECK-NEXT: @_alwaysEmitIntoClient public func scalar(_ m: Int32, _ n: Int32, _ p: UnsafeMutableBufferPointer<Int32>)
1825
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int{{.*}}, _ p1: UnsafeMutableBufferPointer<Int{{.*}}>, _ p2: UnsafeMutableBufferPointer<Int{{.*}}>)
1926
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
27+
// CHECK-NEXT: @_alwaysEmitIntoClient public func simpleFlipped(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
28+
// CHECK-NEXT: @_alwaysEmitIntoClient public func sizeofParam(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
29+
// CHECK-NEXT: @_alwaysEmitIntoClient public func sizeofType(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
2030
// CHECK-NEXT: @_alwaysEmitIntoClient public func swiftAttr(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
2131

2232
@inlinable
2333
public func callComplexExpr(_ p: UnsafeMutableBufferPointer<CInt>) {
2434
complexExpr(CInt(p.count), 1, p)
2535
}
2636

37+
@inlinable
38+
public func callConstInt(_ p: UnsafeMutableBufferPointer<CInt>) {
39+
constInt(p)
40+
}
41+
2742
@inlinable
2843
public func callNonnull(_ p: UnsafeMutableBufferPointer<CInt>) {
2944
nonnull(p)
@@ -39,12 +54,22 @@ public func callNullable(_ p: UnsafeMutableBufferPointer<CInt>?) {
3954
nullable(p)
4055
}
4156

57+
@inlinable
58+
public func callOffByOne(_ p: UnsafeMutableBufferPointer<CInt>) {
59+
offByOne(0, p)
60+
}
61+
4262
@inlinable
4363
public func callReturnPointer() {
4464
let a: UnsafeMutableBufferPointer<CInt>? = returnPointer(4) // call wrapper
4565
let b: UnsafeMutablePointer<CInt>? = returnPointer(4) // call unsafe interop
4666
}
4767

68+
@inlinable
69+
public func callScalar(_ p: UnsafeMutableBufferPointer<CInt>) {
70+
scalar(4, 2, p)
71+
}
72+
4873
@inlinable
4974
public func callShared(_ p: UnsafeMutableBufferPointer<CInt>, _ p2: UnsafeMutableBufferPointer<CInt>) {
5075
shared(CInt(p.count), p, p2)
@@ -55,6 +80,11 @@ public func callSimple(_ p: UnsafeMutableBufferPointer<CInt>) {
5580
simple(p)
5681
}
5782

83+
@inlinable
84+
public func callSimpleFlipped(_ p: UnsafeMutableBufferPointer<CInt>) {
85+
simpleFlipped(p)
86+
}
87+
5888
@inlinable
5989
public func callSwiftAttr(_ p: UnsafeMutableBufferPointer<CInt>) {
6090
swiftAttr(p)

0 commit comments

Comments
 (0)