Esempio n. 1
0
File: DeclCXX.cpp Progetto: CPFL/guc
bool CXXConstructorDecl::isCopyConstructorLikeSpecialization() const {
  if ((getNumParams() < 1) ||
      (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) ||
      (getPrimaryTemplate() == 0) ||
      (getDescribedFunctionTemplate() != 0))
    return false;

  const ParmVarDecl *Param = getParamDecl(0);

  ASTContext &Context = getASTContext();
  CanQualType ParamType = Context.getCanonicalType(Param->getType());
  
  // Strip off the lvalue reference, if any.
  if (CanQual<LValueReferenceType> ParamRefType
                                    = ParamType->getAs<LValueReferenceType>())
    ParamType = ParamRefType->getPointeeType();

  
  // Is it the same as our our class type?
  CanQualType ClassTy 
    = Context.getCanonicalType(Context.getTagDeclType(getParent()));
  if (ParamType.getUnqualifiedType() != ClassTy)
    return false;
  
  return true;  
}
Esempio n. 2
0
llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
  QualType Ty = E->getType();
  const llvm::Type *LTy = ConvertType(Ty)->getPointerTo();
  if (E->isTypeOperand()) {
    Ty = E->getTypeOperand();
    CanQualType CanTy = CGM.getContext().getCanonicalType(Ty);
    Ty = CanTy.getUnqualifiedType().getNonReferenceType();
    if (const RecordType *RT = Ty->getAs<RecordType>()) {
      const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
      if (RD->isPolymorphic())
        return Builder.CreateBitCast(CGM.GenerateRttiRef(RD), LTy);
      return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy);
    }
    return Builder.CreateBitCast(CGM.GenerateRttiNonClass(Ty), LTy);
  }
  Expr *subE = E->getExprOperand();
  Ty = subE->getType();
  CanQualType CanTy = CGM.getContext().getCanonicalType(Ty);
  Ty = CanTy.getUnqualifiedType().getNonReferenceType();
  if (const RecordType *RT = Ty->getAs<RecordType>()) {
    const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
    if (RD->isPolymorphic()) {
      // FIXME: if subE is an lvalue do
      LValue Obj = EmitLValue(subE);
      llvm::Value *This = Obj.getAddress();
      LTy = LTy->getPointerTo()->getPointerTo();
      llvm::Value *V = Builder.CreateBitCast(This, LTy);
      // We need to do a zero check for *p, unless it has NonNullAttr.
      // FIXME: PointerType->hasAttr<NonNullAttr>()
      bool CanBeZero = false;
      if (UnaryOperator *UO = dyn_cast<UnaryOperator>(subE->IgnoreParens()))
        if (UO->getOpcode() == UnaryOperator::Deref)
          CanBeZero = true;
      if (CanBeZero) {
        llvm::BasicBlock *NonZeroBlock = createBasicBlock();
        llvm::BasicBlock *ZeroBlock = createBasicBlock();
        
        llvm::Value *Zero = llvm::Constant::getNullValue(LTy);
        Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero),
                             NonZeroBlock, ZeroBlock);
        EmitBlock(ZeroBlock);
        /// Call __cxa_bad_typeid
        const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext);
        const llvm::FunctionType *FTy;
        FTy = llvm::FunctionType::get(ResultType, false);
        llvm::Value *F = CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid");
        Builder.CreateCall(F)->setDoesNotReturn();
        Builder.CreateUnreachable();
        EmitBlock(NonZeroBlock);
      }
      V = Builder.CreateLoad(V, "vtable");
      V = Builder.CreateConstInBoundsGEP1_64(V, -1ULL);
      V = Builder.CreateLoad(V);
      return V;
    }      
    return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy);
  }
  return Builder.CreateBitCast(CGM.GenerateRttiNonClass(Ty), LTy);
}
void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
                                              ProgramStateRef state,
                                              const ObjCMethodCall &Msg) const {
  ASTContext &Ctx = C.getASTContext();
  static CheckerProgramPointTag Tag(this, "NilReceiver");

  // Check the return type of the message expression.  A message to nil will
  // return different values depending on the return type and the architecture.
  QualType RetTy = Msg.getResultType();
  CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
  const LocationContext *LCtx = C.getLocationContext();

  if (CanRetTy->isStructureOrClassType()) {
    // Structure returns are safe since the compiler zeroes them out.
    SVal V = C.getSValBuilder().makeZeroVal(RetTy);
    C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
    return;
  }

  // Other cases: check if sizeof(return type) > sizeof(void*)
  if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
                                  .isConsumedExpr(Msg.getOriginExpr())) {
    // Compute: sizeof(void *) and sizeof(return type)
    const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
    const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);

    if (CanRetTy.getTypePtr()->isReferenceType()||
        (voidPtrSize < returnTypeSize &&
         !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
           (Ctx.FloatTy == CanRetTy ||
            Ctx.DoubleTy == CanRetTy ||
            Ctx.LongDoubleTy == CanRetTy ||
            Ctx.LongLongTy == CanRetTy ||
            Ctx.UnsignedLongLongTy == CanRetTy)))) {
      if (ExplodedNode *N = C.generateSink(state, nullptr, &Tag))
        emitNilReceiverBug(C, Msg, N);
      return;
    }

    // Handle the safe cases where the return value is 0 if the
    // receiver is nil.
    //
    // FIXME: For now take the conservative approach that we only
    // return null values if we *know* that the receiver is nil.
    // This is because we can have surprises like:
    //
    //   ... = [[NSScreens screens] objectAtIndex:0];
    //
    // What can happen is that [... screens] could return nil, but
    // it most likely isn't nil.  We should assume the semantics
    // of this case unless we have *a lot* more knowledge.
    //
    SVal V = C.getSValBuilder().makeZeroVal(RetTy);
    C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
    return;
  }

  C.addTransition(state);
}
static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
                                       Cl::Kinds Kind, SourceLocation &Loc) {
  // As a general rule, we only care about lvalues. But there are some rvalues
  // for which we want to generate special results.
  if (Kind == Cl::CL_PRValue) {
    // For the sake of better diagnostics, we want to specifically recognize
    // use of the GCC cast-as-lvalue extension.
    if (const ExplicitCastExpr *CE =
          dyn_cast<ExplicitCastExpr>(E->IgnoreParens())) {
      if (CE->getSubExpr()->IgnoreParenImpCasts()->isLValue()) {
        Loc = CE->getExprLoc();
        return Cl::CM_LValueCast;
      }
    }
  }
  if (Kind != Cl::CL_LValue)
    return Cl::CM_RValue;

  // This is the lvalue case.
  // Functions are lvalues in C++, but not modifiable. (C++ [basic.lval]p6)
  if (Ctx.getLangOpts().CPlusPlus && E->getType()->isFunctionType())
    return Cl::CM_Function;

  // Assignment to a property in ObjC is an implicit setter access. But a
  // setter might not exist.
  if (const ObjCPropertyRefExpr *Expr = dyn_cast<ObjCPropertyRefExpr>(E)) {
    if (Expr->isImplicitProperty() && Expr->getImplicitPropertySetter() == 0)
      return Cl::CM_NoSetterProperty;
  }

  CanQualType CT = Ctx.getCanonicalType(E->getType());
  // Const stuff is obviously not modifiable.
  if (CT.isConstQualified())
    return Cl::CM_ConstQualified;
  if (CT.getQualifiers().getAddressSpace() == LangAS::opencl_constant)
    return Cl::CM_ConstQualified;

  // Arrays are not modifiable, only their elements are.
  if (CT->isArrayType())
    return Cl::CM_ArrayType;
  // Incomplete types are not modifiable.
  if (CT->isIncompleteType())
    return Cl::CM_IncompleteType;

  // Records with any const fields (recursively) are not modifiable.
  if (const RecordType *R = CT->getAs<RecordType>()) {
    assert((E->getObjectKind() == OK_ObjCProperty ||
            !Ctx.getLangOpts().CPlusPlus) &&
           "C++ struct assignment should be resolved by the "
           "copy assignment operator.");
    if (R->hasConstFields())
      return Cl::CM_ConstQualified;
  }

  return Cl::CM_Modifiable;
}
Esempio n. 5
0
// Asks whether the type in 'context' can ever instantiate to the type
// in 'friend'.
static bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) {
  if (Friend == Context)
    return true;

  if (!Friend->isDependentType() && !Context->isDependentType())
    return false;

  // TODO: this is very conservative.
  return true;
}
Esempio n. 6
0
DeclarationName
DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind,
                                        CanQualType Ty) {
  assert(Kind >= DeclarationName::CXXConstructorName &&
         Kind <= DeclarationName::CXXConversionFunctionName &&
         "Kind must be a C++ special name kind");
  llvm::FoldingSet<CXXSpecialName> *SpecialNames
    = static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl);

  DeclarationNameExtra::ExtraKind EKind;
  switch (Kind) {
  case DeclarationName::CXXConstructorName:
    EKind = DeclarationNameExtra::CXXConstructor;
    assert(!Ty.hasQualifiers() &&"Constructor type must be unqualified");
    break;
  case DeclarationName::CXXDestructorName:
    EKind = DeclarationNameExtra::CXXDestructor;
    assert(!Ty.hasQualifiers() && "Destructor type must be unqualified");
    break;
  case DeclarationName::CXXConversionFunctionName:
    EKind = DeclarationNameExtra::CXXConversionFunction;
    break;
  default:
    return DeclarationName();
  }

  // Unique selector, to guarantee there is one per name.
  llvm::FoldingSetNodeID ID;
  ID.AddInteger(EKind);
  ID.AddPointer(Ty.getAsOpaquePtr());

  void *InsertPos = nullptr;
  if (CXXSpecialName *Name = SpecialNames->FindNodeOrInsertPos(ID, InsertPos))
    return DeclarationName(Name);

  CXXSpecialName *SpecialName = new (Ctx) CXXSpecialName;
  SpecialName->ExtraKindOrNumArgs = EKind;
  SpecialName->Type = Ty;
  SpecialName->FETokenInfo = nullptr;

  SpecialNames->InsertNode(SpecialName, InsertPos);
  return DeclarationName(SpecialName);
}
Esempio n. 7
0
static AccessResult MatchesFriend(Sema &S,
                                  const EffectiveContext &EC,
                                  CanQualType Friend) {
  if (const RecordType *RT = Friend->getAs<RecordType>())
    return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl()));

  // TODO: we can do better than this
  if (Friend->isDependentType())
    return AR_dependent;

  return AR_inaccessible;
}
Esempio n. 8
0
File: CGDecl.cpp Progetto: aaasz/SHP
/// Emit an alloca (or GlobalValue depending on target)
/// for the specified parameter and set up LocalDeclMap.
void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) {
  // FIXME: Why isn't ImplicitParamDecl a ParmVarDecl?
  assert((isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D)) &&
         "Invalid argument to EmitParmDecl");
  QualType Ty = D.getType();
  CanQualType CTy = getContext().getCanonicalType(Ty);

  llvm::Value *DeclPtr;
  if (!Ty->isConstantSizeType()) {
    // Variable sized values always are passed by-reference.
    DeclPtr = Arg;
  } else {
    // A fixed sized single-value variable becomes an alloca in the entry block.
    const llvm::Type *LTy = ConvertTypeForMem(Ty);
    if (LTy->isSingleValueType()) {
      // TODO: Alignment
      DeclPtr = CreateTempAlloca(LTy);
      DeclPtr->setName(D.getNameAsString() + llvm::StringRef(".addr"));

      // Store the initial value into the alloca.
      EmitStoreOfScalar(Arg, DeclPtr, CTy.isVolatileQualified(), Ty);
    } else {
      // Otherwise, if this is an aggregate, just use the input pointer.
      DeclPtr = Arg;
    }
    Arg->setName(D.getNameAsString());
  }

  llvm::Value *&DMEntry = LocalDeclMap[&D];
  assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
  DMEntry = DeclPtr;

  // Emit debug info for param declaration.
  if (CGDebugInfo *DI = getDebugInfo()) {
    DI->setLocation(D.getLocation());
    DI->EmitDeclareOfArgVariable(&D, DeclPtr, Builder);
  }
}
Esempio n. 9
0
File: DeclCXX.cpp Progetto: CPFL/guc
bool
CXXConstructorDecl::isCopyConstructor(unsigned &TypeQuals) const {
  // C++ [class.copy]p2:
  //   A non-template constructor for class X is a copy constructor
  //   if its first parameter is of type X&, const X&, volatile X& or
  //   const volatile X&, and either there are no other parameters
  //   or else all other parameters have default arguments (8.3.6).
  if ((getNumParams() < 1) ||
      (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) ||
      (getPrimaryTemplate() != 0) ||
      (getDescribedFunctionTemplate() != 0))
    return false;

  const ParmVarDecl *Param = getParamDecl(0);

  // Do we have a reference type? Rvalue references don't count.
  const LValueReferenceType *ParamRefType =
    Param->getType()->getAs<LValueReferenceType>();
  if (!ParamRefType)
    return false;

  // Is it a reference to our class type?
  ASTContext &Context = getASTContext();
  
  CanQualType PointeeType
    = Context.getCanonicalType(ParamRefType->getPointeeType());
  CanQualType ClassTy 
    = Context.getCanonicalType(Context.getTagDeclType(getParent()));
  if (PointeeType.getUnqualifiedType() != ClassTy)
    return false;

  // FIXME: other qualifiers?

  // We have a copy constructor.
  TypeQuals = PointeeType.getCVRQualifiers();
  return true;
}
void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
                                              const ProgramState *state,
                                              ObjCMessage msg) const {
  ASTContext &Ctx = C.getASTContext();

  // Check the return type of the message expression.  A message to nil will
  // return different values depending on the return type and the architecture.
  QualType RetTy = msg.getType(Ctx);

  CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);

  if (CanRetTy->isStructureOrClassType()) {
    // FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead
    // have the "use of undefined value" be smarter about where the
    // undefined value came from.
    if (C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())){
      if (ExplodedNode *N = C.generateSink(state))
        emitNilReceiverBug(C, msg, N);
      return;
    }

    // The result is not consumed by a surrounding expression.  Just propagate
    // the current state.
    C.addTransition(state);
    return;
  }

  // Other cases: check if the return type is smaller than void*.
  if (CanRetTy != Ctx.VoidTy &&
      C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())) {
    // Compute: sizeof(void *) and sizeof(return type)
    const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
    const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);

    if (voidPtrSize < returnTypeSize &&
        !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
          (Ctx.FloatTy == CanRetTy ||
           Ctx.DoubleTy == CanRetTy ||
           Ctx.LongDoubleTy == CanRetTy ||
           Ctx.LongLongTy == CanRetTy ||
           Ctx.UnsignedLongLongTy == CanRetTy))) {
      if (ExplodedNode *N = C.generateSink(state))
        emitNilReceiverBug(C, msg, N);
      return;
    }

    // Handle the safe cases where the return value is 0 if the
    // receiver is nil.
    //
    // FIXME: For now take the conservative approach that we only
    // return null values if we *know* that the receiver is nil.
    // This is because we can have surprises like:
    //
    //   ... = [[NSScreens screens] objectAtIndex:0];
    //
    // What can happen is that [... screens] could return nil, but
    // it most likely isn't nil.  We should assume the semantics
    // of this case unless we have *a lot* more knowledge.
    //
    SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
    C.generateNode(state->BindExpr(msg.getOriginExpr(), V));
    return;
  }

  C.addTransition(state);
}
Esempio n. 11
0
/// isAmbiguous - Determines whether the set of paths provided is
/// ambiguous, i.e., there are two or more paths that refer to
/// different base class subobjects of the same type. BaseType must be
/// an unqualified, canonical class type.
bool CXXBasePaths::isAmbiguous(CanQualType BaseType) {
  BaseType = BaseType.getUnqualifiedType();
  std::pair<bool, unsigned>& Subobjects = ClassSubobjects[BaseType];
  return Subobjects.second + (Subobjects.first? 1 : 0) > 1;
}
Esempio n. 12
0
llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V,
                                              const CXXDynamicCastExpr *DCE) {
  QualType CastTy = DCE->getTypeAsWritten();
  QualType InnerType = CastTy->getPointeeType();
  QualType ArgTy = DCE->getSubExpr()->getType();
  const llvm::Type *LArgTy = ConvertType(ArgTy);
  const llvm::Type *LTy = ConvertType(DCE->getType());

  bool CanBeZero = false;
  bool ToVoid = false;
  bool ThrowOnBad = false;
  if (CastTy->isPointerType()) {
    // FIXME: if PointerType->hasAttr<NonNullAttr>(), we don't set this
    CanBeZero = true;
    if (InnerType->isVoidType())
      ToVoid = true;
  } else {
    LTy = LTy->getPointerTo();
    ThrowOnBad = true;
  }

  CXXRecordDecl *SrcTy;
  QualType Ty = ArgTy;
  if (ArgTy.getTypePtr()->isPointerType()
      || ArgTy.getTypePtr()->isReferenceType())
    Ty = Ty.getTypePtr()->getPointeeType();
  CanQualType CanTy = CGM.getContext().getCanonicalType(Ty);
  Ty = CanTy.getUnqualifiedType();
  SrcTy = cast<CXXRecordDecl>(Ty->getAs<RecordType>()->getDecl());

  llvm::BasicBlock *ContBlock = createBasicBlock();
  llvm::BasicBlock *NullBlock = 0;
  llvm::BasicBlock *NonZeroBlock = 0;
  if (CanBeZero) {
    NonZeroBlock = createBasicBlock();
    NullBlock = createBasicBlock();
    llvm::Value *Zero = llvm::Constant::getNullValue(LArgTy);
    Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero),
                         NonZeroBlock, NullBlock);
    EmitBlock(NonZeroBlock);
  }

  llvm::BasicBlock *BadCastBlock = 0;

  const llvm::Type *PtrDiffTy = ConvertType(getContext().getSizeType());

  // See if this is a dynamic_cast(void*)
  if (ToVoid) {
    llvm::Value *This = V;
    V = Builder.CreateBitCast(This, PtrDiffTy->getPointerTo()->getPointerTo());
    V = Builder.CreateLoad(V, "vtable");
    V = Builder.CreateConstInBoundsGEP1_64(V, -2ULL);
    V = Builder.CreateLoad(V, "offset to top");
    This = Builder.CreateBitCast(This, llvm::Type::getInt8PtrTy(VMContext));
    V = Builder.CreateInBoundsGEP(This, V);
    V = Builder.CreateBitCast(V, LTy);
  } else {
    /// Call __dynamic_cast
    const llvm::Type *ResultType = llvm::Type::getInt8PtrTy(VMContext);
    const llvm::FunctionType *FTy;
    std::vector<const llvm::Type*> ArgTys;
    const llvm::Type *PtrToInt8Ty
      = llvm::Type::getInt8Ty(VMContext)->getPointerTo();
    ArgTys.push_back(PtrToInt8Ty);
    ArgTys.push_back(PtrToInt8Ty);
    ArgTys.push_back(PtrToInt8Ty);
    ArgTys.push_back(PtrDiffTy);
    FTy = llvm::FunctionType::get(ResultType, ArgTys, false);
    CXXRecordDecl *DstTy;
    Ty = CastTy.getTypePtr()->getPointeeType();
    CanTy = CGM.getContext().getCanonicalType(Ty);
    Ty = CanTy.getUnqualifiedType();
    DstTy = cast<CXXRecordDecl>(Ty->getAs<RecordType>()->getDecl());

    // FIXME: Calculate better hint.
    llvm::Value *hint = llvm::ConstantInt::get(PtrDiffTy, -1ULL);
    llvm::Value *SrcArg = CGM.GenerateRttiRef(SrcTy);
    llvm::Value *DstArg = CGM.GenerateRttiRef(DstTy);
    V = Builder.CreateBitCast(V, PtrToInt8Ty);
    V = Builder.CreateCall4(CGM.CreateRuntimeFunction(FTy, "__dynamic_cast"),
                            V, SrcArg, DstArg, hint);
    V = Builder.CreateBitCast(V, LTy);

    if (ThrowOnBad) {
      BadCastBlock = createBasicBlock();

      llvm::Value *Zero = llvm::Constant::getNullValue(LTy);
      Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero),
                           ContBlock, BadCastBlock);
      EmitBlock(BadCastBlock);
      /// Call __cxa_bad_cast
      ResultType = llvm::Type::getVoidTy(VMContext);
      const llvm::FunctionType *FBadTy;
      FBadTy = llvm::FunctionType::get(ResultType, false);
      llvm::Value *F = CGM.CreateRuntimeFunction(FBadTy, "__cxa_bad_cast");
      Builder.CreateCall(F)->setDoesNotReturn();
      Builder.CreateUnreachable();
    }
  }
  
  if (CanBeZero) {
    Builder.CreateBr(ContBlock);
    EmitBlock(NullBlock);
    Builder.CreateBr(ContBlock);
  }
  EmitBlock(ContBlock);
  if (CanBeZero) {
    llvm::PHINode *PHI = Builder.CreatePHI(LTy);
    PHI->reserveOperandSpace(2);
    PHI->addIncoming(V, NonZeroBlock);
    PHI->addIncoming(llvm::Constant::getNullValue(LTy), NullBlock);
    V = PHI;
  }

  return V;
}
Esempio n. 13
0
static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
                                       Cl::Kinds Kind, SourceLocation &Loc) {
  // As a general rule, we only care about lvalues. But there are some rvalues
  // for which we want to generate special results.
  if (Kind == Cl::CL_PRValue) {
    // For the sake of better diagnostics, we want to specifically recognize
    // use of the GCC cast-as-lvalue extension.
    if (const CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(E->IgnoreParens())){
      if (CE->getSubExpr()->Classify(Ctx).isLValue()) {
        Loc = CE->getLParenLoc();
        return Cl::CM_LValueCast;
      }
    }
  }
  if (Kind != Cl::CL_LValue)
    return Cl::CM_RValue;

  // This is the lvalue case.
  // Functions are lvalues in C++, but not modifiable. (C++ [basic.lval]p6)
  if (Ctx.getLangOptions().CPlusPlus && E->getType()->isFunctionType())
    return Cl::CM_Function;

  // You cannot assign to a variable outside a block from within the block if
  // it is not marked __block, e.g.
  //   void takeclosure(void (^C)(void));
  //   void func() { int x = 1; takeclosure(^{ x = 7; }); }
  if (const BlockDeclRefExpr *BDR = dyn_cast<BlockDeclRefExpr>(E)) {
    if (!BDR->isByRef() && isa<VarDecl>(BDR->getDecl()))
      return Cl::CM_NotBlockQualified;
  }

  // Assignment to a property in ObjC is an implicit setter access. But a
  // setter might not exist.
  if (const ObjCImplicitSetterGetterRefExpr *Expr =
        dyn_cast<ObjCImplicitSetterGetterRefExpr>(E)) {
    if (Expr->getSetterMethod() == 0)
      return Cl::CM_NoSetterProperty;
  }

  CanQualType CT = Ctx.getCanonicalType(E->getType());
  // Const stuff is obviously not modifiable.
  if (CT.isConstQualified())
    return Cl::CM_ConstQualified;
  // Arrays are not modifiable, only their elements are.
  if (CT->isArrayType())
    return Cl::CM_ArrayType;
  // Incomplete types are not modifiable.
  if (CT->isIncompleteType())
    return Cl::CM_IncompleteType;

  // Records with any const fields (recursively) are not modifiable.
  if (const RecordType *R = CT->getAs<RecordType>()) {
    assert(!Ctx.getLangOptions().CPlusPlus &&
           "C++ struct assignment should be resolved by the "
           "copy assignment operator.");
    if (R->hasConstFields())
      return Cl::CM_ConstQualified;
  }

  return Cl::CM_Modifiable;
}
Esempio n. 14
0
DeclarationName DeclarationNameTable::getCXXDestructorName(CanQualType Ty) {
  return getCXXSpecialName(DeclarationName::CXXDestructorName,
                           Ty.getUnqualifiedType());
}