Skip to content

Commit e63e9d7

Browse files
author
Erich Keane
committedOct 24, 2017
mplement __has_unique_object_representations
A helper builtin to facilitate implementing the std::has_unique_object_representations type trait. Requested here: https://bugs.llvm.org/show_bug.cgi?id=34942 Also already exists in GCC and MSVC. Differential Revision: https://reviews.llvm.org/D39064 llvm-svn: 316518
1 parent c70b392 commit e63e9d7

File tree

7 files changed

+393
-1
lines changed

7 files changed

+393
-1
lines changed
 

‎clang/include/clang/AST/Type.h

+6
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,10 @@ class QualType {
770770
/// Return true if this is a trivially copyable type (C++0x [basic.types]p9)
771771
bool isTriviallyCopyableType(const ASTContext &Context) const;
772772

773+
/// Return true if this has unique object representations according to (C++17
774+
/// [meta.unary.prop]p9)
775+
bool hasUniqueObjectRepresentations(const ASTContext &Context) const;
776+
773777
// Don't promise in the API that anything besides 'const' can be
774778
// easily added.
775779

@@ -1114,6 +1118,8 @@ class QualType {
11141118
QualType getAtomicUnqualifiedType() const;
11151119

11161120
private:
1121+
bool unionHasUniqueObjectRepresentations(const ASTContext& Context) const;
1122+
bool structHasUniqueObjectRepresentations(const ASTContext& Context) const;
11171123
// These methods are implemented in a separate translation unit;
11181124
// "static"-ize them to avoid creating temporary QualTypes in the
11191125
// caller.

‎clang/include/clang/Basic/TokenKinds.def

+2
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,8 @@ TYPE_TRAIT_1(__is_pod, IsPOD, KEYCXX)
455455
TYPE_TRAIT_1(__is_polymorphic, IsPolymorphic, KEYCXX)
456456
TYPE_TRAIT_1(__is_trivial, IsTrivial, KEYCXX)
457457
TYPE_TRAIT_1(__is_union, IsUnion, KEYCXX)
458+
TYPE_TRAIT_1(__has_unique_object_representations,
459+
HasUniqueObjectRepresentations, KEYCXX)
458460

459461
// Clang-only C++ Type Traits
460462
TYPE_TRAIT_N(__is_trivially_constructible, IsTriviallyConstructible, KEYCXX)

‎clang/include/clang/Basic/TypeTraits.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ namespace clang {
7070
UTT_IsUnsigned,
7171
UTT_IsVoid,
7272
UTT_IsVolatile,
73-
UTT_Last = UTT_IsVolatile,
73+
UTT_HasUniqueObjectRepresentations,
74+
UTT_Last = UTT_HasUniqueObjectRepresentations,
7475
BTT_IsBaseOf,
7576
BTT_IsConvertible,
7677
BTT_IsConvertibleTo,

‎clang/lib/AST/Type.cpp

+146
Original file line numberDiff line numberDiff line change
@@ -2166,6 +2166,152 @@ bool QualType::isTriviallyCopyableType(const ASTContext &Context) const {
21662166
return false;
21672167
}
21682168

2169+
bool QualType::unionHasUniqueObjectRepresentations(
2170+
const ASTContext &Context) const {
2171+
assert((*this)->isUnionType() && "must be union type");
2172+
CharUnits UnionSize = Context.getTypeSizeInChars(*this);
2173+
const RecordDecl *Union = getTypePtr()->getAs<RecordType>()->getDecl();
2174+
2175+
for (const auto *Field : Union->fields()) {
2176+
if (!Field->getType().hasUniqueObjectRepresentations(Context))
2177+
return false;
2178+
CharUnits FieldSize = Context.getTypeSizeInChars(Field->getType());
2179+
if (FieldSize != UnionSize)
2180+
return false;
2181+
}
2182+
return true;
2183+
}
2184+
2185+
bool isStructEmpty(QualType Ty) {
2186+
assert(Ty.getTypePtr()->isStructureOrClassType() &&
2187+
"Must be struct or class");
2188+
const RecordDecl *RD = Ty.getTypePtr()->getAs<RecordType>()->getDecl();
2189+
2190+
if (!RD->field_empty())
2191+
return false;
2192+
2193+
if (const CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RD)) {
2194+
return ClassDecl->isEmpty();
2195+
}
2196+
2197+
return true;
2198+
}
2199+
2200+
bool QualType::structHasUniqueObjectRepresentations(
2201+
const ASTContext &Context) const {
2202+
assert((*this)->isStructureOrClassType() && "Must be struct or class");
2203+
const RecordDecl *RD = getTypePtr()->getAs<RecordType>()->getDecl();
2204+
2205+
if (isStructEmpty(*this))
2206+
return false;
2207+
2208+
// Check base types.
2209+
CharUnits BaseSize{};
2210+
if (const CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RD)) {
2211+
for (const auto Base : ClassDecl->bases()) {
2212+
if (Base.isVirtual())
2213+
return false;
2214+
2215+
// Empty bases are permitted, otherwise ensure base has unique
2216+
// representation. Also, Empty Base Optimization means that an
2217+
// Empty base takes up 0 size.
2218+
if (!isStructEmpty(Base.getType())) {
2219+
if (!Base.getType().structHasUniqueObjectRepresentations(Context))
2220+
return false;
2221+
BaseSize += Context.getTypeSizeInChars(Base.getType());
2222+
}
2223+
}
2224+
}
2225+
2226+
CharUnits StructSize = Context.getTypeSizeInChars(*this);
2227+
2228+
// This struct obviously has bases that keep it from being 'empty', so
2229+
// checking fields is no longer required. Ensure that the struct size
2230+
// is the sum of the bases.
2231+
if (RD->field_empty())
2232+
return StructSize == BaseSize;
2233+
;
2234+
2235+
CharUnits CurOffset =
2236+
Context.toCharUnitsFromBits(Context.getFieldOffset(*RD->field_begin()));
2237+
2238+
// If the first field isn't at the sum of the size of the bases, there
2239+
// is padding somewhere.
2240+
if (BaseSize != CurOffset)
2241+
return false;
2242+
2243+
for (const auto *Field : RD->fields()) {
2244+
if (!Field->getType().hasUniqueObjectRepresentations(Context))
2245+
return false;
2246+
CharUnits FieldSize = Context.getTypeSizeInChars(Field->getType());
2247+
CharUnits FieldOffset =
2248+
Context.toCharUnitsFromBits(Context.getFieldOffset(Field));
2249+
// Has padding between fields.
2250+
if (FieldOffset != CurOffset)
2251+
return false;
2252+
CurOffset += FieldSize;
2253+
}
2254+
// Check for tail padding.
2255+
return CurOffset == StructSize;
2256+
}
2257+
2258+
bool QualType::hasUniqueObjectRepresentations(const ASTContext &Context) const {
2259+
// C++17 [meta.unary.prop]:
2260+
// The predicate condition for a template specialization
2261+
// has_unique_object_representations<T> shall be
2262+
// satisfied if and only if:
2263+
// (9.1) — T is trivially copyable, and
2264+
// (9.2) — any two objects of type T with the same value have the same
2265+
// object representation, where two objects
2266+
// of array or non-union class type are considered to have the same value
2267+
// if their respective sequences of
2268+
// direct subobjects have the same values, and two objects of union type
2269+
// are considered to have the same
2270+
// value if they have the same active member and the corresponding members
2271+
// have the same value.
2272+
// The set of scalar types for which this condition holds is
2273+
// implementation-defined. [ Note: If a type has padding
2274+
// bits, the condition does not hold; otherwise, the condition holds true
2275+
// for unsigned integral types. — end
2276+
// note ]
2277+
if (isNull())
2278+
return false;
2279+
2280+
// Arrays are unique only if their element type is unique.
2281+
if ((*this)->isArrayType())
2282+
return Context.getBaseElementType(*this).hasUniqueObjectRepresentations(
2283+
Context);
2284+
2285+
// (9.1) — T is trivially copyable, and
2286+
if (!isTriviallyCopyableType(Context))
2287+
return false;
2288+
2289+
// Functions are not unique.
2290+
if ((*this)->isFunctionType())
2291+
return false;
2292+
2293+
// All integrals and enums are unique!
2294+
if ((*this)->isIntegralOrEnumerationType())
2295+
return true;
2296+
2297+
// All pointers are unique, since they're just integrals.
2298+
if ((*this)->isPointerType() || (*this)->isMemberPointerType())
2299+
return true;
2300+
2301+
if ((*this)->isRecordType()) {
2302+
const RecordDecl *Record = getTypePtr()->getAs<RecordType>()->getDecl();
2303+
2304+
// Lambda types are not unique, so exclude them immediately.
2305+
if (Record->isLambda())
2306+
return false;
2307+
2308+
if (Record->isUnion())
2309+
return unionHasUniqueObjectRepresentations(Context);
2310+
return structHasUniqueObjectRepresentations(Context);
2311+
}
2312+
return false;
2313+
}
2314+
21692315
bool QualType::isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const {
21702316
return !Context.getLangOpts().ObjCAutoRefCount &&
21712317
Context.getLangOpts().ObjCWeak &&

‎clang/lib/Parse/ParseExpr.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,7 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback {
716716
/// '__is_sealed' [MS]
717717
/// '__is_trivial'
718718
/// '__is_union'
719+
/// '__has_unique_object_representations'
719720
///
720721
/// [Clang] unary-type-trait:
721722
/// '__is_aggregate'

‎clang/lib/Sema/SemaExprCXX.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -4175,6 +4175,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
41754175
case UTT_IsDestructible:
41764176
case UTT_IsNothrowDestructible:
41774177
case UTT_IsTriviallyDestructible:
4178+
case UTT_HasUniqueObjectRepresentations:
41784179
if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType())
41794180
return true;
41804181

@@ -4614,6 +4615,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
46144615
// Returns True if and only if T is a complete type at the point of the
46154616
// function call.
46164617
return !T->isIncompleteType();
4618+
case UTT_HasUniqueObjectRepresentations:
4619+
return T.hasUniqueObjectRepresentations(C);
46174620
}
46184621
}
46194622

0 commit comments

Comments
 (0)