erik.pilkington updated this revision to Diff 208545.
erik.pilkington marked 2 inline comments as done.
erik.pilkington added a comment.

Address review comments.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63912/new/

https://reviews.llvm.org/D63912

Files:
  clang/include/clang/Basic/DiagnosticGroups.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaChecking.cpp
  clang/test/Sema/objc-bool-constant-conversion-fixit.m
  clang/test/Sema/objc-bool-constant-conversion.m

Index: clang/test/Sema/objc-bool-constant-conversion.m
===================================================================
--- /dev/null
+++ clang/test/Sema/objc-bool-constant-conversion.m
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+
+typedef signed char BOOL;
+#define YES __objc_yes
+#define NO __objc_no
+
+BOOL B;
+
+int main() {
+  B = 0;
+  B = 1;
+  B = YES;
+  B = NO;
+
+  B = -1; // expected-warning{{implicit conversion from constant value -1 to BOOL; the only well defined values for BOOL are YES and NO}}
+  B = 0 - 1; // expected-warning{{implicit conversion from constant value -1 to BOOL; the only well defined values for BOOL are YES and NO}}
+  B = YES + YES; // expected-warning {{implicit conversion from constant value 2 to BOOL; the only well defined values for BOOL are YES and NO}}
+  B = YES | YES;
+
+  B = B ? 2 : 2; // expected-warning 2 {{implicit conversion from constant value 2 to BOOL; the only well defined values for BOOL are YES and NO}}
+
+  BOOL Init = -1; // expected-warning{{implicit conversion from constant value -1 to BOOL; the only well defined values for BOOL are YES and NO}}
+  BOOL Init2 = B ? 2 : 2; // expected-warning 2 {{implicit conversion from constant value 2 to BOOL; the only well defined values for BOOL are YES and NO}}
+
+  void takesbool(BOOL);
+  takesbool(43); // expected-warning {{implicit conversion from constant value 43 to BOOL; the only well defined values for BOOL are YES and NO}}
+
+  BOOL OutOfRange = 400; // expected-warning{{implicit conversion from constant value 400 to BOOL; the only well defined values for BOOL are YES and NO}}
+}
+
+@interface BoolProp
+@property BOOL b;
+@end
+
+void f(BoolProp *bp) {
+  bp.b = 43; // expected-warning {{implicit conversion from constant value 43 to BOOL; the only well defined values for BOOL are YES and NO}}
+  [bp setB:43]; // expected-warning {{implicit conversion from constant value 43 to BOOL; the only well defined values for BOOL are YES and NO}}
+}
Index: clang/test/Sema/objc-bool-constant-conversion-fixit.m
===================================================================
--- /dev/null
+++ clang/test/Sema/objc-bool-constant-conversion-fixit.m
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -Werror=constant-conversion %s -fixit-recompile -fixit-to-temporary -E -o - | FileCheck %s
+
+typedef signed char BOOL;
+
+BOOL b;
+
+int main() {
+  BOOL b = 2;
+  // CHECK: BOOL b = 2 ? YES : NO;
+
+  b = b ? 2 : 1;
+  // CHECK: b = b ? 2 ? YES : NO : 1;
+
+  b = b ? 1 : 2;
+  // CHECK: b = b ? 1 : 2 ? YES : NO;
+
+  b = b ? 2 : 2;
+  // CHECK: b = b ? 2 ? YES : NO : 2 ? YES : NO;
+
+  b = 1 + 1;
+  // CHECK: b = (1 + 1) ? YES : NO;
+
+  b = 1 | 2;
+  // CHECK: b = (1 | 2) ? YES : NO;
+
+  b = 1 << 1;
+  // CHECK: b = (1 << 1) ? YES : NO;
+}
+
+@interface BoolProp
+@property BOOL b;
+@end
+
+void f(BoolProp *bp) {
+  bp.b = 43;
+  // CHECK: bp.b = 43 ? YES : NO;
+
+  [bp setB:43];
+  // CHECK: [bp setB:43 ? YES : NO];
+}
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -11135,6 +11135,11 @@
   return true;
 }
 
+static bool isObjCSignedCharBool(Sema &S, QualType Ty) {
+  return Ty->isSpecificBuiltinType(BuiltinType::SChar) &&
+         S.getLangOpts().ObjC && S.NSAPIObj->isObjCBOOLType(Ty);
+}
+
 static void
 CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
                         bool *ICContext = nullptr) {
@@ -11178,6 +11183,29 @@
     }
   }
 
+  // If the we're converting a constant to an ObjC BOOL on a platform where BOOL
+  // is a typedef for signed char (macOS), then that constant value has to be 1
+  // or 0.
+  if (isObjCSignedCharBool(S, T) && Source->isIntegralType(S.Context)) {
+    Expr::EvalResult Result;
+    if (E->EvaluateAsInt(Result, S.getASTContext(),
+                         Expr::SE_AllowSideEffects) &&
+        Result.Val.getInt() != 1 && Result.Val.getInt() != 0) {
+      auto Builder = S.Diag(CC, diag::warn_impcast_constant_int_to_objc_bool)
+                     << Result.Val.getInt().toString(10);
+      Expr *Ignored = E->IgnoreImplicit();
+      bool NeedsParens = isa<AbstractConditionalOperator>(Ignored) ||
+                         isa<BinaryOperator>(Ignored) ||
+                         isa<CXXOperatorCallExpr>(Ignored);
+      SourceLocation EndLoc = S.getLocForEndOfToken(E->getEndLoc());
+      if (NeedsParens)
+        Builder << FixItHint::CreateInsertion(E->getBeginLoc(), "(")
+                << FixItHint::CreateInsertion(EndLoc, ")");
+      Builder << FixItHint::CreateInsertion(EndLoc, " ? YES : NO");
+      return;
+    }
+  }
+
   // Check implicit casts from Objective-C collection literals to specialized
   // collection types, e.g., NSArray<NSString *> *.
   if (auto *ArrayLiteral = dyn_cast<ObjCArrayLiteral>(E))
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3245,6 +3245,10 @@
 def warn_impcast_bitfield_precision_constant : Warning<
   "implicit truncation from %2 to bit-field changes value from %0 to %1">,
   InGroup<BitFieldConstantConversion>;
+def warn_impcast_constant_int_to_objc_bool : Warning<
+  "implicit conversion from constant value %0 to BOOL; "
+  "the only well defined values for BOOL are YES and NO">,
+  InGroup<ObjCBoolConstantConversion>;
 
 def warn_impcast_fixed_point_range : Warning<
   "implicit conversion from %0 cannot fit within the range of values for %1">,
Index: clang/include/clang/Basic/DiagnosticGroups.td
===================================================================
--- clang/include/clang/Basic/DiagnosticGroups.td
+++ clang/include/clang/Basic/DiagnosticGroups.td
@@ -48,8 +48,10 @@
 def CoroutineMissingUnhandledException :
   DiagGroup<"coroutine-missing-unhandled-exception">;
 def Coroutine : DiagGroup<"coroutine", [CoroutineMissingUnhandledException]>;
-def ConstantConversion :
-  DiagGroup<"constant-conversion", [ BitFieldConstantConversion ] >;
+def ObjCBoolConstantConversion : DiagGroup<"objc-bool-constant-conversion">;
+def ConstantConversion : DiagGroup<"constant-conversion",
+                                   [BitFieldConstantConversion,
+                                    ObjCBoolConstantConversion]>;
 def LiteralConversion : DiagGroup<"literal-conversion">;
 def StringConversion : DiagGroup<"string-conversion">;
 def SignConversion : DiagGroup<"sign-conversion">;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to