Skip to content

Commit cad0599

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

File tree

3 files changed

+208
-0
lines changed

3 files changed

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

0 commit comments

Comments
 (0)