Skip to content

Commit 317d75e

Browse files
committed
Lowering of cglobal
Special case lowering of the first (sym,lib) argument to cglobal. Also lower the identifiers `cglobal` and `ccall` to `K"core"` psuedo-refs very early, ensuring that cglobal and ccall can never be turned into normal bindings (and thus never be assigned to local or global variables). Also fixes handling of ccall/foreigncall (sym,lib) argument.
1 parent f7b30d2 commit 317d75e

File tree

8 files changed

+126
-51
lines changed

8 files changed

+126
-51
lines changed

src/ast.jl

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,13 @@ end
517517
#-------------------------------------------------------------------------------
518518
# Predicates and accessors working on expression trees
519519

520+
# For historical reasons, `cglobal` and `ccall` are their own special
521+
# quasi-identifier-like syntax but with special handling inside lowering which
522+
# means they can't be used as normal identifiers.
523+
function is_ccall_or_cglobal(name::AbstractString)
524+
return name == "ccall" || name == "cglobal"
525+
end
526+
520527
function is_quoted(ex)
521528
kind(ex) in KSet"Symbol quote top core globalref break inert
522529
meta inbounds inline noinline loopinfo"
@@ -580,12 +587,16 @@ function is_valid_modref(ex)
580587
(kind(ex[1]) == K"Identifier" || is_valid_modref(ex[1]))
581588
end
582589

590+
function is_core_ref(ex, name)
591+
kind(ex) == K"core" && ex.name_val == name
592+
end
593+
583594
function is_core_nothing(ex)
584-
kind(ex) == K"core" && ex.name_val == "nothing"
595+
is_core_ref(ex, "nothing")
585596
end
586597

587598
function is_core_Any(ex)
588-
kind(ex) == K"core" && ex.name_val == "Any"
599+
is_core_ref(ex, "Any")
589600
end
590601

591602
function is_simple_atom(ctx, ex)

src/desugaring.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1607,7 +1607,7 @@ function expand_kw_call(ctx, srcref, farg, args, kws)
16071607
end
16081608

16091609
function expand_ccall(ctx, ex)
1610-
@assert kind(ex) == K"call" && is_same_identifier_like(ex[1], "ccall")
1610+
@assert kind(ex) == K"call" && is_core_ref(ex[1], "ccall")
16111611
if numchildren(ex) < 4
16121612
throw(LoweringError(ex, "too few arguments to ccall"))
16131613
end
@@ -1806,7 +1806,7 @@ end
18061806

