int32_t sp::ComputeSizeOfType(ReportingContext &cc, Type *aType, size_t level) { if (aType->isUnresolvedTypedef()) { cc.report(rmsg::recursive_type); return 0; } if (!aType->isArray()) { cc.report(rmsg::sizeof_needs_array); return 0; } ArrayType *type = aType->toArray(); for (size_t i = 1; i <= level; i++) { if (!type->contained()->isArray()) { cc.report(rmsg::sizeof_invalid_rank); return 0; } type = type->contained()->toArray(); } if (!type->hasFixedLength()) { cc.report(rmsg::sizeof_indeterminate); return 0; } return type->fixedLength(); }
// Since const is transitive, we require it to be threaded through type // equivalence tests. bool sp::AreTypesEquivalent(Type *a, Type *b, Qualifiers context) { Qualifiers qa = (a->qualifiers() | context); Qualifiers qb = (b->qualifiers() | context); if (qa != qb) return false; a = a->canonical(); b = b->canonical(); if (a == b) return true; switch (a->canonicalKind()) { case Type::Kind::Primitive: // Either |b| is not primitive, or they should not have the same // primitive type since each type is a singleton. assert(!b->isPrimitive() || a->primitive() != b->primitive()); return false; case Type::Kind::Function: { if (!b->isFunction()) return false; // const is not transitive through function signatures. return AreFunctionTypesEqual(a->toFunction(), b->toFunction()); } case Type::Kind::Array: { if (!b->isArray()) return false; ArrayType *aa = a->toArray(); ArrayType *ba = b->toArray(); while (true) { // Both arrays must be either dynamic or have the same fixed size. if (aa->hasFixedLength() != ba->hasFixedLength()) return false; if (aa->hasFixedLength() && aa->fixedLength() != ba->fixedLength()) return false; // Both contained types must be the same type. Type *innerA = aa->contained(); Type *innerB = ba->contained(); if (innerA->isArray() != innerB->isArray()) return false; if (!innerA->isArray()) { // const is transitive through arrays. if (!AreTypesEquivalent(innerA, innerB, context)) return false; // If neither contained type is an array, we're done. break; } // Re-check qualifiers. Qualifiers qa = (innerA->qualifiers() | context); Qualifiers qb = (innerB->qualifiers() | context); if (qa != qb) return false; } return true; } // These types have unique instances. case Type::Kind::Void: case Type::Kind::Unchecked: case Type::Kind::MetaFunction: // These types are named and must have the same identity. case Type::Kind::Struct: case Type::Kind::Typeset: case Type::Kind::Enum: // Handled by a == b check earlier. return false; default: // Should not get Unresolvable, Typedef, or Qualifier here. assert(false); return false; } }