diff --git a/tccgen.c b/tccgen.c
index 05fb50ab..cb7e221b 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -3181,6 +3181,22 @@ static void parse_attribute(AttributeDef *ad)
     }
 }
 
+static Sym * find_field (CType *type, int v)
+{
+    Sym *s = type->ref;
+    v |= SYM_FIELD;
+    while ((s = s->next) != NULL) {
+	if ((s->v & SYM_FIELD) && (s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) {
+	    Sym *ret = find_field (&s->type, v);
+	    if (ret)
+	        return ret;
+	}
+	if (s->v == v)
+	  break;
+    }
+    return s;
+}
+
 /* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */
 static void struct_decl(CType *type, AttributeDef *ad, int u)
 {
@@ -3404,13 +3420,40 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
 #endif
                     }
                     if (v == 0 && (type1.t & VT_BTYPE) == VT_STRUCT) {
+			/* An anonymous struct/union.  Adjust member offsets
+			   to reflect the real offset of our containing struct.
+			   Also set the offset of this anon member inside
+			   the outer struct to be zero.  Via this it
+			   works when accessing the field offset directly
+			   (from base object), as well as when recursing
+			   members in initializer handling.  */
+			int v2 = btype.ref->v;
+			if (!(v2 & SYM_FIELD) &&
+			    (v2 & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
+			    Sym **pps;
+			    /* This happens only with MS extensions.  The
+			       anon member has a named struct type, so it
+			       potentially is shared with other references.
+			       We need to unshare members so we can modify
+			       them.  */
+			    ass = type1.ref;
+			    type1.ref = sym_push(anon_sym++ | SYM_FIELD,
+						 &type1.ref->type, 0,
+						 type1.ref->c);
+			    pps = &type1.ref->next;
+			    while ((ass = ass->next) != NULL) {
+			        *pps = sym_push(ass->v, &ass->type, 0, ass->c);
+				pps = &((*pps)->next);
+			    }
+			    *pps = NULL;
+			}
                         ass = type1.ref;
-                        while ((ass = ass->next) != NULL) {
-                           ss = sym_push(ass->v, &ass->type, 0, offset + ass->c);
-                           *ps = ss;
-                           ps = &ss->next;
-                        }
-                    } else if (v) {
+                        while ((ass = ass->next) != NULL)
+			    ass->c += offset;
+			offset = 0;
+		        v = anon_sym++;
+		    }
+                    if (v) {
                         ss = sym_push(v | SYM_FIELD, &type1, 0, offset);
                         *ps = ss;
                         ps = &ss->next;
@@ -4536,13 +4579,7 @@ ST_FUNC void unary(void)
             next();
             if (tok == TOK_CINT || tok == TOK_CUINT)
                 expect("field name");
-            s = vtop->type.ref;
-            /* find field */
-            tok |= SYM_FIELD;
-            while ((s = s->next) != NULL) {
-                if (s->v == tok)
-                    break;
-            }
+	    s = find_field(&vtop->type, tok);
             if (!s)
                 tcc_error("field not found: %s",  get_tok_str(tok & ~SYM_FIELD, &tokc));
             /* add field offset to pointer */
@@ -5729,14 +5766,7 @@ static void decl_designator(CType *type, Section *sec, unsigned long c,
         struct_field:
             if ((type->t & VT_BTYPE) != VT_STRUCT)
                 expect("struct/union type");
-            s = type->ref;
-            l |= SYM_FIELD;
-            f = s->next;
-            while (f) {
-                if (f->v == l)
-                    break;
-                f = f->next;
-            }
+	    f = find_field(type, l);
             if (!f)
                 expect("field");
             if (!notfirst)
diff --git a/tests/tests2/86-struct-init.c b/tests/tests2/86-struct-init.c
index fa0d9670..6749f984 100644
--- a/tests/tests2/86-struct-init.c
+++ b/tests/tests2/86-struct-init.c
@@ -77,6 +77,25 @@ struct SU {
 };
 struct SU gsu = {5,6};
 
+/* Unnamed struct/union members aren't ISO C, but it's a widely accepted
+   extension.  See below for further extensions to that under -fms-extension.*/
+union UV {
+    struct {u8 a,b;};
+    struct S s;
+};
+union UV guv = {{6,5}};
+union UV guv2 = {{.b = 7, .a = 8}};
+union UV guv3 = {.b = 8, .a = 7};
+
+/* Under -fms-extensions also the following is valid:
+union UV2 {
+    struct Anon {u8 a,b;};    // unnamed member, but tagged struct, ...
+    struct S s;
+};
+struct Anon gan = { 10, 11 }; // ... which makes it available here.
+union UV2 guv4 = {{4,3}};     // and the other inits from above as well
+*/
+
 #include <stdio.h>
 void print_ (const char *name, const u8 *p, long size)
 {
@@ -144,6 +163,10 @@ int main()
   print(sinit16);
   print(gw);
   print(gsu);
+  print(guv);
+  print(guv.b);
+  print(guv2);
+  print(guv3);
   foo(&gw);
   //printf("q: %s\n", q);
   return 0;
diff --git a/tests/tests2/86-struct-init.expect b/tests/tests2/86-struct-init.expect
index 6ae60e00..a5333dce 100644
--- a/tests/tests2/86-struct-init.expect
+++ b/tests/tests2/86-struct-init.expect
@@ -13,6 +13,10 @@ gv3: 7 8 9 a 68 6f 68 6f 0 0 0 0 0 0 0 0 0 0 0 0 31 32
 sinit16: 1 0 0 0 2 0 0 0
 gw: 1 2 3 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 gsu: 5 6
+guv: 6 5 0 0
+guv.b: 5
+guv2: 8 7 0 0
+guv3: 7 8 0 0
 ls: 1 2 3 4
 ls2: 1 2 3 4
 lt: 68 65 6c 6c 6f 0 0 0 0 0 0 0 0 0 0 0 2a