diff --git a/spec/compiler/codegen/macro_spec.cr b/spec/compiler/codegen/macro_spec.cr
index b66010fc82e9d13efbaf2a6a0316e32784ed4451..1bf2af79e90d6a897a4a67fb1b6497a34d58e031 100755
--- a/spec/compiler/codegen/macro_spec.cr
+++ b/spec/compiler/codegen/macro_spec.cr
@@ -578,4 +578,14 @@ describe "Code gen: macro" do
       end
       )).to_i.should eq(2)
   end
+
+  it "executes with named arguments" do
+    run(%(
+      macro foo(x = 1)
+        {{x}} + 1
+      end
+
+      foo x: 2
+      )).to_i.should eq(3)
+  end
 end
diff --git a/spec/compiler/type_inference/macro_spec.cr b/spec/compiler/type_inference/macro_spec.cr
index 5913a915f9725b4184741d6d60521ffa55c769e9..77ad591bab1909962bdc6e9015ddf42d10b98780 100755
--- a/spec/compiler/type_inference/macro_spec.cr
+++ b/spec/compiler/type_inference/macro_spec.cr
@@ -202,4 +202,26 @@ describe "Type inference: macro" do
       ->(x : Foo) { x.foo; x.ivars_length }
       )) { fun_of(types["Foo"], no_return) }
   end
+
+  it "errors if non-existent named arg" do
+    assert_error %(
+      macro foo(x = 1)
+        {{x}} + 1
+      end
+
+      foo y: 2
+      ),
+      "no argument named 'y'"
+  end
+
+  it "errors if named arg already specified" do
+    assert_error %(
+      macro foo(x = 1)
+        {{x}} + 1
+      end
+
+      foo 2, x: 2
+      ),
+      "argument 'x' already specified"
+  end
 end
diff --git a/src/compiler/crystal/macros/macros.cr b/src/compiler/crystal/macros/macros.cr
index d0be3d5ffc3122806d1ea6d443a9500a6a9891f9..24ee8fef5d507ceb6ca2cf62a11eb30f3b217042 100644
--- a/src/compiler/crystal/macros/macros.cr
+++ b/src/compiler/crystal/macros/macros.cr
@@ -165,6 +165,11 @@ module Crystal
           vars[macro_arg.name] = call_arg.to_macro_var
         end
 
+        # The named arguments
+        call.named_args.try &.each do |named_arg|
+          vars[named_arg.name] = named_arg.value
+        end
+
         # The block arg
         call_block = call.block
         macro_block_arg = a_macro.block_arg
diff --git a/src/compiler/crystal/semantic/call.cr b/src/compiler/crystal/semantic/call.cr
index af586b2d9e37df82cec184f2a33339b6ff59ce2d..1cdd1529026e3d51a99a3195fed172f1f9871fcb 100644
--- a/src/compiler/crystal/semantic/call.cr
+++ b/src/compiler/crystal/semantic/call.cr
@@ -492,7 +492,7 @@ module Crystal
     end
 
     def lookup_macro
-      in_macro_target &.lookup_macro(name, args.length)
+      in_macro_target &.lookup_macro(name, args.length, named_args)
     end
 
     def in_macro_target
@@ -1016,6 +1016,17 @@ module Crystal
       if macros
         all_arguments_lengths = Set(Int32).new
         macros.each do |macro|
+          named_args.try &.each do |named_arg|
+            index = macro.args.index { |arg| arg.name == named_arg.name }
+            if index
+              if index < args.length
+                raise "argument '#{named_arg.name}' already specified"
+              end
+            else
+              raise "no argument named '#{named_arg.name}'"
+            end
+          end
+
           min_length = macro.args.index(&.default_value) || macro.args.length
           min_length.upto(macro.args.length) do |args_length|
             all_arguments_lengths << args_length
diff --git a/src/compiler/crystal/syntax/ast.cr b/src/compiler/crystal/syntax/ast.cr
index 7c19941a7a62a9205eef36934ca2b4a45c851406..8ac517cdd8a623bbde3a0572669a808b8bcb1821 100644
--- a/src/compiler/crystal/syntax/ast.cr
+++ b/src/compiler/crystal/syntax/ast.cr
@@ -894,7 +894,7 @@ module Crystal
       name.length
     end
 
-    def matches_args_length?(args_length)
+    def matches?(args_length, named_args)
       my_args_length = args.length
       min_args_length = args.index(&.default_value) || my_args_length
       max_args_length = my_args_length
@@ -902,7 +902,23 @@ module Crystal
         min_args_length -= 1
         max_args_length = Int32::MAX
       end
-      min_args_length <= args_length <= max_args_length
+
+      unless min_args_length <= args_length <= max_args_length
+        return false
+      end
+
+      named_args.try &.each do |named_arg|
+        index = args.index { |arg| arg.name == named_arg.name }
+        if index
+          if index < args_length
+            return false
+          end
+        else
+          return false
+        end
+      end
+
+      true
     end
 
     def clone_without_location
diff --git a/src/compiler/crystal/types.cr b/src/compiler/crystal/types.cr
index 5ac0a6ebac31d050d82045ef4af97aa94d31bc9d..700a462cc801980d9a329577377f314b596436c3 100644
--- a/src/compiler/crystal/types.cr
+++ b/src/compiler/crystal/types.cr
@@ -289,7 +289,7 @@ module Crystal
       raise "Bug: #{self} doesn't implement add_macro"
     end
 
-    def lookup_macro(name, args_length)
+    def lookup_macro(name, args_length, named_args)
       raise "Bug: #{self} doesn't implement lookup_macro"
     end
 
@@ -303,7 +303,7 @@ module Crystal
 
     def lookup_method_missing
       # method_missing is actually stored in the metaclass
-      method_missing = metaclass.lookup_macro("method_missing", 3)
+      method_missing = metaclass.lookup_macro("method_missing", 3, nil)
       return method_missing if method_missing
 
       parents.try &.each do |parent|
@@ -697,14 +697,14 @@ module Crystal
       nil
     end
 
-    def lookup_macro(name, args_length)
+    def lookup_macro(name, args_length, named_args)
       if (macros = self.macros) && (array = macros[name]?)
-        match = array.find &.matches_args_length?(args_length)
+        match = array.find &.matches?(args_length, named_args)
         return match if match
       end
 
       parents.try &.each do |parent|
-        parent_macro = parent.lookup_macro(name, args_length)
+        parent_macro = parent.lookup_macro(name, args_length, named_args)
         return parent_macro if parent_macro
       end
 
@@ -2890,7 +2890,7 @@ module Crystal
       true
     end
 
-    def lookup_macro(name, args_length)
+    def lookup_macro(name, args_length, named_args)
       nil
     end