[libcxx-commits] [clang] [libcxx] [Clang][libc++] Implement C++23 std::start_lifetime_as (P2590R2, P2679R2) (PR #196286)
via libcxx-commits
libcxx-commits at lists.llvm.org
Thu May 7 04:13:12 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Yash Verma (My-Bad-2)
<details>
<summary>Changes</summary>
This PR implements the compiler built-in and standard library interfaces for C++23 Explicit Lifetime Management as proposed in [P2590R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2590r2.pdf) and fixed for arrays in [P2679R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2679r2.pdf).
This PR implements a `__builtin_start_lifetime_as((T*)ptr)` builtin which is used by `std::start_lifetime_as<T>(ptr)` and `std::start_lifetime_as_array<T>(ptr, n)`.
I'm sorry if there are any mistakes in the pull request as this my first PR ever. Also, the commit timestamp is a bit messed up because I forgot to run `git clang-format` hook before pushing a few commits to the remote host.
---
Patch is 209.42 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/196286.diff
17 Files Affected:
- (modified) clang/include/clang/AST/TypeBase.h (+304-385)
- (modified) clang/include/clang/Basic/Builtins.td (+6)
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+3)
- (modified) clang/include/clang/Sema/Sema.h (+7)
- (modified) clang/lib/AST/ExprConstant.cpp (+6)
- (modified) clang/lib/AST/Type.cpp (+51)
- (modified) clang/lib/CodeGen/CGBuiltin.cpp (+265-261)
- (modified) clang/lib/Sema/SemaChecking.cpp (+463-396)
- (added) clang/test/CodeGenCXX/builtin-start-lifetime-as.cpp (+13)
- (added) clang/test/SemaCXX/builtin-start-lifetime-as.cpp (+56)
- (modified) libcxx/include/CMakeLists.txt (+1)
- (added) libcxx/include/__memory/start_lifetime_as.h (+72)
- (modified) libcxx/include/memory (+26)
- (modified) libcxx/include/module.modulemap.in (+1)
- (added) libcxx/test/std/memory/start.lifetime/start_lifetime_as.pass.cpp (+76)
- (added) libcxx/test/std/memory/start.lifetime/start_lifetime_as.verify.cpp (+35)
- (added) libcxx/test/std/memory/start.lifetime/start_lifetime_as_array.pass.cpp (+47)
``````````diff
diff --git a/clang/include/clang/AST/TypeBase.h b/clang/include/clang/AST/TypeBase.h
index b2887bcc36246..2e20cecd8ae1d 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -71,43 +71,37 @@ class TemplateParameterList;
class Type;
class Attr;
-enum {
- TypeAlignmentInBits = 4,
- TypeAlignment = 1 << TypeAlignmentInBits
-};
+enum { TypeAlignmentInBits = 4, TypeAlignment = 1 << TypeAlignmentInBits };
namespace serialization {
- template <class T> class AbstractTypeReader;
- template <class T> class AbstractTypeWriter;
-}
+template <class T> class AbstractTypeReader;
+template <class T> class AbstractTypeWriter;
+} // namespace serialization
} // namespace clang
namespace llvm {
- template <typename T>
- struct PointerLikeTypeTraits;
- template<>
- struct PointerLikeTypeTraits< ::clang::Type*> {
- static inline void *getAsVoidPointer(::clang::Type *P) { return P; }
+template <typename T> struct PointerLikeTypeTraits;
+template <> struct PointerLikeTypeTraits<::clang::Type *> {
+ static inline void *getAsVoidPointer(::clang::Type *P) { return P; }
- static inline ::clang::Type *getFromVoidPointer(void *P) {
- return static_cast< ::clang::Type*>(P);
- }
+ static inline ::clang::Type *getFromVoidPointer(void *P) {
+ return static_cast<::clang::Type *>(P);
+ }
- static constexpr int NumLowBitsAvailable = clang::TypeAlignmentInBits;
- };
+ static constexpr int NumLowBitsAvailable = clang::TypeAlignmentInBits;
+};
- template<>
- struct PointerLikeTypeTraits< ::clang::ExtQuals*> {
- static inline void *getAsVoidPointer(::clang::ExtQuals *P) { return P; }
+template <> struct PointerLikeTypeTraits<::clang::ExtQuals *> {
+ static inline void *getAsVoidPointer(::clang::ExtQuals *P) { return P; }
- static inline ::clang::ExtQuals *getFromVoidPointer(void *P) {
- return static_cast< ::clang::ExtQuals*>(P);
- }
+ static inline ::clang::ExtQuals *getFromVoidPointer(void *P) {
+ return static_cast<::clang::ExtQuals *>(P);
+ }
- static constexpr int NumLowBitsAvailable = clang::TypeAlignmentInBits;
- };
+ static constexpr int NumLowBitsAvailable = clang::TypeAlignmentInBits;
+};
} // namespace llvm
@@ -339,11 +333,7 @@ class Qualifiers {
CVRMask = Const | Volatile | Restrict
};
- enum GC {
- GCNone = 0,
- Weak,
- Strong
- };
+ enum GC { GCNone = 0, Weak, Strong };
enum ObjCLifetime {
/// There is no lifetime qualification on this type.
@@ -496,9 +486,7 @@ class Qualifiers {
assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits");
Mask &= ~static_cast<uint64_t>(mask);
}
- void removeCVRQualifiers() {
- removeCVRQualifiers(CVRMask);
- }
+ void removeCVRQualifiers() { removeCVRQualifiers(CVRMask); }
void addCVRQualifiers(unsigned mask) {
assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits");
Mask |= mask;
@@ -509,9 +497,7 @@ class Qualifiers {
}
bool hasUnaligned() const { return Mask & UMask; }
- void setUnaligned(bool flag) {
- Mask = (Mask & ~UMask) | (flag ? UMask : 0);
- }
+ void setUnaligned(bool flag) { Mask = (Mask & ~UMask) | (flag ? UMask : 0); }
void removeUnaligned() { Mask &= ~UMask; }
void addUnaligned() { Mask |= UMask; }
@@ -590,8 +576,8 @@ class Qualifiers {
}
void setAddressSpace(LangAS space) {
assert((unsigned)space <= MaxAddressSpace);
- Mask = (Mask & ~AddressSpaceMask)
- | (((uint32_t) space) << AddressSpaceShift);
+ Mask =
+ (Mask & ~AddressSpaceMask) | (((uint32_t)space) << AddressSpaceShift);
}
void removeAddressSpace() { setAddressSpace(LangAS::Default); }
void addAddressSpace(LangAS space) {
@@ -625,9 +611,7 @@ class Qualifiers {
assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits");
Mask &= ~static_cast<uint64_t>(mask);
}
- void removeFastQualifiers() {
- removeFastQualifiers(FastMask);
- }
+ void removeFastQualifiers() { removeFastQualifiers(FastMask); }
void addFastQualifiers(unsigned mask) {
assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits");
Mask |= mask;
@@ -687,12 +671,12 @@ class Qualifiers {
/// Add the qualifiers from the given set to this set, given that
/// they don't conflict.
void addConsistentQualifiers(Qualifiers qs) {
- assert(getAddressSpace() == qs.getAddressSpace() ||
- !hasAddressSpace() || !qs.hasAddressSpace());
- assert(getObjCGCAttr() == qs.getObjCGCAttr() ||
- !hasObjCGCAttr() || !qs.hasObjCGCAttr());
- assert(getObjCLifetime() == qs.getObjCLifetime() ||
- !hasObjCLifetime() || !qs.hasObjCLifetime());
+ assert(getAddressSpace() == qs.getAddressSpace() || !hasAddressSpace() ||
+ !qs.hasAddressSpace());
+ assert(getObjCGCAttr() == qs.getObjCGCAttr() || !hasObjCGCAttr() ||
+ !qs.hasObjCGCAttr());
+ assert(getObjCLifetime() == qs.getObjCLifetime() || !hasObjCLifetime() ||
+ !qs.hasObjCLifetime());
assert(!hasPointerAuth() || !qs.hasPointerAuth() ||
getPointerAuth() == qs.getPointerAuth());
Mask |= qs.Mask;
@@ -880,7 +864,7 @@ struct SplitQualType {
SplitQualType getSingleStepDesugaredType() const; // end of this file
// Make std::tie work.
- std::pair<const Type *,Qualifiers> asPair() const {
+ std::pair<const Type *, Qualifiers> asPair() const {
return std::pair<const Type *, Qualifiers>(Ty, Quals);
}
@@ -939,7 +923,8 @@ class QualType {
// Thankfully, these are efficiently composable.
llvm::PointerIntPair<llvm::PointerUnion<const Type *, const ExtQuals *>,
- Qualifiers::FastWidth> Value;
+ Qualifiers::FastWidth>
+ Value;
const ExtQuals *getExtQualsUnsafe() const {
return cast<const ExtQuals *>(Value.getPointer());
@@ -953,7 +938,7 @@ class QualType {
assert(!isNull() && "Cannot retrieve a NULL type pointer");
auto CommonPtrVal = reinterpret_cast<uintptr_t>(Value.getOpaqueValue());
CommonPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1);
- return reinterpret_cast<ExtQualsTypeCommonBase*>(CommonPtrVal);
+ return reinterpret_cast<ExtQualsTypeCommonBase *>(CommonPtrVal);
}
public:
@@ -985,25 +970,19 @@ class QualType {
static QualType getFromOpaquePtr(const void *Ptr) {
QualType T;
- T.Value.setFromOpaqueValue(const_cast<void*>(Ptr));
+ T.Value.setFromOpaqueValue(const_cast<void *>(Ptr));
return T;
}
- const Type &operator*() const {
- return *getTypePtr();
- }
+ const Type &operator*() const { return *getTypePtr(); }
- const Type *operator->() const {
- return getTypePtr();
- }
+ const Type *operator->() const { return getTypePtr(); }
bool isCanonical() const;
bool isCanonicalAsParam() const;
/// Return true if this QualType doesn't point to a type yet.
- bool isNull() const {
- return Value.getPointer().isNull();
- }
+ bool isNull() const { return Value.getPointer().isNull(); }
// Determines if a type can form `T&`.
bool isReferenceable() const;
@@ -1086,15 +1065,13 @@ class QualType {
/// Retrieve the set of CVR (const-volatile-restrict) qualifiers
/// local to this particular QualType instance, not including any qualifiers
/// acquired through typedefs or other sugar.
- unsigned getLocalCVRQualifiers() const {
- return getLocalFastQualifiers();
- }
+ unsigned getLocalCVRQualifiers() const { return getLocalFastQualifiers(); }
/// Retrieve the set of CVR (const-volatile-restrict) qualifiers
/// applied to this type.
unsigned getCVRQualifiers() const;
- bool isConstant(const ASTContext& Ctx) const {
+ bool isConstant(const ASTContext &Ctx) const {
return QualType::isConstant(*this, Ctx);
}
@@ -1164,25 +1141,17 @@ class QualType {
// easily added.
/// Add the `const` type qualifier to this QualType.
- void addConst() {
- addFastQualifiers(Qualifiers::Const);
- }
- QualType withConst() const {
- return withFastQualifiers(Qualifiers::Const);
- }
+ void addConst() { addFastQualifiers(Qualifiers::Const); }
+ QualType withConst() const { return withFastQualifiers(Qualifiers::Const); }
/// Add the `volatile` type qualifier to this QualType.
- void addVolatile() {
- addFastQualifiers(Qualifiers::Volatile);
- }
+ void addVolatile() { addFastQualifiers(Qualifiers::Volatile); }
QualType withVolatile() const {
return withFastQualifiers(Qualifiers::Volatile);
}
/// Add the `restrict` qualifier to this QualType.
- void addRestrict() {
- addFastQualifiers(Qualifiers::Restrict);
- }
+ void addRestrict() { addFastQualifiers(Qualifiers::Restrict); }
QualType withRestrict() const {
return withFastQualifiers(Qualifiers::Restrict);
}
@@ -1192,8 +1161,8 @@ class QualType {
}
void addFastQualifiers(unsigned TQs) {
- assert(!(TQs & ~Qualifiers::FastMask)
- && "non-fast qualifier bits set in mask!");
+ assert(!(TQs & ~Qualifiers::FastMask) &&
+ "non-fast qualifier bits set in mask!");
Value.setInt(Value.getInt() | TQs);
}
@@ -1360,9 +1329,8 @@ class QualType {
return print(split.Ty, split.Quals, OS, policy, PlaceHolder, Indentation);
}
- static void print(const Type *ty, Qualifiers qs,
- raw_ostream &OS, const PrintingPolicy &policy,
- const Twine &PlaceHolder,
+ static void print(const Type *ty, Qualifiers qs, raw_ostream &OS,
+ const PrintingPolicy &policy, const Twine &PlaceHolder,
unsigned Indentation = 0);
void getAsStringInternal(std::string &Str,
@@ -1436,14 +1404,10 @@ class QualType {
inline Qualifiers::GC getObjCGCAttr() const;
/// true when Type is objc's weak.
- bool isObjCGCWeak() const {
- return getObjCGCAttr() == Qualifiers::Weak;
- }
+ bool isObjCGCWeak() const { return getObjCGCAttr() == Qualifiers::Weak; }
/// true when Type is objc's strong.
- bool isObjCGCStrong() const {
- return getObjCGCAttr() == Qualifiers::Strong;
- }
+ bool isObjCGCStrong() const { return getObjCGCAttr() == Qualifiers::Strong; }
/// Returns lifetime attribute of this type.
Qualifiers::ObjCLifetime getObjCLifetime() const {
@@ -1599,8 +1563,7 @@ class QualType {
/// \param context The context in which the subject type was written.
///
/// \returns the resulting type.
- QualType substObjCTypeArgs(ASTContext &ctx,
- ArrayRef<QualType> typeArgs,
+ QualType substObjCTypeArgs(ASTContext &ctx, ArrayRef<QualType> typeArgs,
ObjCSubstitutionContext context) const;
/// Substitute type arguments from an object type for the Objective-C type
@@ -1623,8 +1586,7 @@ class QualType {
///
/// \returns the subject type after replacing all of the Objective-C type
/// parameters with their corresponding arguments.
- QualType substObjCMemberType(QualType objectType,
- const DeclContext *dc,
+ QualType substObjCMemberType(QualType objectType, const DeclContext *dc,
ObjCSubstitutionContext context) const;
/// Strip Objective-C "__kindof" types from the given type.
@@ -1641,7 +1603,7 @@ class QualType {
// These methods are implemented in a separate translation unit;
// "static"-ize them to avoid creating temporary QualTypes in the
// caller.
- static bool isConstant(QualType T, const ASTContext& Ctx);
+ static bool isConstant(QualType T, const ASTContext &Ctx);
static QualType getDesugaredType(QualType T, const ASTContext &Context);
static SplitQualType getSplitDesugaredType(QualType T);
static SplitQualType getSplitUnqualifiedTypeImpl(QualType type);
@@ -1651,7 +1613,8 @@ class QualType {
static DestructionKind isDestructedTypeImpl(QualType type);
/// Check if \param RD is or contains a non-trivial C union.
- static bool hasNonTrivialToPrimitiveDefaultInitializeCUnion(const RecordDecl *RD);
+ static bool
+ hasNonTrivialToPrimitiveDefaultInitializeCUnion(const RecordDecl *RD);
static bool hasNonTrivialToPrimitiveDestructCUnion(const RecordDecl *RD);
static bool hasNonTrivialToPrimitiveCopyCUnion(const RecordDecl *RD);
};
@@ -1664,7 +1627,7 @@ namespace llvm {
/// Implement simplify_type for QualType, so that we can dyn_cast from QualType
/// to a specific Type class.
-template<> struct simplify_type< ::clang::QualType> {
+template <> struct simplify_type<::clang::QualType> {
using SimpleType = const ::clang::Type *;
static SimpleType getSimplifiedValue(::clang::QualType Val) {
@@ -1673,8 +1636,7 @@ template<> struct simplify_type< ::clang::QualType> {
};
// Teach SmallPtrSet that QualType is "basically a pointer".
-template<>
-struct PointerLikeTypeTraits<clang::QualType> {
+template <> struct PointerLikeTypeTraits<clang::QualType> {
static inline void *getAsVoidPointer(clang::QualType P) {
return P.getAsOpaquePtr();
}
@@ -1750,10 +1712,10 @@ class alignas(TypeAlignment) ExtQuals : public ExtQualsTypeCommonBase,
: ExtQualsTypeCommonBase(baseType,
canon.isNull() ? QualType(this_(), 0) : canon),
Quals(quals) {
- assert(Quals.hasNonFastQualifiers()
- && "ExtQuals created with no fast qualifiers");
- assert(!Quals.hasFastQualifiers()
- && "ExtQuals created with fast qualifiers");
+ assert(Quals.hasNonFastQualifiers() &&
+ "ExtQuals created with no fast qualifiers");
+ assert(!Quals.hasFastQualifiers() &&
+ "ExtQuals created with fast qualifiers");
}
Qualifiers getQualifiers() const { return Quals; }
@@ -1776,8 +1738,7 @@ class alignas(TypeAlignment) ExtQuals : public ExtQualsTypeCommonBase,
Profile(ID, getBaseType(), Quals);
}
- static void Profile(llvm::FoldingSetNodeID &ID,
- const Type *BaseType,
+ static void Profile(llvm::FoldingSetNodeID &ID, const Type *BaseType,
Qualifiers Quals) {
assert(!Quals.hasFastQualifiers() && "fast qualifiers in ExtQuals hash!");
ID.AddPointer(BaseType);
@@ -1908,9 +1869,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
LLVM_PREFERRED_TYPE(bool)
mutable unsigned FromAST : 1;
- bool isCacheValid() const {
- return CacheValid;
- }
+ bool isCacheValid() const { return CacheValid; }
Linkage getLinkage() const {
assert(isCacheValid() && "getting linkage from invalid cache");
@@ -2392,9 +2351,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
template <class T> friend class TypePropertyCache;
/// Set whether this type comes from an AST file.
- void setFromAST(bool V = true) const {
- TypeBits.FromAST = V;
- }
+ void setFromAST(bool V = true) const { TypeBits.FromAST = V; }
protected:
friend class ASTContext;
@@ -2533,11 +2490,13 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
/// class), will be set to the declaration.
bool isIncompleteType(NamedDecl **Def = nullptr) const;
+ /// Determines if this type is an implicit-lifetime type as defined in C++20
+ /// [basic.types.general]. Returns true if the type is implicit lifetime type.
+ bool isImplicitLifetimeType() const;
+
/// Return true if this is an incomplete or object
/// type, in other words, not a function type.
- bool isIncompleteOrObjectType() const {
- return !isFunctionType();
- }
+ bool isIncompleteOrObjectType() const { return !isFunctionType(); }
/// \returns True if the type is incomplete and it is also a type that
/// cannot be completed by a later type definition.
@@ -2602,7 +2561,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
/// isIntegerType() does *not* include complex integers (a GCC extension).
/// isComplexIntegerType() can be used to test for complex integers.
- bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum)
+ bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum)
bool isEnumeralType() const;
/// Determine whether this type is a scoped enumeration type.
@@ -2628,21 +2587,21 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double)
/// isComplexType() does *not* include complex integers (a GCC extension).
/// isComplexIntegerType() can be used to test for complex integers.
- bool isComplexType() const; // C99 6.2.5p11 (complex)
- bool isAnyComplexType() const; // C99 6.2.5p11 (complex) + Complex Int.
- bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex)
- bool isHalfType() const; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half)
- bool isFloat16Type() const; // C11 extension ISO/IEC TS 18661
+ bool isComplexType() const; // C99 6.2.5p11 (complex)
+ bool isAnyComplexType() const; // C99 6.2.5p11 (complex) + Complex Int.
+ bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex)
+ bool isHalfType() const; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half)
+ bool isFloat16Type() const; // C11 extension ISO/IEC TS 18661
bool isFloat32Type() const;
bool isDoubleType() const;
bool isBFloat16Type() const;
bool isMFloat8Type() const;
bool isFloat128Type() const;
bool isIbm128Type() const;
- bool isRealType() const; // C99 6.2.5p17 (real floating + integer)
- bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating)
- bool isVoidType() const; // C99 6.2.5p19
- bool isScalarType() const; // C99 6.2.5p21 (arithmetic + pointers)
+ bool isRealType() const; // C99 6.2.5p17 (real floating + integer)
+ bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating)
+ bool isVoidType() const; // C99 6.2.5p19
+ bool isScalarType() const; // C99 6.2.5p21 (arithmetic + pointers)
bool isAggregateType() const;
bool isFundamentalType() const;
bool isCompoundType() const;
@@ -2657,7 +2616,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
bool isSignableType(const ASTContext &Ctx) const;
bool isSignablePointerType() const;
bool isSignableIntegerType(const ASTContext &Ctx) const;
- bool isAnyPointerType() const; // Any C pointer or ObjC object pointer
+ bool isAnyPointerType() const; // Any C pointer or ObjC object pointer
bool isCountAttributedType() const;
bool isCFIUncheckedCalleeFunctionType() const;
bool hasPointeeToCFIUncheckedCalleeFunctionType() const;
@@ -2686,33 +2645,35 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
bool isInterfaceType() const;
bool isStructureOrClassType() const;
bool isUnionType() const;
- bool isComplexIntegerType() const; // GCC _Complex integer type.
- bool isVectorType() const; // GCC vector type.
- bool isExtVectorType() const; // Extended vector type.
- bool isExtVectorBoolType() const; // Extended vector type with bool element.
+ bool isComplexIntegerType() const; // GCC _Complex integer type.
+ bool isVectorType() const; // GCC vector type.
+ bool isExtVectorType() const; // Extended vector type.
+ bool isExtVectorBoolType() const; // Extended vector type with bool element.
bool isConstantMatrixBoolType() const; // Matrix type with bool element.
// Extended vector type with bool element that is packed. HLSL doesn't pack
// its bool vectors.
bool isPackedVectorBoolType(const ASTContext &ctx) const;
bool isSubscriptableVectorType() const;
- bool isMatrixType() const; // Matrix type.
- bool isConstantMatrixType() const; // Constant matrix type.
- bool isOverflowBehaviorType() const; // Overflow behavior type.
- bool isDependentAddressSpaceType() const; // value-dependent address space qualifier
- bool isObjCObjectPointerType() const; // pointer to ObjC object
- bool isObjCRetainableType() const; // ObjC object or block pointer
- bool isObjCLifetimeType() const; // (array of)* retainable type
- bool isObjCIndirectLifetimeType() const; // (pointer to)* lifetime type
- bool isObjCNSObjectType() const; // __attribute__((NSObject))
- bool isObjCIndependentClassType() cons...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/196286
More information about the libcxx-commits
mailing list