From a57403695e11529e2e4f56793450fbb9171c122d Mon Sep 17 00:00:00 2001
From: Ian <i.r.butterworth@gmail.com>
Date: Sun, 7 Aug 2022 15:24:44 -0400
Subject: [PATCH 1/3] make kwdef handle const and atomic fields

---
 base/util.jl | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/base/util.jl b/base/util.jl
index 1dc59e86d7043..12a2f93e08195 100644
--- a/base/util.jl
+++ b/base/util.jl
@@ -577,7 +577,16 @@ function _kwdef!(blk, params_args, call_args)
             push!(params_args, ei)
             push!(call_args, ei)
         elseif ei isa Expr
-            if ei.head === :(=)
+            is_atomic = ei.head == :atomic
+            ei = is_atomic ? first(ei.args) : ei # strip "@atomic" and add it back later
+            is_const = ei.head == :const
+            ei = is_const ? first(ei.args) : ei # strip "const" and add it back later
+            # Note: `@atomic const ..` isn't valid, but reconstruct it anyway to serve a nice error
+            if ei isa Symbol
+                # const var
+                push!(params_args, ei)
+                push!(call_args, ei)
+            elseif ei.head === :(=)
                 lhs = ei.args[1]
                 if lhs isa Symbol
                     #  var = defexpr
@@ -593,7 +602,9 @@ function _kwdef!(blk, params_args, call_args)
                 defexpr = ei.args[2]  # defexpr
                 push!(params_args, Expr(:kw, var, esc(defexpr)))
                 push!(call_args, var)
-                blk.args[i] = lhs
+                lhs = is_const ? Expr(:const, lhs) : lhs
+                lhs = is_atomic ? Expr(:atomic, lhs) : lhs
+                blk.args[i] = lhs # overrides arg
             elseif ei.head === :(::) && ei.args[1] isa Symbol
                 # var::Typ
                 var = ei.args[1]

From 1afddecd98d2d51351bc442939779cd120fb0ae0 Mon Sep 17 00:00:00 2001
From: Ian <i.r.butterworth@gmail.com>
Date: Sun, 7 Aug 2022 15:58:58 -0400
Subject: [PATCH 2/3] add tests

---
 test/misc.jl | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/test/misc.jl b/test/misc.jl
index bf4b4f2bb41e5..8a0ad13403bcd 100644
--- a/test/misc.jl
+++ b/test/misc.jl
@@ -1103,6 +1103,37 @@ const outsidevar = 7
 end
 @test TestOutsideVar() == TestOutsideVar(7)
 
+@kwdef mutable struct Test_kwdef_const_atomic
+    a
+    b::Int
+    c::Int = 1
+    const d
+    const e::Int
+    const f = 1
+    const g::Int = 1
+    @atomic h::Int
+end
+
+@testset "const and @atomic fields in @kwdef" begin
+    x = Test_kwdef_const_atomic(a = 1, b = 1, d = 1, e = 1, h = 1)
+    for f in fieldnames(Test_kwdef_const_atomic)
+        @test getfield(x, f) == 1
+    end
+    @testset "const fields" begin
+        @test_throws ErrorException x.d = 2
+        @test_throws ErrorException x.e = 2
+        @test_throws MethodError x.e = "2"
+        @test_throws ErrorException x.f = 2
+        @test_throws ErrorException x.g = 2
+    end
+    @testset "atomic fields" begin
+        @test_throws ConcurrencyViolationError x.h = 1
+        @atomic x.h = 1
+        @test @atomic(x.h) == 1
+        @atomic x.h = 2
+        @test @atomic(x.h) == 2
+    end
+end
 
 @testset "exports of modules" begin
     for (_, mod) in Base.loaded_modules

From a39ba06b0b62b831285308c9b9afd449e9eb424a Mon Sep 17 00:00:00 2001
From: Ian Butterworth <i.r.butterworth@gmail.com>
Date: Sun, 7 Aug 2022 21:55:54 -0400
Subject: [PATCH 3/3] Update base/util.jl

Co-authored-by: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com>
---
 base/util.jl | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/base/util.jl b/base/util.jl
index 12a2f93e08195..b824fe1c351dc 100644
--- a/base/util.jl
+++ b/base/util.jl
@@ -577,9 +577,9 @@ function _kwdef!(blk, params_args, call_args)
             push!(params_args, ei)
             push!(call_args, ei)
         elseif ei isa Expr
-            is_atomic = ei.head == :atomic
+            is_atomic = ei.head === :atomic
             ei = is_atomic ? first(ei.args) : ei # strip "@atomic" and add it back later
-            is_const = ei.head == :const
+            is_const = ei.head === :const
             ei = is_const ? first(ei.args) : ei # strip "const" and add it back later
             # Note: `@atomic const ..` isn't valid, but reconstruct it anyway to serve a nice error
             if ei isa Symbol