bool isValid() const { return !Version.empty(); }
};
-namespace {
-
+namespace detail {
enum AvailabilitySlot {
IntroducedSlot, DeprecatedSlot, ObsoletedSlot, NumAvailabilitySlots
};
}
};
+struct TypeTagForDatatypeData {
+ ParsedType *MatchingCType;
+ unsigned LayoutCompatible : 1;
+ unsigned MustBeNull : 1;
+};
+struct PropertyData {
+ IdentifierInfo *GetterId, *SetterId;
+
+ PropertyData(IdentifierInfo *getterId, IdentifierInfo *setterId)
+ : GetterId(getterId), SetterId(setterId) {}
+};
+
} // namespace
/// Wraps an identifier and optional source location for the identifier.
/// 3: __attribute__(( format(printf, 1, 2) )). ParmName/Args/NumArgs all used.
/// 4: __attribute__(( aligned(16) )). ParmName is unused, Args/Num used.
///
-class ParsedAttr {
+class ParsedAttr final
+ : private llvm::TrailingObjects<
+ ParsedAttr, ArgsUnion, detail::AvailabilityData,
+ detail::TypeTagForDatatypeData, ParsedType, detail::PropertyData> {
+ friend class llvm::TrailingObjects<
+ ParsedAttr, ArgsUnion, detail::AvailabilityData,
+ detail::TypeTagForDatatypeData, ParsedType, detail::PropertyData>;
+
+ size_t numTrailingObjects(OverloadToken<ArgsUnion>) const { return NumArgs; }
+ size_t numTrailingObjects(OverloadToken<detail::AvailabilityData>) const {
+ return IsAvailability;
+ }
+ size_t
+ numTrailingObjects(OverloadToken<detail::TypeTagForDatatypeData>) const {
+ return IsTypeTagForDatatype;
+ }
+ size_t numTrailingObjects(OverloadToken<ParsedType>) const {
+ return HasParsedType;
+ }
+ size_t numTrailingObjects(OverloadToken<detail::PropertyData>) const {
+ return IsProperty;
+ }
+
public:
/// The style used to specify an attribute.
enum Syntax {
const Expr *MessageExpr;
- /// Arguments, if any, are stored immediately following the object.
- ArgsUnion *getArgsBuffer() { return reinterpret_cast<ArgsUnion *>(this + 1); }
+ ArgsUnion *getArgsBuffer() { return getTrailingObjects<ArgsUnion>(); }
ArgsUnion const *getArgsBuffer() const {
- return reinterpret_cast<ArgsUnion const *>(this + 1);
+ return getTrailingObjects<ArgsUnion>();
}
- /// Availability information is stored immediately following the arguments,
- /// if any, at the end of the object.
- AvailabilityData *getAvailabilityData() {
- return reinterpret_cast<AvailabilityData*>(getArgsBuffer() + NumArgs);
+ detail::AvailabilityData *getAvailabilityData() {
+ return getTrailingObjects<detail::AvailabilityData>();
}
- const AvailabilityData *getAvailabilityData() const {
- return reinterpret_cast<const AvailabilityData*>(getArgsBuffer() + NumArgs);
+ const detail::AvailabilityData *getAvailabilityData() const {
+ return getTrailingObjects<detail::AvailabilityData>();
}
-public:
- struct TypeTagForDatatypeData {
- ParsedType *MatchingCType;
- unsigned LayoutCompatible : 1;
- unsigned MustBeNull : 1;
- };
- struct PropertyData {
- IdentifierInfo *GetterId, *SetterId;
-
- PropertyData(IdentifierInfo *getterId, IdentifierInfo *setterId)
- : GetterId(getterId), SetterId(setterId) {}
- };
-
private:
friend class AttributeFactory;
friend class AttributePool;
MessageExpr(messageExpr) {
ArgsUnion PVal(Parm);
memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion));
- new (getAvailabilityData()) AvailabilityData(
+ new (getAvailabilityData()) detail::AvailabilityData(
introduced, deprecated, obsoleted, strict, replacementExpr);
AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
}
HasProcessingCache(false) {
ArgsUnion PVal(ArgKind);
memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion));
- TypeTagForDatatypeData &ExtraData = getTypeTagForDatatypeDataSlot();
+ detail::TypeTagForDatatypeData &ExtraData = getTypeTagForDatatypeDataSlot();
new (&ExtraData.MatchingCType) ParsedType(matchingCType);
ExtraData.LayoutCompatible = layoutCompatible;
ExtraData.MustBeNull = mustBeNull;
UsedAsTypeAttr(false), IsAvailability(false),
IsTypeTagForDatatype(false), IsProperty(true), HasParsedType(false),
HasProcessingCache(false) {
- new (&getPropertyDataBuffer()) PropertyData(getterId, setterId);
+ new (&getPropertyDataBuffer()) detail::PropertyData(getterId, setterId);
AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
}
/// Type tag information is stored immediately following the arguments, if
/// any, at the end of the object. They are mutually exclusive with
/// availability slots.
- TypeTagForDatatypeData &getTypeTagForDatatypeDataSlot() {
- return *reinterpret_cast<TypeTagForDatatypeData*>(getArgsBuffer()+NumArgs);
+ detail::TypeTagForDatatypeData &getTypeTagForDatatypeDataSlot() {
+ return *getTrailingObjects<detail::TypeTagForDatatypeData>();
}
- const TypeTagForDatatypeData &getTypeTagForDatatypeDataSlot() const {
- return *reinterpret_cast<const TypeTagForDatatypeData*>(getArgsBuffer()
- + NumArgs);
+ const detail::TypeTagForDatatypeData &getTypeTagForDatatypeDataSlot() const {
+ return *getTrailingObjects<detail::TypeTagForDatatypeData>();
}
/// The type buffer immediately follows the object and are mutually exclusive
/// with arguments.
- ParsedType &getTypeBuffer() {
- return *reinterpret_cast<ParsedType *>(this + 1);
- }
+ ParsedType &getTypeBuffer() { return *getTrailingObjects<ParsedType>(); }
const ParsedType &getTypeBuffer() const {
- return *reinterpret_cast<const ParsedType *>(this + 1);
+ return *getTrailingObjects<ParsedType>();
}
/// The property data immediately follows the object is is mutually exclusive
/// with arguments.
- PropertyData &getPropertyDataBuffer() {
+ detail::PropertyData &getPropertyDataBuffer() {
assert(IsProperty);
- return *reinterpret_cast<PropertyData*>(this + 1);
+ return *getTrailingObjects<detail::PropertyData>();
}
- const PropertyData &getPropertyDataBuffer() const {
+ const detail::PropertyData &getPropertyDataBuffer() const {
assert(IsProperty);
- return *reinterpret_cast<const PropertyData*>(this + 1);
+ return *getTrailingObjects<detail::PropertyData>();
}
size_t allocated_size() const;
const AvailabilityChange &getAvailabilityIntroduced() const {
assert(getKind() == AT_Availability && "Not an availability attribute");
- return getAvailabilityData()->Changes[IntroducedSlot];
+ return getAvailabilityData()->Changes[detail::IntroducedSlot];
}
const AvailabilityChange &getAvailabilityDeprecated() const {
assert(getKind() == AT_Availability && "Not an availability attribute");
- return getAvailabilityData()->Changes[DeprecatedSlot];
+ return getAvailabilityData()->Changes[detail::DeprecatedSlot];
}
const AvailabilityChange &getAvailabilityObsoleted() const {
assert(getKind() == AT_Availability && "Not an availability attribute");
- return getAvailabilityData()->Changes[ObsoletedSlot];
+ return getAvailabilityData()->Changes[detail::ObsoletedSlot];
}
SourceLocation getStrictLoc() const {
return getTypeBuffer();
}
- const PropertyData &getPropertyData() const {
- assert(isDeclspecPropertyAttribute() && "Not a __delcspec(property) attribute");
- return getPropertyDataBuffer();
+ IdentifierInfo *getPropertyDataGetter() const {
+ assert(isDeclspecPropertyAttribute() &&
+ "Not a __delcspec(property) attribute");
+ return getPropertyDataBuffer().GetterId;
+ }
+
+ IdentifierInfo *getPropertyDataSetter() const {
+ assert(isDeclspecPropertyAttribute() &&
+ "Not a __delcspec(property) attribute");
+ return getPropertyDataBuffer().SetterId;
}
/// Get an index into the attribute spelling list
class AttributeFactory {
public:
enum {
- /// The required allocation size of an availability attribute,
- /// which we want to ensure is a multiple of sizeof(void*).
AvailabilityAllocSize =
- sizeof(ParsedAttr) +
- ((sizeof(AvailabilityData) + sizeof(void *) + sizeof(ArgsUnion) - 1) /
- sizeof(void *) * sizeof(void *)),
- TypeTagForDatatypeAllocSize = sizeof(ParsedAttr) +
- (sizeof(ParsedAttr::TypeTagForDatatypeData) +
- sizeof(void *) + sizeof(ArgsUnion) - 1) /
- sizeof(void *) * sizeof(void *),
+ ParsedAttr::totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
+ detail::TypeTagForDatatypeData, ParsedType,
+ detail::PropertyData>(1, 1, 0, 0, 0),
+ TypeTagForDatatypeAllocSize =
+ ParsedAttr::totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
+ detail::TypeTagForDatatypeData, ParsedType,
+ detail::PropertyData>(0, 0, 1, 0, 0),
PropertyAllocSize =
- sizeof(ParsedAttr) +
- (sizeof(ParsedAttr::PropertyData) + sizeof(void *) - 1) /
- sizeof(void *) * sizeof(void *)
+ ParsedAttr::totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
+ detail::TypeTagForDatatypeData, ParsedType,
+ detail::PropertyData>(0, 0, 0, 0, 1),
};
private:
ArgsUnion *args, unsigned numArgs,
ParsedAttr::Syntax syntax,
SourceLocation ellipsisLoc = SourceLocation()) {
- void *memory = allocate(sizeof(ParsedAttr) + numArgs * sizeof(ArgsUnion));
+ size_t temp =
+ ParsedAttr::totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
+ detail::TypeTagForDatatypeData, ParsedType,
+ detail::PropertyData>(numArgs, 0, 0, 0, 0);
+ (void)temp;
+ void *memory = allocate(
+ ParsedAttr::totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
+ detail::TypeTagForDatatypeData, ParsedType,
+ detail::PropertyData>(numArgs, 0, 0, 0,
+ 0));
return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc,
args, numArgs, syntax, ellipsisLoc));
}
IdentifierInfo *scopeName, SourceLocation scopeLoc,
IdentifierLoc *Param1, IdentifierLoc *Param2,
IdentifierLoc *Param3, ParsedAttr::Syntax syntax) {
- size_t size = sizeof(ParsedAttr) + 3 * sizeof(ArgsUnion);
- void *memory = allocate(size);
+ void *memory = allocate(
+ ParsedAttr::totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
+ detail::TypeTagForDatatypeData, ParsedType,
+ detail::PropertyData>(3, 0, 0, 0, 0));
return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc,
Param1, Param2, Param3, syntax));
}
IdentifierInfo *scopeName,
SourceLocation scopeLoc, ParsedType typeArg,
ParsedAttr::Syntax syntaxUsed) {
- void *memory = allocate(sizeof(ParsedAttr) + sizeof(void *));
+ void *memory = allocate(
+ ParsedAttr::totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
+ detail::TypeTagForDatatypeData, ParsedType,
+ detail::PropertyData>(0, 0, 0, 1, 0));
return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc,
typeArg, syntaxUsed));
}