From 15871a53a98ad58df7560490408d0942c6ffbdb9 Mon Sep 17 00:00:00 2001
From: Valentin Perrelle <valentin.perrelle@cea.fr>
Date: Mon, 18 Mar 2019 17:53:06 +0100
Subject: [PATCH] [Variadic] Distinguish various cast types

---
 src/plugins/variadic/standard.ml | 61 ++++++++++++++++++--------------
 1 file changed, 35 insertions(+), 26 deletions(-)

diff --git a/src/plugins/variadic/standard.ml b/src/plugins/variadic/standard.ml
index 8f2aac621af..d5b98d5d1d1 100644
--- a/src/plugins/variadic/standard.ml
+++ b/src/plugins/variadic/standard.ml
@@ -78,24 +78,29 @@ let integral_rep ikind =
 let expose t =
   Cil.type_remove_attributes_for_c_cast (Cil.unrollType t)
 
-let is_equivalent_enum given expected =
-  match expose given, expose expected with
-  | TInt (i1,a1), TEnum({ekind=i2},a2)
-  | TEnum({ekind=i1},a1), TInt (i2,a2) ->
-    integral_rep i1 = integral_rep i2 &&
-    Cil_datatype.Attributes.equal a1 a2
-  | _, _ -> false
+(* From most permissive to least permissive *)
+type castability = Strict      (* strictly allowed by the C standard *)
+                 | Tolerated   (* tolerated in practice *)
+                 | NonPortable (* non-portable minor deviation *)
+                 | NonStrict   (* only allowed in non-strict mode *)
+                 | Never       (* never allowed *)
 
 let can_cast given expected =
   match expose given, expose expected with
+  | t1, t2 when Cil_datatype.Typ.equal t1 t2 -> Strict
   | (TInt (i1,a1) | TEnum({ekind=i1},a1)),
-    (TInt (i2,a2) | TEnum({ekind=i2},a2))
-    when not (Strict.get ()) || is_extended_integer_type given ->
-    integral_rep i1 = integral_rep i2 &&
-    Cil_datatype.Attributes.equal a1 a2
-  | TPtr _, TPtr _ -> true
-  | exposed_given, exposed_expected ->
-    Cil_datatype.Typ.equal exposed_given exposed_expected
+    (TInt (i2,a2) | TEnum({ekind=i2},a2)) ->
+    if integral_rep i1 <> integral_rep i2 ||
+       not (Cil_datatype.Attributes.equal a1 a2) then
+      Never
+    else if is_extended_integer_type given then
+      Tolerated
+    else if i1 = i2 then
+      NonPortable
+    else
+      NonStrict
+  | TPtr _, TPtr _ -> Strict
+  | _, _ -> Never
 
 let does_fit exp typ =
   match Cil.constFoldToInt exp, Cil.unrollType typ with
@@ -114,18 +119,22 @@ let pretty_typ fmt t =
 (* cast the i-th argument exp to paramtyp *)
 let cast_arg i paramtyp exp =
   let argtyp = Cil.typeOf exp in
-  if not (can_cast argtyp paramtyp) && not (does_fit exp paramtyp) then
-    if Strict.get () && is_equivalent_enum argtyp paramtyp then
-      Self.warning ~current:true
-        "Possible portability issues with enum type for argument %d \
-         (use -variadic-no-strict to avoid this warning)."
-        (i + 1)
-    else
-      Self.warning ~current:true
-        "Incorrect type for argument %d. \
-         The argument will be cast from %a to %a."
-        (i + 1)
-        pretty_typ argtyp pretty_typ paramtyp;
+  if not (does_fit exp paramtyp) then
+    begin match can_cast argtyp paramtyp with
+      | Strict | Tolerated -> ()
+      | (NonPortable | NonStrict) when not (Strict.get ()) -> ()
+      | NonPortable ->
+        Self.warning ~current:true
+          "Possible portability issues with enum type for argument %d \
+           (use -variadic-no-strict to avoid this warning)."
+          (i + 1)
+      | NonStrict | Never ->
+        Self.warning ~current:true
+          "Incorrect type for argument %d. \
+           The argument will be cast from %a to %a."
+          (i + 1)
+          pretty_typ argtyp pretty_typ paramtyp
+  end;
   Cil.mkCast ~force:false ~e:exp ~newt:paramtyp
 
 
-- 
GitLab