diff --git a/src/kernel_internals/typing/cabs2cil.ml b/src/kernel_internals/typing/cabs2cil.ml
index be7ee677ba43a0c93425491803f9685c3c8138c8..084ea1a8202bb167ed68197be40e8a0d3cc1ac60 100644
--- a/src/kernel_internals/typing/cabs2cil.ml
+++ b/src/kernel_internals/typing/cabs2cil.ml
@@ -1386,10 +1386,16 @@ let findCompType ghost kind name tattr =
     if kind = "enum" then
       let enum, isnew = createEnumInfo name ~norig:name in
       if isnew then
-        cabsPushGlobal (GEnumTagDecl (enum, Current_loc.get ()));
+        begin
+          if not (Machine.gccMode ()) then
+            Kernel.error ~once:true
+              ~source:(fst @@ Current_loc.get ())
+              "forward declaration of enum %s" (Machdep.allowed_machdep "GCC");
+          cabsPushGlobal (GEnumTagDecl (enum, Current_loc.get ()));
+        end;
       mk_tenum ~tattr enum
     else
-      let iss = if kind = "struct" then true else false in
+      let iss = kind = "struct" in
       let self, isnew = createCompInfo iss name ~norig:name in
       if isnew then
         cabsPushGlobal (GCompTagDecl (self, Current_loc.get ()));
@@ -1418,8 +1424,8 @@ class canDropStmtClass pRes = object
 
   method! vinst _ = Cil.SkipChildren
   method! vexpr _ = Cil.SkipChildren
-
 end
+
 let canDropStatement (s: stmt) : bool =
   let pRes = ref true in
   let vis = new canDropStmtClass pRes in
@@ -6510,7 +6516,7 @@ and doExp local_env
         | { tnode = TPtr t } -> begin
             match unrollType t with
             | { tnode = TFun (rt, at, isvar) } -> (* Make the function pointer
-                                                    * explicit  *)
+                                                   * explicit  *)
               let f'' =
                 match f'.enode with
                 | AddrOf lv -> new_exp ~loc:f'.eloc (Lval(lv))
