bool ExprTypeAnalyser::checkEnumCast(const ExplicitCastExpr* expr, QualType DestType, QualType SrcType) { // by now: DestType is: Bool, Integer, Function or Enum switch (DestType->getTypeClass()) { case TC_BUILTIN: return true; // allow case TC_POINTER: case TC_ARRAY: case TC_UNRESOLVED: case TC_ALIAS: case TC_STRUCT: assert(0 && "should not come here"); return false; case TC_ENUM: return true; // allow case TC_FUNCTION: break; // deny case TC_MODULE: assert(0 && "should not come here"); return false; } StringBuilder buf1(MAX_LEN_TYPENAME); StringBuilder buf2(MAX_LEN_TYPENAME); SrcType.DiagName(buf1); DestType.DiagName(buf2); Diags.Report(expr->getLocation(), diag::err_illegal_cast) << buf1 << buf2 << expr->getSourceRange(); return false; }
void ExprTypeAnalyser::error(SourceLocation loc, QualType left, QualType right) const { StringBuilder buf1(MAX_LEN_TYPENAME); StringBuilder buf2(MAX_LEN_TYPENAME); right.DiagName(buf1); left.DiagName(buf2); // TODO error msg depends on conv type (see clang errors) Diags.Report(loc, diag::err_illegal_type_conversion) << buf1 << buf2; }
bool ExprTypeAnalyser::checkExplicitCast(const ExplicitCastExpr* expr, QualType DestType, QualType SrcType) { // C99 6.5.4p2: the cast type needs to be void or scalar and the expression if (!DestType.isScalarType()) { // Dont allow any cast to non-scalar StringBuilder buf1(MAX_LEN_TYPENAME); StringBuilder buf2(MAX_LEN_TYPENAME); DestType.DiagName(buf1); SrcType.DiagName(buf2); Diags.Report(expr->getLocation(), diag::err_typecheck_cond_expect_scalar) << buf1 << buf2 << expr->getSourceRange(); return false; } // If either type is a pointer, the other type has to be either an // integer or a pointer // TODO decide if Enums are arithmatic types or not (they are in C99, not is C++0x) if (DestType.isPointerType()) { if (SrcType.isPointerType()) { // allow all pointer casts return true; } else { // only allow cast to pointer from uint32/64 (pointer size) const BuiltinType* BT = dyncast<BuiltinType>(SrcType.getCanonicalType()); // TODO use TargetInfo to check if 32-bit if (BT && BT->getKind() == BuiltinType::UInt64) return true; QualType expected = Type::UInt64(); StringBuilder buf1(MAX_LEN_TYPENAME); expected.DiagName(buf1); Diags.Report(expr->getLocation(), diag::err_cast_nonword_to_pointer) << buf1; } } else { if (SrcType.isPointerType()) { // only allow cast to uint32/64 (pointer size) const BuiltinType* BT = dyncast<BuiltinType>(DestType.getCanonicalType()); // TODO use TargetInfo to check if 32-bit if (BT && BT->getKind() == BuiltinType::UInt64) return true; QualType expected = Type::UInt64(); StringBuilder buf1(MAX_LEN_TYPENAME); expected.DiagName(buf1); Diags.Report(expr->getLocation(), diag::err_cast_pointer_to_nonword) << buf1; } else { // check non-pointer to non-pointer type // TODO make this top level function? (switch on src-type) return checkNonPointerCast(expr, DestType, SrcType); } } return false; }
bool ExprTypeAnalyser::checkFunctionCast(const ExplicitCastExpr* expr, QualType DestType, QualType SrcType) { switch (DestType->getTypeClass()) { case TC_BUILTIN: { // TODO duplicate code // only allow cast to uint32/64 (pointer size) const BuiltinType* BT = dyncast<BuiltinType>(DestType.getCanonicalType()); // TODO use TargetInfo to check if 32-bit if (BT && BT->getKind() == BuiltinType::UInt64) return true; QualType expected = Type::UInt64(); StringBuilder buf1(MAX_LEN_TYPENAME); expected.DiagName(buf1); // TODO use warn_int_to_void_pointer_cast, remove err_cast_pointer_to_nonword Diags.Report(expr->getLocation(), diag::err_cast_pointer_to_nonword) << buf1; return false; } case TC_POINTER: case TC_ARRAY: case TC_UNRESOLVED: case TC_ALIAS: case TC_STRUCT: assert(0 && "should not come here"); return false; case TC_ENUM: break; // deny case TC_FUNCTION: { // Always allow TEMP return true; /* // check other function proto, allow if same const FunctionType* src = cast<FunctionType>(SrcType); const FunctionType* dest = cast<FunctionType>(DestType); if (FunctionType::sameProto(src, dest)) return true; break; // deny */ } case TC_MODULE: assert(0 && "should not come here"); return false; } StringBuilder buf1(MAX_LEN_TYPENAME); StringBuilder buf2(MAX_LEN_TYPENAME); SrcType.DiagName(buf1); DestType.DiagName(buf2); Diags.Report(expr->getLocation(), diag::err_illegal_cast) << buf1 << buf2 << expr->getSourceRange(); return false; }
bool TypeResolver::requireCompleteType(SourceLocation loc, QualType Q, int msg) { if (Q.isIncompleteType()) { StringBuilder name; Q.DiagName(name); Diags.Report(loc, msg) << name; return false; } return true; }
bool ExprTypeAnalyser::checkNonPointerCast(const ExplicitCastExpr* expr, QualType DestType, QualType SrcType) { // by now: DestType isScalar(): Bool, Arithmetic, Function or Enum QualType C = SrcType.getCanonicalType(); switch (C->getTypeClass()) { case TC_BUILTIN: return checkBuiltinCast(expr, DestType, SrcType); case TC_POINTER: assert(0 && "should not come here"); return false; case TC_ARRAY: // TODO break; case TC_UNRESOLVED: // TODO break; case TC_ALIAS: // TODO break; case TC_STRUCT: // no casts allowed break; case TC_ENUM: return checkEnumCast(expr, DestType, SrcType); case TC_FUNCTION: return checkFunctionCast(expr, DestType, SrcType); case TC_MODULE: // no casts allowed break; } // TODO refactor duplicate code (after completion) StringBuilder buf1(MAX_LEN_TYPENAME); StringBuilder buf2(MAX_LEN_TYPENAME); SrcType.DiagName(buf1); DestType.DiagName(buf2); Diags.Report(expr->getLocation(), diag::err_illegal_cast) << buf1 << buf2 << expr->getSourceRange(); return false; }
bool LiteralAnalyser::checkRange(QualType TLeft, const Expr* Right, clang::SourceLocation Loc, llvm::APSInt Result) { // TODO refactor with check() const QualType QT = TLeft.getCanonicalType(); int availableWidth = 0; if (QT.isBuiltinType()) { const BuiltinType* TL = cast<BuiltinType>(QT); if (!TL->isInteger()) { // TODO floats return false; } availableWidth = TL->getIntegerWidth(); } else { QT.dump(); assert(0 && "todo"); } const Limit* L = getLimit(availableWidth); assert(Result.isSigned() && "TEMP FOR NOW"); int64_t value = Result.getSExtValue(); bool overflow = false; if (Result.isNegative()) { const int64_t limit = L->minVal; if (value < limit) overflow = true; } else { const int64_t limit = (int64_t)L->maxVal; if (value > limit) overflow = true; } //fprintf(stderr, "VAL=%lld width=%d signed=%d\n", value, availableWidth, Result.isSigned()); if (overflow) { SmallString<20> ss; Result.toString(ss, 10, true); StringBuilder buf1; TLeft->DiagName(buf1); if (Right) { Diags.Report(Right->getLocStart(), diag::err_literal_outofbounds) << buf1 << L->minStr << L->maxStr << ss << Right->getSourceRange(); } else { Diags.Report(Loc, diag::err_literal_outofbounds) << buf1 << L->minStr << L->maxStr << ss; } return false; } return true; }
bool LiteralAnalyser::calcWidth(QualType TLeft, const Expr* Right, int* availableWidth) { const QualType QT = TLeft.getCanonicalType(); // TODO check if type is already ok?, then skip check? //if (QT == Right->getType().getCanonicalType()) return; if (QT.isBuiltinType()) { const BuiltinType* TL = cast<BuiltinType>(QT); if (!TL->isInteger()) { // TODO floats return false; } // TODO remove const cast Expr* EE = const_cast<Expr*>(Right); QualType Canon = EE->getType().getCanonicalType(); assert(Canon->isBuiltinType()); const BuiltinType* BI = cast<BuiltinType>(Canon); if (TL->getKind() != BI->getKind()) EE->setImpCast(TL->getKind()); if (QT == Type::Bool()) { // NOTE: any integer to bool is ok return false; } *availableWidth = TL->getIntegerWidth(); } else if (QT.isPointerType()) { *availableWidth = 32; // only 32-bit for now // dont ask for pointer, replace with uint32 here. } else { StringBuilder t1name(128); Right->getType().DiagName(t1name); // Q: allow FuncPtr to return 0? (or nil?) StringBuilder t2name(128); TLeft->DiagName(t2name); Diags.Report(Right->getLocation(), diag::err_typecheck_convert_incompatible) << t1name << t2name << 2 << 0 << 0; return false; //QT.dump(); //assert(0 && "todo"); } return true; }
void LiteralAnalyser::check(QualType TLeft, const Expr* Right) { if (Right->getCTC() == CTC_NONE) return; // TODO assert here instead of check? // special case for assignments to enums if (TLeft.isEnumType()) { // dont check value if right is also same enum type if (TLeft == Right->getType()) return; // TODO should be done elsewhere (checking if conversion is allowed) fprintf(stderr, "TODO refactor checking!!, type conversion not allowed\n"); #if 0 // this part should be used when checking casting CTC's to Enum types APSInt Result = checkLiterals(Right); // check if value has matching enum constant const EnumType* ET = cast<EnumType>(TLeft.getTypePtr()); const EnumTypeDecl* ETD = ET->getDecl(); assert(ETD); if (!ETD->hasConstantValue(Result)) { fprintf(stderr, "NO SUCH CONSTANT\n"); } #endif return; } int availableWidth = 0; if (!calcWidth(TLeft, Right, &availableWidth)) return; StringBuilder tname(128); TLeft->DiagName(tname); const Limit* L = getLimit(availableWidth); checkWidth(availableWidth, L, Right, tname); }
bool ExprTypeAnalyser::checkBuiltin(QualType left, QualType right, const Expr* expr, bool first) const { const BuiltinType* Left = cast<BuiltinType>(left.getCanonicalType()); // left is builtin QualType C = right.getCanonicalType(); switch (C->getTypeClass()) { case TC_BUILTIN: { // NOTE: canonical is builtin, var itself my be UnresolvedType etc const BuiltinType* Right = cast<BuiltinType>(right.getCanonicalType()); int rule = type_conversions[Right->getKind()][Left->getKind()]; // 0 = ok, 1 = loss of precision, 2 sign-conversion, 3=float->integer, 4 incompatible, 5 loss of FP prec. // TODO use matrix with allowed conversions: 3 options: ok, error, warn int errorMsg = 0; if (first) { if (Right->getKind() != Left->getKind()) { // add Implicit Cast // TODO remove const cast Expr* E = const_cast<Expr*>(expr); E->setImpCast(Left->getKind()); } if (rule == 1) { QualType Q = TypeFinder::findType(expr); return checkBuiltin(left, Q, expr, false); } } switch (rule) { case 0: return true; case 1: // loss of precision errorMsg = diag::warn_impcast_integer_precision; break; case 2: // sign-conversion errorMsg = diag::warn_impcast_integer_sign; break; case 3: // float->integer errorMsg = diag::warn_impcast_float_integer; break; case 4: // incompatible errorMsg = diag::err_illegal_type_conversion; break; case 5: // loss of fp-precision errorMsg = diag::warn_impcast_float_precision; break; default: assert(0 && "should not come here"); break; } StringBuilder buf1(MAX_LEN_TYPENAME); StringBuilder buf2(MAX_LEN_TYPENAME); right.DiagName(buf1); left.DiagName(buf2); // TODO error msg depends on conv type (see clang errors) Diags.Report(expr->getLocation(), errorMsg) << buf1 << buf2 << expr->getSourceRange(); return false; } case TC_POINTER: // allow implicit cast to bool if(ptr), TODO other cases if (Left->getKind() == BuiltinType::Bool) return true; break; case TC_ARRAY: break; case TC_UNRESOLVED: break; case TC_ALIAS: break; case TC_STRUCT: break; case TC_ENUM: break; case TC_FUNCTION: break; case TC_MODULE: break; } error(expr->getLocation(), left, right); return false; }
bool ExprTypeAnalyser::checkBuiltinCast(const ExplicitCastExpr* expr, QualType DestType, QualType SrcType) { // by now: DestType isScalar(): Bool, Arithmetic, Function or Enum const BuiltinType* Right = cast<BuiltinType>(SrcType.getCanonicalType()); QualType C = DestType.getCanonicalType(); switch (C->getTypeClass()) { case TC_BUILTIN: { const BuiltinType* Left = cast<BuiltinType>(DestType.getCanonicalType()); int rule = type_conversions[Right->getKind()][Left->getKind()]; switch (rule) { case 0: case 1: // loss of precision case 2: // sign-conversion case 3: // float->integer break; case 4: // incompatible { StringBuilder buf1(MAX_LEN_TYPENAME); StringBuilder buf2(MAX_LEN_TYPENAME); DestType.DiagName(buf1); SrcType.DiagName(buf2); Diags.Report(expr->getLocation(), diag::err_illegal_cast) << buf1 << buf2 << expr->getSourceRange(); return false; } case 5: // loss of fp-precision break; default: assert(0 && "should not come here"); } return true; } case TC_POINTER: assert(0 && "should not come here"); return false; case TC_ARRAY: // TODO break; case TC_UNRESOLVED: case TC_ALIAS: case TC_STRUCT: case TC_ENUM: assert(0 && "should not come here"); return false; case TC_FUNCTION: // only allow if uint32/64 (ptr size) // TODO use TargetInfo to check if 32-bit if (Right->getKind() != BuiltinType::UInt64) { StringBuilder buf1(MAX_LEN_TYPENAME); SrcType.DiagName(buf1); StringBuilder buf2(MAX_LEN_TYPENAME); DestType.DiagName(buf2); Diags.Report(expr->getLocation(), diag::warn_int_to_pointer_cast) << buf1 << buf2; return false; } break; case TC_MODULE: assert(0 && "should not come here"); return false; } return true; }