diff --git a/src/kernel_internals/parsing/cparser.mly b/src/kernel_internals/parsing/cparser.mly
index 653febf25eb19fe0a24364f5d52a798a54a812a0..16b088b68fff25c7eddccdce038155a946c39eca 100644
--- a/src/kernel_internals/parsing/cparser.mly
+++ b/src/kernel_internals/parsing/cparser.mly
@@ -313,6 +313,15 @@ let in_ghost_block ?(battrs=[]) l =
                      get_statementloc (List.hd l),
                      get_statementloc (Extlib.last l)))
 
+let type_to_expr_for_builtin ~loc ~builtin specifier decl_type =
+  (* Prefix the builtin name with __fc_ to avoid collisions with real
+     world code. *)
+  let builtin = "__fc_" ^ builtin in
+  (* Build an expression representing the given type with a marker to indicate
+     the builtin for which this translation was made. *)
+  let info = SINGLE_INIT { expr_loc = loc; expr_node = VARIABLE builtin } in
+  { expr_loc = loc; expr_node = CAST ((specifier, decl_type), info) }
+
 %}
 
 %token <Filepath.position * string> SPEC
@@ -551,28 +560,31 @@ postfix_expression:                     /*(* 6.5.2 *)*/
 | postfix_expression LPAREN arguments RPAREN ghost_arguments_opt
     { make_expr $sloc (CALL ($1, $3, $5))}
 | BUILTIN_VA_ARG LPAREN expression COMMA type_name RPAREN {
+    let builtin = "__builtin_va_arg" in
     let b, d = $5 in
     let loc = Cil_datatype.Location.of_lexing_loc $loc($5) in
     let loc_f = Cil_datatype.Location.of_lexing_loc $loc($1) in
+    let type_as_expr = type_to_expr_for_builtin ~loc ~builtin b d in
     make_expr $sloc
       (CALL
           ({ expr_loc = loc_f;
-            expr_node = VARIABLE "__builtin_va_arg"},
-          [$3; { expr_loc = loc;
-                  expr_node = TYPE_SIZEOF (b, d)}],[]))
+            expr_node = VARIABLE builtin},
+          [$3; type_as_expr],[]))
   }
 | BUILTIN_TYPES_COMPAT LPAREN type_name COMMA type_name RPAREN {
+    let builtin = "__builtin_types_compatible_p" in
     let b1,d1 = $3 in
     let b2,d2 = $5 in
     let loc_f = Cil_datatype.Location.of_lexing_loc $loc($1) in
     let loc1 = Cil_datatype.Location.of_lexing_loc $loc($3) in
     let loc2 = Cil_datatype.Location.of_lexing_loc $loc($5) in
+    let type_as_expr1 = type_to_expr_for_builtin ~loc:loc1 ~builtin b1 d1 in
+    let type_as_expr2 = type_to_expr_for_builtin ~loc:loc2 ~builtin b2 d2 in
     make_expr $sloc
       (CALL
           ({expr_loc = loc_f;
-            expr_node = VARIABLE "__builtin_types_compatible_p"},
-          [ { expr_loc = loc1; expr_node = TYPE_SIZEOF(b1,d1)};
-            { expr_loc = loc2; expr_node = TYPE_SIZEOF(b2,d2)}],[]))
+            expr_node = VARIABLE builtin},
+          [ type_as_expr1; type_as_expr2],[]))
   }
 | BUILTIN_OFFSETOF LPAREN type_name COMMA offsetof_member_designator RPAREN {
     let loc_f = Cil_datatype.Location.of_lexing_loc $loc($1) in
diff --git a/src/kernel_internals/typing/cabs2cil.ml b/src/kernel_internals/typing/cabs2cil.ml
index 2624f808f3295b20ddd30c873b30b3d85b310f27..8ca38fc5074160939c7b5a83a1ec2ce56d50cbc6 100644
--- a/src/kernel_internals/typing/cabs2cil.ml
+++ b/src/kernel_internals/typing/cabs2cil.ml
@@ -260,7 +260,16 @@ let is_relational_bop = function
   | EQ | NE | LT | GT | LE | GE -> true
   | _ -> false
 
-let rec stripParen = function { expr_node = Cabs.PAREN e } -> stripParen e | e -> e
+let rec stripParen e =
+  match e with
+  | { expr_node = Cabs.PAREN e } -> stripParen e
+  | e -> e
+
+let is_for_builtin builtin info =
+  match info with
+  | SINGLE_INIT { expr_node = VARIABLE name } ->
+    String.equal ("__fc_" ^ builtin) name
+  | _ -> false
 
 let rec is_dangerous_offset = function
     NoOffset -> false
@@ -5815,6 +5824,26 @@ and doExp local_env
       finishExp [] scope_chunk (new_exp ~loc (AlignOfE(e'')))
         (Machine.sizeof_type ())
 
+    (* In cparser, the types used as arguments of certain builtins are converted
+       to casts so that they can be represented as expressions. The following
+       matches are special cases to type those expressions. They are then
+       converted to `sizeof typ` for CIL. *)
+    | Cabs.CAST ((specs, dt), info)
+      when is_for_builtin "__builtin_types_compatible_p" info ->
+      let typ = doOnlyType loc local_env.is_ghost specs dt in
+      let res = new_exp ~loc (SizeOf typ) in
+      finishExp [] (unspecified_chunk empty) res (Machine.sizeof_type ())
+
+    | Cabs.CAST ((specs, dt), info)
+      when is_for_builtin "__builtin_va_arg" info ->
+      let typ = doOnlyType loc local_env.is_ghost specs dt in
+      if not (Cil.isCompleteType typ) then
+        Kernel.error ~current:true "__builtin_va_arg on incomplete type '%a'"
+          Cil_datatype.Typ.pretty typ;
+      let res = new_exp ~loc (SizeOf typ) in
+      finishExp [] (unspecified_chunk empty) res (Machine.sizeof_type ())
+    (* End of special casts. *)
+
     | Cabs.CAST ((specs, dt), ie) ->
       let s', dt', ie' = preprocessCast loc local_env.is_ghost specs dt ie in
       (* We know now that we can do s' and dt' many times *)
diff --git a/src/kernel_services/ast_printing/cil_printer.ml b/src/kernel_services/ast_printing/cil_printer.ml
index f3bc4b667c5897190f2def423642db64ac39e9ff..43115b0c53e02396d7d2eace0a01209c23cf7045 100644
--- a/src/kernel_services/ast_printing/cil_printer.ml
+++ b/src/kernel_services/ast_printing/cil_printer.ml
@@ -1097,7 +1097,7 @@ class cil_printer () = object (self)
       let last = self#getLastNamedArgument () in
       self#instr fmt (Call(res,Cil.dummy_exp(Lval(Var vi,NoOffset)),[last],l))
 
-    (* In cparser we have turned the call to
+    (* In cabs2cil we have turned the call to
        __builtin_types_compatible_p(t1, t2) into
        __builtin_types_compatible_p(sizeof t1, sizeof t2), so that we can
        represent the types as expressions.
diff --git a/tests/syntax/builtin_types_compatible.i b/tests/syntax/builtin_types_compatible.i
new file mode 100644
index 0000000000000000000000000000000000000000..891cb5e7e4cc51d1f204b8e4f22cfced2fbc56bb
--- /dev/null
+++ b/tests/syntax/builtin_types_compatible.i
@@ -0,0 +1,6 @@
+/* run.config
+   OPT: -machdep gcc_x86_64 -print
+*/
+int main() {
+  return __builtin_types_compatible_p(int, int[]);
+}
diff --git a/tests/syntax/oracle/builtin_types_compatible.res.oracle b/tests/syntax/oracle/builtin_types_compatible.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..139913b6d02b7ab273e78c70b122d1ddad90dcdc
--- /dev/null
+++ b/tests/syntax/oracle/builtin_types_compatible.res.oracle
@@ -0,0 +1,10 @@
+[kernel] Parsing builtin_types_compatible.i (no preprocessing)
+/* Generated by Frama-C */
+int main(void)
+{
+  int __retres;
+  __retres = 0;
+  return __retres;
+}
+
+