diff options
Diffstat (limited to 'lib/Sema/Sema.cpp')
| -rw-r--r-- | lib/Sema/Sema.cpp | 338 | 
1 files changed, 328 insertions, 10 deletions
| diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 8104dd39d052..b2bbac8bc2a9 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -14,6 +14,7 @@  #include "Sema.h"  #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/APFloat.h"  #include "clang/AST/ASTConsumer.h"  #include "clang/AST/ASTContext.h"  #include "clang/AST/DeclObjC.h" @@ -346,16 +347,18 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {  }  Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, -           bool CompleteTranslationUnit) +           bool CompleteTranslationUnit, +           CodeCompleteConsumer *CodeCompleter)    : LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),      Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), -    ExternalSource(0), CodeCompleter(0), CurContext(0),  +    ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0),       PreDeclaratorDC(0), CurBlock(0), PackContext(0), ParsingDeclDepth(0),      IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0),      GlobalNewDeleteDeclared(false), ExprEvalContext(PotentiallyEvaluated),      CompleteTranslationUnit(CompleteTranslationUnit), -    NumSFINAEErrors(0), CurrentInstantiationScope(0) { - +    NumSFINAEErrors(0), NonInstantiationEntries(0),  +    CurrentInstantiationScope(0)  +{    TUScope = 0;    if (getLangOptions().CPlusPlus)      FieldCollector.reset(new CXXFieldCollector()); @@ -364,6 +367,322 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,    PP.getDiagnostics().SetArgToStringFn(ConvertArgToStringFn, &Context);  } +/// 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; +  } + +  if (const FixedWidthIntType *FWIT = dyn_cast<FixedWidthIntType>(T)) { +    BitWidth = FWIT->getWidth(); +    Signed = FWIT->isSigned(); +    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.ExprEvalContext == 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()) || +        isa<FixedWidthIntType>(Target)) +      // 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. @@ -375,18 +694,17 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty,    if (ExprTy == TypeTy)      return; -  if (Expr->getType().getTypePtr()->isPointerType() && -      Ty.getTypePtr()->isPointerType()) { -    QualType ExprBaseType = -      cast<PointerType>(ExprTy.getUnqualifiedType())->getPointeeType(); -    QualType BaseType = -      cast<PointerType>(TypeTy.getUnqualifiedType())->getPointeeType(); +  if (Expr->getType()->isPointerType() && Ty->isPointerType()) { +    QualType ExprBaseType = cast<PointerType>(ExprTy)->getPointeeType(); +    QualType BaseType = cast<PointerType>(TypeTy)->getPointeeType();      if (ExprBaseType.getAddressSpace() != BaseType.getAddressSpace()) {        Diag(Expr->getExprLoc(), diag::err_implicit_pointer_address_space_cast)          << Expr->getSourceRange();      }    } +  CheckImplicitConversion(*this, Expr, Ty); +    if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) {      if (ImpCast->getCastKind() == Kind) {        ImpCast->setType(Ty); | 
