diff options
author | John McCall <rjmccall@apple.com> | 2010-01-04 23:31:57 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-01-04 23:31:57 +0000 |
commit | 51313c39c84407dd6a323be99a8c322bf8d052a9 (patch) | |
tree | e8f61318c082993401dc60c42057af5b5a375de1 /lib/Sema/Sema.cpp | |
parent | ba26e58c64b4f6233dfc4bcd3ef6ce83aab47ffc (diff) |
Move the -Wconversion logic into SemaChecking.cpp. There's a fair amount of
overlap between this and -Wsign-compare, which is why I want them in the same
place.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@92543 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/Sema.cpp')
-rw-r--r-- | lib/Sema/Sema.cpp | 311 |
1 files changed, 1 insertions, 310 deletions
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 40ad90a129..b32ddfd209 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -368,315 +368,6 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0)); } -/// Retrieves the width and signedness of the given integer type, -/// or returns false if it is not an integer type. -/// -/// \param T must be canonical -static bool getIntProperties(ASTContext &C, const Type *T, - unsigned &BitWidth, bool &Signed) { - assert(T->isCanonicalUnqualified()); - - if (const VectorType *VT = dyn_cast<VectorType>(T)) - T = VT->getElementType().getTypePtr(); - if (const ComplexType *CT = dyn_cast<ComplexType>(T)) - T = CT->getElementType().getTypePtr(); - - if (const BuiltinType *BT = dyn_cast<BuiltinType>(T)) { - if (!BT->isInteger()) return false; - - BitWidth = C.getIntWidth(QualType(T, 0)); - Signed = BT->isSignedInteger(); - return true; - } - - return false; -} - -/// Checks whether the given value will have the same value if it it -/// is truncated to the given width, then extended back to the -/// original width. -static bool IsSameIntAfterCast(const llvm::APSInt &value, - unsigned TargetWidth) { - unsigned SourceWidth = value.getBitWidth(); - llvm::APSInt truncated = value; - truncated.trunc(TargetWidth); - truncated.extend(SourceWidth); - return (truncated == value); -} - -/// Checks whether the given value will have the same value if it -/// is truncated to the given width, then extended back to the original -/// width. -/// -/// The value might be a vector or a complex. -static bool IsSameIntAfterCast(const APValue &value, unsigned TargetWidth) { - if (value.isInt()) - return IsSameIntAfterCast(value.getInt(), TargetWidth); - - if (value.isVector()) { - for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i) - if (!IsSameIntAfterCast(value.getVectorElt(i), TargetWidth)) - return false; - return true; - } - - if (value.isComplexInt()) { - return IsSameIntAfterCast(value.getComplexIntReal(), TargetWidth) && - IsSameIntAfterCast(value.getComplexIntImag(), TargetWidth); - } - - // This can happen with lossless casts to intptr_t of "based" lvalues. - // Assume it might use arbitrary bits. - assert(value.isLValue()); - return false; -} - - -/// Checks whether the given value, which currently has the given -/// source semantics, has the same value when coerced through the -/// target semantics. -static bool IsSameFloatAfterCast(const llvm::APFloat &value, - const llvm::fltSemantics &Src, - const llvm::fltSemantics &Tgt) { - llvm::APFloat truncated = value; - - bool ignored; - truncated.convert(Src, llvm::APFloat::rmNearestTiesToEven, &ignored); - truncated.convert(Tgt, llvm::APFloat::rmNearestTiesToEven, &ignored); - - return truncated.bitwiseIsEqual(value); -} - -/// Checks whether the given value, which currently has the given -/// source semantics, has the same value when coerced through the -/// target semantics. -/// -/// The value might be a vector of floats (or a complex number). -static bool IsSameFloatAfterCast(const APValue &value, - const llvm::fltSemantics &Src, - const llvm::fltSemantics &Tgt) { - if (value.isFloat()) - return IsSameFloatAfterCast(value.getFloat(), Src, Tgt); - - if (value.isVector()) { - for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i) - if (!IsSameFloatAfterCast(value.getVectorElt(i), Src, Tgt)) - return false; - return true; - } - - assert(value.isComplexFloat()); - return (IsSameFloatAfterCast(value.getComplexFloatReal(), Src, Tgt) && - IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt)); -} - -/// Determines if it's reasonable for the given expression to be truncated -/// down to the given integer width. -/// * Boolean expressions are automatically white-listed. -/// * Arithmetic operations on implicitly-promoted operands of the -/// target width or less are okay --- not because the results are -/// actually guaranteed to fit within the width, but because the -/// user is effectively pretending that the operations are closed -/// within the implicitly-promoted type. -static bool IsExprValueWithinWidth(ASTContext &C, Expr *E, unsigned Width) { - E = E->IgnoreParens(); - -#ifndef NDEBUG - { - const Type *ETy = E->getType()->getCanonicalTypeInternal().getTypePtr(); - unsigned EWidth; - bool ESigned; - - if (!getIntProperties(C, ETy, EWidth, ESigned)) - assert(0 && "expression not of integer type"); - - // The caller should never let this happen. - assert(EWidth > Width && "called on expr whose type is too small"); - } -#endif - - // Strip implicit casts off. - while (isa<ImplicitCastExpr>(E)) { - E = cast<ImplicitCastExpr>(E)->getSubExpr(); - - const Type *ETy = E->getType()->getCanonicalTypeInternal().getTypePtr(); - - unsigned EWidth; - bool ESigned; - if (!getIntProperties(C, ETy, EWidth, ESigned)) - return false; - - if (EWidth <= Width) - return true; - } - - if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { - switch (BO->getOpcode()) { - - // Boolean-valued operations are white-listed. - case BinaryOperator::LAnd: - case BinaryOperator::LOr: - case BinaryOperator::LT: - case BinaryOperator::GT: - case BinaryOperator::LE: - case BinaryOperator::GE: - case BinaryOperator::EQ: - case BinaryOperator::NE: - return true; - - // Operations with opaque sources are black-listed. - case BinaryOperator::PtrMemD: - case BinaryOperator::PtrMemI: - return false; - - // Left shift gets black-listed based on a judgement call. - case BinaryOperator::Shl: - return false; - - // Various special cases. - case BinaryOperator::Shr: - return IsExprValueWithinWidth(C, BO->getLHS(), Width); - case BinaryOperator::Comma: - return IsExprValueWithinWidth(C, BO->getRHS(), Width); - case BinaryOperator::Sub: - if (BO->getLHS()->getType()->isPointerType()) - return false; - // fallthrough - - // Any other operator is okay if the operands are - // promoted from expressions of appropriate size. - default: - return IsExprValueWithinWidth(C, BO->getLHS(), Width) && - IsExprValueWithinWidth(C, BO->getRHS(), Width); - } - } - - if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { - switch (UO->getOpcode()) { - // Boolean-valued operations are white-listed. - case UnaryOperator::LNot: - return true; - - // Operations with opaque sources are black-listed. - case UnaryOperator::Deref: - case UnaryOperator::AddrOf: // should be impossible - return false; - - case UnaryOperator::OffsetOf: - return false; - - default: - return IsExprValueWithinWidth(C, UO->getSubExpr(), Width); - } - } - - // Don't diagnose if the expression is an integer constant - // whose value in the target type is the same as it was - // in the original type. - Expr::EvalResult result; - if (E->Evaluate(result, C)) - if (IsSameIntAfterCast(result.Val, Width)) - return true; - - return false; -} - -/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. -static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) { - S.Diag(E->getExprLoc(), diag) << E->getType() << T << E->getSourceRange(); -} - -/// Implements -Wconversion. -static void CheckImplicitConversion(Sema &S, Expr *E, QualType T) { - // Don't diagnose in unevaluated contexts. - if (S.ExprEvalContexts.back().Context == Sema::Unevaluated) - return; - - // Don't diagnose for value-dependent expressions. - if (E->isValueDependent()) - return; - - const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr(); - const Type *Target = S.Context.getCanonicalType(T).getTypePtr(); - - // Never diagnose implicit casts to bool. - if (Target->isSpecificBuiltinType(BuiltinType::Bool)) - return; - - // Strip vector types. - if (isa<VectorType>(Source)) { - if (!isa<VectorType>(Target)) - return DiagnoseImpCast(S, E, T, diag::warn_impcast_vector_scalar); - - Source = cast<VectorType>(Source)->getElementType().getTypePtr(); - Target = cast<VectorType>(Target)->getElementType().getTypePtr(); - } - - // Strip complex types. - if (isa<ComplexType>(Source)) { - if (!isa<ComplexType>(Target)) - return DiagnoseImpCast(S, E, T, diag::warn_impcast_complex_scalar); - - Source = cast<ComplexType>(Source)->getElementType().getTypePtr(); - Target = cast<ComplexType>(Target)->getElementType().getTypePtr(); - } - - const BuiltinType *SourceBT = dyn_cast<BuiltinType>(Source); - const BuiltinType *TargetBT = dyn_cast<BuiltinType>(Target); - - // If the source is floating point... - if (SourceBT && SourceBT->isFloatingPoint()) { - // ...and the target is floating point... - if (TargetBT && TargetBT->isFloatingPoint()) { - // ...then warn if we're dropping FP rank. - - // Builtin FP kinds are ordered by increasing FP rank. - if (SourceBT->getKind() > TargetBT->getKind()) { - // Don't warn about float constants that are precisely - // representable in the target type. - Expr::EvalResult result; - if (E->Evaluate(result, S.Context)) { - // Value might be a float, a float vector, or a float complex. - if (IsSameFloatAfterCast(result.Val, - S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)), - S.Context.getFloatTypeSemantics(QualType(SourceBT, 0)))) - return; - } - - DiagnoseImpCast(S, E, T, diag::warn_impcast_float_precision); - } - return; - } - - // If the target is integral, always warn. - if ((TargetBT && TargetBT->isInteger())) - // TODO: don't warn for integer values? - return DiagnoseImpCast(S, E, T, diag::warn_impcast_float_integer); - - return; - } - - unsigned SourceWidth, TargetWidth; - bool SourceSigned, TargetSigned; - - if (!getIntProperties(S.Context, Source, SourceWidth, SourceSigned) || - !getIntProperties(S.Context, Target, TargetWidth, TargetSigned)) - return; - - if (SourceWidth > TargetWidth) { - if (IsExprValueWithinWidth(S.Context, E, TargetWidth)) - return; - - // People want to build with -Wshorten-64-to-32 and not -Wconversion - // and by god we'll let them. - if (SourceWidth == 64 && TargetWidth == 32) - return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_64_32); - return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_precision); - } - - return; -} - /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. /// If there is already an implicit cast, merge into the existing one. /// If isLvalue, the result of the cast is an lvalue. @@ -697,7 +388,7 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, } } - CheckImplicitConversion(*this, Expr, Ty); + CheckImplicitConversion(Expr, Ty); if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) { if (ImpCast->getCastKind() == Kind) { |