Skip to content

Commit e7bd5d0

Browse files
committed
Switch C type printing to prefer east const/volatile when possible
Consistency be damned, it's what looks nice. Clang does it too.
1 parent bfd791d commit e7bd5d0

File tree

3 files changed

+55
-33
lines changed

3 files changed

+55
-33
lines changed

Sources/JExtractSwift/CTypes/CType.swift

+32-21
Original file line numberDiff line numberDiff line change
@@ -132,33 +132,33 @@ extension CType: CustomStringConvertible {
132132
result += "*"
133133

134134
case .qualified(const: let isConst, volatile: let isVolatile, type: let underlying):
135-
if isConst || isVolatile {
136-
hasEmptyPlaceholder = false
135+
func printQualifier(_ qualifier: String, if condition: Bool) {
136+
if condition {
137+
result += qualifier
138+
hasEmptyPlaceholder = false
139+
140+
spaceBeforePlaceHolder(
141+
hasEmptyPlaceholder: hasEmptyPlaceholder,
142+
result: &result
143+
)
144+
}
137145
}
138146

139-
underlying.printBefore(hasEmptyPlaceholder: &hasEmptyPlaceholder, result: &result)
147+
let canPrefixQualifiers = underlying.canPrefixQualifiers
148+
if canPrefixQualifiers {
149+
printQualifier("const", if: isConst)
150+
printQualifier("volatile", if: isVolatile)
151+
}
140152

141-
// FIXME: "east const" is easier to print correctly, so do that. We could
142-
// follow Clang and decide when it's correct to print "west const" by
143-
// splitting the qualifiers before we get here.
144-
if isConst {
145-
result += "const"
153+
if (isConst || isVolatile) && !canPrefixQualifiers {
146154
hasEmptyPlaceholder = false
147-
148-
spaceBeforePlaceHolder(
149-
hasEmptyPlaceholder: hasEmptyPlaceholder,
150-
result: &result
151-
)
152-
153155
}
154-
if isVolatile {
155-
result += "volatile"
156-
hasEmptyPlaceholder = false
157156

158-
spaceBeforePlaceHolder(
159-
hasEmptyPlaceholder: hasEmptyPlaceholder,
160-
result: &result
161-
)
157+
underlying.printBefore(hasEmptyPlaceholder: &hasEmptyPlaceholder, result: &result)
158+
159+
if !canPrefixQualifiers {
160+
printQualifier("const", if: isConst)
161+
printQualifier("volatile", if: isVolatile)
162162
}
163163

164164
case .tag(let tag):
@@ -265,6 +265,7 @@ extension CType: CustomStringConvertible {
265265
print(placeholder: nil)
266266
}
267267

268+
/// Print a space before the placeholder in a declarator.
268269
private func spaceBeforePlaceHolder(
269270
hasEmptyPlaceholder: Bool,
270271
result: inout String
@@ -273,6 +274,16 @@ extension CType: CustomStringConvertible {
273274
result += " "
274275
}
275276
}
277+
278+
/// Determine whether qualifiers can be printed before the given type
279+
/// (`const int`) vs. having to be afterward to maintain semantics.
280+
var canPrefixQualifiers: Bool {
281+
switch self {
282+
case .floating, .integral, .tag, .void: true
283+
case .function, .pointer: false
284+
case .qualified(const: _, volatile: _, type: let type): type.canPrefixQualifiers
285+
}
286+
}
276287
}
277288

278289
extension CType {

Tests/JExtractSwiftTests/CTypeTests.swift

+13-2
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ struct CTypeTests {
5858
],
5959
isVariadic: true
6060
)
61-
#expect(snprintf.description == "int32_t snprintf(int8_t *str, size_t size, int8_t const *format, ...)")
62-
#expect(snprintf.functionType.description == "int32_t (int8_t *, size_t, int8_t const *, ...)")
61+
#expect(snprintf.description == "int32_t snprintf(int8_t *str, size_t size, const int8_t *format, ...)")
62+
#expect(snprintf.functionType.description == "int32_t (int8_t *, size_t, const int8_t *, ...)")
6363

6464
let rand = CFunction(
6565
resultType: .integral(.signed(bits: 32)),
@@ -91,5 +91,16 @@ struct CTypeTests {
9191
isVariadic: false
9292
)
9393
#expect(doit.description == "void doit(void (*body)(_Bool))")
94+
95+
let ptrptr = CType.pointer(
96+
.qualified(
97+
const: true,
98+
volatile: false,
99+
type: .pointer(
100+
.qualified(const: false, volatile: true, type: .void)
101+
)
102+
)
103+
)
104+
#expect(ptrptr.description == "volatile void *const *")
94105
}
95106
}

Tests/JExtractSwiftTests/FunctionLoweringTests.swift

+10-10
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ final class FunctionLoweringTests {
3030
f(x: x, y: y, z: UnsafeBufferPointer<Bool>(start: z_pointer.assumingMemoryBound(to: Bool.self), count: z_count))
3131
}
3232
""",
33-
expectedCFunction: "void c_f(ptrdiff_t x, float y, void const *z_pointer, ptrdiff_t z_count)"
33+
expectedCFunction: "void c_f(ptrdiff_t x, float y, const void *z_pointer, ptrdiff_t z_count)"
3434
)
3535
}
3636

@@ -45,7 +45,7 @@ final class FunctionLoweringTests {
4545
return f(t: (t_0, (t_1_0, t_1_1)), z: z_pointer.assumingMemoryBound(to: Int.self))
4646
}
4747
""",
48-
expectedCFunction: "ptrdiff_t c_f(ptrdiff_t t_0, float t_1_0, double t_1_1, void const *z_pointer)"
48+
expectedCFunction: "ptrdiff_t c_f(ptrdiff_t t_0, float t_1_0, double t_1_1, const void *z_pointer)"
4949
)
5050
}
5151

