Example #1
0
bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc,
                                   const char *&PrevSpec,
                                   unsigned &DiagID) {
  // OpenCL 1.1 6.8g: "The extern, static, auto and register storage-class
  // specifiers are not supported."
  // It seems sensible to prohibit private_extern too
  // The cl_clang_storage_class_specifiers extension enables support for
  // these storage-class specifiers.
  if (S.getLangOptions().OpenCL &&
      !S.getOpenCLOptions().cl_clang_storage_class_specifiers) {
    switch (SC) {
    case SCS_extern:
    case SCS_private_extern:
    case SCS_auto:
    case SCS_register:
    case SCS_static:
      DiagID   = diag::err_not_opencl_storage_class_specifier;
      PrevSpec = getSpecifierName(SC);
      return true;
    default:
      break;
    }
  }

  if (StorageClassSpec != SCS_unspecified) {
    // Maybe this is an attempt to use C++0x 'auto' outside of C++0x mode.
    bool isInvalid = true;
    if (TypeSpecType == TST_unspecified && S.getLangOptions().CPlusPlus) {
      if (SC == SCS_auto)
        return SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID);
      if (StorageClassSpec == SCS_auto) {
        isInvalid = SetTypeSpecType(TST_auto, StorageClassSpecLoc,
                                    PrevSpec, DiagID);
        assert(!isInvalid && "auto SCS -> TST recovery failed");
      }
    }

    // Changing storage class is allowed only if the previous one
    // was the 'extern' that is part of a linkage specification and
    // the new storage class is 'typedef'.
    if (isInvalid &&
        !(SCS_extern_in_linkage_spec &&
          StorageClassSpec == SCS_extern &&
          SC == SCS_typedef))
      return BadSpecifier(SC, (SCS)StorageClassSpec, PrevSpec, DiagID);
  }
  StorageClassSpec = SC;
  StorageClassSpecLoc = Loc;
  assert((unsigned)SC == StorageClassSpec && "SCS constants overflow bitfield");
  return false;
}
static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
  // check the attribute arguments.
  if (Attr.getNumArgs() != 0) {
    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
    return;
  }

  // Attribute can be applied only to functions or variables.
  if (isa<VarDecl>(D)) {
    D->addAttr(::new (S.Context) DLLImportAttr(Attr.getLoc(), S.Context));
    return;
  }

  FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
  if (!FD) {
    // Apparently Visual C++ thinks it is okay to not emit a warning
    // in this case, so only emit a warning when -fms-extensions is not
    // specified.
    if (!S.getLangOptions().Microsoft)
      S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
        << Attr.getName() << 2 /*variable and function*/;
    return;
  }

  // Currently, the dllimport attribute is ignored for inlined functions.
  // Warning is emitted.
  if (FD->isInlineSpecified()) {
    S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
    return;
  }

  // The attribute is also overridden by a subsequent declaration as dllexport.
  // Warning is emitted.
  for (AttributeList *nextAttr = Attr.getNext(); nextAttr;
       nextAttr = nextAttr->getNext()) {
    if (nextAttr->getKind() == AttributeList::AT_dllexport) {
      S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
      return;
    }
  }

  if (D->getAttr<DLLExportAttr>()) {
    S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
    return;
  }

  D->addAttr(::new (S.Context) DLLImportAttr(Attr.getLoc(), S.Context));
}
/// CheckReinterpretCast - Check that a reinterpret_cast\<DestType\>(SrcExpr) is
/// valid.
/// Refer to C++ 5.2.10 for details. reinterpret_cast is typically used in code
/// like this:
/// char *bytes = reinterpret_cast\<char*\>(int_ptr);
void
CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
                     const SourceRange &OpRange, const SourceRange &DestRange)
{
  QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType();

  DestType = Self.Context.getCanonicalType(DestType);
  QualType SrcType = SrcExpr->getType();
  if (const LValueReferenceType *DestTypeTmp =
        DestType->getAsLValueReferenceType()) {
    if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) {
      // Cannot cast non-lvalue to reference type.
      Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue)
        << "reinterpret_cast" << OrigDestType << SrcExpr->getSourceRange();
      return;
    }

    // C++ 5.2.10p10: [...] a reference cast reinterpret_cast<T&>(x) has the
    //   same effect as the conversion *reinterpret_cast<T*>(&x) with the
    //   built-in & and * operators.
    // This code does this transformation for the checked types.
    DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
    SrcType = Self.Context.getPointerType(SrcType);
  } else if (const RValueReferenceType *DestTypeTmp =
               DestType->getAsRValueReferenceType()) {
    // Both the reference conversion and the rvalue rules apply.
    Self.DefaultFunctionArrayConversion(SrcExpr);
    SrcType = SrcExpr->getType();

    DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
    SrcType = Self.Context.getPointerType(SrcType);
  } else {
    // C++ 5.2.10p1: [...] the lvalue-to-rvalue, array-to-pointer, and
    //   function-to-pointer standard conversions are performed on the
    //   expression v.
    Self.DefaultFunctionArrayConversion(SrcExpr);
    SrcType = SrcExpr->getType();
  }

  // Canonicalize source for comparison.
  SrcType = Self.Context.getCanonicalType(SrcType);

  const MemberPointerType *DestMemPtr = DestType->getAsMemberPointerType(),
                          *SrcMemPtr = SrcType->getAsMemberPointerType();
  if (DestMemPtr && SrcMemPtr) {
    // C++ 5.2.10p9: An rvalue of type "pointer to member of X of type T1"
    //   can be explicitly converted to an rvalue of type "pointer to member
    //   of Y of type T2" if T1 and T2 are both function types or both object
    //   types.
    if (DestMemPtr->getPointeeType()->isFunctionType() !=
        SrcMemPtr->getPointeeType()->isFunctionType()) {
      Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic)
        << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange;
      return;
    }

    // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away
    //   constness.
    if (CastsAwayConstness(Self, SrcType, DestType)) {
      Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away)
        << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange;
      return;
    }

    // A valid member pointer cast.
    return;
  }

  // See below for the enumeral issue.
  if (SrcType->isNullPtrType() && DestType->isIntegralType() &&
      !DestType->isEnumeralType()) {
    // C++0x 5.2.10p4: A pointer can be explicitly converted to any integral
    //   type large enough to hold it. A value of std::nullptr_t can be
    //   converted to an integral type; the conversion has the same meaning
    //   and validity as a conversion of (void*)0 to the integral type.
    if (Self.Context.getTypeSize(SrcType) >
        Self.Context.getTypeSize(DestType)) {
      Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_small_int)
        << OrigDestType << DestRange;
    }
    return;
  }

  bool destIsPtr = DestType->isPointerType();
  bool srcIsPtr = SrcType->isPointerType();
  if (!destIsPtr && !srcIsPtr) {
    // Except for std::nullptr_t->integer and lvalue->reference, which are
    // handled above, at least one of the two arguments must be a pointer.
    Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic)
      << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange;
    return;
  }

  if (SrcType == DestType) {
    // C++ 5.2.10p2 has a note that mentions that, subject to all other
    // restrictions, a cast to the same type is allowed. The intent is not
    // entirely clear here, since all other paragraphs explicitly forbid casts
    // to the same type. However, the behavior of compilers is pretty consistent
    // on this point: allow same-type conversion if the involved types are
    // pointers, disallow otherwise.
    return;
  }

  // Note: Clang treats enumeration types as integral types. If this is ever
  // changed for C++, the additional check here will be redundant.
  if (DestType->isIntegralType() && !DestType->isEnumeralType()) {
    assert(srcIsPtr && "One type must be a pointer");
    // C++ 5.2.10p4: A pointer can be explicitly converted to any integral
    //   type large enough to hold it.
    if (Self.Context.getTypeSize(SrcType) >
        Self.Context.getTypeSize(DestType)) {
      Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_small_int)
        << OrigDestType << DestRange;
    }
    return;
  }

  if (SrcType->isIntegralType() || SrcType->isEnumeralType()) {
    assert(destIsPtr && "One type must be a pointer");
    // C++ 5.2.10p5: A value of integral or enumeration type can be explicitly
    //   converted to a pointer.
    return;
  }

  if (!destIsPtr || !srcIsPtr) {
    // With the valid non-pointer conversions out of the way, we can be even
    // more stringent.
    Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic)
      << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange;
    return;
  }

  // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness.
  if (CastsAwayConstness(Self, SrcType, DestType)) {
    Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away)
      << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange;
    return;
  }

  // Not casting away constness, so the only remaining check is for compatible
  // pointer categories.

  if (SrcType->isFunctionPointerType()) {
    if (DestType->isFunctionPointerType()) {
      // C++ 5.2.10p6: A pointer to a function can be explicitly converted to
      // a pointer to a function of a different type.
      return;
    }

    // C++0x 5.2.10p8: Converting a pointer to a function into a pointer to
    //   an object type or vice versa is conditionally-supported.
    // Compilers support it in C++03 too, though, because it's necessary for
    // casting the return value of dlsym() and GetProcAddress().
    // FIXME: Conditionally-supported behavior should be configurable in the
    // TargetInfo or similar.
    if (!Self.getLangOptions().CPlusPlus0x) {
      Self.Diag(OpRange.getBegin(), diag::ext_reinterpret_cast_fn_obj)
        << OpRange;
    }
    return;
  }

  if (DestType->isFunctionPointerType()) {
    // See above.
    if (!Self.getLangOptions().CPlusPlus0x) {
      Self.Diag(OpRange.getBegin(), diag::ext_reinterpret_cast_fn_obj)
        << OpRange;
    }
    return;
  }

  // C++ 5.2.10p7: A pointer to an object can be explicitly converted to
  //   a pointer to an object of different type.
  // Void pointers are not specified, but supported by every compiler out there.
  // So we finish by allowing everything that remains - it's got to be two
  // object pointers.
}
static unsigned long long getContextsForContextKind(
                                          enum CodeCompletionContext::Kind kind, 
                                                    Sema &S) {
  unsigned long long contexts = 0;
  switch (kind) {
    case CodeCompletionContext::CCC_OtherWithMacros: {
      //We can allow macros here, but we don't know what else is permissible
      //So we'll say the only thing permissible are macros
      contexts = CXCompletionContext_MacroName;
      break;
    }
    case CodeCompletionContext::CCC_TopLevel:
    case CodeCompletionContext::CCC_ObjCIvarList:
    case CodeCompletionContext::CCC_ClassStructUnion:
    case CodeCompletionContext::CCC_Type: {
      contexts = CXCompletionContext_AnyType | 
                 CXCompletionContext_ObjCInterface;
      if (S.getLangOptions().CPlusPlus) {
        contexts |= CXCompletionContext_EnumTag |
                    CXCompletionContext_UnionTag |
                    CXCompletionContext_StructTag |
                    CXCompletionContext_ClassTag |
                    CXCompletionContext_NestedNameSpecifier;
      }
      break;
    }
    case CodeCompletionContext::CCC_Statement: {
      contexts = CXCompletionContext_AnyType |
                 CXCompletionContext_ObjCInterface |
                 CXCompletionContext_AnyValue;
      if (S.getLangOptions().CPlusPlus) {
        contexts |= CXCompletionContext_EnumTag |
                    CXCompletionContext_UnionTag |
                    CXCompletionContext_StructTag |
                    CXCompletionContext_ClassTag |
                    CXCompletionContext_NestedNameSpecifier;
      }
      break;
    }
    case CodeCompletionContext::CCC_Expression: {
      contexts = CXCompletionContext_AnyValue;
      if (S.getLangOptions().CPlusPlus) {
        contexts |= CXCompletionContext_AnyType |
                    CXCompletionContext_ObjCInterface |
                    CXCompletionContext_EnumTag |
                    CXCompletionContext_UnionTag |
                    CXCompletionContext_StructTag |
                    CXCompletionContext_ClassTag |
                    CXCompletionContext_NestedNameSpecifier;
      }
      break;
    }
    case CodeCompletionContext::CCC_ObjCMessageReceiver: {
      contexts = CXCompletionContext_ObjCObjectValue |
                 CXCompletionContext_ObjCSelectorValue |
                 CXCompletionContext_ObjCInterface;
      if (S.getLangOptions().CPlusPlus) {
        contexts |= CXCompletionContext_CXXClassTypeValue |
                    CXCompletionContext_AnyType |
                    CXCompletionContext_EnumTag |
                    CXCompletionContext_UnionTag |
                    CXCompletionContext_StructTag |
                    CXCompletionContext_ClassTag |
                    CXCompletionContext_NestedNameSpecifier;
      }
      break;
    }
    case CodeCompletionContext::CCC_DotMemberAccess: {
      contexts = CXCompletionContext_DotMemberAccess;
      break;
    }
    case CodeCompletionContext::CCC_ArrowMemberAccess: {
      contexts = CXCompletionContext_ArrowMemberAccess;
      break;
    }
    case CodeCompletionContext::CCC_ObjCPropertyAccess: {
      contexts = CXCompletionContext_ObjCPropertyAccess;
      break;
    }
    case CodeCompletionContext::CCC_EnumTag: {
      contexts = CXCompletionContext_EnumTag |
                 CXCompletionContext_NestedNameSpecifier;
      break;
    }
    case CodeCompletionContext::CCC_UnionTag: {
      contexts = CXCompletionContext_UnionTag |
                 CXCompletionContext_NestedNameSpecifier;
      break;
    }
    case CodeCompletionContext::CCC_ClassOrStructTag: {
      contexts = CXCompletionContext_StructTag |
                 CXCompletionContext_ClassTag |
                 CXCompletionContext_NestedNameSpecifier;
      break;
    }
    case CodeCompletionContext::CCC_ObjCProtocolName: {
      contexts = CXCompletionContext_ObjCProtocol;
      break;
    }
    case CodeCompletionContext::CCC_Namespace: {
      contexts = CXCompletionContext_Namespace;
      break;
    }
    case CodeCompletionContext::CCC_PotentiallyQualifiedName: {
      contexts = CXCompletionContext_NestedNameSpecifier;
      break;
    }
    case CodeCompletionContext::CCC_MacroNameUse: {
      contexts = CXCompletionContext_MacroName;
      break;
    }
    case CodeCompletionContext::CCC_NaturalLanguage: {
      contexts = CXCompletionContext_NaturalLanguage;
      break;
    }
    case CodeCompletionContext::CCC_SelectorName: {
      contexts = CXCompletionContext_ObjCSelectorName;
      break;
    }
    case CodeCompletionContext::CCC_ParenthesizedExpression: {
      contexts = CXCompletionContext_AnyType |
                 CXCompletionContext_ObjCInterface |
                 CXCompletionContext_AnyValue;
      if (S.getLangOptions().CPlusPlus) {
        contexts |= CXCompletionContext_EnumTag |
                    CXCompletionContext_UnionTag |
                    CXCompletionContext_StructTag |
                    CXCompletionContext_ClassTag |
                    CXCompletionContext_NestedNameSpecifier;
      }
      break;
    }
    case CodeCompletionContext::CCC_ObjCInstanceMessage: {
      contexts = CXCompletionContext_ObjCInstanceMessage;
      break;
    }
    case CodeCompletionContext::CCC_ObjCClassMessage: {
      contexts = CXCompletionContext_ObjCClassMessage;
      break;
    }
    case CodeCompletionContext::CCC_ObjCInterfaceName: {
      contexts = CXCompletionContext_ObjCInterface;
      break;
    }
    case CodeCompletionContext::CCC_ObjCCategoryName: {
      contexts = CXCompletionContext_ObjCCategory;
      break;
    }
    case CodeCompletionContext::CCC_Other:
    case CodeCompletionContext::CCC_ObjCInterface:
    case CodeCompletionContext::CCC_ObjCImplementation:
    case CodeCompletionContext::CCC_Name:
    case CodeCompletionContext::CCC_MacroName:
    case CodeCompletionContext::CCC_PreprocessorExpression:
    case CodeCompletionContext::CCC_PreprocessorDirective:
    case CodeCompletionContext::CCC_TypeQualifiers: {
      //Only Clang results should be accepted, so we'll set all of the other
      //context bits to 0 (i.e. the empty set)
      contexts = CXCompletionContext_Unexposed;
      break;
    }
    case CodeCompletionContext::CCC_Recovery: {
      //We don't know what the current context is, so we'll return unknown
      //This is the equivalent of setting all of the other context bits
      contexts = CXCompletionContext_Unknown;
      break;
    }
  }
  return contexts;
}