void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) { llvm::SmallVector<llvm::APInt, 3> Dimensions; for (;;) { if (ElementTy->isConstantArrayType()) { const ConstantArrayType *CAT = static_cast<const ConstantArrayType *>(ElementTy.getTypePtr()); Dimensions.push_back(CAT->getSize()); ElementTy = CAT->getElementType(); } else if (ElementTy->isVariableArrayType()) { assert(false && "Don't know how to mangle VLAs!"); } else if (ElementTy->isDependentSizedArrayType()) { // The dependent expression has to be folded into a constant (TODO). assert(false && "Don't know how to mangle dependent-sized arrays!"); } else if (ElementTy->isIncompleteArrayType()) continue; else break; } mangleQualifiers(ElementTy.getQualifiers(), false); // If there are any additional dimensions, mangle them now. if (Dimensions.size() > 0) { Out << 'Y'; // <dimension-count> ::= <number> # number of extra dimensions mangleNumber(Dimensions.size()); for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim) { mangleNumber(Dimensions[Dim].getLimitedValue()); } } mangleType(ElementTy.getLocalUnqualifiedType()); }
// <type> ::= <pointer-to-member-type> // <pointer-to-member-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> // <class name> <type> void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T) { QualType PointeeType = T->getPointeeType(); if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(PointeeType)) { Out << '8'; mangleName(cast<RecordType>(T->getClass())->getDecl()); mangleType(FPT, NULL, false, true); } else { mangleQualifiers(PointeeType.getQualifiers(), true); mangleName(cast<RecordType>(T->getClass())->getDecl()); mangleType(PointeeType.getLocalUnqualifiedType()); } }
void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { // <type-encoding> ::= <storage-class> <variable-type> // <storage-class> ::= 0 # private static member // ::= 1 # protected static member // ::= 2 # public static member // ::= 3 # global // ::= 4 # static local // The first character in the encoding (after the name) is the storage class. if (VD->isStaticDataMember()) { // If it's a static member, it also encodes the access level. switch (VD->getAccess()) { default: case AS_private: Out << '0'; break; case AS_protected: Out << '1'; break; case AS_public: Out << '2'; break; } } else if (!VD->isStaticLocal()) Out << '3'; else Out << '4'; // Now mangle the type. // <variable-type> ::= <type> <cvr-qualifiers> // ::= <type> A # pointers, references, arrays // Pointers and references are odd. The type of 'int * const foo;' gets // mangled as 'QAHA' instead of 'PAHB', for example. QualType Ty = VD->getType(); if (Ty->isPointerType() || Ty->isReferenceType()) { mangleType(Ty); Out << 'A'; } else if (Ty->isArrayType()) { // Global arrays are funny, too. mangleType(cast<ArrayType>(Ty.getTypePtr()), true); Out << 'A'; } else { mangleType(Ty.getLocalUnqualifiedType()); mangleQualifiers(Ty.getLocalQualifiers(), false); } }
const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) { ASTContext& Ctx = StateMgr.getContext(); // Handle casts to Objective-C objects. if (CastToTy->isObjCObjectPointerType()) return R->StripCasts(); if (CastToTy->isBlockPointerType()) { // FIXME: We may need different solutions, depending on the symbol // involved. Blocks can be casted to/from 'id', as they can be treated // as Objective-C objects. This could possibly be handled by enhancing // our reasoning of downcasts of symbolic objects. if (isa<CodeTextRegion>(R) || isa<SymbolicRegion>(R)) return R; // We don't know what to make of it. Return a NULL region, which // will be interpretted as UnknownVal. return NULL; } // Now assume we are casting from pointer to pointer. Other cases should // already be handled. QualType PointeeTy = CastToTy->getAs<PointerType>()->getPointeeType(); QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy); // Handle casts to void*. We just pass the region through. if (CanonPointeeTy.getLocalUnqualifiedType() == Ctx.VoidTy) return R; // Handle casts from compatible types. if (R->isBoundable()) if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) { QualType ObjTy = Ctx.getCanonicalType(TR->getValueType()); if (CanonPointeeTy == ObjTy) return R; } // Process region cast according to the kind of the region being cast. switch (R->getKind()) { case MemRegion::CXXThisRegionKind: case MemRegion::GenericMemSpaceRegionKind: case MemRegion::StackLocalsSpaceRegionKind: case MemRegion::StackArgumentsSpaceRegionKind: case MemRegion::HeapSpaceRegionKind: case MemRegion::UnknownSpaceRegionKind: case MemRegion::NonStaticGlobalSpaceRegionKind: case MemRegion::StaticGlobalSpaceRegionKind: { assert(0 && "Invalid region cast"); break; } case MemRegion::FunctionTextRegionKind: case MemRegion::BlockTextRegionKind: case MemRegion::BlockDataRegionKind: case MemRegion::StringRegionKind: // FIXME: Need to handle arbitrary downcasts. case MemRegion::SymbolicRegionKind: case MemRegion::AllocaRegionKind: case MemRegion::CompoundLiteralRegionKind: case MemRegion::FieldRegionKind: case MemRegion::ObjCIvarRegionKind: case MemRegion::VarRegionKind: case MemRegion::CXXObjectRegionKind: return MakeElementRegion(R, PointeeTy); case MemRegion::ElementRegionKind: { // If we are casting from an ElementRegion to another type, the // algorithm is as follows: // // (1) Compute the "raw offset" of the ElementRegion from the // base region. This is done by calling 'getAsRawOffset()'. // // (2a) If we get a 'RegionRawOffset' after calling // 'getAsRawOffset()', determine if the absolute offset // can be exactly divided into chunks of the size of the // casted-pointee type. If so, create a new ElementRegion with // the pointee-cast type as the new ElementType and the index // being the offset divded by the chunk size. If not, create // a new ElementRegion at offset 0 off the raw offset region. // // (2b) If we don't a get a 'RegionRawOffset' after calling // 'getAsRawOffset()', it means that we are at offset 0. // // FIXME: Handle symbolic raw offsets. const ElementRegion *elementR = cast<ElementRegion>(R); const RegionRawOffset &rawOff = elementR->getAsArrayOffset(); const MemRegion *baseR = rawOff.getRegion(); // If we cannot compute a raw offset, throw up our hands and return // a NULL MemRegion*. if (!baseR) return NULL; CharUnits off = CharUnits::fromQuantity(rawOff.getByteOffset()); if (off.isZero()) { // Edge case: we are at 0 bytes off the beginning of baseR. We // check to see if type we are casting to is the same as the base // region. If so, just return the base region. if (const TypedRegion *TR = dyn_cast<TypedRegion>(baseR)) { QualType ObjTy = Ctx.getCanonicalType(TR->getValueType()); QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy); if (CanonPointeeTy == ObjTy) return baseR; } // Otherwise, create a new ElementRegion at offset 0. return MakeElementRegion(baseR, PointeeTy); } // We have a non-zero offset from the base region. We want to determine // if the offset can be evenly divided by sizeof(PointeeTy). If so, // we create an ElementRegion whose index is that value. Otherwise, we // create two ElementRegions, one that reflects a raw offset and the other // that reflects the cast. // Compute the index for the new ElementRegion. int64_t newIndex = 0; const MemRegion *newSuperR = 0; // We can only compute sizeof(PointeeTy) if it is a complete type. if (IsCompleteType(Ctx, PointeeTy)) { // Compute the size in **bytes**. CharUnits pointeeTySize = Ctx.getTypeSizeInChars(PointeeTy); if (!pointeeTySize.isZero()) { // Is the offset a multiple of the size? If so, we can layer the // ElementRegion (with elementType == PointeeTy) directly on top of // the base region. if (off % pointeeTySize == 0) { newIndex = off / pointeeTySize; newSuperR = baseR; } } } if (!newSuperR) { // Create an intermediate ElementRegion to represent the raw byte. // This will be the super region of the final ElementRegion. newSuperR = MakeElementRegion(baseR, Ctx.CharTy, off.getQuantity()); } return MakeElementRegion(newSuperR, PointeeTy, newIndex); } } assert(0 && "unreachable"); return 0; }
/// CheckExceptionSpecSubset - Check whether the second function type's /// exception specification is a subset (or equivalent) of the first function /// type. This is used by override and pointer assignment checks. bool Sema::CheckExceptionSpecSubset( const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, const FunctionProtoType *Superset, SourceLocation SuperLoc, const FunctionProtoType *Subset, SourceLocation SubLoc) { // FIXME: As usual, we could be more specific in our error messages, but // that better waits until we've got types with source locations. if (!SubLoc.isValid()) SubLoc = SuperLoc; // If superset contains everything, we're done. if (!Superset->hasExceptionSpec() || Superset->hasAnyExceptionSpec()) return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); // It does not. If the subset contains everything, we've failed. if (!Subset->hasExceptionSpec() || Subset->hasAnyExceptionSpec()) { Diag(SubLoc, DiagID); if (NoteID.getDiagID() != 0) Diag(SuperLoc, NoteID); return true; } // Neither contains everything. Do a proper comparison. for (FunctionProtoType::exception_iterator SubI = Subset->exception_begin(), SubE = Subset->exception_end(); SubI != SubE; ++SubI) { // Take one type from the subset. QualType CanonicalSubT = Context.getCanonicalType(*SubI); // Unwrap pointers and references so that we can do checks within a class // hierarchy. Don't unwrap member pointers; they don't have hierarchy // conversions on the pointee. bool SubIsPointer = false; if (const ReferenceType *RefTy = CanonicalSubT->getAs<ReferenceType>()) CanonicalSubT = RefTy->getPointeeType(); if (const PointerType *PtrTy = CanonicalSubT->getAs<PointerType>()) { CanonicalSubT = PtrTy->getPointeeType(); SubIsPointer = true; } bool SubIsClass = CanonicalSubT->isRecordType(); CanonicalSubT = CanonicalSubT.getLocalUnqualifiedType(); CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, /*DetectVirtual=*/false); bool Contained = false; // Make sure it's in the superset. for (FunctionProtoType::exception_iterator SuperI = Superset->exception_begin(), SuperE = Superset->exception_end(); SuperI != SuperE; ++SuperI) { QualType CanonicalSuperT = Context.getCanonicalType(*SuperI); // SubT must be SuperT or derived from it, or pointer or reference to // such types. if (const ReferenceType *RefTy = CanonicalSuperT->getAs<ReferenceType>()) CanonicalSuperT = RefTy->getPointeeType(); if (SubIsPointer) { if (const PointerType *PtrTy = CanonicalSuperT->getAs<PointerType>()) CanonicalSuperT = PtrTy->getPointeeType(); else { continue; } } CanonicalSuperT = CanonicalSuperT.getLocalUnqualifiedType(); // If the types are the same, move on to the next type in the subset. if (CanonicalSubT == CanonicalSuperT) { Contained = true; break; } // Otherwise we need to check the inheritance. if (!SubIsClass || !CanonicalSuperT->isRecordType()) continue; Paths.clear(); if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths)) continue; if (Paths.isAmbiguous(CanonicalSuperT)) continue; // Do this check from a context without privileges. switch (CheckBaseClassAccess(SourceLocation(), false, CanonicalSuperT, CanonicalSubT, Paths.front(), /*ForceCheck*/ true, /*ForceUnprivileged*/ true, ADK_quiet)) { case AR_accessible: break; case AR_inaccessible: continue; case AR_dependent: llvm_unreachable("access check dependent for unprivileged context"); break; case AR_delayed: llvm_unreachable("access check delayed in non-declaration"); break; } Contained = true; break; } if (!Contained) { Diag(SubLoc, DiagID); if (NoteID.getDiagID() != 0) Diag(SuperLoc, NoteID); return true; } } // We've run half the gauntlet. return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); }