Skip to content

Commit 6a65c10

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

File tree

3 files changed

+185
-0
lines changed

3 files changed

+185
-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: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
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+
// SILGen diagnostics prohibits these implicit casts:
15+
func test_errors<T>(arg: T, sarg: String, darg: Data) {
16+
var t: T = arg
17+
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.}}
18+
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.}}
19+
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.}}
20+
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.}}
21+
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.}}
22+
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.}}
23+
24+
let constArray: [T] = [arg]
25+
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.}}
26+
27+
var array: [T] = [arg]
28+
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.}}
29+
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.}}
30+
31+
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.}}
32+
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.}}
33+
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.}}
34+
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.}}
35+
36+
var string: String = sarg
37+
readBytes(&string) // expected-warning {{cannot implicitly convert an inout String to expected argument type 'UnsafeRawPointer'.}}
38+
writeBytes(&string) // expected-warning {{cannot implicitly convert an inout String to expected argument type 'UnsafeMutableRawPointer'.}}
39+
read_char(&string) // expected-warning {{cannot implicitly convert an inout String to expected argument type 'UnsafePointer<Int8>'.}}
40+
write_char(&string) // expected-warning {{cannot implicitly convert an inout String to expected argument type 'UnsafeMutablePointer<Int8>'.}}
41+
read_uchar(&string) // expected-warning {{cannot implicitly convert an inout String to expected argument type 'UnsafePointer<UInt8>'.}}
42+
write_uchar(&string) // expected-warning {{cannot implicitly convert an inout String to expected argument type 'UnsafeMutablePointer<UInt8>'.}}
43+
44+
var data: Data = darg
45+
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.}}
46+
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.}}
47+
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.}}
48+
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.}}
49+
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.}}
50+
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.}}
51+
}
52+
53+
// SILGen diagnostics accepts these implicit casts:
54+
func test_accepted<I: FixedWidthInteger>(intArg: I, sarg: String, darg: Data) {
55+
var int: I = intArg
56+
readBytes(&int)
57+
writeBytes(&int)
58+
read_char(&int)
59+
write_char(&int)
60+
read_uchar(&int)
61+
write_uchar(&int)
62+
63+
let constArray: [I] = [intArg]
64+
readBytes(constArray)
65+
// read_char(constArray) - this case never worked because of a bug in SE-0324
66+
// read_uchar(constArray) - this case never worked because of a bug in SE-0324
67+
68+
var intArray: [I] = [intArg]
69+
readBytes(&intArray)
70+
writeBytes(&intArray)
71+
read_char(&intArray)
72+
write_char(&intArray)
73+
read_uchar(&intArray)
74+
write_uchar(&intArray)
75+
76+
var byteArray: [UInt8] = [0]
77+
readBytes(byteArray)
78+
writeBytes(&byteArray)
79+
// readInt8(&byteArray) - this case never worked because of a bug in SE-0324
80+
// writeInt8(&byteArray) - this case never worked because of a bug in SE-0324
81+
readUInt8(&byteArray)
82+
writeUInt8(&byteArray)
83+
write_char(&byteArray)
84+
read_uchar(byteArray)
85+
write_uchar(&byteArray)
86+
87+
let string: String = sarg
88+
readBytes(string)
89+
readUInt8(string)
90+
read_char(string)
91+
read_uchar(string)
92+
}
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)