Skip to content

Commit ce61d3e

Browse files
authored
Widen integer literal to unsigned when required (#516)
* Widen integer literal to unsigned when required * Handle large integers more robustly * Add changelog entry * Add test * Realize that Clong is system-dependent
1 parent 8ed2dd2 commit ce61d3e

File tree

4 files changed

+36
-3
lines changed

4 files changed

+36
-3
lines changed

docs/src/changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ Changelog](https://keepachangelog.com).
1818
avoid implicit imports ([#488]).
1919
- Added support to the auditor for detecting structs and function-like macros of
2020
the same name, which previously caused the generator to crash ([#500]).
21+
- Large L-suffixed integer literals that are greater than `typemax(Clong)` will now be wrapped
22+
as unsigned integers (`Culong`) ([#516]).
2123

2224
## [v0.18.3] - 2024-04-23
2325

src/generator/macro.jl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const LITERAL_NON_FLOAT_SUFFIXES = [
5555
const LITERAL_FLOAT_SUFFIXES = ["F", "f"]
5656
const LITERAL_SUFFIXES = vcat(LITERAL_NON_FLOAT_SUFFIXES, LITERAL_FLOAT_SUFFIXES)
5757

58-
function c_non_float_literal_to_julia(sfx)
58+
function c_non_float_literal_to_julia(sfx, txt_no_sfx)
5959
sfx = lowercase(sfx)
6060
# integers following http://en.cppreference.com/w/cpp/language/integer_literal
6161
unsigned = occursin("u", sfx)
@@ -66,7 +66,12 @@ function c_non_float_literal_to_julia(sfx)
6666
elseif occursin("ul", sfx) || occursin("lu", sfx)
6767
return "Culong"
6868
elseif !unsigned && endswith(sfx, "l")
69-
return "Clong"
69+
value = tryparse(Clong, txt_no_sfx)
70+
if isnothing(value) && !isnothing(tryparse(Culong, txt_no_sfx))
71+
return "Culong"
72+
else
73+
return "Clong"
74+
end
7075
else
7176
return unsigned ? "Cuint" : "Cint"
7277
end
@@ -89,7 +94,8 @@ function normalize_literal_type(text::AbstractString)
8994
for sfx in LITERAL_NON_FLOAT_SUFFIXES
9095
if endswith(txt, sfx)
9196
txt_no_sfx = replace(txt, Regex(sfx*"\$")=>"")
92-
type = c_non_float_literal_to_julia(sfx)
97+
txt_no_sfx = replace(txt_no_sfx, r"^0X" => "0x")
98+
type = c_non_float_literal_to_julia(sfx, txt_no_sfx)
9399
return "$(type)($txt_no_sfx)"
94100
end
95101
end

test/generators.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,3 +249,23 @@ end
249249
@test docstring_has("callback")
250250
end
251251
end
252+
253+
@testset "Issue 515 - unsigned types for large literals" begin
254+
args = get_default_args()
255+
headers = joinpath(@__DIR__, "include", "large-integer-literals.h")
256+
ctx = create_context(headers, args)
257+
build!(ctx, BUILDSTAGE_NO_PRINTING)
258+
extract_expr(ctx, i) = only(ctx.dag.nodes[i].exprs)
259+
# Clong is Int32 on Windows and Int on other platforms.
260+
clong_is_int32 = Sys.iswindows() || Int === Int32
261+
if clong_is_int32
262+
# We need an unsigned type to be able to hold the value on 4 bytes.
263+
@test extract_expr(ctx, 1) == :(const TEST = Culong(0x80000001))
264+
@test extract_expr(ctx, 2) == :(const TEST_2 = Culong(2147483649))
265+
else
266+
@test extract_expr(ctx, 1) == :(const TEST = Clong(0x80000001))
267+
@test extract_expr(ctx, 2) == :(const TEST_2 = Clong(2147483649))
268+
end
269+
@test extract_expr(ctx, 3) == :(const TEST_SIGNED = Clong(0x00000001))
270+
@test extract_expr(ctx, 4) == :(const TEST_SIGNED_2 = Clong(2147483646))
271+
end

test/include/large-integer-literals.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#define TEST 0x80000001L
2+
#define TEST_2 2147483649L
3+
4+
#define TEST_SIGNED 0x00000001L
5+
#define TEST_SIGNED_2 2147483646L

0 commit comments

Comments
 (0)