SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) { // Casts from pointers -> pointers, just return the lval. // // Casts from pointers -> references, just return the lval. These // can be introduced by the frontend for corner cases, e.g // casting from va_list* to __builtin_va_list&. // if (Loc::isLocType(castTy) || castTy->isReferenceType()) return val; // FIXME: Handle transparent unions where a value can be "transparently" // lifted into a union type. if (castTy->isUnionType()) return UnknownVal(); // Casting a Loc to a bool will almost always be true, // unless this is a weak function or a symbolic region. if (castTy->isBooleanType()) { switch (val.getSubKind()) { case loc::MemRegionValKind: { const MemRegion *R = val.castAs<loc::MemRegionVal>().getRegion(); if (const FunctionCodeRegion *FTR = dyn_cast<FunctionCodeRegion>(R)) if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(FTR->getDecl())) if (FD->isWeak()) // FIXME: Currently we are using an extent symbol here, // because there are no generic region address metadata // symbols to use, only content metadata. return nonloc::SymbolVal(SymMgr.getExtentSymbol(FTR)); if (const SymbolicRegion *SymR = R->getSymbolicBase()) return nonloc::SymbolVal(SymR->getSymbol()); // FALL-THROUGH LLVM_FALLTHROUGH; } case loc::GotoLabelKind: // Labels and non-symbolic memory regions are always true. return makeTruthVal(true, castTy); } } if (castTy->isIntegralOrEnumerationType()) { unsigned BitWidth = Context.getTypeSize(castTy); if (!val.getAs<loc::ConcreteInt>()) return makeLocAsInteger(val, BitWidth); llvm::APSInt i = val.castAs<loc::ConcreteInt>().getValue(); BasicVals.getAPSIntType(castTy).apply(i); return makeIntVal(i); } // All other cases: return 'UnknownVal'. This includes casting pointers // to floats, which is probably badness it itself, but this is a good // intermediate solution until we do something better. return UnknownVal(); }
SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) { bool isLocType = Loc::isLocType(castTy); if (val.getAs<nonloc::PointerToMember>()) return val; if (Optional<nonloc::LocAsInteger> LI = val.getAs<nonloc::LocAsInteger>()) { if (isLocType) return LI->getLoc(); // FIXME: Correctly support promotions/truncations. unsigned castSize = Context.getTypeSize(castTy); if (castSize == LI->getNumBits()) return val; return makeLocAsInteger(LI->getLoc(), castSize); } if (const SymExpr *se = val.getAsSymbolicExpression()) { QualType T = Context.getCanonicalType(se->getType()); // If types are the same or both are integers, ignore the cast. // FIXME: Remove this hack when we support symbolic truncation/extension. // HACK: If both castTy and T are integers, ignore the cast. This is // not a permanent solution. Eventually we want to precisely handle // extension/truncation of symbolic integers. This prevents us from losing // precision when we assign 'x = y' and 'y' is symbolic and x and y are // different integer types. if (haveSameType(T, castTy)) return val; if (!isLocType) return makeNonLoc(se, T, castTy); return UnknownVal(); } // If value is a non-integer constant, produce unknown. if (!val.getAs<nonloc::ConcreteInt>()) return UnknownVal(); // Handle casts to a boolean type. if (castTy->isBooleanType()) { bool b = val.castAs<nonloc::ConcreteInt>().getValue().getBoolValue(); return makeTruthVal(b, castTy); } // Only handle casts from integers to integers - if val is an integer constant // being cast to a non-integer type, produce unknown. if (!isLocType && !castTy->isIntegralOrEnumerationType()) return UnknownVal(); llvm::APSInt i = val.castAs<nonloc::ConcreteInt>().getValue(); BasicVals.getAPSIntType(castTy).apply(i); if (isLocType) return makeIntLocVal(i); else return makeIntVal(i); }
/// Get the number of possible values that can be switched on for the type T. /// /// \return - 0 if bitcount could not be determined /// - numeric_limits<std::size_t>::max() when overflow appeared due to /// more than 64 bits type size. static std::size_t getNumberOfPossibleValues(QualType T, const ASTContext &Context) { // `isBooleanType` must come first because `bool` is an integral type as well // and would not return 2 as result. if (T->isBooleanType()) return 2; else if (T->isIntegralType(Context)) return twoPow(Context.getTypeSize(T)); else return 1; }
static bool isBooleanType(QualType Ty) { if (Ty->isBooleanType()) // C++ or C99 return true; if (const TypedefType *TT = Ty->getAs<TypedefType>()) return TT->getDecl()->getName() == "BOOL" || // Objective-C TT->getDecl()->getName() == "_Bool" || // stdbool.h < C99 TT->getDecl()->getName() == "Boolean"; // MacTypes.h return false; }
PathDiagnosticPiece * ConditionBRVisitor::VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr, const bool tookTrue, BugReporterContext &BRC, BugReport &report, const ExplodedNode *N) { // FIXME: If there's already a constraint tracker for this variable, // we shouldn't emit anything here (c.f. the double note in // test/Analysis/inlining/path-notes.c) SmallString<256> buf; llvm::raw_svector_ostream Out(buf); Out << "Assuming " << LhsString << " is "; QualType Ty = CondVarExpr->getType(); if (Ty->isPointerType()) Out << (tookTrue ? "not null" : "null"); else if (Ty->isObjCObjectPointerType()) Out << (tookTrue ? "not nil" : "nil"); else if (Ty->isBooleanType()) Out << (tookTrue ? "true" : "false"); else if (Ty->isIntegerType()) Out << (tookTrue ? "non-zero" : "zero"); else return 0; const LocationContext *LCtx = N->getLocationContext(); PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(), LCtx); PathDiagnosticEventPiece *event = new PathDiagnosticEventPiece(Loc, Out.str()); if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(CondVarExpr)) { if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { const ProgramState *state = N->getState().getPtr(); if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) { if (report.isInteresting(R)) event->setPrunable(false); } } } return event; }
bool VisitVarDecl(const VarDecl *D) { // Bail out early if this location should not be checked. if (doIgnore(D->getLocation())) { return true; } const QualType qualType = D->getType(); // Bail out if this type is either an enum or does not look like a real // value. if (qualType->isEnumeralType() || qualType->isBooleanType() || qualType->isArithmeticType() == false) { return true; } const Type *t = qualType.getTypePtrOrNull(); assert(t && "Type of arithmetic types has to be available."); const std::string typeName = qualType.getAsString(); // If it is of the same type as "size_t" and does have "size_t" somewhere in // its name we can go with it. // Please note: This also allows a typedef for "unsigned long" to be named // e.g. "size_type" without any size indicator - which may or may not be a // good thing. if (context->hasSameUnqualifiedType(qualType, context->getSizeType()) && typeName.find("size_t") != std::string::npos) { return true; } // char_t and wchar_t are not subject to this rule. const std::string needle = "char_t"; if (std::equal(needle.rbegin(), needle.rend(), typeName.rbegin())) { return true; } const uint64_t typeSize = context->getTypeSize(t); const std::string sizeStr = llvm::utostr(typeSize); // For all remaining types, the number of occupied bits must be embedded in // the typename. if (typeName.rfind(sizeStr) == std::string::npos) { reportError(D->getLocation()); } return true; }
static void SuggestInitializationFixit(Sema &S, const VarDecl *VD) { // Don't issue a fixit if there is already an initializer. if (VD->getInit()) return; // Suggest possible initialization (if any). const char *initialization = 0; QualType VariableTy = VD->getType().getCanonicalType(); if (VariableTy->isObjCObjectPointerType() || VariableTy->isBlockPointerType()) { // Check if 'nil' is defined. if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil"))) initialization = " = nil"; else initialization = " = 0"; } else if (VariableTy->isRealFloatingType()) initialization = " = 0.0"; else if (VariableTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus) initialization = " = false"; else if (VariableTy->isEnumeralType()) return; else if (VariableTy->isPointerType() || VariableTy->isMemberPointerType()) { // Check if 'NULL' is defined. if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("NULL"))) initialization = " = NULL"; else initialization = " = 0"; } else if (VariableTy->isScalarType()) initialization = " = 0"; if (initialization) { SourceLocation loc = S.PP.getLocForEndOfToken(VD->getLocEnd()); S.Diag(loc, diag::note_var_fixit_add_initialization) << FixItHint::CreateInsertion(loc, initialization); } }
// 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; if (castTy->isBooleanType()) { if (val.isUnknownOrUndef()) return val; if (val.isConstant()) return makeTruthVal(!val.isZeroConstant(), castTy); if (!Loc::isLocType(originalTy) && !originalTy->isIntegralOrEnumerationType() && !originalTy->isMemberPointerType()) return UnknownVal(); if (SymbolRef Sym = val.getAsSymbol(true)) { BasicValueFactory &BVF = getBasicValueFactory(); // FIXME: If we had a state here, we could see if the symbol is known to // be zero, but we don't. return makeNonLoc(Sym, BO_NE, BVF.getValue(0, Sym->getType()), castTy); } // Loc values are not always true, they could be weakly linked functions. if (Optional<Loc> L = val.getAs<Loc>()) return evalCastFromLoc(*L, castTy); Loc L = val.castAs<nonloc::LocAsInteger>().getLoc(); return evalCastFromLoc(L, castTy); } // For const casts, casts to void, just propagate the value. if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType()) if (shouldBeModeledWithNoOp(Context, Context.getPointerType(castTy), Context.getPointerType(originalTy))) return val; // Check for casts from pointers to integers. if (castTy->isIntegralOrEnumerationType() && Loc::isLocType(originalTy)) return evalCastFromLoc(val.castAs<Loc>(), castTy); // Check for casts from integers to pointers. if (Loc::isLocType(castTy) && originalTy->isIntegralOrEnumerationType()) { if (Optional<nonloc::LocAsInteger> LV = val.getAs<nonloc::LocAsInteger>()) { 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 (const ArrayType *arrayT = dyn_cast<ArrayType>(originalTy.getCanonicalType())) { // We will always decay to a pointer. QualType elemTy = arrayT->getElementType(); val = StateMgr.ArrayToPointer(val.castAs<Loc>(), elemTy); // Are we casting from an array to a pointer? If so just pass on // the decayed value. if (castTy->isPointerType() || castTy->isReferenceType()) return val; // Are we casting from an array to an integer? If so, cast the decayed // pointer value to an integer. assert(castTy->isIntegralOrEnumerationType()); // 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(val.castAs<Loc>(), castTy); } // Check for casts from a region to a specific type. if (const MemRegion *R = val.getAsRegion()) { // Handle other casts of locations to integers. if (castTy->isIntegralOrEnumerationType()) return evalCastFromLoc(loc::MemRegionVal(R), castTy); // 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); }
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. 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()); if (RequireCompleteType(OutputExpr->getLocStart(), Exprs[i]->getType(), diag::err_dereference_incomplete_type)) return StmtError(); 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()); } 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]; 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.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 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).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(); } return NS; }
static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D) { // There are exactly 3 arguments. if (D->param_size() != 3) return nullptr; // Signature: // _Bool OSAtomicCompareAndSwapPtr(void *__oldValue, // void *__newValue, // void * volatile *__theValue) // Generate body: // if (oldValue == *theValue) { // *theValue = newValue; // return YES; // } // else return NO; QualType ResultTy = D->getReturnType(); bool isBoolean = ResultTy->isBooleanType(); if (!isBoolean && !ResultTy->isIntegralType(C)) return nullptr; const ParmVarDecl *OldValue = D->getParamDecl(0); QualType OldValueTy = OldValue->getType(); const ParmVarDecl *NewValue = D->getParamDecl(1); QualType NewValueTy = NewValue->getType(); assert(OldValueTy == NewValueTy); const ParmVarDecl *TheValue = D->getParamDecl(2); QualType TheValueTy = TheValue->getType(); const PointerType *PT = TheValueTy->getAs<PointerType>(); if (!PT) return nullptr; QualType PointeeTy = PT->getPointeeType(); ASTMaker M(C); // Construct the comparison. Expr *Comparison = M.makeComparison( M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy), M.makeLvalueToRvalue( M.makeDereference( M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy), PointeeTy), PointeeTy), BO_EQ); // Construct the body of the IfStmt. Stmt *Stmts[2]; Stmts[0] = M.makeAssignment( M.makeDereference( M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy), PointeeTy), M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy), NewValueTy); Expr *BoolVal = M.makeObjCBool(true); Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal) : M.makeIntegralCast(BoolVal, ResultTy); Stmts[1] = M.makeReturn(RetVal); CompoundStmt *Body = M.makeCompound(Stmts); // Construct the else clause. BoolVal = M.makeObjCBool(false); RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal) : M.makeIntegralCast(BoolVal, ResultTy); Stmt *Else = M.makeReturn(RetVal); /// Construct the If. Stmt *If = new (C) IfStmt(C, SourceLocation(), false, nullptr, nullptr, Comparison, Body, SourceLocation(), Else); return If; }
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()); bool ValidateConstraints = DeclAttrsMatchCUDAMode(getLangOpts(), getCurFunctionDecl()); 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 (ValidateConstraints && !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(); // Bitfield can't be referenced with a pointer. if (Info.allowsMemory() && OutputExpr->refersToBitField()) return StmtError(Diag(OutputExpr->getLocStart(), diag::err_asm_bitfield_in_memory_constraint) << 1 << Info.getConstraintStr() << OutputExpr->getSourceRange()); 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 (ValidateConstraints && !Context.getTargetInfo().validateInputConstraint( OutputConstraintInfos.data(), NumOutputs, 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(); // Bitfield can't be referenced with a pointer. if (Info.allowsMemory() && InputExpr->refersToBitField()) return StmtError(Diag(InputExpr->getLocStart(), diag::err_asm_bitfield_in_memory_constraint) << 0 << Info.getConstraintStr() << InputExpr->getSourceRange()); // 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); } 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]; 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(); } return NS; }
SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy) { NonLoc InputLHS = lhs; NonLoc InputRHS = rhs; // 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: if (resultTy->isIntegralOrEnumerationType()) return makeIntVal(0, resultTy); return evalCastFromNonLoc(makeIntVal(0, /*Unsigned=*/false), resultTy); case BO_Or: case BO_And: return evalCastFromNonLoc(lhs, resultTy); } while (1) { switch (lhs.getSubKind()) { default: return makeSymExprValNN(state, op, lhs, rhs, resultTy); case nonloc::PointerToMemberKind: { assert(rhs.getSubKind() == nonloc::PointerToMemberKind && "Both SVals should have pointer-to-member-type"); auto LPTM = lhs.castAs<nonloc::PointerToMember>(), RPTM = rhs.castAs<nonloc::PointerToMember>(); auto LPTMD = LPTM.getPTMData(), RPTMD = RPTM.getPTMData(); switch (op) { case BO_EQ: return makeTruthVal(LPTMD == RPTMD, resultTy); case BO_NE: return makeTruthVal(LPTMD != RPTMD, resultTy); default: return UnknownVal(); } } case nonloc::LocAsIntegerKind: { Loc lhsL = lhs.castAs<nonloc::LocAsInteger>().getLoc(); switch (rhs.getSubKind()) { case nonloc::LocAsIntegerKind: return evalBinOpLL(state, op, lhsL, rhs.castAs<nonloc::LocAsInteger>().getLoc(), resultTy); case nonloc::ConcreteIntKind: { // Transform the integer into a location and compare. // FIXME: This only makes sense for comparisons. If we want to, say, // add 1 to a LocAsInteger, we'd better unpack the Loc and add to it, // then pack it back into a LocAsInteger. llvm::APSInt i = rhs.castAs<nonloc::ConcreteInt>().getValue(); BasicVals.getAPSIntType(Context.VoidPtrTy).apply(i); 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 makeSymExprValNN(state, op, InputLHS, InputRHS, resultTy); } } } case nonloc::ConcreteIntKind: { llvm::APSInt LHSValue = lhs.castAs<nonloc::ConcreteInt>().getValue(); // If we're dealing with two known constants, just perform the operation. if (const llvm::APSInt *KnownRHSValue = getKnownValue(state, rhs)) { llvm::APSInt RHSValue = *KnownRHSValue; if (BinaryOperator::isComparisonOp(op)) { // We're looking for a type big enough to compare the two values. // FIXME: This is not correct. char + short will result in a promotion // to int. Unfortunately we have lost types by this point. APSIntType CompareType = std::max(APSIntType(LHSValue), APSIntType(RHSValue)); CompareType.apply(LHSValue); CompareType.apply(RHSValue); } else if (!BinaryOperator::isShiftOp(op)) { APSIntType IntType = BasicVals.getAPSIntType(resultTy); IntType.apply(LHSValue); IntType.apply(RHSValue); } const llvm::APSInt *Result = BasicVals.evalAPSInt(op, LHSValue, RHSValue); if (!Result) return UndefinedVal(); return nonloc::ConcreteInt(*Result); } // 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. switch (op) { case BO_LT: case BO_GT: case BO_LE: case BO_GE: op = BinaryOperator::reverseComparisonOp(op); // FALL-THROUGH case BO_EQ: case BO_NE: case BO_Add: case BO_Mul: case BO_And: case BO_Xor: case BO_Or: std::swap(lhs, rhs); continue; case BO_Shr: // (~0)>>a if (LHSValue.isAllOnesValue() && LHSValue.isSigned()) return evalCastFromNonLoc(lhs, resultTy); // FALL-THROUGH case BO_Shl: // 0<<a and 0>>a if (LHSValue == 0) return evalCastFromNonLoc(lhs, resultTy); return makeSymExprValNN(state, op, InputLHS, InputRHS, resultTy); default: return makeSymExprValNN(state, op, InputLHS, InputRHS, resultTy); } } case nonloc::SymbolValKind: { // We only handle LHS as simple symbols or SymIntExprs. SymbolRef Sym = lhs.castAs<nonloc::SymbolVal>().getSymbol(); // LHS is a symbolic expression. if (const SymIntExpr *symIntExpr = dyn_cast<SymIntExpr>(Sym)) { // 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: assert(resultTy->isBooleanType() || resultTy == getConditionType()); assert(symIntExpr->getType()->isBooleanType() || getContext().hasSameUnqualifiedType(symIntExpr->getType(), getConditionType())); // Negate the comparison and make a value. opc = BinaryOperator::negateComparisonOp(opc); return makeNonLoc(symIntExpr->getLHS(), opc, symIntExpr->getRHS(), resultTy); } } // For now, only handle expressions whose RHS is a constant. if (const llvm::APSInt *RHSValue = getKnownValue(state, rhs)) { // If both the LHS and the current expression are additive, // fold their constants and try again. if (BinaryOperator::isAdditiveOp(op)) { BinaryOperator::Opcode lop = symIntExpr->getOpcode(); if (BinaryOperator::isAdditiveOp(lop)) { // Convert the two constants to a common type, then combine them. // 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. APSIntType IntType = BasicVals.getAPSIntType(resultTy); const llvm::APSInt &first = IntType.convert(symIntExpr->getRHS()); const llvm::APSInt &second = IntType.convert(*RHSValue); const llvm::APSInt *newRHS; if (lop == op) newRHS = BasicVals.evalAPSInt(BO_Add, first, second); else newRHS = BasicVals.evalAPSInt(BO_Sub, first, second); assert(newRHS && "Invalid operation despite common type!"); rhs = nonloc::ConcreteInt(*newRHS); lhs = nonloc::SymbolVal(symIntExpr->getLHS()); op = lop; continue; } } // Otherwise, make a SymIntExpr out of the expression. return MakeSymIntVal(symIntExpr, op, *RHSValue, resultTy); } } // Does the symbolic expression simplify to a constant? // If so, "fold" the constant by setting 'lhs' to a ConcreteInt // and try again. ConstraintManager &CMgr = state->getConstraintManager(); if (const llvm::APSInt *Constant = CMgr.getSymVal(state, Sym)) { lhs = nonloc::ConcreteInt(*Constant); continue; } // Is the RHS a constant? if (const llvm::APSInt *RHSValue = getKnownValue(state, rhs)) return MakeSymIntVal(Sym, op, *RHSValue, resultTy); // Give up -- this is not a symbolic expression we can handle. return makeSymExprValNN(state, op, InputLHS, InputRHS, resultTy); } } } }
void ICEVisitor::VisitBinaryOperator(BinaryOperator *BO) { const NamedDecl *ACD = dyn_cast_or_null<NamedDecl>(AC->getDecl()); VisitChildren(BO); std::string ename = "EventNumber_t"; clang::Expr *LHS = BO->getLHS(); clang::Expr *RHS = BO->getRHS(); if (!LHS || !RHS) return; std::string lname = LHS->getType().getAsString(); std::string rname = RHS->getType().getAsString(); if (IntegerLiteral::classof(LHS->IgnoreCasts()) || IntegerLiteral::classof(RHS->IgnoreCasts())) return; if (!(lname == ename || rname == ename)) return; if (lname == ename && rname == ename) return; clang::QualType OTy; clang::QualType TTy; if (lname == ename && ImplicitCastExpr::classof(RHS)) { ImplicitCastExpr *ICE = dyn_cast_or_null<ImplicitCastExpr>(RHS); TTy = BR.getContext().getCanonicalType(LHS->getType()); OTy = BR.getContext().getCanonicalType(ICE->getSubExprAsWritten()->getType()); } if (rname == ename && ImplicitCastExpr::classof(LHS)) { ImplicitCastExpr *ICE = dyn_cast_or_null<ImplicitCastExpr>(LHS); TTy = BR.getContext().getCanonicalType(RHS->getType()); OTy = BR.getContext().getCanonicalType(ICE->getSubExprAsWritten()->getType()); } if (TTy.isNull() || OTy.isNull()) return; 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(BO, BR.getSourceManager(), AC); BR.EmitBasicReport(ACD, CheckName(), "implicit cast of int type to float type", "CMS code rules", os.str(), CELoc, BO->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(BO, BR.getSourceManager(), AC); BR.EmitBasicReport(ACD, CheckName(), "implicit cast of int type to smaller int type could truncate", "CMS code rules", os.str(), CELoc, BO->getSourceRange()); } if ((size_otype == size_ttype) && (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(BO, BR.getSourceManager(), AC); BR.EmitBasicReport( ACD, CheckName(), "implicit cast ins sign type", "CMS code rules", os.str(), CELoc, BO->getSourceRange()); } return; return; }
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; }
void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ switch (getKind()) { case APValue::Uninitialized: Out << "<uninitialized>"; return; case APValue::Int: if (Ty->isBooleanType()) Out << (getInt().getBoolValue() ? "true" : "false"); else Out << getInt(); return; case APValue::Float: Out << GetApproxValue(getFloat()); return; case APValue::Vector: { Out << '{'; QualType ElemTy = Ty->getAs<VectorType>()->getElementType(); getVectorElt(0).printPretty(Out, Ctx, ElemTy); for (unsigned i = 1; i != getVectorLength(); ++i) { Out << ", "; getVectorElt(i).printPretty(Out, Ctx, ElemTy); } Out << '}'; return; } case APValue::ComplexInt: Out << getComplexIntReal() << "+" << getComplexIntImag() << "i"; return; case APValue::ComplexFloat: Out << GetApproxValue(getComplexFloatReal()) << "+" << GetApproxValue(getComplexFloatImag()) << "i"; return; case APValue::LValue: { LValueBase Base = getLValueBase(); if (!Base) { Out << "0"; return; } bool IsReference = Ty->isReferenceType(); QualType InnerTy = IsReference ? Ty.getNonReferenceType() : Ty->getPointeeType(); if (InnerTy.isNull()) InnerTy = Ty; if (!hasLValuePath()) { // No lvalue path: just print the offset. CharUnits O = getLValueOffset(); CharUnits S = Ctx.getTypeSizeInChars(InnerTy); if (!O.isZero()) { if (IsReference) Out << "*("; if (O % S) { Out << "(char*)"; S = CharUnits::One(); } Out << '&'; } else if (!IsReference) Out << '&'; if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) Out << *VD; else { assert(Base.get<const Expr *>() != nullptr && "Expecting non-null Expr"); Base.get<const Expr*>()->printPretty(Out, nullptr, Ctx.getPrintingPolicy()); } if (!O.isZero()) { Out << " + " << (O / S); if (IsReference) Out << ')'; } return; } // We have an lvalue path. Print it out nicely. if (!IsReference) Out << '&'; else if (isLValueOnePastTheEnd()) Out << "*(&"; QualType ElemTy; if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) { Out << *VD; ElemTy = VD->getType(); } else { const Expr *E = Base.get<const Expr*>(); assert(E != nullptr && "Expecting non-null Expr"); E->printPretty(Out, nullptr, Ctx.getPrintingPolicy()); ElemTy = E->getType(); } ArrayRef<LValuePathEntry> Path = getLValuePath(); const CXXRecordDecl *CastToBase = nullptr; for (unsigned I = 0, N = Path.size(); I != N; ++I) { if (ElemTy->getAs<RecordType>()) { // The lvalue refers to a class type, so the next path entry is a base // or member. const Decl *BaseOrMember = BaseOrMemberType::getFromOpaqueValue(Path[I].BaseOrMember).getPointer(); if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) { CastToBase = RD; ElemTy = Ctx.getRecordType(RD); } else { const ValueDecl *VD = cast<ValueDecl>(BaseOrMember); Out << "."; if (CastToBase) Out << *CastToBase << "::"; Out << *VD; ElemTy = VD->getType(); } } else { // The lvalue must refer to an array. Out << '[' << Path[I].ArrayIndex << ']'; ElemTy = Ctx.getAsArrayType(ElemTy)->getElementType(); } } // Handle formatting of one-past-the-end lvalues. if (isLValueOnePastTheEnd()) { // FIXME: If CastToBase is non-0, we should prefix the output with // "(CastToBase*)". Out << " + 1"; if (IsReference) Out << ')'; } return; } case APValue::Array: { const ArrayType *AT = Ctx.getAsArrayType(Ty); QualType ElemTy = AT->getElementType(); Out << '{'; if (unsigned N = getArrayInitializedElts()) { getArrayInitializedElt(0).printPretty(Out, Ctx, ElemTy); for (unsigned I = 1; I != N; ++I) { Out << ", "; if (I == 10) { // Avoid printing out the entire contents of large arrays. Out << "..."; break; } getArrayInitializedElt(I).printPretty(Out, Ctx, ElemTy); } } Out << '}'; return; } case APValue::Struct: { Out << '{'; const RecordDecl *RD = Ty->getAs<RecordType>()->getDecl(); bool First = true; if (unsigned N = getStructNumBases()) { const CXXRecordDecl *CD = cast<CXXRecordDecl>(RD); CXXRecordDecl::base_class_const_iterator BI = CD->bases_begin(); for (unsigned I = 0; I != N; ++I, ++BI) { assert(BI != CD->bases_end()); if (!First) Out << ", "; getStructBase(I).printPretty(Out, Ctx, BI->getType()); First = false; } } for (const auto *FI : RD->fields()) { if (!First) Out << ", "; if (FI->isUnnamedBitfield()) continue; getStructField(FI->getFieldIndex()). printPretty(Out, Ctx, FI->getType()); First = false; } Out << '}'; return; } case APValue::Union: Out << '{'; if (const FieldDecl *FD = getUnionField()) { Out << "." << *FD << " = "; getUnionValue().printPretty(Out, Ctx, FD->getType()); } Out << '}'; return; case APValue::MemberPointer: // FIXME: This is not enough to unambiguously identify the member in a // multiple-inheritance scenario. if (const ValueDecl *VD = getMemberPointerDecl()) { Out << '&' << *cast<CXXRecordDecl>(VD->getDeclContext()) << "::" << *VD; return; } Out << "0"; return; case APValue::AddrLabelDiff: Out << "&&" << getAddrLabelDiffLHS()->getLabel()->getName(); Out << " - "; Out << "&&" << getAddrLabelDiffRHS()->getLabel()->getName(); return; } llvm_unreachable("Unknown APValue kind!"); }