Skip to content

Commit ef178bd

Browse files
committed
Add unit tests for implicit inout to raw pointer diagnostics.
1 parent 778b773 commit ef178bd

File tree

3 files changed

+196
-0
lines changed

3 files changed

+196
-0
lines changed

test/SILGen/Inputs/readbytes.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
void read_char(const char *input);
2+
void read_uchar(const unsigned char *input);
3+
void read_void(const void *input);
4+
void write_char(char *input);
5+
void write_uchar(unsigned char *input);
6+
void write_void(void *input);
7+
8+
void take_opaque_pointer(const void *);
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// RUN: %target-swift-emit-silgen -import-objc-header %S/Inputs/readbytes.h %s -o /dev/null -verify
2+
//
3+
// Diagnose invalid conversion from an inout argument to a raw pointer.
4+
5+
func readBytes(_ pointer: UnsafeRawPointer) {}
6+
func writeBytes(_ pointer: UnsafeMutableRawPointer) {}
7+
func readInt8(_ pointer: UnsafePointer<Int8>) {}
8+
func writeInt8(_ pointer: UnsafeMutablePointer<Int8>) {}
9+
func readUInt8(_ pointer: UnsafePointer<UInt8>) {}
10+
func writeUInt8(_ pointer: UnsafeMutablePointer<UInt8>) {}
11+
12+
struct Aggregate {
13+
var pointer: UnsafeRawPointer?
14+
var value: Int32
15+
}
16+
17+
class C {
18+
init() {}
19+
}
20+
21+
struct NonTrivial {
22+
var c: C
23+
}
24+
25+
// SILGen diagnostics prohibits these implicit casts:
26+
func test_errors<T>(arg: T, sarg: String) {
27+
var nonTrivial = NonTrivial(c: C())
28+
readBytes(&nonTrivial) // expected-warning {{cannot implicitly convert an inout value of type 'NonTrivial' to expected argument type 'UnsafeRawPointer' because 'NonTrivial' may contain an object reference.}}
29+
writeBytes(&nonTrivial) // expected-warning {{cannot implicitly convert an inout value of type 'NonTrivial' to expected argument type 'UnsafeMutableRawPointer' because 'NonTrivial' may contain an object reference.}}
30+
31+
var t: T = arg
32+
readBytes(&t) // expected-warning {{cannot implicitly convert an inout value of type 'T' to expected argument type 'UnsafeRawPointer' because 'T' may contain an object reference.}}
33+
writeBytes(&t) // expected-warning {{cannot implicitly convert an inout value of type 'T' to expected argument type 'UnsafeMutableRawPointer' because 'T' may contain an object reference.}}
34+
read_char(&t) // expected-warning {{cannot implicitly convert an inout value of type 'T' to expected argument type 'UnsafePointer<Int8>' because 'T' may contain an object reference.}}
35+
write_char(&t) // expected-warning {{cannot implicitly convert an inout value of type 'T' to expected argument type 'UnsafeMutablePointer<Int8>' because 'T' may contain an object reference.}}
36+
read_uchar(&t) // expected-warning {{cannot implicitly convert an inout value of type 'T' to expected argument type 'UnsafePointer<UInt8>' because 'T' may contain an object reference.}}
37+
write_uchar(&t) // expected-warning {{cannot implicitly convert an inout value of type 'T' to expected argument type 'UnsafeMutablePointer<UInt8>' because 'T' may contain an object reference.}}
38+
39+
let constArray: [T] = [arg]
40+
readBytes(constArray) // expected-warning {{cannot implicitly convert an inout value of type '[T]' to expected argument type 'UnsafeRawPointer' because 'T' may contain an object reference.}}
41+
42+
var array: [T] = [arg]
43+
readBytes(&array) // expected-warning {{cannot implicitly convert an inout value of type '[T]' to expected argument type 'UnsafeRawPointer' because 'T' may contain an object reference.}}
44+
writeBytes(&array) // expected-warning {{cannot implicitly convert an inout value of type '[T]' to expected argument type 'UnsafeMutableRawPointer' because 'T' may contain an object reference.}}
45+
46+
read_char(&array) // expected-warning {{cannot implicitly convert an inout value of type 'Array<T>' to expected argument type 'UnsafePointer<Int8>' because 'T' may contain an object reference.}}
47+
write_char(&array) // expected-warning {{cannot implicitly convert an inout value of type 'Array<T>' to expected argument type 'UnsafeMutablePointer<Int8>' because 'T' may contain an object reference.}}
48+
read_uchar(&array) // expected-warning {{cannot implicitly convert an inout value of type 'Array<T>' to expected argument type 'UnsafePointer<UInt8>' because 'T' may contain an object reference.}}
49+
write_uchar(&array) // expected-warning {{cannot implicitly convert an inout value of type 'Array<T>' to expected argument type 'UnsafeMutablePointer<UInt8>' because 'T' may contain an object reference.}}
50+
51+
var string: String = sarg
52+
readBytes(&string) // expected-warning {{cannot implicitly convert an inout String to expected argument type 'UnsafeRawPointer'.}}
53+
writeBytes(&string) // expected-warning {{cannot implicitly convert an inout String to expected argument type 'UnsafeMutableRawPointer'.}}
54+
read_char(&string) // expected-warning {{cannot implicitly convert an inout String to expected argument type 'UnsafePointer<Int8>'.}}
55+
write_char(&string) // expected-warning {{cannot implicitly convert an inout String to expected argument type 'UnsafeMutablePointer<Int8>'.}}
56+
read_uchar(&string) // expected-warning {{cannot implicitly convert an inout String to expected argument type 'UnsafePointer<UInt8>'.}}
57+
write_uchar(&string) // expected-warning {{cannot implicitly convert an inout String to expected argument type 'UnsafeMutablePointer<UInt8>'.}}
58+
}
59+
60+
// SILGen diagnostics accepts these implicit casts:
61+
func test_accepted<I: FixedWidthInteger>(intArg: I, sarg: String) {
62+
var aggregate = Aggregate(pointer: UnsafeRawPointer(bitPattern: 0), value: 0)
63+
readBytes(&aggregate)
64+
writeBytes(&aggregate)
65+
read_char(&aggregate)
66+
write_char(&aggregate)
67+
read_uchar(&aggregate)
68+
write_uchar(&aggregate)
69+
70+
var int: I = intArg
71+
readBytes(&int)
72+
writeBytes(&int)
73+
read_char(&int)
74+
write_char(&int)
75+
read_uchar(&int)
76+
write_uchar(&int)
77+
78+
let constArray: [I] = [intArg]
79+
readBytes(constArray)
80+
// read_char(constArray) - this case never worked because of a bug in SE-0324
81+
// read_uchar(constArray) - this case never worked because of a bug in SE-0324
82+
83+
var intArray: [I] = [intArg]
84+
readBytes(&intArray)
85+
writeBytes(&intArray)
86+
read_char(&intArray)
87+
write_char(&intArray)
88+
read_uchar(&intArray)
89+
write_uchar(&intArray)
90+
91+
var byteArray: [UInt8] = [0]
92+
readBytes(&byteArray)
93+
writeBytes(&byteArray)
94+
readUInt8(&byteArray)
95+
writeUInt8(&byteArray)
96+
write_char(&byteArray)
97+
read_uchar(byteArray)
98+
write_uchar(&byteArray)
99+
100+
let string: String = sarg
101+
readBytes(string)
102+
readUInt8(string)
103+
read_char(string)
104+
read_uchar(string)
105+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// RUN: %target-swift-emit-silgen -import-objc-header %S/Inputs/readbytes.h %s -o /dev/null -verify
2+
//
3+
// Diagnose invalid conversion from an inout argument to a raw pointer.
4+
//
5+
// These cases are caught early during Sema, so they are never seen by SILGen's implicit conversion diagnostics.
6+
7+
func readBytes(_ pointer: UnsafeRawPointer) {}
8+
func writeBytes(_ pointer: UnsafeMutableRawPointer) {}
9+
func readInt8(_ pointer: UnsafePointer<Int8>) {}
10+
func writeInt8(_ pointer: UnsafeMutablePointer<Int8>) {}
11+
func readUInt8(_ pointer: UnsafePointer<UInt8>) {}
12+
func writeUInt8(_ pointer: UnsafeMutablePointer<UInt8>) {}
13+
14+
// These implicit casts never worked and will continue to be unsupported.
15+
func test_unsupported<T>(arg: T) {
16+
var t: T = arg
17+
readInt8(&t) // expected-error {{cannot convert value of type 'UnsafePointer<T>' to expected argument type 'UnsafePointer<Int8>'}}
18+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('T' and 'Int8') are expected to be equal}}
19+
writeInt8(&t) // expected-error {{cannot convert value of type 'UnsafeMutablePointer<T>' to expected argument type 'UnsafeMutablePointer<Int8>'}}
20+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('T' and 'Int8') are expected to be equal}}
21+
readUInt8(&t) // expected-error {{cannot convert value of type 'UnsafePointer<T>' to expected argument type 'UnsafePointer<UInt8>'}}
22+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('T' and 'UInt8') are expected to be equal}}
23+
writeUInt8(&t) // expected-error {{cannot convert value of type 'UnsafeMutablePointer<T>' to expected argument type 'UnsafeMutablePointer<UInt8>'}}
24+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('T' and 'UInt8') are expected to be equal}}
25+
26+
let constArray: [UInt8] = [0]
27+
readInt8(constArray) // expected-error {{cannot convert value of type 'UnsafePointer<UInt8>' to expected argument type 'UnsafePointer<Int8>'}}
28+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('UInt8' and 'Int8') are expected to be equal}}
29+
30+
// Mutating a const array obviously does not work, no need to show these
31+
// in the proposal
32+
writeBytes(constArray) // expected-error {{cannot convert value of type '[UInt8]' to expected argument type 'UnsafeMutableRawPointer'}}
33+
writeInt8(constArray) // expected-error {{cannot convert value of type '[UInt8]' to expected argument type 'UnsafeMutablePointer<Int8>'}}
34+
writeUInt8(constArray) // expected-error {{cannot convert value of type '[UInt8]' to expected argument type 'UnsafeMutablePointer<UInt8>'}}
35+
36+
var byteArray: [UInt8] = [0]
37+
readInt8(&byteArray) // expected-error {{cannot convert value of type 'UnsafePointer<UInt8>' to expected argument type 'UnsafePointer<Int8>'}}
38+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('UInt8' and 'Int8') are expected to be equal}}
39+
writeInt8(&byteArray) // expected-error {{cannot convert value of type 'UnsafeMutablePointer<UInt8>' to expected argument type 'UnsafeMutablePointer<Int8>'}}
40+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('UInt8' and 'Int8') are expected to be equal}}
41+
}
42+
43+
// These implicit casts should work according to
44+
// [SE-0324: Relax diagnostics for pointer arguments to C functions]
45+
// (https://github.com/apple/swift-evolution/blob/main/proposals/0324-c-lang-pointer-arg-conversion.md)
46+
// They currently raise a "cannot convert value" error because of
47+
// the `UInt8` vs. `Int8` mismatch.
48+
//
49+
// If we decide to support these as bug-fixes for SE-0324, then the
50+
// implicit inout-to-raw conversion should also accept them.
51+
func test_se0324_accept() {
52+
let constIntArray: [Int8] = [0]
53+
read_uchar(constIntArray) // expected-error {{cannot convert value of type 'UnsafePointer<Int8>' to expected argument type 'UnsafePointer<UInt8>'}}
54+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('Int8' and 'UInt8') are expected to be equal}}
55+
56+
let constUIntArray: [UInt8] = [0]
57+
read_char(constUIntArray) // expected-error {{cannot convert value of type 'UnsafePointer<UInt8>' to expected argument type 'UnsafePointer<CChar>' (aka 'UnsafePointer<Int8>')}}
58+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('UInt8' and 'CChar' (aka 'Int8')) are expected to be equal}}
59+
60+
var intArray: [Int8] = [0]
61+
read_uchar(intArray) // expected-error {{cannot convert value of type 'UnsafePointer<Int8>' to expected argument type 'UnsafePointer<UInt8>'}}
62+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('Int8' and 'UInt8') are expected to be equal}}
63+
64+
var uintArray: [UInt8] = [0]
65+
read_char(uintArray) // expected-error {{cannot convert value of type 'UnsafePointer<UInt8>' to expected argument type 'UnsafePointer<CChar>' (aka 'UnsafePointer<Int8>')}}
66+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('UInt8' and 'CChar' (aka 'Int8')) are expected to be equal}}
67+
68+
}
69+
70+
// These implicit casts should work according to
71+
// SE-0324: Relax diagnostics for pointer arguments to C functions]
72+
// They currently raise a "cannot convert value" error because of
73+
// the `UInt8` vs. `Int8` mismatch.
74+
//
75+
// If we decide to support these as bug-fixes for SE-0324, then the
76+
// implicit inout-to-raw conversion should issue a warning instead.
77+
func test_se0324_error<T>(arg: T) {
78+
let constArray: [T] = [arg]
79+
read_char(constArray) // expected-error {{cannot convert value of type 'UnsafePointer<T>' to expected argument type 'UnsafePointer<CChar>' (aka 'UnsafePointer<Int8>')}}
80+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('T' and 'CChar' (aka 'Int8')) are expected to be equal}}
81+
read_uchar(constArray) // expected-error {{cannot convert value of type 'UnsafePointer<T>' to expected argument type 'UnsafePointer<UInt8>'}}
82+
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('T' and 'UInt8') are expected to be equal}}
83+
}

0 commit comments

Comments
 (0)