@@ -9770,7 +9776,8 @@ and doTypedef ghost ((specs, nl): Cabs.name_group) =
                 Cil_datatype.Location.pretty oldloc
             in
             (* Tested with GCC+Clang: redefinition of compatible types in same scope:
-               - enums are NOT allowed;
+               - enums are NOT allowed, except if they refer to the exact same
+                 enumerated type
                - composite types are allowed only if the composite type itself is
                  not redefined (complex rules; with some extra tag checking performed
                  in compatibleTypesp, we use tags here to detect redefinitions,
@@ -9798,8 +9805,29 @@ and doTypedef ghost ((specs, nl): Cabs.name_group) =
                       Kernel.fatal ~current:true "typeinfo.ttype (%a) should be TComp"
                         Cil_datatype.Typ.pretty typeinfo.ttype
                   end
-                | TEnum _ -> (* GCC/Clang: "conflicting types" *)
-                  error_conflicting_types ()
+                | TEnum newei -> (* GCC/Clang: "conflicting types" *)
+                  let t = unrollType typeinfo.ttype in
+                  (match t.tnode with
+                   | TEnum ei ->
+                     if ei.ename <> newei.ename then
+                       error_conflicting_types ()
+                     else
+                       warn_c11_redefinition ()
+                   | TInt _ -> error_conflicting_types ()
+                   | _ ->
+                     Kernel.fatal
+                       ~current:true "typeinfo.ttype (%a) should be an Enum"
+                       Cil_datatype.Typ.pretty t)
+                | TInt _ ->
+                  let t = unrollType typeinfo.ttype in
+                  (match t.tnode with
+                   | TInt _ -> warn_c11_redefinition ()
+                   | TEnum _ -> error_conflicting_types ()
+                   | _ ->
+                     Kernel.fatal
+                       ~current:true "typeinfo.ttype (%a) should be an int"
+                       Cil_datatype.Typ.pretty t
+                  )
                 | _ -> (* redeclaration in same scope valid only in C11 *)
                   warn_c11_redefinition ()
               end
diff --git a/tests/syntax/ast_diff_1.i b/tests/syntax/ast_diff_1.i
index 86b0c7606e68395abec4be4f0e5f217d056450c7..4d93a93c5eaae6eca99f167bedf110ed48e44494 100644
--- a/tests/syntax/ast_diff_1.i
+++ b/tests/syntax/ast_diff_1.i
@@ -2,8 +2,8 @@
    COMMENT: we need Eva for the loop unroll ACSL extension
    PLUGIN: eva
    MODULE: @PTEST_NAME@
-     OPT: -then -ast-diff %{dep:ast_diff_2.c}
-     OPT: -then -ast-diff %{dep:ast_diff_2.c} -cpp-extra-args="-DADD_ENUM_TAG"
+     OPT: -machdep gcc_x86_64 -then -ast-diff %{dep:ast_diff_2.c}
+     OPT: -machdep gcc_x86_64 -then -ast-diff %{dep:ast_diff_2.c} -cpp-extra-args="-DADD_ENUM_TAG"
 */
 int X;
 int Y=3;
diff --git a/tests/syntax/enum_forward.i b/tests/syntax/enum_forward.i
new file mode 100644
index 0000000000000000000000000000000000000000..6ae9fbdd9386d367b955bae2fb9f9de792c70b3f
--- /dev/null
+++ b/tests/syntax/enum_forward.i
@@ -0,0 +1,21 @@
+/* run.config
+   OPT: -machdep gcc_x86_64 -print
+   EXIT: 1
+   STDOPT:
+*/
+/* forward declaration of enum is supported by GCC but nonstandard */
+
+enum e X;
+enum e { V };
+
+enum g Y;
+typedef enum g { W } g;
+
+enum h;
+typedef enum h h;
+typedef enum h { Z } h;
+h hh = Z;
+
+typedef enum i { A } i;
+typedef enum i i;
+i ii = A;
diff --git a/tests/syntax/enum_redef_ko.i b/tests/syntax/enum_redef_ko.i
new file mode 100644
index 0000000000000000000000000000000000000000..d7358e0eceeb59fb30d06be5669994aa00b5eec6
--- /dev/null
+++ b/tests/syntax/enum_redef_ko.i
@@ -0,0 +1,9 @@
+/* run.config
+   EXIT: 1
+   STDOPT:
+*/
+
+/* redeclaration of enum */
+
+enum e { U };
+enum e { U };
diff --git a/tests/syntax/enum_redef_ok.i b/tests/syntax/enum_redef_ok.i
new file mode 100644
index 0000000000000000000000000000000000000000..bc488d4b192ed189f34e8289fa966466bee63e9d
--- /dev/null
+++ b/tests/syntax/enum_redef_ok.i
@@ -0,0 +1,9 @@
+/* run.config
+   STDOPT:
+*/
+
+/* "tentative definition" is allowed */
+
+enum e { U };
+enum e;
+enum e x = U;
diff --git a/tests/syntax/enum_typedef_redef.i b/tests/syntax/enum_typedef_redef.i
new file mode 100644
index 0000000000000000000000000000000000000000..2858e9f2778e1041a3c851b037ec596d277ff822
--- /dev/null
+++ b/tests/syntax/enum_typedef_redef.i
@@ -0,0 +1,19 @@
+/* run.config
+   EXIT: 1
+   STDOPT:
+*/
+
+/* this is the counterpart of enum_forward.i: we can accept a double typedef
+   with of an enum only if the first type is a forward declaration. */
+
+typedef enum h { Z } h;
+typedef enum h { Z } h;
+h hh = Z;
+
+// other problematic case, even though the enum is compatible with int
+
+typedef enum { E } t;
+typedef int t;
+
+typedef int q;
+typedef enum { F } q;
diff --git a/tests/syntax/oracle/enum_forward.0.res.oracle b/tests/syntax/oracle/enum_forward.0.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..c55d86c1ce477a053f345be172757f59f28ffd6a
--- /dev/null
+++ b/tests/syntax/oracle/enum_forward.0.res.oracle
@@ -0,0 +1,25 @@
+[kernel] Parsing enum_forward.i (no preprocessing)
+/* Generated by Frama-C */
+enum e;
+enum e {
+    V = 0
+};
+enum g;
+enum g {
+    W = 0
+};
+enum h;
+enum h;
+typedef enum h h;
+enum h {
+    Z = 0
+};
+enum i {
+    A = 0
+};
+typedef enum i i;
+enum e X;
+enum g Y;
+h hh = Z;
+i ii = A;
+
diff --git a/tests/syntax/oracle/enum_forward.1.res.oracle b/tests/syntax/oracle/enum_forward.1.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..30e3f01128fdd3df65d47b15337175297a729031
--- /dev/null
+++ b/tests/syntax/oracle/enum_forward.1.res.oracle
@@ -0,0 +1,9 @@
+[kernel] Parsing enum_forward.i (no preprocessing)
+[kernel] enum_forward.i:8: User Error: 
+  forward declaration of enum only allowed for GCC machdeps; see option -machdep or run 'frama-c -machdep help' for the list of available machdeps
+[kernel] enum_forward.i:11: User Error: 
+  forward declaration of enum only allowed for GCC machdeps; see option -machdep or run 'frama-c -machdep help' for the list of available machdeps
+[kernel] enum_forward.i:14: User Error: 
+  forward declaration of enum only allowed for GCC machdeps; see option -machdep or run 'frama-c -machdep help' for the list of available machdeps
+[kernel] User Error: stopping on file "enum_forward.i" that has errors.
+[kernel] Frama-C aborted: invalid user input.
diff --git a/tests/syntax/oracle/enum_redef_ko.res.oracle b/tests/syntax/oracle/enum_redef_ko.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..93c3071d301a32de6b049ee62a9911f51300e439
--- /dev/null
+++ b/tests/syntax/oracle/enum_redef_ko.res.oracle
@@ -0,0 +1,9 @@
+[kernel] Parsing enum_redef_ko.i (no preprocessing)
+[kernel] enum_redef_ko.i:9: User Error: 
+  redefinition of 'e' in the same scope.
+  Previous declaration was at enum_redef_ko.i:8
+[kernel] enum_redef_ko.i:9: User Error: 
+  redefinition of 'U' in the same scope.
+  Previous declaration was at enum_redef_ko.i:8
+[kernel] User Error: stopping on file "enum_redef_ko.i" that has errors.
+[kernel] Frama-C aborted: invalid user input.
diff --git a/tests/syntax/oracle/enum_redef_ok.res.oracle b/tests/syntax/oracle/enum_redef_ok.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..c7df72848b6b4be8c95761feb7d2ba6959cf68af
--- /dev/null
+++ b/tests/syntax/oracle/enum_redef_ok.res.oracle
@@ -0,0 +1,8 @@
+[kernel] Parsing enum_redef_ok.i (no preprocessing)
+/* Generated by Frama-C */
+enum e {
+    U = 0
+};
+enum e;
+enum e x = U;
+
diff --git a/tests/syntax/oracle/enum_typedef_redef.res.oracle b/tests/syntax/oracle/enum_typedef_redef.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..75c247e34e14f5f1028fcd82ece255c02b046582
--- /dev/null
+++ b/tests/syntax/oracle/enum_typedef_redef.res.oracle
@@ -0,0 +1,18 @@
+[kernel] Parsing enum_typedef_redef.i (no preprocessing)
+[kernel] enum_typedef_redef.i:10: User Error: 
+  redefinition of 'h' in the same scope.
+  Previous declaration was at enum_typedef_redef.i:9
+[kernel] enum_typedef_redef.i:10: User Error: 
+  redefinition of 'Z' in the same scope.
+  Previous declaration was at enum_typedef_redef.i:9
+[kernel] enum_typedef_redef.i:10: User Error: 
+  redefinition of type 'h' in the same scope with conflicting type.
+  Previous declaration was at enum_typedef_redef.i:9
+[kernel] enum_typedef_redef.i:16: User Error: 
+  redefinition of type 't' in the same scope with conflicting type.
+  Previous declaration was at enum_typedef_redef.i:15
+[kernel] enum_typedef_redef.i:19: User Error: 
+  redefinition of type 'q' in the same scope with conflicting type.
+  Previous declaration was at enum_typedef_redef.i:18
+[kernel] User Error: stopping on file "enum_typedef_redef.i" that has errors.
+[kernel] Frama-C aborted: invalid user input.