Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add @[Linkage("value")] annotation (applies to fun) #15426

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions spec/compiler/codegen/fun_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
require "../../spec_helper"

describe "Codegen: fun" do
it "sets linkage" do
mod = codegen(<<-CRYSTAL, inject_primitives: false)
fun foo
end

@[Linkage("external")]
fun ext_foo
end

@[Linkage("internal")]
fun int_foo
end
CRYSTAL

mod.functions["foo"].linkage.should eq(LLVM::Linkage::External)
mod.functions["ext_foo"].linkage.should eq(LLVM::Linkage::External)
mod.functions["int_foo"].linkage.should eq(LLVM::Linkage::Internal)
end
end
2 changes: 1 addition & 1 deletion spec/compiler/semantic/annotation_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -1126,7 +1126,7 @@ describe "Semantic: annotation" do
fun foo : Void
end
),
"funs can only be annotated with: NoInline, AlwaysInline, Naked, ReturnsTwice, Raises, CallConvention"
"funs can only be annotated with: NoInline, AlwaysInline, Naked, ReturnsTwice, Raises, CallConvention or Linkage"
end

it "doesn't carry link annotation from lib to fun" do
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/crystal/codegen/ast.cr
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ module Crystal
nil
end

def linkage
nil
end
ysbaddaden marked this conversation as resolved.
Show resolved Hide resolved

@c_calling_convention : Bool? = nil
property c_calling_convention

Expand Down
4 changes: 4 additions & 0 deletions src/compiler/crystal/codegen/fun.cr
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,10 @@ class Crystal::CodeGenVisitor
context.fun.call_convention = call_convention
end

if linkage = target_def.linkage
context.fun.linkage = linkage
end

i = 0
args.each do |arg|
param = context.fun.params[i + offset]
Expand Down
4 changes: 3 additions & 1 deletion src/compiler/crystal/program.cr
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ module Crystal
types["Extern"] = @extern_annotation = AnnotationType.new self, self, "Extern"
types["Flags"] = @flags_annotation = AnnotationType.new self, self, "Flags"
types["Link"] = @link_annotation = AnnotationType.new self, self, "Link"
types["Linkage"] = @linkage_annotation = AnnotationType.new self, self, "Linkage"
types["Naked"] = @naked_annotation = AnnotationType.new self, self, "Naked"
types["NoInline"] = @no_inline_annotation = AnnotationType.new self, self, "NoInline"
types["Packed"] = @packed_annotation = AnnotationType.new self, self, "Packed"
Expand Down Expand Up @@ -534,7 +535,8 @@ module Crystal
packed_annotation thread_local_annotation no_inline_annotation
always_inline_annotation naked_annotation returns_twice_annotation
raises_annotation primitive_annotation call_convention_annotation
flags_annotation link_annotation extern_annotation deprecated_annotation experimental_annotation) %}
flags_annotation link_annotation linkage_annotation extern_annotation
deprecated_annotation experimental_annotation) %}
def {{name.id}}
@{{name.id}}.not_nil!
end
Expand Down
1 change: 1 addition & 0 deletions src/compiler/crystal/semantic/ast.cr
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,7 @@ module Crystal
property real_name : String
property! fun_def : FunDef
property call_convention : LLVM::CallConvention?
property linkage : LLVM::Linkage?
property wasm_import_module : String?

property? dead = false
Expand Down
24 changes: 23 additions & 1 deletion src/compiler/crystal/semantic/top_level_visitor.cr
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,26 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
node.body = primitive
end

private def process_fun_linkage_annotation(node, ann)
if ann.args.size != 1
ann.wrong_number_of_arguments "annotation Linkage", ann.args.size, 1
end

arg = ann.args.first
unless arg.is_a?(StringLiteral)
arg.raise "argument to Linkage must be a string"
end

case arg.value
when "internal"
node.linkage = LLVM::Linkage::Internal
when "external"
node.linkage = LLVM::Linkage::External
else
arg.raise "invalid linkage. Valid values are 'external' and 'internal'"
end
end

def visit(node : Include)
check_outside_exp node, "include"
include_in current_type, node, :included
Expand Down Expand Up @@ -984,8 +1004,10 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
call_convention = parse_call_convention(ann, call_convention)
elsif annotation_type == @program.primitive_annotation
process_def_primitive_annotation(external, ann)
elsif annotation_type == @program.linkage_annotation
process_fun_linkage_annotation(external, ann)
else
ann.raise "funs can only be annotated with: NoInline, AlwaysInline, Naked, ReturnsTwice, Raises, CallConvention"
ann.raise "funs can only be annotated with: NoInline, AlwaysInline, Naked, ReturnsTwice, Raises, CallConvention or Linkage"
end
end

Expand Down