Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -47,7 +47,6 @@ def ConstantConversion : DiagGroup<"constant-conversion", [ BitFieldConstantConversion ] >; def LiteralConversion : DiagGroup<"literal-conversion">; -def StringConversion : DiagGroup<"string-conversion">; def SignConversion : DiagGroup<"sign-conversion">; def PointerBoolConversion : DiagGroup<"pointer-bool-conversion">; def UndefinedBoolConversion : DiagGroup<"undefined-bool-conversion">; @@ -676,8 +675,7 @@ NonLiteralNullConversion, // (1-1)->pointer (etc) NullConversion, // NULL->non-pointer ObjCLiteralConversion, - SignConversion, - StringConversion]>, + SignConversion]>, DiagCategory<"Value Conversion Issue">; def Unused : DiagGroup<"unused", Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -3144,9 +3144,9 @@ "implicit conversion from %0 to %1 changes non-zero value from %2 to %3">, InGroup, DefaultIgnore; -def warn_impcast_string_literal_to_bool : Warning< - "implicit conversion turns string literal into bool: %0 to %1">, - InGroup, DefaultIgnore; +def warn_impcast_literal_to_bool : Warning< + "implicit conversion from %0 to %1; will always evaluate to " + "'%select{false|true}2'">, InGroup; def warn_impcast_different_enum_types : Warning< "implicit conversion from enumeration type %0 to different enumeration type " "%1">, InGroup; Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -9348,10 +9348,7 @@ Value.toString(PrettySourceValue, precision); SmallString<16> PrettyTargetValue; - if (IsBool) - PrettyTargetValue = Value.isZero() ? "false" : "true"; - else - IntegerValue.toString(PrettyTargetValue); + IntegerValue.toString(PrettyTargetValue); if (PruneWarnings) { S.DiagRuntimeBehavior(E->getExprLoc(), E, @@ -9609,12 +9606,31 @@ // Diagnose implicit casts to bool. if (Target->isSpecificBuiltinType(BuiltinType::Bool)) { - if (isa(E)) - // Warn on string literal to bool. Checks for string literals in logical - // and expressions, for instance, assert(0 && "error here"), are - // prevented by a check in AnalyzeImplicitConversions(). - return DiagnoseImpCast(S, E, T, CC, - diag::warn_impcast_string_literal_to_bool); + if (isa(E)) { + // Warn on string literal to bool. Checks for string literals in logical + // AND expressions, for instance, assert(0 && "error here"), are + // prevented by a check in AnalyzeImplicitConversions(). All string + // literal implicit conversions to bool evaluate to true. + S.Diag(E->getLocStart(), diag::warn_impcast_literal_to_bool) + << E->getType() << T << true << E->getSourceRange() + << SourceRange(CC); + return; + } + if (const auto *CharLit = dyn_cast(E)) { + // Warn on char literal to bool. + S.Diag(CharLit->getLocation(), diag::warn_impcast_literal_to_bool) + << E->getType() << T << (bool)CharLit->getValue() + << E->getSourceRange() << SourceRange(CC); + return; + } + if (const auto *FL = dyn_cast(E)) { + // When converting from a floating-point literal to boolean, always + // diagnose, even if the literal will exactly convert to an interger. + S.Diag(FL->getExprLoc(), diag::warn_impcast_literal_to_bool) + << FL->getType() << T.getUnqualifiedType() << !FL->getValue().isZero() + << FL->getSourceRange() << SourceRange(CC); + return; + } if (isa(E) || isa(E) || isa(E) || isa(E)) { // This covers the literal expressions that evaluate to Objective-C Index: test/Analysis/casts.c =================================================================== --- test/Analysis/casts.c +++ test/Analysis/casts.c @@ -1,10 +1,10 @@ -// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin9 -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify %s -// RUN: %clang_analyze_cc1 -triple i386-apple-darwin9 -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify %s +// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin9 -Wno-literal-conversion -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify %s +// RUN: %clang_analyze_cc1 -triple i386-apple-darwin9 -Wno-literal-conversion -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify %s extern void clang_analyzer_eval(_Bool); // Test if the 'storage' region gets properly initialized after it is cast to -// 'struct sockaddr *'. +// 'struct sockaddr *'. typedef unsigned char __uint8_t; typedef unsigned int __uint32_t; Index: test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp =================================================================== --- test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp +++ test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -std=c++11 -triple x86_64-apple-macosx10.6.7 -verify %s +// RUN: %clang_cc1 -fsyntax-only -Wno-literal-conversion -std=c++11 -triple x86_64-apple-macosx10.6.7 -verify %s // Verify that narrowing conversions in initializer lists cause errors in C++0x // mode. Index: test/CXX/expr/expr.unary/expr.unary.op/p6.cpp =================================================================== --- test/CXX/expr/expr.unary/expr.unary.op/p6.cpp +++ test/CXX/expr/expr.unary/expr.unary.op/p6.cpp @@ -4,7 +4,7 @@ bool b = !0; -bool b2 = !1.2; //expected-warning{{implicit conversion from 'double' to 'bool' changes value from 1.2 to true}} +bool b2 = !1.2; //expected-warning{{implicit conversion from 'double' to 'bool'; will always evaluate to 'true'}} bool b3 = !4; Index: test/Sema/exprs.c =================================================================== --- test/Sema/exprs.c +++ test/Sema/exprs.c @@ -242,7 +242,7 @@ // Make sure we do function/array decay. void test22() { - if ("help") + if ("help") // expected-warning {{implicit conversion from 'char [5]' to '_Bool'; will always evaluate to 'true'}} (void) 0; if (test22) // expected-warning {{address of function 'test22' will always evaluate to 'true'}} \ Index: test/Sema/warn-string-conversion.c =================================================================== --- test/Sema/warn-string-conversion.c +++ test/Sema/warn-string-conversion.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fsyntax-only -Wstring-conversion %s +// RUN: %clang_cc1 -verify -fsyntax-only %s void do_nothing(); void assert_error(); @@ -16,19 +16,19 @@ void test1() { assert1(0 && "foo"); assert1("foo" && 0); - assert1(0 || "foo"); // expected-warning {{string literal}} - assert1("foo"); // expected-warning {{string literal}} + assert1(0 || "foo"); // expected-warning {{implicit conversion from 'char [4]' to '_Bool'; will always evaluate to 'true'}} + assert1("foo"); // expected-warning {{implicit conversion from 'char [4]' to '_Bool'; will always evaluate to 'true'}} assert2(0 && "foo"); assert2("foo" && 0); - assert2(0 || "foo"); // expected-warning {{string literal}} - assert2("foo"); // expected-warning {{string literal}} + assert2(0 || "foo"); // expected-warning {{implicit conversion from 'char [4]' to '_Bool'; will always evaluate to 'true'}} + assert2("foo"); // expected-warning {{implicit conversion from 'char [4]' to '_Bool'; will always evaluate to 'true'}} } void test2() { - if ("hi") {} // expected-warning {{string literal}} - while ("hello") {} // expected-warning {{string literal}} - for (;"howdy";) {} // expected-warning {{string literal}} - do { } while ("hey"); // expected-warning {{string literal}} - int x = "hey" ? 1 : 2; // expected-warning {{string literal}} + if ("hi") {} // expected-warning {{implicit conversion from 'char [3]' to '_Bool'; will always evaluate to 'true'}} + while ("hello") {} // expected-warning {{implicit conversion from 'char [6]' to '_Bool'; will always evaluate to 'true'}} + for (;"howdy";) {} // expected-warning {{implicit conversion from 'char [6]' to '_Bool'; will always evaluate to 'true'}} + do { } while ("hey"); // expected-warning {{implicit conversion from 'char [4]' to '_Bool'; will always evaluate to 'true'}} + int x = "hey" ? 1 : 2; // expected-warning {{implicit conversion from 'char [4]' to '_Bool'; will always evaluate to 'true'}} } Index: test/SemaCXX/condition.cpp =================================================================== --- test/SemaCXX/condition.cpp +++ test/SemaCXX/condition.cpp @@ -45,7 +45,7 @@ // Make sure we do function/array decay. void test3() { - if ("help") + if ("help") // expected-warning {{implicit conversion from 'const char [5]' to 'bool'; will always evaluate to 'true'}} (void) 0; if (test3) // expected-warning {{address of function 'test3' will always evaluate to 'true'}} \ Index: test/SemaCXX/overload-call.cpp =================================================================== --- test/SemaCXX/overload-call.cpp +++ test/SemaCXX/overload-call.cpp @@ -69,7 +69,7 @@ #else // expected-error@-4 {{cannot initialize a variable of type 'int *' with an rvalue of type 'double *'}} #endif - double* dp1 = k(L"foo"); + double* dp1 = k(L"foo"); // expected-warning {{implicit conversion from 'const wchar_t [4]' to 'bool'; will always evaluate to 'true'}} } int* l(wchar_t*); @@ -82,7 +82,7 @@ #else // expected-error@-4 {{cannot initialize a variable of type 'int *' with an rvalue of type 'double *'}} #endif - double* dp1 = l("foo"); + double* dp1 = l("foo"); // expected-warning {{implicit conversion from 'const char [4]' to 'bool'; will always evaluate to 'true'}} } int* m(const char*); Index: test/SemaCXX/warn-literal-conversion.cpp =================================================================== --- test/SemaCXX/warn-literal-conversion.cpp +++ test/SemaCXX/warn-literal-conversion.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -Wliteral-conversion -verify %s +// RUN: %clang_cc1 -fsyntax-only -Wliteral-conversion -std=c++1z -verify %s void foo(int y); @@ -42,10 +42,26 @@ // Similarly, test floating point conversion to bool. Only float values of zero // are converted to false; everything else is converted to true. void test1() { - bool b1 = 0.99f; // expected-warning {{implicit conversion from 'float' to 'bool' changes value from 0.99 to true}} - bool b2 = 0.99; // expected-warning {{implicit conversion from 'double' to 'bool' changes value from 0.99 to true}} - // These do not warn because they can be directly converted to integral - // values. - bool b3 = 0.0f; - bool b4 = 0.0; + bool b1 = 0.99f; // expected-warning {{implicit conversion from 'float' to 'bool'; will always evaluate to 'true'}} + bool b2 = 0.99; // expected-warning {{implicit conversion from 'double' to 'bool'; will always evaluate to 'true'}} + bool b3 = 0.0f; // expected-warning {{implicit conversion from 'float' to 'bool'; will always evaluate to 'false'}} + bool b4 = 0.0; // expected-warning {{implicit conversion from 'double' to 'bool'; will always evaluate to 'false'}} + + bool b5 = "false"; // expected-warning {{implicit conversion from 'const char [6]' to 'bool'; will always evaluate to 'true'}} + bool b6 = L"false"; // expected-warning {{implicit conversion from 'const wchar_t [6]' to 'bool'; will always evaluate to 'true'}} + bool b7 = u"0"; // expected-warning {{implicit conversion from 'const char16_t [2]' to 'bool'; will always evaluate to 'true'}} + bool b8 = U"false"; // expected-warning {{implicit conversion from 'const char32_t [6]' to 'bool'; will always evaluate to 'true'}} + bool b9 = u8"0"; // expected-warning {{implicit conversion from 'const char [2]' to 'bool'; will always evaluate to 'true'}} + + bool b10 = '\0'; // expected-warning {{implicit conversion from 'char' to 'bool'; will always evaluate to 'false'}} + bool b11 = L'1'; // expected-warning {{implicit conversion from 'wchar_t' to 'bool'; will always evaluate to 'true'}} + bool b12 = U'\0'; // expected-warning {{implicit conversion from 'char32_t' to 'bool'; will always evaluate to 'false'}} + bool b13 = u'1'; // expected-warning {{implicit conversion from 'char16_t' to 'bool'; will always evaluate to 'true'}} + bool b14 = u8'\0'; // expected-warning {{implicit conversion from 'char' to 'bool'; will always evaluate to 'false'}} } + +#define assert(x) (void)(!!(x)) +void should_not_diagnose() { + assert(1 && "false"); + assert(1 && "some random string"); +} Index: test/SemaCXX/warn-string-conversion.cpp =================================================================== --- test/SemaCXX/warn-string-conversion.cpp +++ test/SemaCXX/warn-string-conversion.cpp @@ -1,24 +1,24 @@ -// RUN: %clang_cc1 -fsyntax-only -Wstring-conversion -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify %s // Warn on cases where a string literal is converted into a bool. // An exception is made for this in logical and operators. void assert(bool condition); void test0() { - bool b0 = "hi"; // expected-warning{{implicit conversion turns string literal into bool: 'const char [3]' to 'bool'}} - b0 = ""; // expected-warning{{implicit conversion turns string literal into bool: 'const char [1]' to 'bool'}} - b0 = 0 || ""; // expected-warning{{implicit conversion turns string literal into bool: 'const char [1]' to 'bool'}} - b0 = "" || 0; // expected-warning{{implicit conversion turns string literal into bool: 'const char [1]' to 'bool'}} + bool b0 = "hi"; // expected-warning{{implicit conversion from 'const char [3]' to 'bool'; will always evaluate to 'true'}} + b0 = ""; // expected-warning{{implicit conversion from 'const char [1]' to 'bool'; will always evaluate to 'true'}} + b0 = 0 || ""; // expected-warning{{implicit conversion from 'const char [1]' to 'bool'; will always evaluate to 'true'}} + b0 = "" || 0; // expected-warning{{implicit conversion from 'const char [1]' to 'bool'; will always evaluate to 'true'}} b0 = 0 && ""; b0 = "" && 0; - assert("error"); // expected-warning{{implicit conversion turns string literal into bool: 'const char [6]' to 'bool'}} - assert(0 || "error"); // expected-warning{{implicit conversion turns string literal into bool: 'const char [6]' to 'bool'}} - assert("error" || 0); // expected-warning{{implicit conversion turns string literal into bool: 'const char [6]' to 'bool'}} + assert("error"); // expected-warning{{implicit conversion from 'const char [6]' to 'bool'; will always evaluate to 'true'}} + assert(0 || "error"); // expected-warning{{implicit conversion from 'const char [6]' to 'bool'; will always evaluate to 'true'}} + assert("error" || 0); // expected-warning{{implicit conversion from 'const char [6]' to 'bool'; will always evaluate to 'true'}} assert(0 && "error"); assert("error" && 0); - while("hi") {} // expected-warning{{implicit conversion turns string literal into bool: 'const char [3]' to 'bool'}} - do {} while("hi"); // expected-warning{{implicit conversion turns string literal into bool: 'const char [3]' to 'bool'}} - for (;"hi";); // expected-warning{{implicit conversion turns string literal into bool: 'const char [3]' to 'bool'}} - if("hi") {} // expected-warning{{implicit conversion turns string literal into bool: 'const char [3]' to 'bool'}} + while("hi") {} // expected-warning{{implicit conversion from 'const char [3]' to 'bool'; will always evaluate to 'true'}} + do {} while("hi"); // expected-warning{{implicit conversion from 'const char [3]' to 'bool'; will always evaluate to 'true'}} + for (;"hi";); // expected-warning{{implicit conversion from 'const char [3]' to 'bool'; will always evaluate to 'true'}} + if("hi") {} // expected-warning{{implicit conversion from 'const char [3]' to 'bool'; will always evaluate to 'true'}} } Index: test/SemaCXX/warn-thread-safety-analysis.cpp =================================================================== --- test/SemaCXX/warn-thread-safety-analysis.cpp +++ test/SemaCXX/warn-thread-safety-analysis.cpp @@ -1054,8 +1054,8 @@ struct Bas { void operator& (Foo &) {} }; void mumble() { - Bas() & Bar().func() << "" << ""; - Bas() & Bar().func() << ""; + Bas() & Bar().func() << true << true; + Bas() & Bar().func() << true; } } // end namespace thread_annot_lock_61_modified