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 TypePrinter::Print(QualType T, std::string &S) { if (T.isNull()) { S += "NULL TYPE"; return; } if (Policy.SuppressSpecifiers && T->isSpecifierType()) return; // Print qualifiers as appropriate. Qualifiers Quals = T.getLocalQualifiers(); if (!Quals.empty()) { std::string TQS; Quals.getAsStringInternal(TQS, Policy); if (!S.empty()) { TQS += ' '; TQS += S; } std::swap(S, TQS); } switch (T->getTypeClass()) { #define ABSTRACT_TYPE(CLASS, PARENT) #define TYPE(CLASS, PARENT) case Type::CLASS: \ Print##CLASS(cast<CLASS##Type>(T.getTypePtr()), S); \ break; #include "clang/AST/TypeNodes.def" } }
QualType TypeResolver::resolveCanonical(QualType Q) const { if (Q->hasCanonicalType()) return Q.getCanonicalType(); const Type* T = Q.getTypePtr(); switch (Q->getTypeClass()) { case TC_BUILTIN: return Q; case TC_POINTER: { const PointerType* P = cast<PointerType>(T); QualType t1 = P->getPointeeType(); // Pointee will always be in same TypeContext (file), since it's either built-in or UnresolvedType QualType t2 = resolveCanonical(t1); assert(t2.isValid()); if (t1 == t2) { Q->setCanonicalType(Q); return Q; } else { // TODO qualifiers QualType Canon = typeContext.getPointerType(t2); if (!Canon->hasCanonicalType()) Canon->setCanonicalType(Canon); Q->setCanonicalType(Canon); return Canon; } } case TC_ARRAY: { const ArrayType* A = cast<ArrayType>(T); QualType t1 = A->getElementType(); // NOTE: qualifiers are lost here! QualType t2 = resolveCanonical(t1); if (t1 == t2) { Q->setCanonicalType(Q); return Q; } else { // NOTE: need size Expr, but set ownership to none QualType Canon = typeContext.getArrayType(t2, A->getSizeExpr(), false, A->isIncremental()); if (!Canon->hasCanonicalType()) Canon->setCanonicalType(Canon); Q->setCanonicalType(Canon); return Canon; } } case TC_UNRESOLVED: assert(0 && "should not get here"); return QualType(); case TC_ALIAS: case TC_STRUCT: case TC_ENUM: case TC_FUNCTION: return Q.getCanonicalType(); case TC_MODULE: assert(0 && "TBD"); return Q; } assert(0); }
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; }
QualType TypeResolver::resolveUnresolved(QualType Q) const { const Type* T = Q.getTypePtr(); switch (Q->getTypeClass()) { case TC_BUILTIN: return Q; case TC_POINTER: { // Dont return new type if not needed const PointerType* P = cast<PointerType>(T); QualType t1 = P->getPointeeType(); QualType Result = resolveUnresolved(t1); if (t1 == Result) return Q; // TODO qualifiers return typeContext.getPointerType(Result); } case TC_ARRAY: { const ArrayType* A = cast<ArrayType>(T); QualType t1 = A->getElementType(); QualType Result = resolveUnresolved(t1); if (t1 == Result) return Q; // TODO qualifiers return typeContext.getArrayType(Result, A->getSizeExpr(), false, A->isIncremental()); } case TC_UNRESOLVED: { const UnresolvedType* U = cast<UnresolvedType>(T); TypeDecl* TD = U->getDecl(); assert(TD); QualType result = TD->getType(); if (Q.isConstQualified()) result.addConst(); if (Q.isVolatileQualified()) result.addVolatile(); return result; } case TC_ALIAS: case TC_STRUCT: case TC_ENUM: case TC_FUNCTION: return Q; case TC_MODULE: assert(0 && "TBD"); return Q; } return Q; }
void MicrosoftCXXNameMangler::mangleType(QualType T) { // Only operate on the canonical type! T = getASTContext().getCanonicalType(T); Qualifiers Quals = T.getLocalQualifiers(); if (Quals) { // We have to mangle these now, while we still have enough information. // <pointer-cvr-qualifiers> ::= P # pointer // ::= Q # const pointer // ::= R # volatile pointer // ::= S # const volatile pointer if (T->isAnyPointerType() || T->isMemberPointerType() || T->isBlockPointerType()) { if (!Quals.hasVolatile()) Out << 'Q'; else { if (!Quals.hasConst()) Out << 'R'; else Out << 'S'; } } else // Just emit qualifiers like normal. // NB: When we mangle a pointer/reference type, and the pointee // type has no qualifiers, the lack of qualifier gets mangled // in there. mangleQualifiers(Quals, false); } else if (T->isAnyPointerType() || T->isMemberPointerType() || T->isBlockPointerType()) { Out << 'P'; } switch (T->getTypeClass()) { #define ABSTRACT_TYPE(CLASS, PARENT) #define NON_CANONICAL_TYPE(CLASS, PARENT) \ case Type::CLASS: \ llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \ return; #define TYPE(CLASS, PARENT) \ case Type::CLASS: \ mangleType(static_cast<const CLASS##Type*>(T.getTypePtr())); \ break; #include "clang/AST/TypeNodes.def" } }
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; }
QualType TypeResolver::checkCanonicals(Decls& decls, QualType Q, bool set) const { if (Q->hasCanonicalType()) return Q.getCanonicalType(); const Type* T = Q.getTypePtr(); switch (Q->getTypeClass()) { case TC_BUILTIN: return Q; case TC_POINTER: { const PointerType* P = cast<PointerType>(T); QualType t1 = P->getPointeeType(); // Pointee will always be in same TypeContext (file), since it's either built-in or UnresolvedType QualType t2 = checkCanonicals(decls, t1, set); if (!t2.isValid()) return t2; QualType canon; if (t1 == t2) canon = Q; else { canon = typeContext.getPointerType(t2); if (!canon->hasCanonicalType()) canon->setCanonicalType(canon); } assert(Q.isValid()); if (set) P->setCanonicalType(canon); return canon; } case TC_ARRAY: { const ArrayType* A = cast<ArrayType>(T); QualType t1 = A->getElementType(); // NOTE: qualifiers are lost here! QualType t2 = checkCanonicals(decls, t1, set); if (!t2.isValid()) return t2; QualType canon; if (t1 == t2) canon = Q; // NOTE: need size Expr, but set ownership to none else { canon = typeContext.getArrayType(t2, A->getSizeExpr(), false, A->isIncremental()); if (!canon->hasCanonicalType()) canon->setCanonicalType(canon); } if (set) A->setCanonicalType(canon); return canon; } case TC_UNRESOLVED: { const UnresolvedType* U = cast<UnresolvedType>(T); TypeDecl* TD = U->getDecl(); assert(TD); // check if exists if (!checkDecls(decls, TD)) { return QualType(); } QualType canonical = checkCanonicals(decls, TD->getType(), false); if (set) U->setCanonicalType(canonical); return canonical; } case TC_ALIAS: { const AliasType* A = cast<AliasType>(T); if (!checkDecls(decls, A->getDecl())) { return QualType(); } QualType canonical = checkCanonicals(decls, A->getRefType(), set); assert(Q.isValid()); if (set) A->setCanonicalType(canonical); return canonical; } case TC_STRUCT: return Q.getCanonicalType(); case TC_ENUM: { assert(0 && "TODO"); return 0; } case TC_FUNCTION: return Q.getCanonicalType(); case TC_MODULE: assert(0 && "TBD"); return 0; } assert(0); }
/// getOrCreateType - Get the type from the cache or create a new /// one if necessary. llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DICompileUnit Unit) { if (Ty.isNull()) return llvm::DIType(); // Check to see if the compile unit already has created this type. llvm::DIType &Slot = TypeCache[Ty.getAsOpaquePtr()]; if (!Slot.isNull()) return Slot; // Handle CVR qualifiers, which recursively handles what they refer to. if (Ty.getCVRQualifiers()) return Slot = CreateCVRType(Ty, Unit); // Work out details of type. switch (Ty->getTypeClass()) { #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) #define NON_CANONICAL_TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) case Type::Class: #include "clang/AST/TypeNodes.def" assert(false && "Dependent types cannot show up in debug information"); case Type::Complex: case Type::LValueReference: case Type::RValueReference: case Type::Vector: case Type::ExtVector: case Type::ExtQual: case Type::ObjCQualifiedInterface: case Type::ObjCQualifiedId: case Type::FixedWidthInt: case Type::BlockPointer: case Type::MemberPointer: case Type::TemplateSpecialization: case Type::QualifiedName: case Type::ObjCQualifiedClass: // Unsupported types return llvm::DIType(); case Type::ObjCInterface: Slot = CreateType(cast<ObjCInterfaceType>(Ty), Unit); break; case Type::Builtin: Slot = CreateType(cast<BuiltinType>(Ty), Unit); break; case Type::Pointer: Slot = CreateType(cast<PointerType>(Ty), Unit); break; case Type::Typedef: Slot = CreateType(cast<TypedefType>(Ty), Unit); break; case Type::Record: case Type::Enum: Slot = CreateType(cast<TagType>(Ty), Unit); break; case Type::FunctionProto: case Type::FunctionNoProto: return Slot = CreateType(cast<FunctionType>(Ty), Unit); case Type::ConstantArray: case Type::VariableArray: case Type::IncompleteArray: return Slot = CreateType(cast<ArrayType>(Ty), Unit); case Type::TypeOfExpr: return Slot = getOrCreateType(cast<TypeOfExprType>(Ty)->getUnderlyingExpr() ->getType(), Unit); case Type::TypeOf: return Slot = getOrCreateType(cast<TypeOfType>(Ty)->getUnderlyingType(), Unit); } return Slot; }
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; }