@@ -82,7 +82,7 @@ final class FunctionLoweringTests {
8282
_result.assumingMemoryBound(to: Point.self).initialize(to: self.assumingMemoryBound(to: Point.self).pointee.shifted(by: (delta_0, delta_1)))
8383
}
8484
""",
85-
expectedCFunction: "void c_shifted(double delta_0, double delta_1, void const *self, void *_result)"
85+
expectedCFunction: "void c_shifted(double delta_0, double delta_1, const void *self, void *_result)"
8686
)
8787
}
8888

@@ -120,7 +120,7 @@ final class FunctionLoweringTests {
120120
unsafeBitCast(self, to: Point.self).shift(by: (delta_0, delta_1))
121121
}
122122
""",
123-
expectedCFunction: "void c_shift(double delta_0, double delta_1, void const *self)"
123+
expectedCFunction: "void c_shift(double delta_0, double delta_1, const void *self)"
124124
)
125125
}
126126

@@ -155,7 +155,7 @@ final class FunctionLoweringTests {
155155
return unsafeBitCast(Person.randomPerson(seed: seed), to: UnsafeRawPointer.self)
156156
}
157157
""",
158-
expectedCFunction: "void const *c_randomPerson(double seed)"
158+
expectedCFunction: "const void *c_randomPerson(double seed)"
159159
)
160160
}
161161

@@ -190,7 +190,7 @@ final class FunctionLoweringTests {
190190
return unsafeBitCast(Person(seed: seed), to: UnsafeRawPointer.self)
191191
}
192192
""",
193-
expectedCFunction: "void const *c_init(double seed)"
193+
expectedCFunction: "const void *c_init(double seed)"
194194
)
195195
}
196196

@@ -205,7 +205,7 @@ final class FunctionLoweringTests {
205205
f(t: unsafeBitCast(t, to: Int.self))
206206
}
207207
""",
208-
expectedCFunction: "void c_f(void const *t)"
208+
expectedCFunction: "void c_f(const void *t)"
209209
)
210210

211211
try assertLoweredFunction("""
@@ -217,7 +217,7 @@ final class FunctionLoweringTests {
217217
return unsafeBitCast(f(), to: UnsafeRawPointer.self)
218218
}
219219
""",
220-
expectedCFunction: "void const *c_f(void)"
220+
expectedCFunction: "const void *c_f(void)"
221221
)
222222
}
223223

@@ -236,7 +236,7 @@ final class FunctionLoweringTests {
236236
return unsafeBitCast(unsafeBitCast(self, to: Point.self).shifted(by: (delta_0, delta_1)), to: UnsafeRawPointer.self)
237237
}
238238
""",
239-
expectedCFunction: "void const *c_shifted(double delta_0, double delta_1, void const *self)"
239+
expectedCFunction: "const void *c_shifted(double delta_0, double delta_1, const void *self)"
240240
)
241241
}
242242

@@ -254,7 +254,7 @@ final class FunctionLoweringTests {
254254
return UnsafeRawPointer(getPointer())
255255
}
256256
""",
257-
expectedCFunction: "void const *c_getPointer(void)"
257+
expectedCFunction: "const void *c_getPointer(void)"
258258
)
259259
}
260260

0 commit comments

Comments
 (0)