void ICEVisitor::VisitImplicitCastExpr(ImplicitCastExpr *CE) { const NamedDecl *ACD = dyn_cast<NamedDecl>(AC->getDecl()); VisitChildren(CE); const Expr *SE = CE->getSubExprAsWritten(); std::string sename = SE->getType().getAsString(); const clang::Expr *E = CE->getSubExpr(); if (!(sename == "EventNumber_t")) return; QualType OTy = BR.getContext().getCanonicalType(E->getType()); QualType TTy = BR.getContext().getCanonicalType(CE->getType()); QualType ToTy = TTy.getUnqualifiedType(); QualType OrigTy = OTy.getUnqualifiedType(); if (!(ToTy->isIntegerType() || ToTy->isFloatingType())) return; if (ToTy->isBooleanType()) return; CharUnits size_otype = BR.getContext().getTypeSizeInChars(OrigTy); CharUnits size_ttype = BR.getContext().getTypeSizeInChars(ToTy); std::string oname = OrigTy.getAsString(); std::string tname = ToTy.getAsString(); if (ToTy->isFloatingType()) { llvm::SmallString<100> buf; llvm::raw_svector_ostream os(buf); os << "Cast-to type, " << tname << ". Cast-from type, " << oname << " . " << support::getQualifiedName(*(ACD)); clang::ento::PathDiagnosticLocation CELoc = clang::ento::PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport(ACD, CheckName(), "implicit cast of int type to float type", "CMS code rules", os.str(), CELoc, CE->getSourceRange()); } if ((size_otype > size_ttype)) { llvm::SmallString<100> buf; llvm::raw_svector_ostream os(buf); os << "Cast-to type, " << tname << ". Cast-from type, " << oname << ". Cast may result in truncation. " << support::getQualifiedName(*(ACD)); clang::ento::PathDiagnosticLocation CELoc = clang::ento::PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport(ACD, CheckName(), "implicit cast of int type to smaller int type could truncate", "CMS code rules", os.str(), CELoc, CE->getSourceRange()); } if (ToTy->hasSignedIntegerRepresentation() && OrigTy->hasUnsignedIntegerRepresentation() || ToTy->hasUnsignedIntegerRepresentation() && OrigTy->hasSignedIntegerRepresentation()) { llvm::SmallString<100> buf; llvm::raw_svector_ostream os(buf); os << "Cast-to type, " << tname << ". Cast-from type, " << oname << ". Changes int sign type. " << support::getQualifiedName(*(ACD)); clang::ento::PathDiagnosticLocation CELoc = clang::ento::PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport(ACD, CheckName(), "implicit cast changes int sign type", "CMS code rules", os.str(), CELoc, CE->getSourceRange()); } return; }
// FIXME: should rewrite according to the cast kind. SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) { castTy = Context.getCanonicalType(castTy); originalTy = Context.getCanonicalType(originalTy); if (val.isUnknownOrUndef() || castTy == originalTy) return val; // For const casts, just propagate the value. if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType()) if (haveSimilarTypes(Context, Context.getPointerType(castTy), Context.getPointerType(originalTy))) return val; // Check for casts from pointers to integers. if (castTy->isIntegerType() && Loc::isLocType(originalTy)) return evalCastFromLoc(cast<Loc>(val), castTy); // Check for casts from integers to pointers. if (Loc::isLocType(castTy) && originalTy->isIntegerType()) { if (nonloc::LocAsInteger *LV = dyn_cast<nonloc::LocAsInteger>(&val)) { if (const MemRegion *R = LV->getLoc().getAsRegion()) { StoreManager &storeMgr = StateMgr.getStoreManager(); R = storeMgr.castRegion(R, castTy); return R ? SVal(loc::MemRegionVal(R)) : UnknownVal(); } return LV->getLoc(); } return dispatchCast(val, castTy); } // Just pass through function and block pointers. if (originalTy->isBlockPointerType() || originalTy->isFunctionPointerType()) { assert(Loc::isLocType(castTy)); return val; } // Check for casts from array type to another type. if (originalTy->isArrayType()) { // We will always decay to a pointer. val = StateMgr.ArrayToPointer(cast<Loc>(val)); // Are we casting from an array to a pointer? If so just pass on // the decayed value. if (castTy->isPointerType()) return val; // Are we casting from an array to an integer? If so, cast the decayed // pointer value to an integer. assert(castTy->isIntegerType()); // FIXME: Keep these here for now in case we decide soon that we // need the original decayed type. // QualType elemTy = cast<ArrayType>(originalTy)->getElementType(); // QualType pointerTy = C.getPointerType(elemTy); return evalCastFromLoc(cast<Loc>(val), castTy); } // Check for casts from a region to a specific type. if (const MemRegion *R = val.getAsRegion()) { // FIXME: We should handle the case where we strip off view layers to get // to a desugared type. if (!Loc::isLocType(castTy)) { // FIXME: There can be gross cases where one casts the result of a function // (that returns a pointer) to some other value that happens to fit // within that pointer value. We currently have no good way to // model such operations. When this happens, the underlying operation // is that the caller is reasoning about bits. Conceptually we are // layering a "view" of a location on top of those bits. Perhaps // we need to be more lazy about mutual possible views, even on an // SVal? This may be necessary for bit-level reasoning as well. return UnknownVal(); } // We get a symbolic function pointer for a dereference of a function // pointer, but it is of function type. Example: // struct FPRec { // void (*my_func)(int * x); // }; // // int bar(int x); // // int f1_a(struct FPRec* foo) { // int x; // (*foo->my_func)(&x); // return bar(x)+1; // no-warning // } assert(Loc::isLocType(originalTy) || originalTy->isFunctionType() || originalTy->isBlockPointerType() || castTy->isReferenceType()); StoreManager &storeMgr = StateMgr.getStoreManager(); // Delegate to store manager to get the result of casting a region to a // different type. If the MemRegion* returned is NULL, this expression // Evaluates to UnknownVal. R = storeMgr.castRegion(R, castTy); return R ? SVal(loc::MemRegionVal(R)) : UnknownVal(); } return dispatchCast(val, castTy); }
/// Create a fake body for dispatch_once. static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { // Check if we have at least two parameters. if (D->param_size() != 2) return 0; // Check if the first parameter is a pointer to integer type. const ParmVarDecl *Predicate = D->getParamDecl(0); QualType PredicateQPtrTy = Predicate->getType(); const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>(); if (!PredicatePtrTy) return 0; QualType PredicateTy = PredicatePtrTy->getPointeeType(); if (!PredicateTy->isIntegerType()) return 0; // Check if the second parameter is the proper block type. const ParmVarDecl *Block = D->getParamDecl(1); QualType Ty = Block->getType(); if (!isDispatchBlock(Ty)) return 0; // Everything checks out. Create a fakse body that checks the predicate, // sets it, and calls the block. Basically, an AST dump of: // // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) { // if (!*predicate) { // *predicate = 1; // block(); // } // } ASTMaker M(C); // (1) Create the call. DeclRefExpr *DR = M.makeDeclRefExpr(Block); ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty); CallExpr *CE = new (C) CallExpr(C, ICE, None, C.VoidTy, VK_RValue, SourceLocation()); // (2) Create the assignment to the predicate. IntegerLiteral *IL = IntegerLiteral::Create(C, llvm::APInt(C.getTypeSize(C.IntTy), (uint64_t) 1), C.IntTy, SourceLocation()); BinaryOperator *B = M.makeAssignment( M.makeDereference( M.makeLvalueToRvalue( M.makeDeclRefExpr(Predicate), PredicateQPtrTy), PredicateTy), M.makeIntegralCast(IL, PredicateTy), PredicateTy); // (3) Create the compound statement. Stmt *Stmts[2]; Stmts[0] = B; Stmts[1] = CE; CompoundStmt *CS = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2)); // (4) Create the 'if' condition. ImplicitCastExpr *LValToRval = M.makeLvalueToRvalue( M.makeDereference( M.makeLvalueToRvalue( M.makeDeclRefExpr(Predicate), PredicateQPtrTy), PredicateTy), PredicateTy); UnaryOperator *UO = new (C) UnaryOperator(LValToRval, UO_LNot, C.IntTy, VK_RValue, OK_Ordinary, SourceLocation()); // (5) Create the 'if' statement. IfStmt *If = new (C) IfStmt(C, SourceLocation(), 0, UO, CS); return If; }
const GRState *SimpleConstraintManager::AssumeSymRel(const GRState *state, const SymExpr *LHS, BinaryOperator::Opcode op, const llvm::APSInt& Int) { assert(BinaryOperator::isComparisonOp(op) && "Non-comparison ops should be rewritten as comparisons to zero."); // We only handle simple comparisons of the form "$sym == constant" // or "($sym+constant1) == constant2". // The adjustment is "constant1" in the above expression. It's used to // "slide" the solution range around for modular arithmetic. For example, // x < 4 has the solution [0, 3]. x+2 < 4 has the solution [0-2, 3-2], which // in modular arithmetic is [0, 1] U [UINT_MAX-1, UINT_MAX]. It's up to // the subclasses of SimpleConstraintManager to handle the adjustment. llvm::APSInt Adjustment; // First check if the LHS is a simple symbol reference. SymbolRef Sym = dyn_cast<SymbolData>(LHS); if (Sym) { Adjustment = 0; } else { // Next, see if it's a "($sym+constant1)" expression. const SymIntExpr *SE = dyn_cast<SymIntExpr>(LHS); // We don't handle "($sym1+$sym2)". // Give up and assume the constraint is feasible. if (!SE) return state; // We don't handle "(<expr>+constant1)". // Give up and assume the constraint is feasible. Sym = dyn_cast<SymbolData>(SE->getLHS()); if (!Sym) return state; // Get the constant out of the expression "($sym+constant1)". switch (SE->getOpcode()) { case BO_Add: Adjustment = SE->getRHS(); break; case BO_Sub: Adjustment = -SE->getRHS(); break; default: // We don't handle non-additive operators. // Give up and assume the constraint is feasible. return state; } } // FIXME: This next section is a hack. It silently converts the integers to // be of the same type as the symbol, which is not always correct. Really the // comparisons should be performed using the Int's type, then mapped back to // the symbol's range of values. GRStateManager &StateMgr = state->getStateManager(); ASTContext &Ctx = StateMgr.getContext(); QualType T = Sym->getType(Ctx); assert(T->isIntegerType() || Loc::IsLocType(T)); unsigned bitwidth = Ctx.getTypeSize(T); bool isSymUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T); // Convert the adjustment. Adjustment.setIsUnsigned(isSymUnsigned); Adjustment.extOrTrunc(bitwidth); // Convert the right-hand side integer. llvm::APSInt ConvertedInt(Int, isSymUnsigned); ConvertedInt.extOrTrunc(bitwidth); switch (op) { default: // No logic yet for other operators. Assume the constraint is feasible. return state; case BO_EQ: return AssumeSymEQ(state, Sym, ConvertedInt, Adjustment); case BO_NE: return AssumeSymNE(state, Sym, ConvertedInt, Adjustment); case BO_GT: return AssumeSymGT(state, Sym, ConvertedInt, Adjustment); case BO_GE: return AssumeSymGE(state, Sym, ConvertedInt, Adjustment); case BO_LT: return AssumeSymLT(state, Sym, ConvertedInt, Adjustment); case BO_LE: return AssumeSymLE(state, Sym, ConvertedInt, Adjustment); } // end switch }
void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const { ProgramStateRef state = C.getState(); if (CE->getNumArgs() < 2) { // The frontend should issue a warning for this case, so this is a sanity // check. return; } else if (CE->getNumArgs() == 3) { const Expr *Arg = CE->getArg(2); QualType QT = Arg->getType(); if (!QT->isIntegerType()) { ReportOpenBug(C, state, "Third argument to 'open' is not an integer", Arg->getSourceRange()); return; } } else if (CE->getNumArgs() > 3) { ReportOpenBug(C, state, "Call to 'open' with more than three arguments", CE->getArg(3)->getSourceRange()); return; } // The definition of O_CREAT is platform specific. We need a better way // of querying this information from the checking environment. if (!Val_O_CREAT.hasValue()) { if (C.getASTContext().getTargetInfo().getTriple().getVendor() == llvm::Triple::Apple) Val_O_CREAT = 0x0200; else { // FIXME: We need a more general way of getting the O_CREAT value. // We could possibly grovel through the preprocessor state, but // that would require passing the Preprocessor object to the ExprEngine. // See also: MallocChecker.cpp / M_ZERO. return; } } // Now check if oflags has O_CREAT set. const Expr *oflagsEx = CE->getArg(1); const SVal V = state->getSVal(oflagsEx, C.getLocationContext()); if (!V.getAs<NonLoc>()) { // The case where 'V' can be a location can only be due to a bad header, // so in this case bail out. return; } NonLoc oflags = V.castAs<NonLoc>(); NonLoc ocreateFlag = C.getSValBuilder() .makeIntVal(Val_O_CREAT.getValue(), oflagsEx->getType()).castAs<NonLoc>(); SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And, oflags, ocreateFlag, oflagsEx->getType()); if (maskedFlagsUC.isUnknownOrUndef()) return; DefinedSVal maskedFlags = maskedFlagsUC.castAs<DefinedSVal>(); // Check if maskedFlags is non-zero. ProgramStateRef trueState, falseState; std::tie(trueState, falseState) = state->assume(maskedFlags); // Only emit an error if the value of 'maskedFlags' is properly // constrained; if (!(trueState && !falseState)) return; if (CE->getNumArgs() < 3) { ReportOpenBug(C, trueState, "Call to 'open' requires a third argument when " "the 'O_CREAT' flag is set", oflagsEx->getSourceRange()); } }
bool AuditCFNumberCreate::Audit(ExplodedNode* N,GRStateManager&){ const CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt()); const Expr* Callee = CE->getCallee(); SVal CallV = N->getState()->getSVal(Callee); const FunctionDecl* FD = CallV.getAsFunctionDecl(); if (!FD || FD->getIdentifier() != II || CE->getNumArgs()!=3) return false; // Get the value of the "theType" argument. SVal TheTypeVal = N->getState()->getSVal(CE->getArg(1)); // FIXME: We really should allow ranges of valid theType values, and // bifurcate the state appropriately. nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal); if (!V) return false; uint64_t NumberKind = V->getValue().getLimitedValue(); Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind); // FIXME: In some cases we can emit an error. if (!TargetSize.isKnown()) return false; // Look at the value of the integer being passed by reference. Essentially // we want to catch cases where the value passed in is not equal to the // size of the type being created. SVal TheValueExpr = N->getState()->getSVal(CE->getArg(2)); // FIXME: Eventually we should handle arbitrary locations. We can do this // by having an enhanced memory model that does low-level typing. loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr); if (!LV) return false; const TypedRegion* R = dyn_cast<TypedRegion>(LV->StripCasts()); if (!R) return false; QualType T = Ctx.getCanonicalType(R->getValueType(Ctx)); // FIXME: If the pointee isn't an integer type, should we flag a warning? // People can do weird stuff with pointers. if (!T->isIntegerType()) return false; uint64_t SourceSize = Ctx.getTypeSize(T); // CHECK: is SourceSize == TargetSize if (SourceSize == TargetSize) return false; AddError(R, CE->getArg(2), N, SourceSize, TargetSize, NumberKind); // FIXME: We can actually create an abstract "CFNumber" object that has // the bits initialized to the provided values. return SourceSize < TargetSize; }
StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, IdentifierInfo **Names, MultiExprArg constraints, MultiExprArg exprs, Expr *asmString, MultiExprArg clobbers, SourceLocation RParenLoc) { unsigned NumClobbers = clobbers.size(); StringLiteral **Constraints = reinterpret_cast<StringLiteral**>(constraints.data()); Expr **Exprs = exprs.data(); StringLiteral *AsmString = cast<StringLiteral>(asmString); StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.data()); SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos; // The parser verifies that there is a string literal here. if (!AsmString->isAscii()) return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character) << AsmString->getSourceRange()); for (unsigned i = 0; i != NumOutputs; i++) { StringLiteral *Literal = Constraints[i]; if (!Literal->isAscii()) return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) << Literal->getSourceRange()); StringRef OutputName; if (Names[i]) OutputName = Names[i]->getName(); TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName); if (!Context.getTargetInfo().validateOutputConstraint(Info)) return StmtError(Diag(Literal->getLocStart(), diag::err_asm_invalid_output_constraint) << Info.getConstraintStr()); // Check that the output exprs are valid lvalues. Expr *OutputExpr = Exprs[i]; if (CheckAsmLValue(OutputExpr, *this)) { return StmtError(Diag(OutputExpr->getLocStart(), diag::err_asm_invalid_lvalue_in_output) << OutputExpr->getSourceRange()); } OutputConstraintInfos.push_back(Info); } SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos; for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) { StringLiteral *Literal = Constraints[i]; if (!Literal->isAscii()) return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) << Literal->getSourceRange()); StringRef InputName; if (Names[i]) InputName = Names[i]->getName(); TargetInfo::ConstraintInfo Info(Literal->getString(), InputName); if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos.data(), NumOutputs, Info)) { return StmtError(Diag(Literal->getLocStart(), diag::err_asm_invalid_input_constraint) << Info.getConstraintStr()); } Expr *InputExpr = Exprs[i]; // Only allow void types for memory constraints. if (Info.allowsMemory() && !Info.allowsRegister()) { if (CheckAsmLValue(InputExpr, *this)) return StmtError(Diag(InputExpr->getLocStart(), diag::err_asm_invalid_lvalue_in_input) << Info.getConstraintStr() << InputExpr->getSourceRange()); } if (Info.allowsRegister()) { if (InputExpr->getType()->isVoidType()) { return StmtError(Diag(InputExpr->getLocStart(), diag::err_asm_invalid_type_in_input) << InputExpr->getType() << Info.getConstraintStr() << InputExpr->getSourceRange()); } } ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]); if (Result.isInvalid()) return StmtError(); Exprs[i] = Result.take(); InputConstraintInfos.push_back(Info); const Type *Ty = Exprs[i]->getType().getTypePtr(); if (Ty->isDependentType() || Ty->isIncompleteType()) continue; unsigned Size = Context.getTypeSize(Ty); if (!Context.getTargetInfo().validateInputSize(Literal->getString(), Size)) return StmtError(Diag(InputExpr->getLocStart(), diag::err_asm_invalid_input_size) << Info.getConstraintStr()); } // Check that the clobbers are valid. for (unsigned i = 0; i != NumClobbers; i++) { StringLiteral *Literal = Clobbers[i]; if (!Literal->isAscii()) return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) << Literal->getSourceRange()); StringRef Clobber = Literal->getString(); if (!Context.getTargetInfo().isValidClobber(Clobber)) return StmtError(Diag(Literal->getLocStart(), diag::err_asm_unknown_register_name) << Clobber); } GCCAsmStmt *NS = new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs, Names, Constraints, Exprs, AsmString, NumClobbers, Clobbers, RParenLoc); // Validate the asm string, ensuring it makes sense given the operands we // have. SmallVector<GCCAsmStmt::AsmStringPiece, 8> Pieces; unsigned DiagOffs; if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) { Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID) << AsmString->getSourceRange(); return StmtError(); } // Validate constraints and modifiers. for (unsigned i = 0, e = Pieces.size(); i != e; ++i) { GCCAsmStmt::AsmStringPiece &Piece = Pieces[i]; if (!Piece.isOperand()) continue; // Look for the correct constraint index. unsigned Idx = 0; unsigned ConstraintIdx = 0; for (unsigned i = 0, e = NS->getNumOutputs(); i != e; ++i, ++ConstraintIdx) { TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i]; if (Idx == Piece.getOperandNo()) break; ++Idx; if (Info.isReadWrite()) { if (Idx == Piece.getOperandNo()) break; ++Idx; } } for (unsigned i = 0, e = NS->getNumInputs(); i != e; ++i, ++ConstraintIdx) { TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i]; if (Idx == Piece.getOperandNo()) break; ++Idx; if (Info.isReadWrite()) { if (Idx == Piece.getOperandNo()) break; ++Idx; } } // Now that we have the right indexes go ahead and check. StringLiteral *Literal = Constraints[ConstraintIdx]; const Type *Ty = Exprs[ConstraintIdx]->getType().getTypePtr(); if (Ty->isDependentType() || Ty->isIncompleteType()) continue; unsigned Size = Context.getTypeSize(Ty); if (!Context.getTargetInfo() .validateConstraintModifier(Literal->getString(), Piece.getModifier(), Size)) Diag(Exprs[ConstraintIdx]->getLocStart(), diag::warn_asm_mismatched_size_modifier); } // Validate tied input operands for type mismatches. for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) { TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i]; // If this is a tied constraint, verify that the output and input have // either exactly the same type, or that they are int/ptr operands with the // same size (int/long, int*/long, are ok etc). if (!Info.hasTiedOperand()) continue; unsigned TiedTo = Info.getTiedOperand(); unsigned InputOpNo = i+NumOutputs; Expr *OutputExpr = Exprs[TiedTo]; Expr *InputExpr = Exprs[InputOpNo]; if (OutputExpr->isTypeDependent() || InputExpr->isTypeDependent()) continue; QualType InTy = InputExpr->getType(); QualType OutTy = OutputExpr->getType(); if (Context.hasSameType(InTy, OutTy)) continue; // All types can be tied to themselves. // Decide if the input and output are in the same domain (integer/ptr or // floating point. enum AsmDomain { AD_Int, AD_FP, AD_Other } InputDomain, OutputDomain; if (InTy->isIntegerType() || InTy->isPointerType()) InputDomain = AD_Int; else if (InTy->isRealFloatingType()) InputDomain = AD_FP; else InputDomain = AD_Other; if (OutTy->isIntegerType() || OutTy->isPointerType()) OutputDomain = AD_Int; else if (OutTy->isRealFloatingType()) OutputDomain = AD_FP; else OutputDomain = AD_Other; // They are ok if they are the same size and in the same domain. This // allows tying things like: // void* to int* // void* to int if they are the same size. // double to long double if they are the same size. // uint64_t OutSize = Context.getTypeSize(OutTy); uint64_t InSize = Context.getTypeSize(InTy); if (OutSize == InSize && InputDomain == OutputDomain && InputDomain != AD_Other) continue; // If the smaller input/output operand is not mentioned in the asm string, // then we can promote the smaller one to a larger input and the asm string // won't notice. bool SmallerValueMentioned = false; // If this is a reference to the input and if the input was the smaller // one, then we have to reject this asm. if (isOperandMentioned(InputOpNo, Pieces)) { // This is a use in the asm string of the smaller operand. Since we // codegen this by promoting to a wider value, the asm will get printed // "wrong". SmallerValueMentioned |= InSize < OutSize; } if (isOperandMentioned(TiedTo, Pieces)) { // If this is a reference to the output, and if the output is the larger // value, then it's ok because we'll promote the input to the larger type. SmallerValueMentioned |= OutSize < InSize; } // If the smaller value wasn't mentioned in the asm string, and if the // output was a register, just extend the shorter one to the size of the // larger one. if (!SmallerValueMentioned && InputDomain != AD_Other && OutputConstraintInfos[TiedTo].allowsRegister()) continue; // Either both of the operands were mentioned or the smaller one was // mentioned. One more special case that we'll allow: if the tied input is // integer, unmentioned, and is a constant, then we'll allow truncating it // down to the size of the destination. if (InputDomain == AD_Int && OutputDomain == AD_Int && !isOperandMentioned(InputOpNo, Pieces) && InputExpr->isEvaluatable(Context)) { CastKind castKind = (OutTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast); InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).take(); Exprs[InputOpNo] = InputExpr; NS->setInputExpr(i, InputExpr); continue; } Diag(InputExpr->getLocStart(), diag::err_asm_tying_incompatible_types) << InTy << OutTy << OutputExpr->getSourceRange() << InputExpr->getSourceRange(); return StmtError(); } return Owned(NS); }
StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, IdentifierInfo **Names, MultiExprArg constraints, MultiExprArg Exprs, Expr *asmString, MultiExprArg clobbers, SourceLocation RParenLoc) { unsigned NumClobbers = clobbers.size(); StringLiteral **Constraints = reinterpret_cast<StringLiteral**>(constraints.data()); StringLiteral *AsmString = cast<StringLiteral>(asmString); StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.data()); SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos; // The parser verifies that there is a string literal here. assert(AsmString->isAscii()); // If we're compiling CUDA file and function attributes indicate that it's not // for this compilation side, skip all the checks. if (!DeclAttrsMatchCUDAMode(getLangOpts(), getCurFunctionDecl())) { GCCAsmStmt *NS = new (Context) GCCAsmStmt( Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs, Names, Constraints, Exprs.data(), AsmString, NumClobbers, Clobbers, RParenLoc); return NS; } // If we're compiling HCC file and function attributes indicate that it's not // for this compilation side, skip all the checks. if (!DeclAttrsMatchHCCMode(getLangOpts(), getCurFunctionDecl())) { GCCAsmStmt *NS = new (Context) GCCAsmStmt( Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs, Names, Constraints, Exprs.data(), AsmString, NumClobbers, Clobbers, RParenLoc); return NS; } for (unsigned i = 0; i != NumOutputs; i++) { StringLiteral *Literal = Constraints[i]; assert(Literal->isAscii()); StringRef OutputName; if (Names[i]) OutputName = Names[i]->getName(); TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName); if (!Context.getTargetInfo().validateOutputConstraint(Info)) return StmtError(Diag(Literal->getLocStart(), diag::err_asm_invalid_output_constraint) << Info.getConstraintStr()); ExprResult ER = CheckPlaceholderExpr(Exprs[i]); if (ER.isInvalid()) return StmtError(); Exprs[i] = ER.get(); // Check that the output exprs are valid lvalues. Expr *OutputExpr = Exprs[i]; // Referring to parameters is not allowed in naked functions. if (CheckNakedParmReference(OutputExpr, *this)) return StmtError(); // Check that the output expression is compatible with memory constraint. if (Info.allowsMemory() && checkExprMemoryConstraintCompat(*this, OutputExpr, Info, false)) return StmtError(); OutputConstraintInfos.push_back(Info); // If this is dependent, just continue. if (OutputExpr->isTypeDependent()) continue; Expr::isModifiableLvalueResult IsLV = OutputExpr->isModifiableLvalue(Context, /*Loc=*/nullptr); switch (IsLV) { case Expr::MLV_Valid: // Cool, this is an lvalue. break; case Expr::MLV_ArrayType: // This is OK too. break; case Expr::MLV_LValueCast: { const Expr *LVal = OutputExpr->IgnoreParenNoopCasts(Context); if (!getLangOpts().HeinousExtensions) { Diag(LVal->getLocStart(), diag::err_invalid_asm_cast_lvalue) << OutputExpr->getSourceRange(); } else { Diag(LVal->getLocStart(), diag::warn_invalid_asm_cast_lvalue) << OutputExpr->getSourceRange(); } // Accept, even if we emitted an error diagnostic. break; } case Expr::MLV_IncompleteType: case Expr::MLV_IncompleteVoidType: if (RequireCompleteType(OutputExpr->getLocStart(), Exprs[i]->getType(), diag::err_dereference_incomplete_type)) return StmtError(); default: return StmtError(Diag(OutputExpr->getLocStart(), diag::err_asm_invalid_lvalue_in_output) << OutputExpr->getSourceRange()); } unsigned Size = Context.getTypeSize(OutputExpr->getType()); if (!Context.getTargetInfo().validateOutputSize(Literal->getString(), Size)) return StmtError(Diag(OutputExpr->getLocStart(), diag::err_asm_invalid_output_size) << Info.getConstraintStr()); } SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos; for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) { StringLiteral *Literal = Constraints[i]; assert(Literal->isAscii()); StringRef InputName; if (Names[i]) InputName = Names[i]->getName(); TargetInfo::ConstraintInfo Info(Literal->getString(), InputName); if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos, Info)) { return StmtError(Diag(Literal->getLocStart(), diag::err_asm_invalid_input_constraint) << Info.getConstraintStr()); } ExprResult ER = CheckPlaceholderExpr(Exprs[i]); if (ER.isInvalid()) return StmtError(); Exprs[i] = ER.get(); Expr *InputExpr = Exprs[i]; // Referring to parameters is not allowed in naked functions. if (CheckNakedParmReference(InputExpr, *this)) return StmtError(); // Check that the input expression is compatible with memory constraint. if (Info.allowsMemory() && checkExprMemoryConstraintCompat(*this, InputExpr, Info, true)) return StmtError(); // Only allow void types for memory constraints. if (Info.allowsMemory() && !Info.allowsRegister()) { if (CheckAsmLValue(InputExpr, *this)) return StmtError(Diag(InputExpr->getLocStart(), diag::err_asm_invalid_lvalue_in_input) << Info.getConstraintStr() << InputExpr->getSourceRange()); } else if (Info.requiresImmediateConstant() && !Info.allowsRegister()) { if (!InputExpr->isValueDependent()) { llvm::APSInt Result; if (!InputExpr->EvaluateAsInt(Result, Context)) return StmtError( Diag(InputExpr->getLocStart(), diag::err_asm_immediate_expected) << Info.getConstraintStr() << InputExpr->getSourceRange()); if (!Info.isValidAsmImmediate(Result)) return StmtError(Diag(InputExpr->getLocStart(), diag::err_invalid_asm_value_for_constraint) << Result.toString(10) << Info.getConstraintStr() << InputExpr->getSourceRange()); } } else { ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]); if (Result.isInvalid()) return StmtError(); Exprs[i] = Result.get(); } if (Info.allowsRegister()) { if (InputExpr->getType()->isVoidType()) { return StmtError(Diag(InputExpr->getLocStart(), diag::err_asm_invalid_type_in_input) << InputExpr->getType() << Info.getConstraintStr() << InputExpr->getSourceRange()); } } InputConstraintInfos.push_back(Info); const Type *Ty = Exprs[i]->getType().getTypePtr(); if (Ty->isDependentType()) continue; if (!Ty->isVoidType() || !Info.allowsMemory()) if (RequireCompleteType(InputExpr->getLocStart(), Exprs[i]->getType(), diag::err_dereference_incomplete_type)) return StmtError(); unsigned Size = Context.getTypeSize(Ty); if (!Context.getTargetInfo().validateInputSize(Literal->getString(), Size)) return StmtError(Diag(InputExpr->getLocStart(), diag::err_asm_invalid_input_size) << Info.getConstraintStr()); } // Check that the clobbers are valid. for (unsigned i = 0; i != NumClobbers; i++) { StringLiteral *Literal = Clobbers[i]; assert(Literal->isAscii()); StringRef Clobber = Literal->getString(); if (!Context.getTargetInfo().isValidClobber(Clobber)) return StmtError(Diag(Literal->getLocStart(), diag::err_asm_unknown_register_name) << Clobber); } GCCAsmStmt *NS = new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs, Names, Constraints, Exprs.data(), AsmString, NumClobbers, Clobbers, RParenLoc); // Validate the asm string, ensuring it makes sense given the operands we // have. SmallVector<GCCAsmStmt::AsmStringPiece, 8> Pieces; unsigned DiagOffs; if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) { Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID) << AsmString->getSourceRange(); return StmtError(); } // Validate constraints and modifiers. for (unsigned i = 0, e = Pieces.size(); i != e; ++i) { GCCAsmStmt::AsmStringPiece &Piece = Pieces[i]; if (!Piece.isOperand()) continue; // Look for the correct constraint index. unsigned ConstraintIdx = Piece.getOperandNo(); unsigned NumOperands = NS->getNumOutputs() + NS->getNumInputs(); // Look for the (ConstraintIdx - NumOperands + 1)th constraint with // modifier '+'. if (ConstraintIdx >= NumOperands) { unsigned I = 0, E = NS->getNumOutputs(); for (unsigned Cnt = ConstraintIdx - NumOperands; I != E; ++I) if (OutputConstraintInfos[I].isReadWrite() && Cnt-- == 0) { ConstraintIdx = I; break; } assert(I != E && "Invalid operand number should have been caught in " " AnalyzeAsmString"); } // Now that we have the right indexes go ahead and check. StringLiteral *Literal = Constraints[ConstraintIdx]; const Type *Ty = Exprs[ConstraintIdx]->getType().getTypePtr(); if (Ty->isDependentType() || Ty->isIncompleteType()) continue; unsigned Size = Context.getTypeSize(Ty); std::string SuggestedModifier; if (!Context.getTargetInfo().validateConstraintModifier( Literal->getString(), Piece.getModifier(), Size, SuggestedModifier)) { Diag(Exprs[ConstraintIdx]->getLocStart(), diag::warn_asm_mismatched_size_modifier); if (!SuggestedModifier.empty()) { auto B = Diag(Piece.getRange().getBegin(), diag::note_asm_missing_constraint_modifier) << SuggestedModifier; SuggestedModifier = "%" + SuggestedModifier + Piece.getString(); B.AddFixItHint(FixItHint::CreateReplacement(Piece.getRange(), SuggestedModifier)); } } } // Validate tied input operands for type mismatches. unsigned NumAlternatives = ~0U; for (unsigned i = 0, e = OutputConstraintInfos.size(); i != e; ++i) { TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i]; StringRef ConstraintStr = Info.getConstraintStr(); unsigned AltCount = ConstraintStr.count(',') + 1; if (NumAlternatives == ~0U) NumAlternatives = AltCount; else if (NumAlternatives != AltCount) return StmtError(Diag(NS->getOutputExpr(i)->getLocStart(), diag::err_asm_unexpected_constraint_alternatives) << NumAlternatives << AltCount); } SmallVector<size_t, 4> InputMatchedToOutput(OutputConstraintInfos.size(), ~0U); for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) { TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i]; StringRef ConstraintStr = Info.getConstraintStr(); unsigned AltCount = ConstraintStr.count(',') + 1; if (NumAlternatives == ~0U) NumAlternatives = AltCount; else if (NumAlternatives != AltCount) return StmtError(Diag(NS->getInputExpr(i)->getLocStart(), diag::err_asm_unexpected_constraint_alternatives) << NumAlternatives << AltCount); // If this is a tied constraint, verify that the output and input have // either exactly the same type, or that they are int/ptr operands with the // same size (int/long, int*/long, are ok etc). if (!Info.hasTiedOperand()) continue; unsigned TiedTo = Info.getTiedOperand(); unsigned InputOpNo = i+NumOutputs; Expr *OutputExpr = Exprs[TiedTo]; Expr *InputExpr = Exprs[InputOpNo]; // Make sure no more than one input constraint matches each output. assert(TiedTo < InputMatchedToOutput.size() && "TiedTo value out of range"); if (InputMatchedToOutput[TiedTo] != ~0U) { Diag(NS->getInputExpr(i)->getLocStart(), diag::err_asm_input_duplicate_match) << TiedTo; Diag(NS->getInputExpr(InputMatchedToOutput[TiedTo])->getLocStart(), diag::note_asm_input_duplicate_first) << TiedTo; return StmtError(); } InputMatchedToOutput[TiedTo] = i; if (OutputExpr->isTypeDependent() || InputExpr->isTypeDependent()) continue; QualType InTy = InputExpr->getType(); QualType OutTy = OutputExpr->getType(); if (Context.hasSameType(InTy, OutTy)) continue; // All types can be tied to themselves. // Decide if the input and output are in the same domain (integer/ptr or // floating point. enum AsmDomain { AD_Int, AD_FP, AD_Other } InputDomain, OutputDomain; if (InTy->isIntegerType() || InTy->isPointerType()) InputDomain = AD_Int; else if (InTy->isRealFloatingType()) InputDomain = AD_FP; else InputDomain = AD_Other; if (OutTy->isIntegerType() || OutTy->isPointerType()) OutputDomain = AD_Int; else if (OutTy->isRealFloatingType()) OutputDomain = AD_FP; else OutputDomain = AD_Other; // They are ok if they are the same size and in the same domain. This // allows tying things like: // void* to int* // void* to int if they are the same size. // double to long double if they are the same size. // uint64_t OutSize = Context.getTypeSize(OutTy); uint64_t InSize = Context.getTypeSize(InTy); if (OutSize == InSize && InputDomain == OutputDomain && InputDomain != AD_Other) continue; // If the smaller input/output operand is not mentioned in the asm string, // then we can promote the smaller one to a larger input and the asm string // won't notice. bool SmallerValueMentioned = false; // If this is a reference to the input and if the input was the smaller // one, then we have to reject this asm. if (isOperandMentioned(InputOpNo, Pieces)) { // This is a use in the asm string of the smaller operand. Since we // codegen this by promoting to a wider value, the asm will get printed // "wrong". SmallerValueMentioned |= InSize < OutSize; } if (isOperandMentioned(TiedTo, Pieces)) { // If this is a reference to the output, and if the output is the larger // value, then it's ok because we'll promote the input to the larger type. SmallerValueMentioned |= OutSize < InSize; } // If the smaller value wasn't mentioned in the asm string, and if the // output was a register, just extend the shorter one to the size of the // larger one. if (!SmallerValueMentioned && InputDomain != AD_Other && OutputConstraintInfos[TiedTo].allowsRegister()) continue; // Either both of the operands were mentioned or the smaller one was // mentioned. One more special case that we'll allow: if the tied input is // integer, unmentioned, and is a constant, then we'll allow truncating it // down to the size of the destination. if (InputDomain == AD_Int && OutputDomain == AD_Int && !isOperandMentioned(InputOpNo, Pieces) && InputExpr->isEvaluatable(Context)) { CastKind castKind = (OutTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast); InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).get(); Exprs[InputOpNo] = InputExpr; NS->setInputExpr(i, InputExpr); continue; } Diag(InputExpr->getLocStart(), diag::err_asm_tying_incompatible_types) << InTy << OutTy << OutputExpr->getSourceRange() << InputExpr->getSourceRange(); return StmtError(); } // Check for conflicts between clobber list and input or output lists SourceLocation ConstraintLoc = getClobberConflictLocation(Exprs, Constraints, Clobbers, NumClobbers, Context.getTargetInfo(), Context); if (ConstraintLoc.isValid()) return Diag(ConstraintLoc, diag::error_inoutput_conflict_with_clobber); return NS; }
// caller must free returned value const EmuVal* eval_rexpr(const Expr* e){ errs() << "\nDEBUG: about to eval rexpr:\n"; e->dump(); if(isa<IntegerLiteral>(e)){ const IntegerLiteral *obj = (const IntegerLiteral*)e; APInt i = obj->getValue(); if(i.slt(EMU_MIN_INT) || i.sgt(EMU_MAX_INT)){ e->dump(); cant_handle(); } return new EmuNum<NUM_TYPE_INT>(i); } else if(isa<CharacterLiteral>(e)){ const CharacterLiteral *obj = (const CharacterLiteral*)e; unsigned int i = obj->getValue(); if(i > 127){ e->dump(); cant_handle(); } return new EmuNum<NUM_TYPE_CHAR>(new APInt(8, i, true)); } else if(isa<UnaryOperator>(e)){ const UnaryOperator *obj = (const UnaryOperator*)e; const Expr* sub = obj->getSubExpr(); const auto op = obj->getOpcode(); switch(op){ case UO_AddrOf: { lvalue arg = eval_lexpr(sub); return new EmuPtr(arg.ptr, e->getType()); } case UO_LNot: case UO_Minus: { const EmuVal* arg = eval_rexpr(sub); if(!arg->obj_type->isIntegerType()){ cant_cast(); } if(op == UO_LNot){ return ((const EmuNumGeneric*)arg)->lnot(); } else if (op == UO_Minus){ return ((const EmuNumGeneric*)arg)->neg(); } } case UO_Deref: case UO_Extension: case UO_Imag: case UO_Real: case UO_Not: case UO_PostInc: case UO_PostDec: case UO_PreInc: case UO_PreDec: case UO_Plus: default: llvm::errs() << "Got opcode " << obj->getOpcode() << "\n"; cant_handle(); } } else if(isa<BinaryOperator>(e)){ const BinaryOperator* ex = (const BinaryOperator*)e; BinaryOperatorKind op = ex->getOpcode(); // right always an rexpr const EmuVal *right = eval_rexpr(ex->getRHS()); switch(op){ case BO_Assign: { lvalue left = eval_lexpr(ex->getLHS()); const EmuVal* ans = right->cast_to(left.type); delete right; left.ptr.block->write(ans, left.ptr.offset); return ans; } case BO_LT: case BO_GT: case BO_LE: case BO_GE: case BO_EQ: case BO_NE: { const EmuVal *left = eval_rexpr(ex->getLHS()); QualType tl = left->obj_type.getCanonicalType(); QualType tr = right->obj_type.getCanonicalType(); if(tl != IntType || tr != IntType){ left->obj_type.dump(); right->obj_type.dump(); cant_handle(); } const llvm::APInt* lval = &((const EmuNum<NUM_TYPE_INT>*)left)->val; llvm::APInt rval = ((const EmuNum<NUM_TYPE_INT>*)right)->val; int ans; if(lval->isNegative()){ if(op == BO_LT) ans = (lval->slt(rval))?1:0; else if(op==BO_GT) ans = (lval->sgt(rval))?1:0; else if(op==BO_LE) ans = (lval->sle(rval))?1:0; else if(op==BO_GE) ans = (lval->sge(rval))?1:0; else if(op==BO_EQ) ans = (lval->eq( rval))?1:0; else if(op==BO_NE) ans = (lval->ne( rval))?1:0; } else if(rval.isNegative()){ if(op == BO_LT) ans = 0; else if(op==BO_GT) ans = 1; else if(op==BO_LE) ans = 0; else if(op==BO_GE) ans = 1; else if(op==BO_EQ) ans = 0; else if(op==BO_NE) ans = 1; } else { if(op == BO_LT) ans = (lval->ult(rval))?1:0; else if(op==BO_GT) ans = (lval->ugt(rval))?1:0; else if(op==BO_LE) ans = (lval->ule(rval))?1:0; else if(op==BO_GE) ans = (lval->uge(rval))?1:0; else if(op==BO_EQ) ans = (lval->eq( rval))?1:0; else if(op==BO_NE) ans = (lval->ne( rval))?1:0; } delete left; delete right; return new EmuNum<NUM_TYPE_INT>(APInt(32, apint_signed_repr(ans), true)); } case BO_AddAssign: case BO_SubAssign: { lvalue left = eval_lexpr(ex->getLHS()); QualType tl = left.type.getCanonicalType(); QualType tr = right->obj_type.getCanonicalType(); if(tl != IntType || tr != IntType){ left.type.dump(); right->obj_type.dump(); cant_handle(); } void* ptr = &((char*)left.ptr.block->data)[left.ptr.offset]; size_t space = left.ptr.block->size; if(space < 4 || space-4 < left.ptr.offset){ bad_memread(); } const EmuNum<NUM_TYPE_INT> value(ptr); const EmuNum<NUM_TYPE_INT>* result; if(op == BO_AddAssign) result = value.add((const EmuNum<NUM_TYPE_INT>*)right); else result = value.sub((const EmuNum<NUM_TYPE_INT>*)right); left.ptr.block->write(result, left.ptr.offset); delete right; return result; } case BO_Add: case BO_Sub: case BO_Mul: case BO_Div: case BO_And: case BO_Or: { const EmuVal* left = eval_rexpr(ex->getLHS()); if(!right->obj_type->isIntegerType()){ right->obj_type.dump(); cant_cast(); } const EmuNumGeneric* trueright = (const EmuNumGeneric*)right; const EmuVal* retval; QualType tl = left->obj_type; // special case: add integer to pointer if(tl->isPointerType()){ int n; if(op == BO_Add) n = trueright->val.getSExtValue(); else if(op == BO_Sub) n = -trueright->val.getSExtValue(); else err_exit("Undefined op on pointer"); QualType sub = tl->getAs<PointerType>()->getPointeeType(); int s = getSizeOf(sub); const EmuPtr* lp = (const EmuPtr*)left; retval = new EmuPtr(mem_ptr(lp->u.block,lp->offset+n*s), tl); } else if(tl->isIntegerType()){ const EmuNumGeneric* trueleft = (const EmuNumGeneric*)left; if(op == BO_Add) retval = trueleft->add(trueright); else if(op == BO_Sub) retval = trueleft->sub(trueright); else if(op == BO_Mul) retval = trueleft->mul(trueright); else if(op == BO_Div) retval = trueleft->div(trueright); else if(op == BO_Or) retval = trueleft->_or(trueright); else if(op == BO_And)retval = trueleft->_and(trueright); else cant_cast(); } else { tl.dump(); cant_cast(); } delete left; delete right; return retval; } case BO_PtrMemD: case BO_PtrMemI: case BO_Rem: case BO_Shl: case BO_Shr: case BO_LAnd: case BO_Xor: case BO_LOr: case BO_MulAssign: case BO_DivAssign: case BO_RemAssign: case BO_ShlAssign: case BO_ShrAssign: case BO_AndAssign: case BO_XorAssign: case BO_OrAssign: case BO_Comma: default: e->dump(); cant_handle(); } } else if(isa<CastExpr>(e)){ const CastExpr* expr = (const CastExpr*)e; const Expr* sub = expr->getSubExpr(); switch(expr->getCastKind()){ case CK_LValueToRValue: return from_lvalue(eval_lexpr(sub)); case CK_NoOp: return eval_rexpr(sub); case CK_BitCast: { if(isa<ExplicitCastExpr>(e)){ const ExplicitCastExpr* expr = (const ExplicitCastExpr*)e; return eval_rexpr(sub)->cast_to(expr->getTypeAsWritten()); } // else ImplicitCastExpr return eval_rexpr(sub)->cast_to(e->getType()); } case CK_IntegralCast: { return eval_rexpr(sub)->cast_to(expr->getType()); } case CK_FunctionToPointerDecay: { lvalue l = eval_lexpr(sub); if(!l.type->isFunctionType()){ e->dump(); cant_cast(); } return new EmuPtr(l.ptr, sources[curr_source]->getPointerType(l.type)); } case CK_ArrayToPointerDecay: { lvalue l = eval_lexpr(sub); const EmuVal* ans = new EmuPtr(l.ptr, expr->getType()); return ans; } case CK_BuiltinFnToFnPtr: { if(!isa<DeclRefExpr>(sub)){ err_exit("Don't know how to convert builtin function"); } std::string name = ((const DeclRefExpr*)sub)->getDecl()->getNameAsString(); const EmuFunc* f = get_external_func(name, sub->getType()); mem_block* ptr = new mem_block(MEM_TYPE_STATIC, f); delete f; return new EmuPtr(mem_ptr(ptr,0), expr->getType()); } case CK_NullToPointer: { return new EmuPtr(mem_ptr(nullptr,0), expr->getType()); } case CK_PointerToIntegral: { const EmuVal* ptr = eval_rexpr(sub); if(!ptr->obj_type->isPointerType()){ err_exit("Expected pointer"); } const EmuPtr* p = (const EmuPtr*)ptr; if(p->status != STATUS_DEFINED) cant_handle(); uint64_t segment; uint64_t offset = p->offset; if(p->u.block == nullptr){ segment = 0; } else { segment = p->u.block->id; } delete ptr; if((expr->getType()->getAs<BuiltinType>())->isSignedInteger()){ return new EmuNum<NUM_TYPE_LONGLONG>(APInt(64, (segment << 32) + offset, true)); } else { return new EmuNum<NUM_TYPE_ULONGLONG>(APInt(64, (segment << 32) + offset, false)); } } case CK_VectorSplat: case CK_IntegralToBoolean: case CK_IntegralToFloating: case CK_FloatingToIntegral: case CK_FloatingToBoolean: case CK_FloatingCast: case CK_CPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_ObjCObjectLValueCast: case CK_FloatingRealToComplex: case CK_FloatingComplexToReal: case CK_FloatingComplexToBoolean: case CK_FloatingComplexCast: case CK_FloatingComplexToIntegralComplex: case CK_IntegralRealToComplex: case CK_IntegralComplexToReal: case CK_IntegralComplexToBoolean: case CK_IntegralComplexCast: case CK_IntegralComplexToFloatingComplex: case CK_ARCProduceObject: case CK_ARCConsumeObject: case CK_ARCReclaimReturnedObject: case CK_ARCExtendBlockObject: case CK_AtomicToNonAtomic: case CK_NonAtomicToAtomic: case CK_CopyAndAutoreleaseBlockObject: case CK_ZeroToOCLEvent: case CK_AddressSpaceConversion: case CK_ReinterpretMemberPointer: case CK_UserDefinedConversion: case CK_ConstructorConversion: case CK_IntegralToPointer: case CK_PointerToBoolean: case CK_ToVoid: default: llvm::errs() << "\n\n"; e->dump(); cant_cast(); } } else if(isa<CallExpr>(e)){ const CallExpr* expr = (const CallExpr*)e; const Expr* const* args = expr->getArgs(); const Expr* callee = expr->getCallee(); llvm::errs() << "DOUG DEBUG: executing the following call:\n"; callee->dump(); const EmuVal* f = eval_rexpr(callee); if(f->status != STATUS_DEFINED || !f->obj_type->isFunctionPointerType()){ f->obj_type.dump(); err_exit("Calling an invalid function"); } const EmuPtr* p = (const EmuPtr*)f; if(p->u.block->memtype == MEM_TYPE_EXTERN){ err_exit("Tried to call an unimplemented function"); } const EmuFunc* func = (const EmuFunc*)from_lvalue(lvalue(p->u.block, ((const PointerType*)p->obj_type.getTypePtr())->getPointeeType(), p->offset)); uint32_t fid = func->func_id; const EmuVal* retval; add_stack_frame(); if(fid < NUM_EXTERNAL_FUNCTIONS){ if(is_lvalue_based_macro(fid)){ // special handling for va_args stuff for(unsigned int i=0; i < expr->getNumArgs(); i++){ const Expr* arg = args[i]; while(isa<ImplicitCastExpr>(arg)){ arg = ((const ImplicitCastExpr*)arg)->getSubExpr(); } if(!isa<DeclRefExpr>(arg)){ err_exit("Passed non-variable as lvalue to builtin macro"); } std::string name = ((const DeclRefExpr*)arg)->getDecl()->getNameAsString(); std::unordered_map<std::string,std::deque<std::pair<int,int> > >::const_iterator list = stack_var_map.find(name); if(list == stack_var_map.end()){ err_exit("Can't find appropriate lvalue for macro"); } const auto test = list->second; const auto item = test.back(); const EmuVal* val = new EmuStackPos(item.first, item.second); mem_block* storage = new mem_block(MEM_TYPE_STACK, val); add_stack_var("", lvalue(storage,val->obj_type,0)); delete val; } } else { // we are dealing with an external function for(unsigned int i=0; i < expr->getNumArgs(); i++){ const EmuVal* val = eval_rexpr(args[i]); mem_block* storage = new mem_block(MEM_TYPE_STACK, val); add_stack_var("", lvalue(storage,val->obj_type,0)); delete val; } } retval = call_external(fid); } else { const auto it = global_functions.find(fid); const FunctionDecl* defn = (const FunctionDecl*)it->second.second; for(unsigned int i=0; i < expr->getNumArgs(); i++){ const EmuVal* val = eval_rexpr(args[i]); mem_block* storage = new mem_block(MEM_TYPE_STACK, val); std::string name; if(i >= defn->getNumParams()){ name = ""; // relevant for later args of e.g. printf(char*, ...) } else { name = defn->getParamDecl(i)->getNameAsString(); } llvm::errs() << "DOUG DEBUG: adding stack variable "<<name<<" for arg "<<i<<" of internal function call (numparams="<< defn->getNumParams() <<")\n"; defn->dump(); add_stack_var(name, lvalue(storage,val->obj_type,0)); delete val; } int save = curr_source; curr_source = it->second.first; llvm::errs() << "DOUG DEBUG: actually executing:\n"; defn->getBody()->dump(); retval = exec_stmt(defn->getBody()); llvm::errs() << "DOUG DEBUG: call returned with retval at "<<((const void*)retval)<<"\n"; curr_source = save; } llvm::errs() << "DOUG DEBUG: popping frame leaving call\n"; pop_stack_frame(); return retval; } else if(isa<UnaryExprOrTypeTraitExpr>(e)){ const UnaryExprOrTypeTraitExpr* expr = (const UnaryExprOrTypeTraitExpr*)e; switch(expr->getKind()){ case UETT_SizeOf: { QualType qt = expr->getArgumentType(); const EmuVal* fake = from_lvalue(lvalue(nullptr, qt, 0)); uint64_t thesize = (uint64_t)fake->size(); delete fake; return new EmuNum<NUM_TYPE_ULONG>(APInt(32, thesize, false)); } case UETT_AlignOf: case UETT_VecStep: default: e->dump(); cant_handle(); } } else if(isa<InitListExpr>(e)){ const InitListExpr* expr = (const InitListExpr*)e; unsigned int n = expr->getNumInits(); QualType qt = expr->getType(); if(qt->isArrayType()){ const EmuPtr* array = (const EmuPtr*)from_lvalue(lvalue(nullptr, qt, 0)); if(array->status != STATUS_DEFINED) cant_handle(); size_t loc = 0; for(unsigned int i = 0; i < n; i++){ const EmuVal* curr = eval_rexpr(expr->getInit(i)); array->u.block->write(curr, loc); loc += curr->size(); delete curr; } return array; } else if(qt->isStructureType()){ unsigned int n = expr->getNumInits(); const EmuVal** arr = new const EmuVal*[n]; for(unsigned int i = 0; i < n; i++){ arr[i] = eval_rexpr(expr->getInit(i)); } return new EmuStruct(STATUS_DEFINED, qt, n, arr); } cant_handle(); } else if(isa<ImplicitValueInitExpr>(e)){ return zero_init(e->getType()); } else if(isa<ParenExpr>(e)){ return eval_rexpr(((const ParenExpr*)e)->getSubExpr()); } e->dump(); cant_handle(); }
void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const { ProgramStateRef state = C.getState(); const FunctionDecl *FD = C.getCalleeDecl(CE); if (!FD) return; ASTContext &Ctx = C.getASTContext(); if (!II) II = &Ctx.Idents.get("CFNumberCreate"); if (FD->getIdentifier() != II || CE->getNumArgs() != 3) return; // Get the value of the "theType" argument. const LocationContext *LCtx = C.getLocationContext(); SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx); // FIXME: We really should allow ranges of valid theType values, and // bifurcate the state appropriately. nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal); if (!V) return; uint64_t NumberKind = V->getValue().getLimitedValue(); Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind); // FIXME: In some cases we can emit an error. if (!TargetSize.isKnown()) return; // Look at the value of the integer being passed by reference. Essentially // we want to catch cases where the value passed in is not equal to the // size of the type being created. SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx); // FIXME: Eventually we should handle arbitrary locations. We can do this // by having an enhanced memory model that does low-level typing. loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr); if (!LV) return; const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts()); if (!R) return; QualType T = Ctx.getCanonicalType(R->getValueType()); // FIXME: If the pointee isn't an integer type, should we flag a warning? // People can do weird stuff with pointers. if (!T->isIntegerType()) return; uint64_t SourceSize = Ctx.getTypeSize(T); // CHECK: is SourceSize == TargetSize if (SourceSize == TargetSize) return; // Generate an error. Only generate a sink if 'SourceSize < TargetSize'; // otherwise generate a regular node. // // FIXME: We can actually create an abstract "CFNumber" object that has // the bits initialized to the provided values. // if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink() : C.addTransition()) { SmallString<128> sbuf; llvm::raw_svector_ostream os(sbuf); os << (SourceSize == 8 ? "An " : "A ") << SourceSize << " bit integer is used to initialize a CFNumber " "object that represents " << (TargetSize == 8 ? "an " : "a ") << TargetSize << " bit integer. "; if (SourceSize < TargetSize) os << (TargetSize - SourceSize) << " bits of the CFNumber value will be garbage." ; else os << (SourceSize - TargetSize) << " bits of the input integer will be lost."; if (!BT) BT.reset(new APIMisuse("Bad use of CFNumberCreate")); BugReport *report = new BugReport(*BT, os.str(), N); report->addRange(CE->getArg(2)->getSourceRange()); C.EmitReport(report); } }
SVal SimpleSValBuilder::evalBinOpNN(const ProgramState *state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy) { // Handle trivial case where left-side and right-side are the same. if (lhs == rhs) switch (op) { default: break; case BO_EQ: case BO_LE: case BO_GE: return makeTruthVal(true, resultTy); case BO_LT: case BO_GT: case BO_NE: return makeTruthVal(false, resultTy); case BO_Xor: case BO_Sub: return makeIntVal(0, resultTy); case BO_Or: case BO_And: return evalCastFromNonLoc(lhs, resultTy); } while (1) { switch (lhs.getSubKind()) { default: return generateUnknownVal(state, op, lhs, rhs, resultTy); case nonloc::LocAsIntegerKind: { Loc lhsL = cast<nonloc::LocAsInteger>(lhs).getLoc(); switch (rhs.getSubKind()) { case nonloc::LocAsIntegerKind: return evalBinOpLL(state, op, lhsL, cast<nonloc::LocAsInteger>(rhs).getLoc(), resultTy); case nonloc::ConcreteIntKind: { // Transform the integer into a location and compare. llvm::APSInt i = cast<nonloc::ConcreteInt>(rhs).getValue(); i.setIsUnsigned(true); i = i.extOrTrunc(Context.getTypeSize(Context.VoidPtrTy)); return evalBinOpLL(state, op, lhsL, makeLoc(i), resultTy); } default: switch (op) { case BO_EQ: return makeTruthVal(false, resultTy); case BO_NE: return makeTruthVal(true, resultTy); default: // This case also handles pointer arithmetic. return generateUnknownVal(state, op, lhs, rhs, resultTy); } } } case nonloc::SymExprValKind: { nonloc::SymExprVal *selhs = cast<nonloc::SymExprVal>(&lhs); // Only handle LHS of the form "$sym op constant", at least for now. const SymIntExpr *symIntExpr = dyn_cast<SymIntExpr>(selhs->getSymbolicExpression()); if (!symIntExpr) return generateUnknownVal(state, op, lhs, rhs, resultTy); // Is this a logical not? (!x is represented as x == 0.) if (op == BO_EQ && rhs.isZeroConstant()) { // We know how to negate certain expressions. Simplify them here. BinaryOperator::Opcode opc = symIntExpr->getOpcode(); switch (opc) { default: // We don't know how to negate this operation. // Just handle it as if it were a normal comparison to 0. break; case BO_LAnd: case BO_LOr: llvm_unreachable("Logical operators handled by branching logic."); case BO_Assign: case BO_MulAssign: case BO_DivAssign: case BO_RemAssign: case BO_AddAssign: case BO_SubAssign: case BO_ShlAssign: case BO_ShrAssign: case BO_AndAssign: case BO_XorAssign: case BO_OrAssign: case BO_Comma: llvm_unreachable("'=' and ',' operators handled by ExprEngine."); case BO_PtrMemD: case BO_PtrMemI: llvm_unreachable("Pointer arithmetic not handled here."); case BO_LT: case BO_GT: case BO_LE: case BO_GE: case BO_EQ: case BO_NE: // Negate the comparison and make a value. opc = NegateComparison(opc); assert(symIntExpr->getType(Context) == resultTy); return makeNonLoc(symIntExpr->getLHS(), opc, symIntExpr->getRHS(), resultTy); } } // For now, only handle expressions whose RHS is a constant. const nonloc::ConcreteInt *rhsInt = dyn_cast<nonloc::ConcreteInt>(&rhs); if (!rhsInt) return generateUnknownVal(state, op, lhs, rhs, resultTy); // If both the LHS and the current expression are additive, // fold their constants. if (BinaryOperator::isAdditiveOp(op)) { BinaryOperator::Opcode lop = symIntExpr->getOpcode(); if (BinaryOperator::isAdditiveOp(lop)) { // resultTy may not be the best type to convert to, but it's // probably the best choice in expressions with mixed type // (such as x+1U+2LL). The rules for implicit conversions should // choose a reasonable type to preserve the expression, and will // at least match how the value is going to be used. const llvm::APSInt &first = BasicVals.Convert(resultTy, symIntExpr->getRHS()); const llvm::APSInt &second = BasicVals.Convert(resultTy, rhsInt->getValue()); const llvm::APSInt *newRHS; if (lop == op) newRHS = BasicVals.evalAPSInt(BO_Add, first, second); else newRHS = BasicVals.evalAPSInt(BO_Sub, first, second); return MakeSymIntVal(symIntExpr->getLHS(), lop, *newRHS, resultTy); } } // Otherwise, make a SymExprVal out of the expression. return MakeSymIntVal(symIntExpr, op, rhsInt->getValue(), resultTy); } case nonloc::ConcreteIntKind: { const nonloc::ConcreteInt& lhsInt = cast<nonloc::ConcreteInt>(lhs); // Is the RHS a symbol we can simplify? // FIXME: This was mostly copy/pasted from the LHS-is-a-symbol case. if (const nonloc::SymbolVal *srhs = dyn_cast<nonloc::SymbolVal>(&rhs)) { SymbolRef RSym = srhs->getSymbol(); if (RSym->getType(Context)->isIntegerType()) { if (const llvm::APSInt *Constant = state->getSymVal(RSym)) { // The symbol evaluates to a constant. const llvm::APSInt *rhs_I; if (BinaryOperator::isRelationalOp(op)) rhs_I = &BasicVals.Convert(lhsInt.getValue(), *Constant); else rhs_I = &BasicVals.Convert(resultTy, *Constant); rhs = nonloc::ConcreteInt(*rhs_I); } } } if (isa<nonloc::ConcreteInt>(rhs)) { return lhsInt.evalBinOp(*this, op, cast<nonloc::ConcreteInt>(rhs)); } else { const llvm::APSInt& lhsValue = lhsInt.getValue(); // Swap the left and right sides and flip the operator if doing so // allows us to better reason about the expression (this is a form // of expression canonicalization). // While we're at it, catch some special cases for non-commutative ops. NonLoc tmp = rhs; rhs = lhs; lhs = tmp; switch (op) { case BO_LT: case BO_GT: case BO_LE: case BO_GE: op = ReverseComparison(op); continue; case BO_EQ: case BO_NE: case BO_Add: case BO_Mul: case BO_And: case BO_Xor: case BO_Or: continue; case BO_Shr: if (lhsValue.isAllOnesValue() && lhsValue.isSigned()) // At this point lhs and rhs have been swapped. return rhs; // FALL-THROUGH case BO_Shl: if (lhsValue == 0) // At this point lhs and rhs have been swapped. return rhs; return generateUnknownVal(state, op, lhs, rhs, resultTy); default: return generateUnknownVal(state, op, lhs, rhs, resultTy); } } } case nonloc::SymbolValKind: { nonloc::SymbolVal *slhs = cast<nonloc::SymbolVal>(&lhs); SymbolRef Sym = slhs->getSymbol(); QualType lhsType = Sym->getType(Context); // The conversion type is usually the result type, but not in the case // of relational expressions. QualType conversionType = resultTy; if (BinaryOperator::isRelationalOp(op)) conversionType = lhsType; // Does the symbol simplify to a constant? If so, "fold" the constant // by setting 'lhs' to a ConcreteInt and try again. if (lhsType->isIntegerType()) if (const llvm::APSInt *Constant = state->getSymVal(Sym)) { // The symbol evaluates to a constant. If necessary, promote the // folded constant (LHS) to the result type. const llvm::APSInt &lhs_I = BasicVals.Convert(conversionType, *Constant); lhs = nonloc::ConcreteInt(lhs_I); // Also promote the RHS (if necessary). // For shifts, it is not necessary to promote the RHS. if (BinaryOperator::isShiftOp(op)) continue; // Other operators: do an implicit conversion. This shouldn't be // necessary once we support truncation/extension of symbolic values. if (nonloc::ConcreteInt *rhs_I = dyn_cast<nonloc::ConcreteInt>(&rhs)){ rhs = nonloc::ConcreteInt(BasicVals.Convert(conversionType, rhs_I->getValue())); } continue; } // Is the RHS a symbol we can simplify? if (const nonloc::SymbolVal *srhs = dyn_cast<nonloc::SymbolVal>(&rhs)) { SymbolRef RSym = srhs->getSymbol(); if (RSym->getType(Context)->isIntegerType()) { if (const llvm::APSInt *Constant = state->getSymVal(RSym)) { // The symbol evaluates to a constant. const llvm::APSInt &rhs_I = BasicVals.Convert(conversionType, *Constant); rhs = nonloc::ConcreteInt(rhs_I); } } } if (isa<nonloc::ConcreteInt>(rhs)) { return MakeSymIntVal(slhs->getSymbol(), op, cast<nonloc::ConcreteInt>(rhs).getValue(), resultTy); } return generateUnknownVal(state, op, lhs, rhs, resultTy); } } } }
/// Create a fake body for dispatch_once. static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { // Check if we have at least two parameters. if (D->param_size() != 2) return nullptr; // Check if the first parameter is a pointer to integer type. const ParmVarDecl *Predicate = D->getParamDecl(0); QualType PredicateQPtrTy = Predicate->getType(); const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>(); if (!PredicatePtrTy) return nullptr; QualType PredicateTy = PredicatePtrTy->getPointeeType(); if (!PredicateTy->isIntegerType()) return nullptr; // Check if the second parameter is the proper block type. const ParmVarDecl *Block = D->getParamDecl(1); QualType Ty = Block->getType(); if (!isDispatchBlock(Ty)) return nullptr; // Everything checks out. Create a fakse body that checks the predicate, // sets it, and calls the block. Basically, an AST dump of: // // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) { // if (*predicate != ~0l) { // *predicate = ~0l; // block(); // } // } ASTMaker M(C); // (1) Create the call. CallExpr *CE = CallExpr::Create( /*ASTContext=*/C, /*StmtClass=*/M.makeLvalueToRvalue(/*Expr=*/Block), /*args=*/None, /*QualType=*/C.VoidTy, /*ExprValueType=*/VK_RValue, /*SourceLocation=*/SourceLocation()); // (2) Create the assignment to the predicate. Expr *DoneValue = new (C) UnaryOperator(M.makeIntegerLiteral(0, C.LongTy), UO_Not, C.LongTy, VK_RValue, OK_Ordinary, SourceLocation(), /*CanOverflow*/false); BinaryOperator *B = M.makeAssignment( M.makeDereference( M.makeLvalueToRvalue( M.makeDeclRefExpr(Predicate), PredicateQPtrTy), PredicateTy), M.makeIntegralCast(DoneValue, PredicateTy), PredicateTy); // (3) Create the compound statement. Stmt *Stmts[] = { B, CE }; CompoundStmt *CS = M.makeCompound(Stmts); // (4) Create the 'if' condition. ImplicitCastExpr *LValToRval = M.makeLvalueToRvalue( M.makeDereference( M.makeLvalueToRvalue( M.makeDeclRefExpr(Predicate), PredicateQPtrTy), PredicateTy), PredicateTy); Expr *GuardCondition = M.makeComparison(LValToRval, DoneValue, BO_NE); // (5) Create the 'if' statement. auto *If = IfStmt::Create(C, SourceLocation(), /* IsConstexpr=*/false, /* init=*/nullptr, /* var=*/nullptr, /* cond=*/GuardCondition, /* then=*/CS); return If; }
void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, const Decl *TargetDecl, AttributeListType &PAL, unsigned &CallingConv) { unsigned FuncAttrs = 0; unsigned RetAttrs = 0; CallingConv = FI.getEffectiveCallingConvention(); // FIXME: handle sseregparm someday... if (TargetDecl) { if (TargetDecl->hasAttr<NoThrowAttr>()) FuncAttrs |= llvm::Attribute::NoUnwind; if (TargetDecl->hasAttr<NoReturnAttr>()) FuncAttrs |= llvm::Attribute::NoReturn; if (TargetDecl->hasAttr<ConstAttr>()) FuncAttrs |= llvm::Attribute::ReadNone; else if (TargetDecl->hasAttr<PureAttr>()) FuncAttrs |= llvm::Attribute::ReadOnly; if (TargetDecl->hasAttr<MallocAttr>()) RetAttrs |= llvm::Attribute::NoAlias; } if (CodeGenOpts.OptimizeSize) FuncAttrs |= llvm::Attribute::OptimizeForSize; if (CodeGenOpts.DisableRedZone) FuncAttrs |= llvm::Attribute::NoRedZone; if (CodeGenOpts.NoImplicitFloat) FuncAttrs |= llvm::Attribute::NoImplicitFloat; QualType RetTy = FI.getReturnType(); unsigned Index = 1; const ABIArgInfo &RetAI = FI.getReturnInfo(); switch (RetAI.getKind()) { case ABIArgInfo::Extend: if (RetTy->isSignedIntegerType()) { RetAttrs |= llvm::Attribute::SExt; } else if (RetTy->isUnsignedIntegerType()) { RetAttrs |= llvm::Attribute::ZExt; } // FALLTHROUGH case ABIArgInfo::Direct: break; case ABIArgInfo::Indirect: PAL.push_back(llvm::AttributeWithIndex::get(Index, llvm::Attribute::StructRet | llvm::Attribute::NoAlias)); ++Index; // sret disables readnone and readonly FuncAttrs &= ~(llvm::Attribute::ReadOnly | llvm::Attribute::ReadNone); break; case ABIArgInfo::Ignore: case ABIArgInfo::Coerce: break; case ABIArgInfo::Expand: assert(0 && "Invalid ABI kind for return argument"); } if (RetAttrs) PAL.push_back(llvm::AttributeWithIndex::get(0, RetAttrs)); // FIXME: we need to honour command line settings also... // FIXME: RegParm should be reduced in case of nested functions and/or global // register variable. signed RegParm = 0; if (TargetDecl) if (const RegparmAttr *RegParmAttr = TargetDecl->getAttr<RegparmAttr>()) RegParm = RegParmAttr->getNumParams(); unsigned PointerWidth = getContext().Target.getPointerWidth(0); for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) { QualType ParamType = it->type; const ABIArgInfo &AI = it->info; unsigned Attributes = 0; switch (AI.getKind()) { case ABIArgInfo::Coerce: break; case ABIArgInfo::Indirect: if (AI.getIndirectByVal()) Attributes |= llvm::Attribute::ByVal; Attributes |= llvm::Attribute::constructAlignmentFromInt(AI.getIndirectAlign()); // byval disables readnone and readonly. FuncAttrs &= ~(llvm::Attribute::ReadOnly | llvm::Attribute::ReadNone); break; case ABIArgInfo::Extend: if (ParamType->isSignedIntegerType()) { Attributes |= llvm::Attribute::SExt; } else if (ParamType->isUnsignedIntegerType()) { Attributes |= llvm::Attribute::ZExt; } // FALLS THROUGH case ABIArgInfo::Direct: if (RegParm > 0 && (ParamType->isIntegerType() || ParamType->isPointerType())) { RegParm -= (Context.getTypeSize(ParamType) + PointerWidth - 1) / PointerWidth; if (RegParm >= 0) Attributes |= llvm::Attribute::InReg; } // FIXME: handle sseregparm someday... break; case ABIArgInfo::Ignore: // Skip increment, no matching LLVM parameter. continue; case ABIArgInfo::Expand: { std::vector<const llvm::Type*> Tys; // FIXME: This is rather inefficient. Do we ever actually need to do // anything here? The result should be just reconstructed on the other // side, so extension should be a non-issue. getTypes().GetExpandedTypes(ParamType, Tys); Index += Tys.size(); continue; } } if (Attributes) PAL.push_back(llvm::AttributeWithIndex::get(Index, Attributes)); ++Index; } if (FuncAttrs) PAL.push_back(llvm::AttributeWithIndex::get(~0, FuncAttrs)); }
/// \brief Build an Objective-C instance message expression. /// /// This routine takes care of both normal instance messages and /// instance messages to the superclass instance. /// /// \param Receiver The expression that computes the object that will /// receive this message. This may be empty, in which case we are /// sending to the superclass instance and \p SuperLoc must be a valid /// source location. /// /// \param ReceiverType The (static) type of the object receiving the /// message. When a \p Receiver expression is provided, this is the /// same type as that expression. For a superclass instance send, this /// is a pointer to the type of the superclass. /// /// \param SuperLoc The location of the "super" keyword in a /// superclass instance message. /// /// \param Sel The selector to which the message is being sent. /// /// \param Method The method that this instance message is invoking, if /// already known. /// /// \param LBracLoc The location of the opening square bracket ']'. /// /// \param RBrac The location of the closing square bracket ']'. /// /// \param Args The message arguments. Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE, QualType ReceiverType, SourceLocation SuperLoc, Selector Sel, ObjCMethodDecl *Method, SourceLocation LBracLoc, SourceLocation RBracLoc, MultiExprArg ArgsIn) { // If we have a receiver expression, perform appropriate promotions // and determine receiver type. Expr *Receiver = ReceiverE.takeAs<Expr>(); if (Receiver) { if (Receiver->isTypeDependent()) { // If the receiver is type-dependent, we can't type-check anything // at this point. Build a dependent expression. unsigned NumArgs = ArgsIn.size(); Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); assert(SuperLoc.isInvalid() && "Message to super with dependent type"); return Owned(ObjCMessageExpr::Create(Context, Context.DependentTy, LBracLoc, Receiver, Sel, /*Method=*/0, Args, NumArgs, RBracLoc)); } // If necessary, apply function/array conversion to the receiver. // C99 6.7.5.3p[7,8]. DefaultFunctionArrayLvalueConversion(Receiver); ReceiverType = Receiver->getType(); } // The location of the receiver. SourceLocation Loc = SuperLoc.isValid()? SuperLoc : Receiver->getLocStart(); if (!Method) { // Handle messages to id. bool receiverIsId = ReceiverType->isObjCIdType(); if (receiverIsId || ReceiverType->isBlockPointerType() || (Receiver && Context.isObjCNSObjectType(Receiver->getType()))) { Method = LookupInstanceMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc), receiverIsId); if (!Method) Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc), receiverIsId); } else if (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()) { // Handle messages to Class. if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) { // First check the public methods in the class interface. Method = ClassDecl->lookupClassMethod(Sel); if (!Method) Method = LookupPrivateClassMethod(Sel, ClassDecl); // FIXME: if we still haven't found a method, we need to look in // protocols (if we have qualifiers). } if (Method && DiagnoseUseOfDecl(Method, Loc)) return ExprError(); } if (!Method) { // If not messaging 'self', look for any factory method named 'Sel'. if (!Receiver || !isSelfExpr(Receiver)) { Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc), true); if (!Method) { // If no class (factory) method was found, check if an _instance_ // method of the same name exists in the root class only. Method = LookupInstanceMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc), true); if (Method) if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) { if (ID->getSuperClass()) Diag(Loc, diag::warn_root_inst_method_not_found) << Sel << SourceRange(LBracLoc, RBracLoc); } } } } } else { ObjCInterfaceDecl* ClassDecl = 0; // We allow sending a message to a qualified ID ("id<foo>"), which is ok as // long as one of the protocols implements the selector (if not, warn). if (const ObjCObjectPointerType *QIdTy = ReceiverType->getAsObjCQualifiedIdType()) { // Search protocols for instance methods. for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), E = QIdTy->qual_end(); I != E; ++I) { ObjCProtocolDecl *PDecl = *I; if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel))) break; // Since we aren't supporting "Class<foo>", look for a class method. if (PDecl && (Method = PDecl->lookupClassMethod(Sel))) break; } } else if (const ObjCObjectPointerType *OCIType = ReceiverType->getAsObjCInterfacePointerType()) { // We allow sending a message to a pointer to an interface (an object). ClassDecl = OCIType->getInterfaceDecl(); // FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be // faster than the following method (which can do *many* linear searches). // The idea is to add class info to MethodPool. Method = ClassDecl->lookupInstanceMethod(Sel); if (!Method) { // Search protocol qualifiers. for (ObjCObjectPointerType::qual_iterator QI = OCIType->qual_begin(), E = OCIType->qual_end(); QI != E; ++QI) { if ((Method = (*QI)->lookupInstanceMethod(Sel))) break; } } if (!Method) { // If we have implementations in scope, check "private" methods. Method = LookupPrivateInstanceMethod(Sel, ClassDecl); if (!Method && (!Receiver || !isSelfExpr(Receiver))) { // If we still haven't found a method, look in the global pool. This // behavior isn't very desirable, however we need it for GCC // compatibility. FIXME: should we deviate?? if (OCIType->qual_empty()) { Method = LookupInstanceMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc)); if (Method && !OCIType->getInterfaceDecl()->isForwardDecl()) Diag(Loc, diag::warn_maynot_respond) << OCIType->getInterfaceDecl()->getIdentifier() << Sel; } } } if (Method && DiagnoseUseOfDecl(Method, Loc)) return ExprError(); } else if (!Context.getObjCIdType().isNull() && (ReceiverType->isPointerType() || ReceiverType->isIntegerType())) { // Implicitly convert integers and pointers to 'id' but emit a warning. Diag(Loc, diag::warn_bad_receiver_type) << ReceiverType << Receiver->getSourceRange(); if (ReceiverType->isPointerType()) ImpCastExprToType(Receiver, Context.getObjCIdType(), CastExpr::CK_BitCast); else ImpCastExprToType(Receiver, Context.getObjCIdType(), CastExpr::CK_IntegralToPointer); ReceiverType = Receiver->getType(); } else if (getLangOptions().CPlusPlus && !PerformContextuallyConvertToObjCId(Receiver)) { if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Receiver)) { Receiver = ICE->getSubExpr(); ReceiverType = Receiver->getType(); } return BuildInstanceMessage(Owned(Receiver), ReceiverType, SuperLoc, Sel, Method, LBracLoc, RBracLoc, move(ArgsIn)); } else { // Reject other random receiver types (e.g. structs). Diag(Loc, diag::err_bad_receiver_type) << ReceiverType << Receiver->getSourceRange(); return ExprError(); } } } // Check the message arguments. unsigned NumArgs = ArgsIn.size(); Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); QualType ReturnType; if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, false, LBracLoc, RBracLoc, ReturnType)) return ExprError(); if (!ReturnType->isVoidType()) { if (RequireCompleteType(LBracLoc, ReturnType, diag::err_illegal_message_expr_incomplete_type)) return ExprError(); } // Construct the appropriate ObjCMessageExpr instance. Expr *Result; if (SuperLoc.isValid()) Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, SuperLoc, /*IsInstanceSuper=*/true, ReceiverType, Sel, Method, Args, NumArgs, RBracLoc); else Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, Receiver, Sel, Method, Args, NumArgs, RBracLoc); return MaybeBindToTemporary(Result); }