18071807
function expand_call(ctx, ex)
18081808
farg = ex[1]
1809-
if is_same_identifier_like(farg, "ccall")
1809+
if is_core_ref(farg, "ccall")
18101810
return expand_ccall(ctx, ex)
18111811
end
18121812
args = copy(ex[2:end])
@@ -2741,25 +2741,25 @@ function keyword_function_defs(ctx, srcref, callex_srcref, name_str,
27412741
end
27422742

27432743
# Check valid identifier/function names
2744-
function is_valid_func_name(ex)
2744+
function is_invalid_func_name(ex)
27452745
k = kind(ex)
27462746
if k == K"Identifier"
27472747
name = ex.name_val
27482748
elseif k == K"." && numchildren(ex) == 2 && kind(ex[2]) == K"Symbol"
27492749
# `function A.f(x,y) ...`
27502750
name = ex[2].name_val
27512751
else
2752-
return false
2752+
return true
27532753
end
2754-
return name != "ccall" && name != "cglobal"
2754+
return is_ccall_or_cglobal(name)
27552755
end
27562756

27572757
function expand_function_def(ctx, ex, docs, rewrite_call=identity, rewrite_body=identity)
27582758
@chk numchildren(ex) in (1,2)
27592759
name = ex[1]
27602760
if numchildren(ex) == 1 && is_identifier_like(name)
27612761
# Function declaration with no methods
2762-
if !is_valid_func_name(name)
2762+
if is_invalid_func_name(name)
27632763
throw(LoweringError(name, "Invalid function name"))
27642764
end
27652765
return @ast ctx ex [K"block"
@@ -2837,7 +2837,7 @@ function expand_function_def(ctx, ex, docs, rewrite_call=identity, rewrite_body=
28372837
name_str = name.name_val
28382838
name = ssavar(ctx, name, name.name_val)
28392839
bare_func_name = name
2840-
elseif !is_valid_func_name(name)
2840+
elseif is_invalid_func_name(name)
28412841
throw(LoweringError(name, "Invalid function name"))
28422842
elseif is_identifier_like(name)
28432843
# Add methods to a global `Function` object, or local closure

src/eval.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,13 @@ function to_lowered_expr(mod, ex, ssa_offset=0)
203203
if is_literal(k)
204204
ex.value
205205
elseif k == K"core"
206-
GlobalRef(Core, Symbol(ex.name_val))
206+
name = ex.name_val
207+
if name == "cglobal"
208+
# cglobal isn't a true name within core - instead it's a builtin
209+
:cglobal
210+
else
211+
GlobalRef(Core, Symbol(name))
212+
end
207213
elseif k == K"top"
208214
GlobalRef(Base, Symbol(ex.name_val))
209215
elseif k == K"globalref"

src/linear_ir.jl

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,19 @@ function compile_args(ctx, args)
174174
return args_out
175175
end
176176

177+
# Compile the (sym,lib) argument to ccall/cglobal
178+
function compile_C_library_symbol(ctx, ex)
179+
if kind(ex) == K"call" && kind(ex[1]) == K"core" && ex[1].name_val == "tuple"
180+
# Tuples like core.tuple(:funcname, mylib_name) are allowed and are
181+
# kept inline, but may only reference globals.
182+
check_no_local_bindings(ctx, ex,
183+
"function name and library expression cannot reference local variables")
184+
ex
185+
else
186+
only(compile_args(ctx, (ex,)))
187+
end
188+
end
189+
177190
function emit(ctx::LinearIRContext, ex)
178191
push!(ctx.code, ex)
179192
return ex
@@ -588,18 +601,7 @@ function compile(ctx::LinearIRContext, ex, needs_value, in_tail_pos)
588601
k == K"new_opaque_closure" || k == K"cfunction"
589602
if k == K"foreigncall"
590603
args = SyntaxList(ctx)
591-
# todo: is is_leaf correct here? flisp uses `atom?`
592-
func = ex[1]
593-
if kind(func) == K"call" && kind(func[1]) == K"core" && func[1].name_val == "tuple"
594-
# Tuples like core.tuple(:funcname, mylib_name) are allowed,
595-
# but may only reference globals.
596-
check_no_local_bindings(ctx, func, "ccall function name and library expression cannot reference local variables")
597-
append!(args, compile_args(ctx, ex[1:1]))
598-
elseif is_leaf(func)
599-
append!(args, compile_args(ctx, ex[1:1]))
600-
else
601-
push!(args, func)
602-
end
604+
push!(args, compile_C_library_symbol(ctx, ex[1]))
603605
# 2nd to 5th arguments of foreigncall are special. They must be
604606
# left in place but cannot reference locals.
605607
check_no_local_bindings(ctx, ex[2], "ccall return type cannot reference local variables")
@@ -621,8 +623,12 @@ function compile(ctx::LinearIRContext, ex, needs_value, in_tail_pos)
621623
check_no_local_bindings(ctx, arg,
622624
"cfunction argument cannot reference local variables")
623625
end
626+
elseif k == K"call" && is_core_ref(ex[1], "cglobal")
627+
args = SyntaxList(ctx)
628+
push!(args, ex[1])
629+
push!(args, compile_C_library_symbol(ctx, ex[2]))
630+
append!(args, compile_args(ctx, ex[3:end]))
624631
else
625-
# TODO: cglobal
626632
args = compile_args(ctx, children(ex))
627633
end
628634
callex = makenode(ctx, ex, k, args)

src/macro_expansion.jl

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,16 @@ need to be dealt with before other lowering.
202202
"""
203203
function expand_forms_1(ctx::MacroExpansionContext, ex::SyntaxTree)
204204
k = kind(ex)
205-
if k == K"Identifier" && all(==('_'), ex.name_val)
206-
@ast ctx ex ex=>K"Placeholder"
205+
if k == K"Identifier"
206+
name_str = ex.name_val
207+
if all(==('_'), name_str)
208+
@ast ctx ex ex=>K"Placeholder"
209+
elseif is_ccall_or_cglobal(name_str)
210+
@ast ctx ex name_str::K"core"
211+
else
212+
layerid = get(ex, :scope_layer, ctx.current_layer.id)
213+
makeleaf(ctx, ex, ex, kind=K"Identifier", scope_layer=layerid)
214+
end
207215
elseif k == K"Identifier" || k == K"MacroName" || k == K"StringMacroName"
208216
layerid = get(ex, :scope_layer, ctx.current_layer.id)
209217
makeleaf(ctx, ex, ex, kind=K"Identifier", scope_layer=layerid)

test/demo.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,10 @@ begin
793793
end
794794
"""
795795

796+
src = """
797+
cglobal(:jl_uv_stdin, Ptr{Cvoid})
798+
"""
799+
796800
ex = parsestmt(SyntaxTree, src, filename="foo.jl")
797801
ex = ensure_attributes(ex, var_id=Int)
798802
#ex = softscope_test(ex)

test/function_calls_ir.jl

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -369,11 +369,9 @@ ccall((:strlen, libc), Csize_t, (Cstring,), "asdfg")
369369
#---------------------
370370
1 TestMod.Cstring
371371
2 (call top.cconvert %"asdfg")
372-
3 TestMod.libc
373-
4 (call core.tuple :strlen %₃)
374-
5 (call top.unsafe_convert %%₂)
375-
6 (foreigncall %₄ TestMod.Csize_t (call core.svec TestMod.Cstring) 0 :ccall %%₂)
376-
7 (return %₆)
372+
3 (call top.unsafe_convert %%₂)
373+
4 (foreigncall (call core.tuple :strlen TestMod.libc) TestMod.Csize_t (call core.svec TestMod.Cstring) 0 :ccall %%₂)
374+
5 (return %₄)
377375

378376
########################################
379377
# ccall with a calling convention
@@ -458,7 +456,7 @@ end
458456
LoweringError:
459457
let libc = "libc"
460458
ccall((:strlen, libc), Csize_t, (Cstring,), "asdfg")
461-
# └─────────────┘ ── ccall function name and library expression cannot reference local variables
459+
# └─────────────┘ ── function name and library expression cannot reference local variables
462460
end
463461

464462
########################################
@@ -517,3 +515,65 @@ LoweringError:
517515
ccall(:foo, Csize_t, (Cstring..., Cstring...), "asdfg", "blah")
518516
# └────────┘ ── only the trailing ccall argument type should have `...`
519517

518+
########################################
519+
# cglobal special support for (sym, lib) tuple
520+
cglobal((:sym, lib), Int)
521+
#---------------------
522+
1 TestMod.Int
523+
2 (call core.cglobal (call core.tuple :sym TestMod.lib) %₁)
524+
3 (return %₂)
525+
526+
########################################
527+
# cglobal - non-tuple expressions in first arg are lowered as normal
528+
cglobal(f(), Int)
529+
#---------------------
530+
1 TestMod.f
531+
2 (call %₁)
532+
3 TestMod.Int
533+
4 (call core.cglobal %%₃)
534+
5 (return %₄)
535+
536+
########################################
537+
# Error: assigning to `cglobal`
538+
cglobal = 10
539+
#---------------------
540+
LoweringError:
541+
cglobal = 10
542+
└─────┘ ── invalid assignment location
543+
544+
########################################
545+
# Error: assigning to `ccall`
546+
ccall = 10
547+
#---------------------
548+
LoweringError:
549+
ccall = 10
550+
└───┘ ── invalid assignment location
551+
552+
########################################
553+
# Error: assigning to `var"ccall"`
554+
var"ccall" = 10
555+
#---------------------
556+
LoweringError:
557+
var"ccall" = 10
558+
# └───┘ ── invalid assignment location
559+
560+
########################################
561+
# Error: Invalid function name ccall
562+
function ccall()
563+
end
564+
#---------------------
565+
LoweringError:
566+
function ccall()
567+
# └───┘ ── Invalid function name
568+
end
569+
570+
########################################
571+
# Error: Invalid function name ccall
572+
function A.ccall()
573+
end
574+
#---------------------
575+
LoweringError:
576+
function A.ccall()
577+
# └─────┘ ── Invalid function name
578+
end
579+

test/functions_ir.jl

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -332,26 +332,6 @@ end
332332
1 (return core.nothing)
333333
9 (return core.nothing)
334334

335-
########################################
336-
# Error: Invalid function name ccall
337-
function ccall()
338-
end
339-
#---------------------
340-
LoweringError:
341-
function ccall()
342-
# └───┘ ── Invalid function name
343-
end
344-
345-
########################################
346-
# Error: Invalid function name ccall
347-
function A.ccall()
348-
end
349-
#---------------------
350-
LoweringError:
351-
function A.ccall()
352-
# └─────┘ ── Invalid function name
353-
end
354-
355335
########################################
356336
# Error: Invalid dotop function name
357337
function (.+)(x,y)

0 commit comments

Comments
 (0)