diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index b138619de301..fad654f3a51b 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -4728,8 +4728,9 @@ def warn_lunsigned_always_true_comparison : Warning< "comparison of unsigned%select{| enum}2 expression %0 is always %1">, InGroup; def warn_out_of_range_compare : Warning< - "comparison of constant %0 with expression of type %1 is always " - "%select{false|true}2">, InGroup; + "comparison of %select{constant %0|true|false}1 with " + "%select{expression of type %2|boolean expression}3 is always " + "%select{false|true}4">, InGroup; def warn_runsigned_always_true_comparison : Warning< "comparison of %0 unsigned%select{| enum}2 expression is always %1">, InGroup; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 2f5f14f38e3d..f29e9fe4c072 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -121,6 +121,8 @@ bool Expr::isKnownToHaveBooleanValue() const { switch (UO->getOpcode()) { case UO_Plus: return UO->getSubExpr()->isKnownToHaveBooleanValue(); + case UO_LNot: + return true; default: return false; } diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 27cc8a37a5b1..93c5cac6b043 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -5334,90 +5334,182 @@ static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, if (!S.ActiveTemplateInstantiations.empty()) return; + // TODO: Investigate using GetExprRange() to get tighter bounds + // on the bit ranges. + QualType OtherT = Other->getType(); + IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT); + unsigned OtherWidth = OtherRange.Width; + + bool OtherIsBooleanType = Other->isKnownToHaveBooleanValue(); + // 0 values are handled later by CheckTrivialUnsignedComparison(). - if (Value == 0) + if ((Value == 0) && (!OtherIsBooleanType)) return; BinaryOperatorKind op = E->getOpcode(); - QualType OtherT = Other->getType(); - QualType ConstantT = Constant->getType(); - QualType CommonT = E->getLHS()->getType(); - if (S.Context.hasSameUnqualifiedType(OtherT, ConstantT)) - return; - assert((OtherT->isIntegerType() && ConstantT->isIntegerType()) - && "comparison with non-integer type"); + bool IsTrue = true; - bool ConstantSigned = ConstantT->isSignedIntegerType(); - bool CommonSigned = CommonT->isSignedIntegerType(); + // Used for diagnostic printout. + enum { + LiteralConstant = 0, + CXXBoolLiteralTrue, + CXXBoolLiteralFalse + } LiteralOrBoolConstant = LiteralConstant; - bool EqualityOnly = false; + if (!OtherIsBooleanType) { + QualType ConstantT = Constant->getType(); + QualType CommonT = E->getLHS()->getType(); - // TODO: Investigate using GetExprRange() to get tighter bounds on - // on the bit ranges. - IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT); - unsigned OtherWidth = OtherRange.Width; - - if (CommonSigned) { - // The common type is signed, therefore no signed to unsigned conversion. - if (!OtherRange.NonNegative) { - // Check that the constant is representable in type OtherT. - if (ConstantSigned) { - if (OtherWidth >= Value.getMinSignedBits()) - return; - } else { // !ConstantSigned - if (OtherWidth >= Value.getActiveBits() + 1) - return; + if (S.Context.hasSameUnqualifiedType(OtherT, ConstantT)) + return; + assert((OtherT->isIntegerType() && ConstantT->isIntegerType()) && + "comparison with non-integer type"); + + bool ConstantSigned = ConstantT->isSignedIntegerType(); + bool CommonSigned = CommonT->isSignedIntegerType(); + + bool EqualityOnly = false; + + if (CommonSigned) { + // The common type is signed, therefore no signed to unsigned conversion. + if (!OtherRange.NonNegative) { + // Check that the constant is representable in type OtherT. + if (ConstantSigned) { + if (OtherWidth >= Value.getMinSignedBits()) + return; + } else { // !ConstantSigned + if (OtherWidth >= Value.getActiveBits() + 1) + return; + } + } else { // !OtherSigned + // Check that the constant is representable in type OtherT. + // Negative values are out of range. + if (ConstantSigned) { + if (Value.isNonNegative() && OtherWidth >= Value.getActiveBits()) + return; + } else { // !ConstantSigned + if (OtherWidth >= Value.getActiveBits()) + return; + } } - } else { // !OtherSigned - // Check that the constant is representable in type OtherT. - // Negative values are out of range. - if (ConstantSigned) { - if (Value.isNonNegative() && OtherWidth >= Value.getActiveBits()) - return; - } else { // !ConstantSigned + } else { // !CommonSigned + if (OtherRange.NonNegative) { if (OtherWidth >= Value.getActiveBits()) return; + } else if (!OtherRange.NonNegative && !ConstantSigned) { + // Check to see if the constant is representable in OtherT. + if (OtherWidth > Value.getActiveBits()) + return; + // Check to see if the constant is equivalent to a negative value + // cast to CommonT. + if (S.Context.getIntWidth(ConstantT) == + S.Context.getIntWidth(CommonT) && + Value.isNegative() && Value.getMinSignedBits() <= OtherWidth) + return; + // The constant value rests between values that OtherT can represent + // after conversion. Relational comparison still works, but equality + // comparisons will be tautological. + EqualityOnly = true; + } else { // OtherSigned && ConstantSigned + assert(0 && "Two signed types converted to unsigned types."); } } - } else { // !CommonSigned - if (OtherRange.NonNegative) { - if (OtherWidth >= Value.getActiveBits()) - return; - } else if (!OtherRange.NonNegative && !ConstantSigned) { - // Check to see if the constant is representable in OtherT. - if (OtherWidth > Value.getActiveBits()) - return; - // Check to see if the constant is equivalent to a negative value - // cast to CommonT. - if (S.Context.getIntWidth(ConstantT) == S.Context.getIntWidth(CommonT) && - Value.isNegative() && Value.getMinSignedBits() <= OtherWidth) - return; - // The constant value rests between values that OtherT can represent after - // conversion. Relational comparison still works, but equality - // comparisons will be tautological. - EqualityOnly = true; - } else { // OtherSigned && ConstantSigned - assert(0 && "Two signed types converted to unsigned types."); + + bool PositiveConstant = !ConstantSigned || Value.isNonNegative(); + + if (op == BO_EQ || op == BO_NE) { + IsTrue = op == BO_NE; + } else if (EqualityOnly) { + return; + } else if (RhsConstant) { + if (op == BO_GT || op == BO_GE) + IsTrue = !PositiveConstant; + else // op == BO_LT || op == BO_LE + IsTrue = PositiveConstant; + } else { + if (op == BO_LT || op == BO_LE) + IsTrue = !PositiveConstant; + else // op == BO_GT || op == BO_GE + IsTrue = PositiveConstant; } - } - - bool PositiveConstant = !ConstantSigned || Value.isNonNegative(); - - bool IsTrue = true; - if (op == BO_EQ || op == BO_NE) { - IsTrue = op == BO_NE; - } else if (EqualityOnly) { - return; - } else if (RhsConstant) { - if (op == BO_GT || op == BO_GE) - IsTrue = !PositiveConstant; - else // op == BO_LT || op == BO_LE - IsTrue = PositiveConstant; } else { - if (op == BO_LT || op == BO_LE) - IsTrue = !PositiveConstant; - else // op == BO_GT || op == BO_GE - IsTrue = PositiveConstant; + // Other isKnownToHaveBooleanValue + enum CompareBoolWithConstantResult { AFals, ATrue, Unkwn }; + enum ConstantValue { LT_Zero, Zero, One, GT_One, SizeOfConstVal }; + enum ConstantSide { Lhs, Rhs, SizeOfConstSides }; + + static const struct LinkedConditions { + CompareBoolWithConstantResult BO_LT_OP[SizeOfConstSides][SizeOfConstVal]; + CompareBoolWithConstantResult BO_GT_OP[SizeOfConstSides][SizeOfConstVal]; + CompareBoolWithConstantResult BO_LE_OP[SizeOfConstSides][SizeOfConstVal]; + CompareBoolWithConstantResult BO_GE_OP[SizeOfConstSides][SizeOfConstVal]; + CompareBoolWithConstantResult BO_EQ_OP[SizeOfConstSides][SizeOfConstVal]; + CompareBoolWithConstantResult BO_NE_OP[SizeOfConstSides][SizeOfConstVal]; + + } TruthTable = { + // Constant on LHS. | Constant on RHS. | + // LT_Zero| Zero | One |GT_One| LT_Zero| Zero | One |GT_One| + { { ATrue, Unkwn, AFals, AFals }, { AFals, AFals, Unkwn, ATrue } }, + { { AFals, AFals, Unkwn, ATrue }, { ATrue, Unkwn, AFals, AFals } }, + { { ATrue, ATrue, Unkwn, AFals }, { AFals, Unkwn, ATrue, ATrue } }, + { { AFals, Unkwn, ATrue, ATrue }, { ATrue, ATrue, Unkwn, AFals } }, + { { AFals, Unkwn, Unkwn, AFals }, { AFals, Unkwn, Unkwn, AFals } }, + { { ATrue, Unkwn, Unkwn, ATrue }, { ATrue, Unkwn, Unkwn, ATrue } } + }; + + bool ConstantIsBoolLiteral = isa(Constant); + + enum ConstantValue ConstVal = Zero; + if (Value.isUnsigned() || Value.isNonNegative()) { + if (Value == 0) { + LiteralOrBoolConstant = + ConstantIsBoolLiteral ? CXXBoolLiteralFalse : LiteralConstant; + ConstVal = Zero; + } else if (Value == 1) { + LiteralOrBoolConstant = + ConstantIsBoolLiteral ? CXXBoolLiteralTrue : LiteralConstant; + ConstVal = One; + } else { + LiteralOrBoolConstant = LiteralConstant; + ConstVal = GT_One; + } + } else { + ConstVal = LT_Zero; + } + + CompareBoolWithConstantResult CmpRes; + + switch (op) { + case BO_LT: + CmpRes = TruthTable.BO_LT_OP[RhsConstant][ConstVal]; + break; + case BO_GT: + CmpRes = TruthTable.BO_GT_OP[RhsConstant][ConstVal]; + break; + case BO_LE: + CmpRes = TruthTable.BO_LE_OP[RhsConstant][ConstVal]; + break; + case BO_GE: + CmpRes = TruthTable.BO_GE_OP[RhsConstant][ConstVal]; + break; + case BO_EQ: + CmpRes = TruthTable.BO_EQ_OP[RhsConstant][ConstVal]; + break; + case BO_NE: + CmpRes = TruthTable.BO_NE_OP[RhsConstant][ConstVal]; + break; + default: + CmpRes = Unkwn; + break; + } + + if (CmpRes == AFals) { + IsTrue = false; + } else if (CmpRes == ATrue) { + IsTrue = true; + } else { + return; + } } // If this is a comparison to an enum constant, include that @@ -5433,11 +5525,12 @@ static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, else OS << Value; - S.DiagRuntimeBehavior(E->getOperatorLoc(), E, - S.PDiag(diag::warn_out_of_range_compare) - << OS.str() << OtherT << IsTrue - << E->getLHS()->getSourceRange() - << E->getRHS()->getSourceRange()); + S.DiagRuntimeBehavior( + E->getOperatorLoc(), E, + S.PDiag(diag::warn_out_of_range_compare) + << OS.str() << LiteralOrBoolConstant + << OtherT << (OtherIsBooleanType && !OtherT->isBooleanType()) << IsTrue + << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange()); } /// Analyze the operands of the given comparison. Implements the diff --git a/clang/test/Sema/bool-compare.c b/clang/test/Sema/bool-compare.c new file mode 100644 index 000000000000..3f1f286a2a38 --- /dev/null +++ b/clang/test/Sema/bool-compare.c @@ -0,0 +1,162 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + + +void f(int x, int y, int z) { + int a,b; + + + if ((a > 2) > 1) {} // expected-warning {{comparison of constant 1 with boolean expression is always false}} + + if (a > b) {} // no warning + if (a < b) {} // no warning + if (a >= b) {} // no warning + if (a <= b) {} // no warning + if (a == b) {} // no warning + if (a != b) {} // no warning + + if (a > 0) {} // no warning + if (a > 1) {} // no warning + if (a > 2) {} // no warning + + if (a >= 0) {} // no warning + if (a >= 1) {} // no warning + if (a >= 2) {} // no warning + if (a >= -1) {} // no warning + + if (a <= 0) {} // no warning + if (a <= 1) {} // no warning + if (a <= 2) {} // no warning + if (a <= -1) {} // no warning + + + if (!a > 0) {} // no warning + if (!a > 1) {} // expected-warning {{comparison of constant 1 with boolean expression is always false}} + if (!a > 2) {} // expected-warning {{comparison of constant 2 with boolean expression is always false}} + if (!a > y) {} // no warning + if (!a > b) {} // no warning + if (!a > -1) {} // expected-warning {{comparison of constant -1 with boolean expression is always true}} + + if (!a < 0) {} // expected-warning {{comparison of constant 0 with boolean expression is always false}} + if (!a < 1) {} // no warning + if (!a < 2) {} // expected-warning {{comparison of constant 2 with boolean expression is always true}} + if (!a < y) {} // no warning + if (!a < b) {} // no warning + if (!a < -1) {} // expected-warning {{comparison of constant -1 with boolean expression is always false}} + + if (!a >= 0) {} // expected-warning {{comparison of constant 0 with boolean expression is always true}} + if (!a >= 1) {} // no warning + if (!a >= 2) {} // expected-warning {{comparison of constant 2 with boolean expression is always false}} + if (!a >= y) {} // no warning + if (!a >= b) {} // no warning + if (!a >= -1) {} // expected-warning {{comparison of constant -1 with boolean expression is always true}} + + if (!a <= 0) {} // no warning + if (!a <= 1) {} // expected-warning {{comparison of constant 1 with boolean expression is always true}} + if (!a <= 2) {} // expected-warning {{comparison of constant 2 with boolean expression is always true}} + if (!a <= y) {} // no warning + if (!a <= b) {} // no warning + if (!a <= -1) {} // expected-warning {{comparison of constant -1 with boolean expression is always false}} + + if ((a||b) > 0) {} // no warning + if ((a||b) > 1) {} // expected-warning {{comparison of constant 1 with boolean expression is always false}} + if ((a||b) > 4) {} // expected-warning {{comparison of constant 4 with boolean expression is always false}} + if ((a||b) > -1) {}// expected-warning {{comparison of constant -1 with boolean expression is always true}} + + if ((a&&b) > 0) {} // no warning + if ((a&&b) > 1) {} // expected-warning {{comparison of constant 1 with boolean expression is always false}} + if ((a&&b) > 4) {} // expected-warning {{comparison of constant 4 with boolean expression is always false}} + + if ((a 0) {} // no warning + if ((a 1) {} // expected-warning {{comparison of constant 1 with boolean expression is always false}} + if ((a 4) {} // expected-warning {{comparison of constant 4 with boolean expression is always false}} + if ((a z) {} // no warning + if ((a -1) {} // expected-warning {{comparison of constant -1 with boolean expression is always true}} + + if ((ay z) {} // no warning + if((a(z !a) {} // expected-warning {{comparison of constant 0 with boolean expression is always false}} + if (1 > !a) {} // no warning + if (2 > !a) {} // expected-warning {{comparison of constant 2 with boolean expression is always true}} + if (y > !a) {} // no warning + if (-1 > !a) {} // expected-warning {{comparison of constant -1 with boolean expression is always false}} + + if (0 < !a) {} // no warning + if (1 < !a) {} // expected-warning {{comparison of constant 1 with boolean expression is always false}} + if (2 < !a) {} // expected-warning {{comparison of constant 2 with boolean expression is always false}} + if (y < !a) {} // no warning + if (-1 < !a) {} // expected-warning {{comparison of constant -1 with boolean expression is always true}} + + if (0 >= !a) {} // no warning + if (1 >= !a) {} // expected-warning {{comparison of constant 1 with boolean expression is always true}} + if (2 >= !a) {} // expected-warning {{comparison of constant 2 with boolean expression is always true}} + if (y >= !a) {} // no warning + if (-1 >= !a) {} // expected-warning {{comparison of constant -1 with boolean expression is always false}} + + if (0 <= !a) {} // expected-warning {{comparison of constant 0 with boolean expression is always true}} + if (1 <= !a) {} // no warning + if (2 <= !a) {} // expected-warning {{comparison of constant 2 with boolean expression is always false}} + if (y <= !a) {} // no warning + if (-1 <= !a) {} // expected-warning {{comparison of constant -1 with boolean expression is always true}} + + if (0 > (a||b)) {} // expected-warning {{comparison of constant 0 with boolean expression is always false}} + if (1 > (a||b)) {} // no warning + if (4 > (a||b)) {} // expected-warning {{comparison of constant 4 with boolean expression is always true}} + + if (0 > (a&&b)) {} // expected-warning {{comparison of constant 0 with boolean expression is always false}} + if (1 > (a&&b)) {} // no warning + if (4 > (a&&b)) {} // expected-warning {{comparison of constant 4 with boolean expression is always true}} + + if (0 > (a (a (a (a (ay) {} // no warning + if (z > (a(a2))!=(a true) {} // expected-warning {{comparison of true with expression of type 'bool' is always false}} + if(b < true) {} // no warning + if(b >= true) {} // no warning + if(b <= true) {} // expected-warning {{comparison of true with expression of type 'bool' is always true}} + if(b == true) {} // no warning + if(b != true) {} // no warning + + if(b > false) {} // no warning + if(b < false) {} // expected-warning {{comparison of false with expression of type 'bool' is always false}} + if(b >= false) {} // expected-warning {{comparison of false with expression of type 'bool' is always true}} + if(b <= false) {} // no warning + if(b == false) {} // no warning + if(b != false) {} // no warning + + if(b > 1U){} // expected-warning {{comparison of constant 1 with expression of type 'bool' is always false}} + + if (a > b) {} // no warning + if (a < b) {} // no warning + if (a >= b) {} // no warning + if (a <= b) {} // no warning + if (a == b) {} // no warning + if (a != b) {} // no warning + + if (a > 0) {} // no warning + if (a > 1) {} // expected-warning {{comparison of constant 1 with expression of type 'bool' is always false}} + if (a > 2) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always false}} + + if (a >= 0) {} // expected-warning {{comparison of constant 0 with expression of type 'bool' is always true}} + if (a >= 1) {} // no warning + if (a >= 2) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always false}} + if (a >= -1) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always true}} + + if (a <= 0) {} // no warning + if (a <= 1) {} // expected-warning {{comparison of constant 1 with expression of type 'bool' is always true}} + if (a <= 2) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always true}} + if (a <= -1) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always false}} + + if (!a > 0) {} // no warning + if (!a > 1) {} // expected-warning {{comparison of constant 1 with expression of type 'bool' is always false}} + if (!a > 2) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always false}} + if (!a > y) {} // no warning + if (!a > b) {} // no warning + if (!a > -1) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always true}} + + if (!a < 0) {} // expected-warning {{comparison of constant 0 with expression of type 'bool' is always false}} + if (!a < 1) {} // no warning + if (!a < 2) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always true}} + if (!a < y) {} // no warning + if (!a < b) {} // no warning + if (!a < -1) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always false}} + + if (!a >= 0) {} // expected-warning {{comparison of constant 0 with expression of type 'bool' is always true}} + if (!a >= 1) {} // no warning + if (!a >= 2) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always false}} + if (!a >= y) {} // no warning + if (!a >= b) {} // no warning + if (!a >= -1) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always true}} + + if (!a <= 0) {} // no warning + if (!a <= 1) {} // expected-warning {{comparison of constant 1 with expression of type 'bool' is always true}} + if (!a <= 2) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always true}} + if (!a <= y) {} // no warning + if (!a <= b) {} // no warning + if (!a <= -1) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always false}} + + if ((a||b) > 0) {} // no warning + if ((a||b) > 1) {} // expected-warning {{comparison of constant 1 with expression of type 'bool' is always false}} + if ((a||b) > 4) {} // expected-warning {{comparison of constant 4 with expression of type 'bool' is always false}} + if ((a||b) > -1) {}// expected-warning {{comparison of constant -1 with expression of type 'bool' is always true}} + + if ((a&&b) > 0) {} // no warning + if ((a&&b) > 1) {} // expected-warning {{comparison of constant 1 with expression of type 'bool' is always false}} + if ((a&&b) > 4) {} // expected-warning {{comparison of constant 4 with expression of type 'bool' is always false}} + + if ((a 0) {} // no warning + if ((a 1) {} // expected-warning {{comparison of constant 1 with expression of type 'bool' is always false}} + if ((a 4) {} // expected-warning {{comparison of constant 4 with expression of type 'bool' is always false}} + if ((a z) {} // no warning + if ((a -1) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always true}} + + if ((ay z) {} // no warning + if((a(z !a) {} // expected-warning {{comparison of constant 0 with expression of type 'bool' is always false}} + if (1 > !a) {} // no warning + if (2 > !a) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always true}} + if (y > !a) {} // no warning + if (-1 > !a) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always false}} + + if (0 < !a) {} // no warning + if (1 < !a) {} // expected-warning {{comparison of constant 1 with expression of type 'bool' is always false}} + if (2 < !a) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always false}} + if (y < !a) {} // no warning + if (-1 < !a) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always true}} + + + if (0 >= !a) {} // no warning + if (1 >= !a) {} // expected-warning {{comparison of constant 1 with expression of type 'bool' is always true}} + if (2 >= !a) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always true}} + if (y >= !a) {} // no warning + if (-1 >= !a) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always false}} + + if (0 <= !a) {} // expected-warning {{comparison of constant 0 with expression of type 'bool' is always true}} + if (1 <= !a) {} // no warning + if (2 <= !a) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always false}} + if (y <= !a) {} // + if (-1 <= !a) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always true}} + + if (0 > (a||b)) {} // expected-warning {{comparison of constant 0 with expression of type 'bool' is always false}} + if (1 > (a||b)) {} // no warning + if (4 > (a||b)) {} // expected-warning {{comparison of constant 4 with expression of type 'bool' is always true}} + + if (0 > (a&&b)) {} // expected-warning {{comparison of constant 0 with expression of type 'bool' is always false}} + if (1 > (a&&b)) {} // no warning + if (4 > (a&&b)) {} // expected-warning {{comparison of constant 4 with expression of type 'bool' is always true}} + + if (0 > (a (a (a (a (ay) {} // no warning + if (z > (a(a2))!=(a struct X6 { + U f(T t, U u, V v) { + // IfStmt + if (t > 0) + return u; + else { + if (t < 0) + return v; // expected-error{{cannot initialize return object of type}} + } + bool r; + // FIXME: We should warn here, DiagRuntimeBehavior does currently not detect this. + if(r<0){} + + if (T x = t) { + t = x; + } + return v; // expected-error{{cannot initialize return object of type}} + } +}; + +struct ConvertibleToInt { + operator int() const; +}; + +template struct X6; +template struct X6; // expected-note{{instantiation}} + + +