[libcxx-commits] [clang] [libcxx] [Clang][libc++] Implement C++23 std::start_lifetime_as (P2590R2, P2679R2) (PR #196286)
Yash Verma via libcxx-commits
libcxx-commits at lists.llvm.org
Thu May 7 04:12:11 PDT 2026
https://github.com/My-Bad-2 created https://github.com/llvm/llvm-project/pull/196286
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.
>From 40693914c62d5f86556fccf60fb2bd2f84dec800 Mon Sep 17 00:00:00 2001
From: Yash Verma <yashverma056 at proton.me>
Date: Thu, 7 May 2026 01:36:11 -0400
Subject: [PATCH 1/4] [Clang][AST] Implement isImplicitLifetimetype()
Adds `bool isImplicitLifetimeType() const` to `clang::Type` to map the C++20 [basic.types.general] rules to the AST. This methods recursively unwraps arrays and validates CXXRecordDecls for trivial constructors and destructors.
---
clang/include/clang/AST/TypeBase.h | 689 +++++++++++++----------------
clang/lib/AST/Type.cpp | 51 +++
2 files changed, 355 insertions(+), 385 deletions(-)
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() const; // __attribute__((objc_independent_class))
+ 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() const; // __attribute__((objc_independent_class))
// FIXME: change this to 'raw' interface type, so we can used 'interface' type
// for the common case.
- bool isObjCObjectType() const; // NSString or typeof(*(id)0)
- bool isObjCQualifiedInterfaceType() const; // NSString<foo>
- bool isObjCQualifiedIdType() const; // id<foo>
- bool isObjCQualifiedClassType() const; // Class<foo>
+ bool isObjCObjectType() const; // NSString or typeof(*(id)0)
+ bool isObjCQualifiedInterfaceType() const; // NSString<foo>
+ bool isObjCQualifiedIdType() const; // id<foo>
+ bool isObjCQualifiedClassType() const; // Class<foo>
bool isObjCObjectOrInterfaceType() const;
- bool isObjCIdType() const; // id
+ bool isObjCIdType() const; // id
bool isDecltypeType() const;
/// Was this type written with the special inert-in-ARC __unsafe_unretained
/// qualifier?
@@ -2734,7 +2695,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
bool isObjCIdOrObjectKindOfType(const ASTContext &ctx,
const ObjCObjectType *&bound) const;
- bool isObjCClassType() const; // Class
+ bool isObjCClassType() const; // Class
/// Whether the type is Objective-C 'Class' or a __kindof type of an
/// Class type, e.g., __kindof Class <NSCopying>.
@@ -2745,47 +2706,46 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
bool isObjCClassOrClassKindOfType() const;
bool isBlockCompatibleObjCPointerType(ASTContext &ctx) const;
- bool isObjCSelType() const; // Class
- bool isObjCBuiltinType() const; // 'id' or 'Class'
+ bool isObjCSelType() const; // Class
+ bool isObjCBuiltinType() const; // 'id' or 'Class'
bool isObjCARCBridgableType() const;
bool isCARCBridgableType() const;
- bool isTemplateTypeParmType() const; // C++ template type parameter
- bool isNullPtrType() const; // C++11 std::nullptr_t or
- // C23 nullptr_t
- bool isNothrowT() const; // C++ std::nothrow_t
- bool isAlignValT() const; // C++17 std::align_val_t
- bool isStdByteType() const; // C++17 std::byte
- bool isAtomicType() const; // C11 _Atomic()
- bool isUndeducedAutoType() const; // C++11 auto or
- // C++14 decltype(auto)
- bool isTypedefNameType() const; // typedef or alias template
-
-#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
+ bool isTemplateTypeParmType() const; // C++ template type parameter
+ bool isNullPtrType() const; // C++11 std::nullptr_t or
+ // C23 nullptr_t
+ bool isNothrowT() const; // C++ std::nothrow_t
+ bool isAlignValT() const; // C++17 std::align_val_t
+ bool isStdByteType() const; // C++17 std::byte
+ bool isAtomicType() const; // C11 _Atomic()
+ bool isUndeducedAutoType() const; // C++11 auto or
+ // C++14 decltype(auto)
+ bool isTypedefNameType() const; // typedef or alias template
+
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
bool is##Id##Type() const;
#include "clang/Basic/OpenCLImageTypes.def"
- bool isImageType() const; // Any OpenCL image type
+ bool isImageType() const; // Any OpenCL image type
- bool isSamplerT() const; // OpenCL sampler_t
- bool isEventT() const; // OpenCL event_t
- bool isClkEventT() const; // OpenCL clk_event_t
- bool isQueueT() const; // OpenCL queue_t
- bool isReserveIDT() const; // OpenCL reserve_id_t
+ bool isSamplerT() const; // OpenCL sampler_t
+ bool isEventT() const; // OpenCL event_t
+ bool isClkEventT() const; // OpenCL clk_event_t
+ bool isQueueT() const; // OpenCL queue_t
+ bool isReserveIDT() const; // OpenCL reserve_id_t
-#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
- bool is##Id##Type() const;
+#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) bool is##Id##Type() const;
#include "clang/Basic/OpenCLExtensionTypes.def"
// Type defined in cl_intel_device_side_avc_motion_estimation OpenCL extension
bool isOCLIntelSubgroupAVCType() const;
- bool isOCLExtOpaqueType() const; // Any OpenCL extension type
+ bool isOCLExtOpaqueType() const; // Any OpenCL extension type
- bool isPipeType() const; // OpenCL pipe type
- bool isBitIntType() const; // Bit-precise integer type
- bool isOpenCLSpecificType() const; // Any OpenCL specific type
+ bool isPipeType() const; // OpenCL pipe type
+ bool isBitIntType() const; // Bit-precise integer type
+ bool isOpenCLSpecificType() const; // Any OpenCL specific type
#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) bool is##Id##Type() const;
#include "clang/Basic/HLSLIntangibleTypes.def"
- bool isHLSLSpecificType() const; // Any HLSL specific type
+ bool isHLSLSpecificType() const; // Any HLSL specific type
bool isHLSLBuiltinIntangibleType() const; // Any HLSL builtin intangible type
bool isHLSLAttributedResourceType() const;
bool isHLSLInlineSpirvType() const;
@@ -3171,9 +3131,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
const char *getTypeClassName() const;
- QualType getCanonicalTypeInternal() const {
- return CanonicalType;
- }
+ QualType getCanonicalTypeInternal() const { return CanonicalType; }
CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h
void dump() const;
@@ -3277,9 +3235,7 @@ class BuiltinType : public Type {
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
- bool isInteger() const {
- return getKind() >= Bool && getKind() <= Int128;
- }
+ bool isInteger() const { return getKind() >= Bool && getKind() <= Int128; }
bool isSignedInteger() const {
return getKind() >= Char_S && getKind() <= Int128;
@@ -3298,16 +3254,12 @@ class BuiltinType : public Type {
bool isSVECount() const { return getKind() == Kind::SveCount; }
/// Determines whether the given kind corresponds to a placeholder type.
- static bool isPlaceholderTypeKind(Kind K) {
- return K >= Overload;
- }
+ static bool isPlaceholderTypeKind(Kind K) { return K >= Overload; }
/// Determines whether this type is a placeholder type, i.e. a type
/// which cannot appear in arbitrary positions in a fully-formed
/// expression.
- bool isPlaceholderType() const {
- return isPlaceholderTypeKind(getKind());
- }
+ bool isPlaceholderType() const { return isPlaceholderTypeKind(getKind()); }
/// Determines whether this type is a placeholder type other than
/// Overload. Most placeholder types require only syntactic
@@ -3318,9 +3270,7 @@ class BuiltinType : public Type {
/// from their context, like whether the context expects a
/// specific function-pointer type, and so frequently need
/// special treatment.
- bool isNonOverloadPlaceholderType() const {
- return getKind() > Overload;
- }
+ bool isNonOverloadPlaceholderType() const { return getKind() > Overload; }
static bool classof(const Type *T) { return T->getTypeClass() == Builtin; }
};
@@ -3342,9 +3292,7 @@ class ComplexType : public Type, public llvm::FoldingSetNode {
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getElementType());
- }
+ void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType()); }
static void Profile(llvm::FoldingSetNodeID &ID, QualType Element) {
ID.AddPointer(Element.getAsOpaquePtr());
@@ -3368,9 +3316,7 @@ class ParenType : public Type, public llvm::FoldingSetNode {
bool isSugared() const { return true; }
QualType desugar() const { return getInnerType(); }
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getInnerType());
- }
+ void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getInnerType()); }
static void Profile(llvm::FoldingSetNodeID &ID, QualType Inner) {
Inner.Profile(ID);
@@ -3395,9 +3341,7 @@ class PointerType : public Type, public llvm::FoldingSetNode {
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getPointeeType());
- }
+ void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType()); }
static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) {
ID.AddPointer(Pointee.getAsOpaquePtr());
@@ -3580,8 +3524,8 @@ class AdjustedType : public Type, public llvm::FoldingSetNode {
class DecayedType : public AdjustedType {
friend class ASTContext; // ASTContext creates these.
- inline
- DecayedType(QualType OriginalType, QualType Decayed, QualType Canonical);
+ inline DecayedType(QualType OriginalType, QualType Decayed,
+ QualType Canonical);
public:
QualType getDecayedType() const { return getAdjustedType(); }
@@ -3611,12 +3555,10 @@ class BlockPointerType : public Type, public llvm::FoldingSetNode {
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getPointeeType());
- }
+ void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType()); }
static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) {
- ID.AddPointer(Pointee.getAsOpaquePtr());
+ ID.AddPointer(Pointee.getAsOpaquePtr());
}
static bool classof(const Type *T) {
@@ -3655,8 +3597,7 @@ class ReferenceType : public Type, public llvm::FoldingSetNode {
Profile(ID, PointeeType, isSpelledAsLValue());
}
- static void Profile(llvm::FoldingSetNodeID &ID,
- QualType Referencee,
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType Referencee,
bool SpelledAsLValue) {
ID.AddPointer(Referencee.getAsOpaquePtr());
ID.AddBoolean(SpelledAsLValue);
@@ -3691,7 +3632,7 @@ class RValueReferenceType : public ReferenceType {
friend class ASTContext; // ASTContext creates these
RValueReferenceType(QualType Referencee, QualType CanonicalRef)
- : ReferenceType(RValueReference, Referencee, CanonicalRef, false) {}
+ : ReferenceType(RValueReference, Referencee, CanonicalRef, false) {}
public:
bool isSugared() const { return false; }
@@ -3964,8 +3905,8 @@ class ArrayParameterType : public ConstantArrayType {
class IncompleteArrayType : public ArrayType {
friend class ASTContext; // ASTContext creates these.
- IncompleteArrayType(QualType et, QualType can,
- ArraySizeModifier sm, unsigned tq)
+ IncompleteArrayType(QualType et, QualType can, ArraySizeModifier sm,
+ unsigned tq)
: ArrayType(IncompleteArray, et, can, sm, tq) {}
public:
@@ -4035,7 +3976,7 @@ class VariableArrayType : public ArrayType {
Expr *getSizeExpr() const {
// We use C-style casts instead of cast<> here because we do not wish
// to have a dependency of Type.h on Stmt.h/Expr.h.
- return (Expr*) SizeExpr;
+ return (Expr *)SizeExpr;
}
bool isSugared() const { return false; }
@@ -4082,7 +4023,7 @@ class DependentSizedArrayType : public ArrayType {
Expr *getSizeExpr() const {
// We use C-style casts instead of cast<> here because we do not wish
// to have a dependency of Type.h on Stmt.h/Expr.h.
- return (Expr*) SizeExpr;
+ return (Expr *)SizeExpr;
}
bool isSugared() const { return false; }
@@ -4093,8 +4034,8 @@ class DependentSizedArrayType : public ArrayType {
}
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
- Profile(ID, Context, getElementType(),
- getSizeModifier(), getIndexTypeCVRQualifiers(), getSizeExpr());
+ Profile(ID, Context, getElementType(), getSizeModifier(),
+ getIndexTypeCVRQualifiers(), getSizeExpr());
}
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
@@ -4104,7 +4045,8 @@ class DependentSizedArrayType : public ArrayType {
/// Represents an extended address space qualifier where the input address space
/// value is dependent. Non-dependent address spaces are not represented with a
-/// special Type subclass; they are stored on an ExtQuals node as part of a QualType.
+/// special Type subclass; they are stored on an ExtQuals node as part of a
+/// QualType.
///
/// For example:
/// \code
@@ -4252,8 +4194,8 @@ class VectorType : public Type, public llvm::FoldingSetNode {
}
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getElementType(), getNumElements(),
- getTypeClass(), getVectorKind());
+ Profile(ID, getElementType(), getNumElements(), getTypeClass(),
+ getVectorKind());
}
static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType,
@@ -4329,39 +4271,65 @@ class ExtVectorType : public VectorType {
public:
static int getPointAccessorIdx(char c) {
switch (c) {
- default: return -1;
- case 'x': case 'r': return 0;
- case 'y': case 'g': return 1;
- case 'z': case 'b': return 2;
- case 'w': case 'a': return 3;
+ default:
+ return -1;
+ case 'x':
+ case 'r':
+ return 0;
+ case 'y':
+ case 'g':
+ return 1;
+ case 'z':
+ case 'b':
+ return 2;
+ case 'w':
+ case 'a':
+ return 3;
}
}
static int getNumericAccessorIdx(char c) {
switch (c) {
- default: return -1;
- case '0': return 0;
- case '1': return 1;
- case '2': return 2;
- case '3': return 3;
- case '4': return 4;
- case '5': return 5;
- case '6': return 6;
- case '7': return 7;
- case '8': return 8;
- case '9': return 9;
- case 'A':
- case 'a': return 10;
- case 'B':
- case 'b': return 11;
- case 'C':
- case 'c': return 12;
- case 'D':
- case 'd': return 13;
- case 'E':
- case 'e': return 14;
- case 'F':
- case 'f': return 15;
+ default:
+ return -1;
+ case '0':
+ return 0;
+ case '1':
+ return 1;
+ case '2':
+ return 2;
+ case '3':
+ return 3;
+ case '4':
+ return 4;
+ case '5':
+ return 5;
+ case '6':
+ return 6;
+ case '7':
+ return 7;
+ case '8':
+ return 8;
+ case '9':
+ return 9;
+ case 'A':
+ case 'a':
+ return 10;
+ case 'B':
+ case 'b':
+ return 11;
+ case 'C':
+ case 'c':
+ return 12;
+ case 'D':
+ case 'd':
+ return 13;
+ case 'E':
+ case 'e':
+ return 14;
+ case 'F':
+ case 'f':
+ return 15;
}
}
@@ -4373,17 +4341,15 @@ class ExtVectorType : public VectorType {
}
bool isAccessorWithinNumElements(char c, bool isNumericAccessor) const {
- if (int idx = getAccessorIdx(c, isNumericAccessor)+1)
- return unsigned(idx-1) < getNumElements();
+ if (int idx = getAccessorIdx(c, isNumericAccessor) + 1)
+ return unsigned(idx - 1) < getNumElements();
return false;
}
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
- static bool classof(const Type *T) {
- return T->getTypeClass() == ExtVector;
- }
+ static bool classof(const Type *T) { return T->getTypeClass() == ExtVector; }
};
/// Represents a matrix type, as defined in the Matrix Types clang extensions.
@@ -4716,7 +4682,9 @@ class FunctionType : public Type {
bool getCmseNSCall() const { return Bits & CmseNSCallMask; }
bool getNoCallerSavedRegs() const { return Bits & NoCallerSavedRegsMask; }
bool getNoCfCheck() const { return Bits & NoCfCheckMask; }
- bool getHasRegParm() const { return ((Bits & RegParmMask) >> RegParmOffset) != 0; }
+ bool getHasRegParm() const {
+ return ((Bits & RegParmMask) >> RegParmOffset) != 0;
+ }
unsigned getRegParm() const {
unsigned RegParm = (Bits & RegParmMask) >> RegParmOffset;
@@ -4727,12 +4695,8 @@ class FunctionType : public Type {
CallingConv getCC() const { return CallingConv(Bits & CallConvMask); }
- bool operator==(ExtInfo Other) const {
- return Bits == Other.Bits;
- }
- bool operator!=(ExtInfo Other) const {
- return Bits != Other.Bits;
- }
+ bool operator==(ExtInfo Other) const { return Bits == Other.Bits; }
+ bool operator!=(ExtInfo Other) const { return Bits != Other.Bits; }
// Note that we don't have setters. That is by design, use
// the following with methods instead of mutating these objects.
@@ -4774,23 +4738,22 @@ class FunctionType : public Type {
ExtInfo withRegParm(unsigned RegParm) const {
assert(RegParm < 7 && "Invalid regparm value");
- return ExtInfo((Bits & ~RegParmMask) |
- ((RegParm + 1) << RegParmOffset));
+ return ExtInfo((Bits & ~RegParmMask) | ((RegParm + 1) << RegParmOffset));
}
ExtInfo withCallingConv(CallingConv cc) const {
- return ExtInfo((Bits & ~CallConvMask) | (unsigned) cc);
+ return ExtInfo((Bits & ~CallConvMask) | (unsigned)cc);
}
- void Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddInteger(Bits);
- }
+ void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Bits); }
};
/// A simple holder for a QualType representing a type in an
/// exception specification. Unfortunately needed by FunctionProtoType
/// because TrailingObjects cannot handle repeated types.
- struct ExceptionType { QualType Type; };
+ struct ExceptionType {
+ QualType Type;
+ };
/// A simple holder for various uncommon bits which do not fit in
/// FunctionTypeBitfields. Aligned to alignof(void *) to maintain the
@@ -5617,7 +5580,6 @@ class FunctionProtoType final
FunctionTypeBits.HasExtraBitfields) &&
"ExtraBitfields are required for given ExceptionSpecType");
return FunctionTypeBits.HasExtraBitfields;
-
}
bool hasExtraAttributeInfo() const {
@@ -5632,9 +5594,7 @@ class FunctionProtoType final
->HasArmTypeAttributes;
}
- bool hasExtQualifiers() const {
- return FunctionTypeBits.HasExtQuals;
- }
+ bool hasExtQualifiers() const { return FunctionTypeBits.HasExtQuals; }
public:
unsigned getNumParams() const { return FunctionTypeBits.NumParams; }
@@ -6747,9 +6707,7 @@ class AttributedType : public Type, public llvm::FoldingSetNode {
ID.AddPointer(attr);
}
- static bool classof(const Type *T) {
- return T->getTypeClass() == Attributed;
- }
+ static bool classof(const Type *T) { return T->getTypeClass() == Attributed; }
};
class BTFTagAttributedType : public Type, public llvm::FoldingSetNode {
@@ -7329,9 +7287,7 @@ class AutoType : public DeducedType, public llvm::FoldingSetNode {
return TypeConstraintConcept;
}
- bool isConstrained() const {
- return TypeConstraintConcept != nullptr;
- }
+ bool isConstrained() const { return TypeConstraintConcept != nullptr; }
bool isDecltypeAuto() const {
return getKeyword() == AutoTypeKeyword::DecltypeAuto;
@@ -7350,9 +7306,7 @@ class AutoType : public DeducedType, public llvm::FoldingSetNode {
DeducedKind DK, QualType Deduced, AutoTypeKeyword Keyword,
TemplateDecl *CD, ArrayRef<TemplateArgument> Arguments);
- static bool classof(const Type *T) {
- return T->getTypeClass() == Auto;
- }
+ static bool classof(const Type *T) { return T->getTypeClass() == Auto; }
};
/// Represents a C++17 deduced template specialization type.
@@ -7510,8 +7464,7 @@ class TemplateSpecializationType : public TypeWithKeyword,
/// Print a template argument list, including the '<' and '>'
/// enclosing the template arguments.
-void printTemplateArgumentList(raw_ostream &OS,
- ArrayRef<TemplateArgument> Args,
+void printTemplateArgumentList(raw_ostream &OS, ArrayRef<TemplateArgument> Args,
const PrintingPolicy &Policy,
const TemplateParameterList *TPL = nullptr);
@@ -7569,9 +7522,7 @@ class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode {
/// Retrieve the identifier that terminates this type name.
/// For example, "type" in "typename T::type".
- const IdentifierInfo *getIdentifier() const {
- return Name;
- }
+ const IdentifierInfo *getIdentifier() const { return Name; }
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
@@ -7665,21 +7616,20 @@ class PackExpansionType : public Type, public llvm::FoldingSetNode {
/// This class wraps the list of protocol qualifiers. For types that can
/// take ObjC protocol qualifers, they can subclass this class.
-template <class T>
-class ObjCProtocolQualifiers {
+template <class T> class ObjCProtocolQualifiers {
protected:
ObjCProtocolQualifiers() = default;
- ObjCProtocolDecl * const *getProtocolStorage() const {
- return const_cast<ObjCProtocolQualifiers*>(this)->getProtocolStorage();
+ ObjCProtocolDecl *const *getProtocolStorage() const {
+ return const_cast<ObjCProtocolQualifiers *>(this)->getProtocolStorage();
}
ObjCProtocolDecl **getProtocolStorage() {
- return static_cast<T*>(this)->getProtocolStorageImpl();
+ return static_cast<T *>(this)->getProtocolStorageImpl();
}
void setNumProtocols(unsigned N) {
- static_cast<T*>(this)->setNumProtocolsImpl(N);
+ static_cast<T *>(this)->setNumProtocolsImpl(N);
}
void initialize(ArrayRef<ObjCProtocolDecl *> protocols) {
@@ -7688,11 +7638,11 @@ class ObjCProtocolQualifiers {
"bitfield overflow in protocol count");
if (!protocols.empty())
memcpy(getProtocolStorage(), protocols.data(),
- protocols.size() * sizeof(ObjCProtocolDecl*));
+ protocols.size() * sizeof(ObjCProtocolDecl *));
}
public:
- using qual_iterator = ObjCProtocolDecl * const *;
+ using qual_iterator = ObjCProtocolDecl *const *;
using qual_range = llvm::iterator_range<qual_iterator>;
qual_range quals() const { return qual_range(qual_begin(), qual_end()); }
@@ -7704,7 +7654,7 @@ class ObjCProtocolQualifiers {
/// Return the number of qualifying protocols in this type, or 0 if
/// there are none.
unsigned getNumProtocols() const {
- return static_cast<const T*>(this)->getNumProtocolsImpl();
+ return static_cast<const T *>(this)->getNumProtocolsImpl();
}
/// Fetch a protocol by index.
@@ -7739,16 +7689,11 @@ class ObjCTypeParamType : public Type,
/// Return the number of qualifying protocols in this interface type,
/// or 0 if there are none.
- unsigned getNumProtocolsImpl() const {
- return NumProtocols;
- }
+ unsigned getNumProtocolsImpl() const { return NumProtocols; }
- void setNumProtocolsImpl(unsigned N) {
- NumProtocols = N;
- }
+ void setNumProtocolsImpl(unsigned N) { NumProtocols = N; }
- ObjCTypeParamType(const ObjCTypeParamDecl *D,
- QualType can,
+ ObjCTypeParamType(const ObjCTypeParamDecl *D, QualType can,
ArrayRef<ObjCProtocolDecl *> protocols);
public:
@@ -7761,8 +7706,7 @@ class ObjCTypeParamType : public Type,
void Profile(llvm::FoldingSetNodeID &ID);
static void Profile(llvm::FoldingSetNodeID &ID,
- const ObjCTypeParamDecl *OTPDecl,
- QualType CanonicalType,
+ const ObjCTypeParamDecl *OTPDecl, QualType CanonicalType,
ArrayRef<ObjCProtocolDecl *> protocols);
ObjCTypeParamDecl *getDecl() const { return OTPDecl; }
@@ -7817,7 +7761,7 @@ class ObjCObjectType : public Type,
/// Cached superclass type.
mutable llvm::PointerIntPair<const ObjCObjectType *, 1, bool>
- CachedSuperClassType;
+ CachedSuperClassType;
QualType *getTypeArgStorage();
const QualType *getTypeArgStorage() const {
@@ -7830,17 +7774,13 @@ class ObjCObjectType : public Type,
unsigned getNumProtocolsImpl() const {
return ObjCObjectTypeBits.NumProtocols;
}
- void setNumProtocolsImpl(unsigned N) {
- ObjCObjectTypeBits.NumProtocols = N;
- }
+ void setNumProtocolsImpl(unsigned N) { ObjCObjectTypeBits.NumProtocols = N; }
protected:
enum Nonce_ObjCInterface { Nonce_ObjCInterface };
- ObjCObjectType(QualType Canonical, QualType Base,
- ArrayRef<QualType> typeArgs,
- ArrayRef<ObjCProtocolDecl *> protocols,
- bool isKindOf);
+ ObjCObjectType(QualType Canonical, QualType Base, ArrayRef<QualType> typeArgs,
+ ArrayRef<ObjCProtocolDecl *> protocols, bool isKindOf);
ObjCObjectType(enum Nonce_ObjCInterface)
: Type(ObjCInterface, QualType(), TypeDependence::None),
@@ -7872,7 +7812,8 @@ class ObjCObjectType : public Type,
bool isObjCUnqualifiedId() const { return qual_empty() && isObjCId(); }
bool isObjCUnqualifiedClass() const { return qual_empty() && isObjCClass(); }
bool isObjCUnqualifiedIdOrClass() const {
- if (!qual_empty()) return false;
+ if (!qual_empty())
+ return false;
if (const BuiltinType *T = getBaseType()->getAs<BuiltinType>())
return T->getKind() == BuiltinType::ObjCId ||
T->getKind() == BuiltinType::ObjCClass;
@@ -7956,31 +7897,29 @@ class ObjCObjectTypeImpl : public ObjCObjectType, public llvm::FoldingSetNode {
ObjCObjectTypeImpl(QualType Canonical, QualType Base,
ArrayRef<QualType> typeArgs,
- ArrayRef<ObjCProtocolDecl *> protocols,
- bool isKindOf)
+ ArrayRef<ObjCProtocolDecl *> protocols, bool isKindOf)
: ObjCObjectType(Canonical, Base, typeArgs, protocols, isKindOf) {}
public:
void Profile(llvm::FoldingSetNodeID &ID);
- static void Profile(llvm::FoldingSetNodeID &ID,
- QualType Base,
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType Base,
ArrayRef<QualType> typeArgs,
- ArrayRef<ObjCProtocolDecl *> protocols,
- bool isKindOf);
+ ArrayRef<ObjCProtocolDecl *> protocols, bool isKindOf);
};
inline QualType *ObjCObjectType::getTypeArgStorage() {
- return reinterpret_cast<QualType *>(static_cast<ObjCObjectTypeImpl*>(this)+1);
+ return reinterpret_cast<QualType *>(static_cast<ObjCObjectTypeImpl *>(this) +
+ 1);
}
inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorageImpl() {
- return reinterpret_cast<ObjCProtocolDecl**>(
- getTypeArgStorage() + ObjCObjectTypeBits.NumTypeArgs);
+ return reinterpret_cast<ObjCProtocolDecl **>(getTypeArgStorage() +
+ ObjCObjectTypeBits.NumTypeArgs);
}
inline ObjCProtocolDecl **ObjCTypeParamType::getProtocolStorageImpl() {
- return reinterpret_cast<ObjCProtocolDecl**>(
- static_cast<ObjCTypeParamType*>(this)+1);
+ return reinterpret_cast<ObjCProtocolDecl **>(
+ static_cast<ObjCTypeParamType *>(this) + 1);
}
/// Interfaces are the core concept in Objective-C for object oriented design.
@@ -8004,7 +7943,7 @@ class ObjCInterfaceType : public ObjCObjectType {
ObjCInterfaceType(const ObjCInterfaceDecl *D)
: ObjCObjectType(Nonce_ObjCInterface),
- Decl(const_cast<ObjCInterfaceDecl*>(D)) {}
+ Decl(const_cast<ObjCInterfaceDecl *>(D)) {}
public:
/// Get the declaration of this interface.
@@ -8021,13 +7960,7 @@ class ObjCInterfaceType : public ObjCObjectType {
// class. People asking for protocols on an ObjCInterfaceType are
// not going to get what they want: ObjCInterfaceTypes are
// guaranteed to have no protocols.
- enum {
- qual_iterator,
- qual_begin,
- qual_end,
- getNumProtocols,
- getProtocol
- };
+ enum { qual_iterator, qual_begin, qual_end, getNumProtocols, getProtocol };
};
inline ObjCInterfaceDecl *ObjCObjectType::getInterface() const {
@@ -8109,9 +8042,7 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
/// True if this is equivalent to the 'id' type, i.e. if
/// its object type is the primitive 'id' type with no protocols.
- bool isObjCIdType() const {
- return getObjectType()->isObjCUnqualifiedId();
- }
+ bool isObjCIdType() const { return getObjectType()->isObjCUnqualifiedId(); }
/// True if this is equivalent to the 'Class' type,
/// i.e. if its object tive is the primitive 'Class' type with no protocols.
@@ -8172,13 +8103,9 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
qual_range quals() const { return qual_range(qual_begin(), qual_end()); }
- qual_iterator qual_begin() const {
- return getObjectType()->qual_begin();
- }
+ qual_iterator qual_begin() const { return getObjectType()->qual_begin(); }
- qual_iterator qual_end() const {
- return getObjectType()->qual_end();
- }
+ qual_iterator qual_end() const { return getObjectType()->qual_end(); }
bool qual_empty() const { return getObjectType()->qual_empty(); }
@@ -8205,12 +8132,10 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
/// Strip off the Objective-C "kindof" type and (with it) any
/// protocol qualifiers.
- const ObjCObjectPointerType *stripObjCKindOfTypeAndQuals(
- const ASTContext &ctx) const;
+ const ObjCObjectPointerType *
+ stripObjCKindOfTypeAndQuals(const ASTContext &ctx) const;
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getPointeeType());
- }
+ void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType()); }
static void Profile(llvm::FoldingSetNodeID &ID, QualType T) {
ID.AddPointer(T.getAsOpaquePtr());
@@ -8237,17 +8162,13 @@ class AtomicType : public Type, public llvm::FoldingSetNode {
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getValueType());
- }
+ void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getValueType()); }
static void Profile(llvm::FoldingSetNodeID &ID, QualType T) {
ID.AddPointer(T.getAsOpaquePtr());
}
- static bool classof(const Type *T) {
- return T->getTypeClass() == Atomic;
- }
+ static bool classof(const Type *T) { return T->getTypeClass() == Atomic; }
};
/// PipeType - OpenCL20.
@@ -8277,9 +8198,7 @@ class PipeType : public Type, public llvm::FoldingSetNode {
ID.AddBoolean(isRead);
}
- static bool classof(const Type *T) {
- return T->getTypeClass() == Pipe;
- }
+ static bool classof(const Type *T) { return T->getTypeClass() == Pipe; }
bool isReadOnly() const { return isRead; }
};
@@ -8317,7 +8236,7 @@ class BitIntType final : public Type, public llvm::FoldingSetNode {
class DependentBitIntType final : public Type, public llvm::FoldingSetNode {
friend class ASTContext;
- llvm::PointerIntPair<Expr*, 1, bool> ExprAndUnsigned;
+ llvm::PointerIntPair<Expr *, 1, bool> ExprAndUnsigned;
protected:
DependentBitIntType(bool IsUnsigned, Expr *NumBits);
@@ -8394,7 +8313,7 @@ class QualifierCollector : public Qualifiers {
QualType apply(const ASTContext &Context, QualType QT) const;
/// Apply the collected qualifiers to the given type.
- QualType apply(const ASTContext &Context, const Type* T) const;
+ QualType apply(const ASTContext &Context, const Type *T) const;
};
/// A container of type source information.
@@ -8428,7 +8347,7 @@ class alignas(8) TypeSourceInfo {
inline SplitQualType SplitQualType::getSingleStepDesugaredType() const {
SplitQualType desugar =
- Ty->getLocallyUnqualifiedSingleStepDesugaredType().split();
+ Ty->getLocallyUnqualifiedSingleStepDesugaredType().split();
desugar.Quals.addConsistentQualifiers(Quals);
return desugar;
}
@@ -8495,8 +8414,10 @@ inline bool QualType::isCanonical() const {
}
inline bool QualType::isCanonicalAsParam() const {
- if (!isCanonical()) return false;
- if (hasLocalQualifiers()) return false;
+ if (!isCanonical())
+ return false;
+ if (hasLocalQualifiers())
+ return false;
const Type *T = getTypePtr();
if (T->isVariablyModifiedType() && T->hasSizedVLAType())
@@ -8516,7 +8437,6 @@ inline bool QualType::isRestrictQualified() const {
getCommonPtr()->CanonicalType.isLocalRestrictQualified();
}
-
inline bool QualType::isVolatileQualified() const {
return isLocalVolatileQualified() ||
getCommonPtr()->CanonicalType.isLocalVolatileQualified();
@@ -8634,8 +8554,7 @@ inline bool QualType::isCForbiddenLValueType() const {
///
/// \returns True for types specified in C++0x [basic.fundamental].
inline bool Type::isFundamentalType() const {
- return isVoidType() ||
- isNullPtrType() ||
+ return isVoidType() || isNullPtrType() ||
// FIXME: It's really annoying that we don't have an
// 'isArithmeticType()' which agrees with the standard definition.
(isArithmeticType() && !isEnumeralType());
@@ -8649,20 +8568,23 @@ inline bool Type::isCompoundType() const {
// Compound types can be constructed in the following ways:
// -- arrays of objects of a given type [...];
return isArrayType() ||
- // -- functions, which have parameters of given types [...];
+ // -- functions, which have parameters of given types [...];
isFunctionType() ||
- // -- pointers to void or objects or functions [...];
+ // -- pointers to void or objects or functions [...];
isPointerType() ||
- // -- references to objects or functions of a given type. [...]
+ // -- references to objects or functions of a given type. [...]
isReferenceType() ||
- // -- classes containing a sequence of objects of various types, [...];
+ // -- classes containing a sequence of objects of various types,
+ // [...];
isRecordType() ||
- // -- unions, which are classes capable of containing objects of different
- // types at different times;
+ // -- unions, which are classes capable of containing objects of
+ // different
+ // types at different times;
isUnionType() ||
- // -- enumerations, which comprise a set of named constant values. [...];
+ // -- enumerations, which comprise a set of named constant values.
+ // [...];
isEnumeralType() ||
- // -- pointers to non-static class members, [...].
+ // -- pointers to non-static class members, [...].
isMemberPointerType();
}
@@ -8769,9 +8691,7 @@ inline bool Type::isMemberDataPointerType() const {
return false;
}
-inline bool Type::isArrayType() const {
- return isa<ArrayType>(CanonicalType);
-}
+inline bool Type::isArrayType() const { return isa<ArrayType>(CanonicalType); }
inline bool Type::isConstantArrayType() const {
return isa<ConstantArrayType>(CanonicalType);
@@ -8859,7 +8779,7 @@ inline bool Type::isObjCObjectType() const {
inline bool Type::isObjCObjectOrInterfaceType() const {
return isa<ObjCInterfaceType>(CanonicalType) ||
- isa<ObjCObjectType>(CanonicalType);
+ isa<ObjCObjectType>(CanonicalType);
}
inline bool Type::isAtomicType() const {
@@ -8904,13 +8824,11 @@ inline bool Type::isObjCBuiltinType() const {
return isObjCIdType() || isObjCClassType() || isObjCSelType();
}
-inline bool Type::isDecltypeType() const {
- return isa<DecltypeType>(this);
-}
+inline bool Type::isDecltypeType() const { return isa<DecltypeType>(this); }
-#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
- inline bool Type::is##Id##Type() const { \
- return isSpecificBuiltinType(BuiltinType::Id); \
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
+ inline bool Type::is##Id##Type() const { \
+ return isSpecificBuiltinType(BuiltinType::Id); \
}
#include "clang/Basic/OpenCLImageTypes.def"
@@ -8941,33 +8859,31 @@ inline bool Type::isImageType() const {
false; // end boolean or operation
}
-inline bool Type::isPipeType() const {
- return isa<PipeType>(CanonicalType);
-}
+inline bool Type::isPipeType() const { return isa<PipeType>(CanonicalType); }
inline bool Type::isBitIntType() const {
return isa<BitIntType>(CanonicalType);
}
-#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
- inline bool Type::is##Id##Type() const { \
- return isSpecificBuiltinType(BuiltinType::Id); \
+#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
+ inline bool Type::is##Id##Type() const { \
+ return isSpecificBuiltinType(BuiltinType::Id); \
}
#include "clang/Basic/OpenCLExtensionTypes.def"
inline bool Type::isOCLIntelSubgroupAVCType() const {
-#define INTEL_SUBGROUP_AVC_TYPE(ExtType, Id) \
+#define INTEL_SUBGROUP_AVC_TYPE(ExtType, Id) \
isOCLIntelSubgroupAVC##Id##Type() ||
return
#include "clang/Basic/OpenCLExtensionTypes.def"
- false; // end of boolean or operation
+ false; // end of boolean or operation
}
inline bool Type::isOCLExtOpaqueType() const {
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) is##Id##Type() ||
return
#include "clang/Basic/OpenCLExtensionTypes.def"
- false; // end of boolean or operation
+ false; // end of boolean or operation
}
inline bool Type::isOpenCLSpecificType() const {
@@ -9026,7 +8942,7 @@ inline const BuiltinType *Type::getAsPlaceholderType() const {
}
inline bool Type::isSpecificPlaceholderType(unsigned K) const {
- assert(BuiltinType::isPlaceholderTypeKind((BuiltinType::Kind) K));
+ assert(BuiltinType::isPlaceholderTypeKind((BuiltinType::Kind)K));
return isSpecificBuiltinType(K);
}
@@ -9281,7 +9197,8 @@ template <typename T> const T *Type::getAs() const {
}
template <typename T> const T *Type::getAsAdjusted() const {
- static_assert(!TypeIsArrayType<T>::value, "ArrayType cannot be used with getAsAdjusted!");
+ static_assert(!TypeIsArrayType<T>::value,
+ "ArrayType cannot be used with getAsAdjusted!");
// If this is directly a T type, return it.
if (const auto *Ty = dyn_cast<T>(this))
@@ -9334,14 +9251,16 @@ template <typename T> const T *Type::castAs() const {
static_assert(!TypeIsArrayType<T>::value,
"ArrayType cannot be used with castAs!");
- if (const auto *ty = dyn_cast<T>(this)) return ty;
+ if (const auto *ty = dyn_cast<T>(this))
+ return ty;
assert(isa<T>(CanonicalType));
return cast<T>(getUnqualifiedDesugaredType());
}
inline const ArrayType *Type::castAsArrayTypeUnsafe() const {
assert(isa<ArrayType>(CanonicalType));
- if (const auto *arr = dyn_cast<ArrayType>(this)) return arr;
+ if (const auto *arr = dyn_cast<ArrayType>(this))
+ return arr;
return cast<ArrayType>(getUnqualifiedDesugaredType());
}
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 06023fc088a32..e6b316c0d90a2 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -5914,3 +5914,54 @@ StringRef PredefinedSugarType::getName(Kind KD) {
}
llvm_unreachable("unexpected kind");
}
+
+bool Type::isImplicitLifetimeType() const {
+ // Scalar types (such as pointers, ints, floats, enums, etc.) asre always
+ // implicit-lifetime types.
+ if (isScalarType())
+ return true;
+
+ // Vector types act like scalars for lifetimes.
+ if (isVectorType() || isExtVectorType())
+ return true;
+
+ // Array types are implicit-lifetime if their base elemnt is also
+ // implicit-lifetime.
+ if (isArrayType())
+ return getBaseElementTypeUnsafe()->isImplicitLifetimeType();
+
+ if (const RecordType *RT = getAs<RecordType>()) {
+ const RecordDecl *RD = RT->getDecl();
+
+ // dyn_cast returns nullptr if RD is not a CXXRecordDecl. If it's not a C++
+ // record, it's a standard C struct/union, which are always
+ // implicit-lifetime.
+ const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
+ if (!CXXRD)
+ return true;
+
+ // We cannot determine lifetime if the class is incomplete.
+ if (!CXXRD->isCompleteDefinition())
+ return false;
+
+ // C++20 [class.prop]: A class S is an implicit-lifetime class if
+ // - a trivial, non-deleted destructor, AND
+ if (!CXXRD->hasTrivialDestructor())
+ return false;
+
+ // - it is an aggregate, OR
+ if (CXXRD->isAggregate())
+ return true;
+
+ // - has at least one trivial eligible constructor.
+ if (CXXRD->hasTrivialDefaultConstructor() ||
+ CXXRD->hasTrivialCopyConstructor() ||
+ CXXRD->hasTrivialMoveConstructor())
+ return true;
+
+ return false;
+ }
+
+ // References, function types and void are not implicit-lifetime.
+ return false;
+}
>From b899636f65b3116cc2829e744744f074a2399985 Mon Sep 17 00:00:00 2001
From: Yash Verma <yashverma056 at proton.me>
Date: Thu, 7 May 2026 03:19:37 -0400
Subject: [PATCH 2/4] [Clang][Sema] Implement __builtin_start_lifetime_as
intrinsic
This patch introduces the `__builtin_start_lifetime_as` instrinsic to support C++23 explicit lifetime management (P2590R2) and its subsequent array-handling refinements (P2679R2).
This instrinsic is designed to take a single-argument. The target type is deduced directly from the pointer cast (e.g., `__builtin_start_lifetime_as((T*)p)`). Thus avoiding the need for a custom AST node.
Key additions:
- Registers `__builtin_start_lifetime_as` in `Builtins.td` using CustomTypeChecking.
- Implements `Sema::BuiltinStartLifetimeAs` to strictly enforce C++23 implicit-lifetime constraints.
- Recursively unwraps array types to evaluate the base element type's lifetime properties (as required by P2679R2).
- Hooks into `ExprConstant.cpp` to explicitly reject the intrinsic inside constant expressions.
- Adds `lit` test coverage in `SemaCXX/` validating diagnostic paths
---
clang/include/clang/Basic/Builtins.td | 6 +
.../clang/Basic/DiagnosticSemaKinds.td | 3 +
clang/include/clang/Sema/Sema.h | 7 +
clang/lib/AST/ExprConstant.cpp | 6 +
clang/lib/Sema/SemaChecking.cpp | 859 ++++++++++--------
.../SemaCXX/builtin-start-lifetime-as.cpp | 56 ++
6 files changed, 541 insertions(+), 396 deletions(-)
create mode 100644 clang/test/SemaCXX/builtin-start-lifetime-as.cpp
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 4a7eaeb3d353e..f53a19c9d85af 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -1251,6 +1251,12 @@ def Launder : Builtin {
let Prototype = "void*(void*)";
}
+def StartLifetimeAs : Builtin {
+ let Spellings = ["__builtin_start_lifetime_as"];
+ let Attributes = [NoThrow, CustomTypeChecking];
+ let Prototype = "void*(...)";
+}
+
def IsConstantEvaluated : LangBuiltin<"CXX_LANG"> {
let Spellings = ["__builtin_is_constant_evaluated"];
let Attributes = [NoThrow, Constexpr];
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 6646b37262d92..0ae9804285153 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -172,6 +172,9 @@ def err_expr_not_string_literal : Error<"expression is not a string literal">;
def note_constexpr_assert_failed : Note<
"assertion failed during evaluation of constant expression">;
+def err_start_lifetime_as_not_implicit : Error<
+ "type %0 is not an implicit-lifetime type, cannot start lifetime">;
+
// Semantic analysis of constant literals.
def ext_predef_outside_function : Warning<
"predefined identifier is only valid inside function">,
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 72beac7526dc5..785ff84ad1e46 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2893,6 +2893,13 @@ class Sema final : public SemaBase {
bool BuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, unsigned ArgNum,
unsigned ArgBits);
+ /// BuiltinStartLifetimeAs - Check if the argument of the
+ /// __builtin_start_lifetime_as instrinsic is a valid pointer to an
+ /// implicit-lifetime type. Defers validation if the call is type-dependent.
+ /// Returns true if the argument is invalid and emits a diagnostic. Returns
+ /// false if the call is well-formed or its evaluation is deferred.
+ bool BuiltinStartLifetimeAs(CallExpr *Call);
+
/// Checks that a call expression's argument count is at least the desired
/// number. This is useful when doing custom type-checking on a variadic
/// function. Returns true on error.
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 3f3a80f5b77a3..33fc6e0309f47 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -10549,6 +10549,12 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return ZeroInitialization(E);
}
+ case Builtin::BI__builtin_start_lifetime_as:
+ // C++20/C++23 forbids evaluating lifetime-altering abstract machine magic
+ // inside a constant expression.
+ Info.FFDiag(E, diag::note_constexpr_invalid_function) << /*IsContexpr=*/0;
+ return false;
+
case Builtin::BImemcpy:
case Builtin::BImemmove:
case Builtin::BIwmemcpy:
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 4706fa5d3cde0..a922c00d42cb8 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -41,6 +41,7 @@
#include "clang/AST/TypeLoc.h"
#include "clang/AST/UnresolvedSet.h"
#include "clang/Basic/AddressSpaces.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/IdentifierTable.h"
@@ -408,35 +409,37 @@ static bool BuiltinOverflow(Sema &S, CallExpr *TheCall, unsigned BuiltinID) {
return true;
std::pair<unsigned, const char *> Builtins[] = {
- { Builtin::BI__builtin_add_overflow, "ckd_add" },
- { Builtin::BI__builtin_sub_overflow, "ckd_sub" },
- { Builtin::BI__builtin_mul_overflow, "ckd_mul" },
+ {Builtin::BI__builtin_add_overflow, "ckd_add"},
+ {Builtin::BI__builtin_sub_overflow, "ckd_sub"},
+ {Builtin::BI__builtin_mul_overflow, "ckd_mul"},
};
- bool CkdOperation = llvm::any_of(Builtins, [&](const std::pair<unsigned,
- const char *> &P) {
- return BuiltinID == P.first && TheCall->getExprLoc().isMacroID() &&
- Lexer::getImmediateMacroName(TheCall->getExprLoc(),
- S.getSourceManager(), S.getLangOpts()) == P.second;
- });
+ bool CkdOperation =
+ llvm::any_of(Builtins, [&](const std::pair<unsigned, const char *> &P) {
+ return BuiltinID == P.first && TheCall->getExprLoc().isMacroID() &&
+ Lexer::getImmediateMacroName(TheCall->getExprLoc(),
+ S.getSourceManager(),
+ S.getLangOpts()) == P.second;
+ });
auto ValidCkdIntType = [](QualType QT) {
// A valid checked integer type is an integer type other than a plain char,
// bool, a bit-precise type, or an enumeration type.
if (const auto *BT = QT.getCanonicalType()->getAs<BuiltinType>())
return (BT->getKind() >= BuiltinType::Short &&
- BT->getKind() <= BuiltinType::Int128) || (
- BT->getKind() >= BuiltinType::UShort &&
- BT->getKind() <= BuiltinType::UInt128) ||
- BT->getKind() == BuiltinType::UChar ||
- BT->getKind() == BuiltinType::SChar;
+ BT->getKind() <= BuiltinType::Int128) ||
+ (BT->getKind() >= BuiltinType::UShort &&
+ BT->getKind() <= BuiltinType::UInt128) ||
+ BT->getKind() == BuiltinType::UChar ||
+ BT->getKind() == BuiltinType::SChar;
return false;
};
// First two arguments should be integers.
for (unsigned I = 0; I < 2; ++I) {
ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(I));
- if (Arg.isInvalid()) return true;
+ if (Arg.isInvalid())
+ return true;
TheCall->setArg(I, Arg.get());
QualType Ty = Arg.get()->getType();
@@ -453,18 +456,18 @@ static bool BuiltinOverflow(Sema &S, CallExpr *TheCall, unsigned BuiltinID) {
// the other qualifiers aren't possible.
{
ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(2));
- if (Arg.isInvalid()) return true;
+ if (Arg.isInvalid())
+ return true;
TheCall->setArg(2, Arg.get());
QualType Ty = Arg.get()->getType();
const auto *PtrTy = Ty->getAs<PointerType>();
- if (!PtrTy ||
- !PtrTy->getPointeeType()->isIntegerType() ||
+ if (!PtrTy || !PtrTy->getPointeeType()->isIntegerType() ||
(!ValidCkdIntType(PtrTy->getPointeeType()) && CkdOperation) ||
PtrTy->getPointeeType().isConstQualified()) {
S.Diag(Arg.get()->getBeginLoc(),
diag::err_overflow_builtin_must_be_ptr_int)
- << CkdOperation << Ty << Arg.get()->getSourceRange();
+ << CkdOperation << Ty << Arg.get()->getSourceRange();
return true;
}
}
@@ -583,7 +586,8 @@ struct BuiltinDumpStructGenerator {
}
analyze_printf::PrintfSpecifier Specifier;
- if (Specifier.fixType(T, S.getLangOpts(), S.Context, /*IsObjCLiteral=*/false)) {
+ if (Specifier.fixType(T, S.getLangOpts(), S.Context,
+ /*IsObjCLiteral=*/false)) {
// We were able to guess how to format this.
if (Specifier.getConversionSpecifier().getKind() ==
analyze_printf::PrintfConversionSpecifier::sArg) {
@@ -844,7 +848,7 @@ static bool BuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) {
}
QualType ReturnTy = CE->getCallReturnType(S.Context);
- QualType ArgTys[2] = { ReturnTy, ChainResult.get()->getType() };
+ QualType ArgTys[2] = {ReturnTy, ChainResult.get()->getType()};
QualType BuiltinTy = S.Context.getFunctionType(
ReturnTy, ArgTys, FunctionProtoType::ExtProtoInfo());
QualType BuiltinPtrTy = S.Context.getPointerType(BuiltinTy);
@@ -2887,9 +2891,9 @@ static QualType getVectorElementType(ASTContext &Context, QualType VecTy) {
return QualType();
}
-ExprResult
-Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
- CallExpr *TheCall) {
+ExprResult Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl,
+ unsigned BuiltinID,
+ CallExpr *TheCall) {
ExprResult TheCallResult(TheCall);
// Find out if any arguments are required to be integer constant expressions.
@@ -2897,12 +2901,13 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
ASTContext::GetBuiltinTypeError Error;
Context.GetBuiltinType(BuiltinID, Error, &ICEArguments);
if (Error != ASTContext::GE_None)
- ICEArguments = 0; // Don't diagnose previously diagnosed errors.
+ ICEArguments = 0; // Don't diagnose previously diagnosed errors.
// If any arguments are required to be ICE's, check and diagnose.
for (unsigned ArgNo = 0; ICEArguments != 0; ++ArgNo) {
// Skip arguments not required to be ICE's.
- if ((ICEArguments & (1 << ArgNo)) == 0) continue;
+ if ((ICEArguments & (1 << ArgNo)) == 0)
+ continue;
llvm::APSInt Result;
// If we don't have enough arguments, continue so we can issue better
@@ -3114,7 +3119,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
if (checkArgCount(TheCall, 1))
return true;
ExprResult Arg = DefaultFunctionArrayLvalueConversion(TheCall->getArg(0));
- if (Arg.isInvalid()) return true;
+ if (Arg.isInvalid())
+ return true;
TheCall->setArg(0, Arg.get());
TheCall->setType(Context.IntTy);
break;
@@ -3125,6 +3131,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
return BuiltinIsWithinLifetime(*this, TheCall);
case Builtin::BI__builtin_trivially_relocate:
return BuiltinTriviallyRelocate(*this, TheCall);
+ case Builtin::BI__builtin_start_lifetime_as:
+ if (BuiltinStartLifetimeAs(TheCall))
+ return ExprError();
+ break;
case Builtin::BI__sync_fetch_and_add:
case Builtin::BI__sync_fetch_and_add_1:
@@ -4019,7 +4029,7 @@ bool Sema::getFormatStringInfo(unsigned FormatIdx, unsigned FirstArg,
// of member functions is counted. However, it doesn't appear in our own
// lists, so decrement format_idx in that case.
if (HasImplicitThisParam) {
- if(FSI->FormatIdx == 0)
+ if (FSI->FormatIdx == 0)
return false;
--FSI->FormatIdx;
if (FSI->FirstDataArg != 0)
@@ -4058,12 +4068,10 @@ static bool CheckNonNullExpr(Sema &S, const Expr *Expr) {
bool Result;
return (!Expr->isValueDependent() &&
- Expr->EvaluateAsBooleanCondition(Result, S.Context) &&
- !Result);
+ Expr->EvaluateAsBooleanCondition(Result, S.Context) && !Result);
}
-static void CheckNonNullArgument(Sema &S,
- const Expr *ArgExpr,
+static void CheckNonNullArgument(Sema &S, const Expr *ArgExpr,
SourceLocation CallSiteLoc) {
if (CheckNonNullExpr(S, ArgExpr))
S.DiagRuntimeBehavior(CallSiteLoc, ArgExpr,
@@ -4079,8 +4087,7 @@ static bool isNonNullType(QualType type) {
return false;
}
-static void CheckNonNullArguments(Sema &S,
- const NamedDecl *FDecl,
+static void CheckNonNullArguments(Sema &S, const NamedDecl *FDecl,
const FunctionProtoType *Proto,
ArrayRef<const Expr *> Args,
SourceLocation CallSiteLoc) {
@@ -4116,14 +4123,14 @@ static void CheckNonNullArguments(Sema &S,
if (FDecl && (isa<FunctionDecl>(FDecl) || isa<ObjCMethodDecl>(FDecl))) {
// Handle the nonnull attribute on the parameters of the
// function/method.
- ArrayRef<ParmVarDecl*> parms;
+ ArrayRef<ParmVarDecl *> parms;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(FDecl))
parms = FD->parameters();
else
parms = cast<ObjCMethodDecl>(FDecl)->parameters();
unsigned ParamIndex = 0;
- for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = parms.end();
+ for (ArrayRef<ParmVarDecl *>::iterator I = parms.begin(), E = parms.end();
I != E; ++I, ++ParamIndex) {
const ParmVarDecl *PVD = *I;
if (PVD->hasAttr<NonNullAttr>() || isNonNullType(PVD->getType())) {
@@ -4501,13 +4508,13 @@ void Sema::CheckConstructorCall(FunctionDecl *FDecl, QualType ThisType,
bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
const FunctionProtoType *Proto) {
- bool IsMemberOperatorCall = isa<CXXOperatorCallExpr>(TheCall) &&
- isa<CXXMethodDecl>(FDecl);
- bool IsMemberFunction = isa<CXXMemberCallExpr>(TheCall) ||
- IsMemberOperatorCall;
- VariadicCallType CallType = getVariadicCallType(FDecl, Proto,
- TheCall->getCallee());
- Expr** Args = TheCall->getArgs();
+ bool IsMemberOperatorCall =
+ isa<CXXOperatorCallExpr>(TheCall) && isa<CXXMethodDecl>(FDecl);
+ bool IsMemberFunction =
+ isa<CXXMemberCallExpr>(TheCall) || IsMemberOperatorCall;
+ VariadicCallType CallType =
+ getVariadicCallType(FDecl, Proto, TheCall->getCallee());
+ Expr **Args = TheCall->getArgs();
unsigned NumArgs = TheCall->getNumArgs();
Expr *ImplicitThis = nullptr;
@@ -4615,8 +4622,8 @@ bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall,
}
bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) {
- VariadicCallType CallType = getVariadicCallType(/*FDecl=*/nullptr, Proto,
- TheCall->getCallee());
+ VariadicCallType CallType =
+ getVariadicCallType(/*FDecl=*/nullptr, Proto, TheCall->getCallee());
checkCall(/*FDecl=*/nullptr, Proto, /*ThisArg=*/nullptr,
llvm::ArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
/*IsMemberFunction=*/false, TheCall->getRParenLoc(),
@@ -4665,7 +4672,8 @@ static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) {
ExprResult Sema::AtomicOpsOverloaded(ExprResult TheCallResult,
AtomicExpr::AtomicOp Op) {
CallExpr *TheCall = cast<CallExpr>(TheCallResult.get());
- DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+ DeclRefExpr *DRE =
+ cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
MultiExprArg Args{TheCall->getArgs(), TheCall->getNumArgs()};
return BuildAtomicExpr({TheCall->getBeginLoc(), TheCall->getEndLoc()},
DRE->getSourceRange(), TheCall->getRParenLoc(), Args,
@@ -4809,9 +4817,9 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
// M is C if C is an integer, and ptrdiff_t if C is a pointer, and
// the int parameters are for orderings.
- static_assert(sizeof(NumArgs)/sizeof(NumArgs[0]) == NumForm
- && sizeof(NumVals)/sizeof(NumVals[0]) == NumForm,
- "need to update code for modified forms");
+ static_assert(sizeof(NumArgs) / sizeof(NumArgs[0]) == NumForm &&
+ sizeof(NumVals) / sizeof(NumVals[0]) == NumForm,
+ "need to update code for modified forms");
static_assert(AtomicExpr::AO__atomic_add_fetch == 0 &&
AtomicExpr::AO__atomic_xor_fetch + 1 ==
AtomicExpr::AO__c11_atomic_compare_exchange_strong,
@@ -5016,7 +5024,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
// For a __c11 builtin, this should be a pointer to an _Atomic type.
QualType AtomTy = pointerType->getPointeeType(); // 'A'
- QualType ValType = AtomTy; // 'C'
+ QualType ValType = AtomTy; // 'C'
if (IsC11) {
if (!AtomTy->isAtomicType()) {
Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic)
@@ -5275,7 +5283,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
}
// Permute the arguments into a 'consistent' order.
- SmallVector<Expr*, 5> SubExprs;
+ SmallVector<Expr *, 5> SubExprs;
SubExprs.push_back(Ptr);
switch (Form) {
case Init:
@@ -5394,7 +5402,7 @@ static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex) {
ParmVarDecl *Param = Fn->getParamDecl(ArgIndex);
InitializedEntity Entity =
- InitializedEntity::InitializeParameter(S.Context, Param);
+ InitializedEntity::InitializeParameter(S.Context, Param);
ExprResult Arg = E->getArg(ArgIndex);
Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg);
@@ -5483,41 +5491,52 @@ ExprResult Sema::BuiltinAtomicOverloaded(ExprResult TheCallResult) {
// We need to figure out which concrete builtin this maps onto. For example,
// __sync_fetch_and_add with a 2 byte object turns into
// __sync_fetch_and_add_2.
-#define BUILTIN_ROW(x) \
- { Builtin::BI##x##_1, Builtin::BI##x##_2, Builtin::BI##x##_4, \
- Builtin::BI##x##_8, Builtin::BI##x##_16 }
+#define BUILTIN_ROW(x) \
+ { \
+ Builtin::BI##x##_1, Builtin::BI##x##_2, Builtin::BI##x##_4, \
+ Builtin::BI##x##_8, Builtin::BI##x##_16 \
+ }
static const unsigned BuiltinIndices[][5] = {
- BUILTIN_ROW(__sync_fetch_and_add),
- BUILTIN_ROW(__sync_fetch_and_sub),
- BUILTIN_ROW(__sync_fetch_and_or),
- BUILTIN_ROW(__sync_fetch_and_and),
- BUILTIN_ROW(__sync_fetch_and_xor),
- BUILTIN_ROW(__sync_fetch_and_nand),
-
- BUILTIN_ROW(__sync_add_and_fetch),
- BUILTIN_ROW(__sync_sub_and_fetch),
- BUILTIN_ROW(__sync_and_and_fetch),
- BUILTIN_ROW(__sync_or_and_fetch),
- BUILTIN_ROW(__sync_xor_and_fetch),
- BUILTIN_ROW(__sync_nand_and_fetch),
-
- BUILTIN_ROW(__sync_val_compare_and_swap),
- BUILTIN_ROW(__sync_bool_compare_and_swap),
- BUILTIN_ROW(__sync_lock_test_and_set),
- BUILTIN_ROW(__sync_lock_release),
- BUILTIN_ROW(__sync_swap)
- };
+ BUILTIN_ROW(__sync_fetch_and_add),
+ BUILTIN_ROW(__sync_fetch_and_sub),
+ BUILTIN_ROW(__sync_fetch_and_or),
+ BUILTIN_ROW(__sync_fetch_and_and),
+ BUILTIN_ROW(__sync_fetch_and_xor),
+ BUILTIN_ROW(__sync_fetch_and_nand),
+
+ BUILTIN_ROW(__sync_add_and_fetch),
+ BUILTIN_ROW(__sync_sub_and_fetch),
+ BUILTIN_ROW(__sync_and_and_fetch),
+ BUILTIN_ROW(__sync_or_and_fetch),
+ BUILTIN_ROW(__sync_xor_and_fetch),
+ BUILTIN_ROW(__sync_nand_and_fetch),
+
+ BUILTIN_ROW(__sync_val_compare_and_swap),
+ BUILTIN_ROW(__sync_bool_compare_and_swap),
+ BUILTIN_ROW(__sync_lock_test_and_set),
+ BUILTIN_ROW(__sync_lock_release),
+ BUILTIN_ROW(__sync_swap)};
#undef BUILTIN_ROW
// Determine the index of the size.
unsigned SizeIndex;
switch (Context.getTypeSizeInChars(ValType).getQuantity()) {
- case 1: SizeIndex = 0; break;
- case 2: SizeIndex = 1; break;
- case 4: SizeIndex = 2; break;
- case 8: SizeIndex = 3; break;
- case 16: SizeIndex = 4; break;
+ case 1:
+ SizeIndex = 0;
+ break;
+ case 2:
+ SizeIndex = 1;
+ break;
+ case 4:
+ SizeIndex = 2;
+ break;
+ case 8:
+ SizeIndex = 3;
+ break;
+ case 16:
+ SizeIndex = 4;
+ break;
default:
Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_pointer_size)
<< FirstArg->getType() << FirstArg->getSourceRange();
@@ -5532,7 +5551,8 @@ ExprResult Sema::BuiltinAtomicOverloaded(ExprResult TheCallResult) {
unsigned BuiltinIndex, NumFixed = 1;
bool WarnAboutSemanticsChange = false;
switch (BuiltinID) {
- default: llvm_unreachable("Unknown overloaded atomic builtin!");
+ default:
+ llvm_unreachable("Unknown overloaded atomic builtin!");
case Builtin::BI__sync_fetch_and_add:
case Builtin::BI__sync_fetch_and_add_1:
case Builtin::BI__sync_fetch_and_add_2:
@@ -5696,7 +5716,7 @@ ExprResult Sema::BuiltinAtomicOverloaded(ExprResult TheCallResult) {
// Now that we know how many fixed arguments we expect, first check that we
// have at least that many.
- if (TheCall->getNumArgs() < 1+NumFixed) {
+ if (TheCall->getNumArgs() < 1 + NumFixed) {
Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least)
<< 0 << 1 + NumFixed << TheCall->getNumArgs() << /*is non object*/ 0
<< Callee->getSourceRange();
@@ -5733,13 +5753,13 @@ ExprResult Sema::BuiltinAtomicOverloaded(ExprResult TheCallResult) {
// deduce the types of the rest of the arguments accordingly. Walk
// the remaining arguments, converting them to the deduced value type.
for (unsigned i = 0; i != NumFixed; ++i) {
- ExprResult Arg = TheCall->getArg(i+1);
+ ExprResult Arg = TheCall->getArg(i + 1);
// GCC does an implicit conversion to the pointer or integer ValType. This
// can fail in some cases (1i -> int**), check for this error case now.
// Initialize the argument.
- InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
- ValType, /*consume*/ false);
+ InitializedEntity Entity = InitializedEntity::InitializeParameter(
+ Context, ValType, /*consume*/ false);
Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg);
if (Arg.isInvalid())
return ExprError();
@@ -5750,7 +5770,7 @@ ExprResult Sema::BuiltinAtomicOverloaded(ExprResult TheCallResult) {
// pass in 42. The 42 gets converted to char. This is even more strange
// for things like 45.123 -> char, etc.
// FIXME: Do this check.
- TheCall->setArg(i+1, Arg.get());
+ TheCall->setArg(i + 1, Arg.get());
}
// Create a new DeclRefExpr to refer to the new decl.
@@ -5762,8 +5782,8 @@ ExprResult Sema::BuiltinAtomicOverloaded(ExprResult TheCallResult) {
// Set the callee in the CallExpr.
// FIXME: This loses syntactic information.
QualType CalleePtrTy = Context.getPointerType(NewBuiltinDecl->getType());
- ExprResult PromotedCall = ImpCastExprToType(NewDRE, CalleePtrTy,
- CK_BuiltinFnToFnPtr);
+ ExprResult PromotedCall =
+ ImpCastExprToType(NewDRE, CalleePtrTy, CK_BuiltinFnToFnPtr);
TheCall->setCallee(PromotedCall.get());
// Change the result type of the call to match the original value type. This
@@ -5911,8 +5931,9 @@ static bool checkVAStartABI(Sema &S, unsigned BuiltinID, Expr *Fn) {
return false;
}
-static bool checkVAStartIsInVariadicFunction(Sema &S, Expr *Fn,
- ParmVarDecl **LastParam = nullptr) {
+static bool
+checkVAStartIsInVariadicFunction(Sema &S, Expr *Fn,
+ ParmVarDecl **LastParam = nullptr) {
// Determine whether the current function, block, or obj-c method is variadic
// and get its parameter list.
bool IsVariadic = false;
@@ -6036,8 +6057,10 @@ bool Sema::BuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
return !Context.typesAreCompatible(ED->getPromotionType(), Type);
}()) {
unsigned Reason = 0;
- if (Type->isReferenceType()) Reason = 1;
- else if (IsCRegister) Reason = 2;
+ if (Type->isReferenceType())
+ Reason = 1;
+ else if (IsCRegister)
+ Reason = 2;
Diag(Arg->getBeginLoc(), diag::warn_va_start_type_is_undefined) << Reason;
Diag(ParamLoc, diag::note_parameter_type) << Type;
}
@@ -6281,8 +6304,8 @@ bool Sema::BuiltinComplex(CallExpr *TheCall) {
if (!Context.hasSameType(Real->getType(), Imag->getType())) {
return Diag(Real->getBeginLoc(),
diag::err_typecheck_call_different_arg_types)
- << Real->getType() << Imag->getType()
- << Real->getSourceRange() << Imag->getSourceRange();
+ << Real->getType() << Imag->getType() << Real->getSourceRange()
+ << Imag->getSourceRange();
}
TheCall->setType(Context.getComplexType(Real->getType()));
@@ -6389,8 +6412,7 @@ ExprResult Sema::ConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo,
QualType SrcTy = E->getType();
if (!SrcTy->isVectorType() && !SrcTy->isDependentType())
- return ExprError(Diag(BuiltinLoc,
- diag::err_convertvector_non_vector)
+ return ExprError(Diag(BuiltinLoc, diag::err_convertvector_non_vector)
<< E->getSourceRange());
if (!DstTy->isVectorType() && !DstTy->isDependentType())
return ExprError(Diag(BuiltinLoc, diag::err_builtin_non_vector_type)
@@ -6401,9 +6423,9 @@ ExprResult Sema::ConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo,
unsigned SrcElts = SrcTy->castAs<VectorType>()->getNumElements();
unsigned DstElts = DstTy->castAs<VectorType>()->getNumElements();
if (SrcElts != DstElts)
- return ExprError(Diag(BuiltinLoc,
- diag::err_convertvector_incompatible_vector)
- << E->getSourceRange());
+ return ExprError(
+ Diag(BuiltinLoc, diag::err_convertvector_incompatible_vector)
+ << E->getSourceRange());
}
return ConvertVectorExpr::Create(Context, E, TInfo, DstTy, VK, OK, BuiltinLoc,
@@ -6452,7 +6474,8 @@ bool Sema::BuiltinArithmeticFence(CallExpr *TheCall) {
bool Sema::BuiltinAssume(CallExpr *TheCall) {
Expr *Arg = TheCall->getArg(0);
- if (Arg->isInstantiationDependent()) return false;
+ if (Arg->isInstantiationDependent())
+ return false;
if (Arg->HasSideEffects(Context))
Diag(Arg->getBeginLoc(), diag::warn_assume_side_effects)
@@ -6501,8 +6524,7 @@ bool Sema::BuiltinAssumeAligned(CallExpr *TheCall) {
Expr *FirstArg = TheCall->getArg(0);
{
- ExprResult FirstArgResult =
- DefaultFunctionArrayLvalueConversion(FirstArg);
+ ExprResult FirstArgResult = DefaultFunctionArrayLvalueConversion(FirstArg);
if (!FirstArgResult.get()->getType()->isPointerType()) {
Diag(TheCall->getBeginLoc(), diag::err_builtin_assume_aligned_invalid_arg)
<< TheCall->getSourceRange();
@@ -6913,9 +6935,7 @@ class UncoveredArgHandler {
public:
UncoveredArgHandler() = default;
- bool hasUncoveredArg() const {
- return (FirstUncoveredArg >= 0);
- }
+ bool hasUncoveredArg() const { return (FirstUncoveredArg >= 0); }
unsigned getUncoveredArg() const {
assert(hasUncoveredArg() && "no uncovered argument");
@@ -6959,8 +6979,7 @@ enum StringLiteralCheckType {
} // namespace
static void sumOffsets(llvm::APSInt &Offset, llvm::APSInt Addend,
- BinaryOperatorKind BinOpKind,
- bool AddendIsRight) {
+ BinaryOperatorKind BinOpKind, bool AddendIsRight) {
unsigned BitWidth = Offset.getBitWidth();
unsigned AddendBitWidth = Addend.getBitWidth();
// There might be negative interim results.
@@ -7034,10 +7053,11 @@ class FormatStringLiteral {
bool isUTF32() const { return FExpr->isUTF32(); }
bool isPascal() const { return FExpr->isPascal(); }
- SourceLocation getLocationOfByte(
- unsigned ByteNo, const SourceManager &SM, const LangOptions &Features,
- const TargetInfo &Target, unsigned *StartToken = nullptr,
- unsigned *StartTokenByteOffset = nullptr) const {
+ SourceLocation
+ getLocationOfByte(unsigned ByteNo, const SourceManager &SM,
+ const LangOptions &Features, const TargetInfo &Target,
+ unsigned *StartToken = nullptr,
+ unsigned *StartTokenByteOffset = nullptr) const {
return FExpr->getLocationOfByte(ByteNo + Offset, SM, Features, Target,
StartToken, StartTokenByteOffset);
}
@@ -7109,8 +7129,7 @@ checkFormatStringExpr(Sema &S, const StringLiteral *ReferenceFormatString,
case Stmt::ConditionalOperatorClass: {
// The expression is a literal if both sub-expressions were, and it was
// completely checked only if both sub-expressions were checked.
- const AbstractConditionalOperator *C =
- cast<AbstractConditionalOperator>(E);
+ const AbstractConditionalOperator *C = cast<AbstractConditionalOperator>(E);
// Determine whether it is necessary to check both sub-expressions, for
// example, because the condition expression is a constant that can be
@@ -7326,7 +7345,8 @@ checkFormatStringExpr(Sema &S, const StringLiteral *ReferenceFormatString,
case Stmt::CallExprClass:
case Stmt::CXXMemberCallExprClass: {
const CallExpr *CE = cast<CallExpr>(E);
- if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
+ if (const NamedDecl *ND =
+ dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
bool IsFirst = true;
StringLiteralCheckType CommonResult;
for (const auto *FA : ND->specific_attrs<FormatArgAttr>()) {
@@ -7740,7 +7760,7 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
if (UncoveredArg.hasUncoveredArg()) {
unsigned ArgIdx = UncoveredArg.getUncoveredArg() + firstDataArg;
assert(ArgIdx < Args.size() && "ArgIdx outside bounds");
- UncoveredArg.Diagnose(*this, /*IsFunctionCall*/true, Args[ArgIdx]);
+ UncoveredArg.Diagnose(*this, /*IsFunctionCall*/ true, Args[ArgIdx]);
}
if (CT != SLCT_NotALiteral)
@@ -7770,7 +7790,7 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
// warn only with -Wformat-nonliteral.
if (Args.size() == firstDataArg) {
Diag(FormatLoc, diag::warn_format_nonliteral_noargs)
- << OrigFormatExpr->getSourceRange();
+ << OrigFormatExpr->getSourceRange();
switch (Type) {
default:
break;
@@ -7778,16 +7798,16 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
case FormatStringType::FreeBSDKPrintf:
case FormatStringType::Printf:
Diag(FormatLoc, diag::note_format_security_fixit)
- << FixItHint::CreateInsertion(FormatLoc, "\"%s\", ");
+ << FixItHint::CreateInsertion(FormatLoc, "\"%s\", ");
break;
case FormatStringType::NSString:
Diag(FormatLoc, diag::note_format_security_fixit)
- << FixItHint::CreateInsertion(FormatLoc, "@\"%@\", ");
+ << FixItHint::CreateInsertion(FormatLoc, "@\"%@\", ");
break;
}
} else {
Diag(FormatLoc, diag::warn_format_nonliteral)
- << OrigFormatExpr->getSourceRange();
+ << OrigFormatExpr->getSourceRange();
}
return false;
}
@@ -8774,11 +8794,11 @@ bool DecomposePrintfHandler::HandlePrintfSpecifier(
// Determines if the specified is a C++ class or struct containing
// a member with the specified name and kind (e.g. a CXXMethodDecl named
// "c_str()").
-template<typename MemberKind>
-static llvm::SmallPtrSet<MemberKind*, 1>
+template <typename MemberKind>
+static llvm::SmallPtrSet<MemberKind *, 1>
CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) {
auto *RD = Ty->getAsCXXRecordDecl();
- llvm::SmallPtrSet<MemberKind*, 1> Results;
+ llvm::SmallPtrSet<MemberKind *, 1> Results;
if (!RD || !(RD->isBeingDefined() || RD->isCompleteDefinition()))
return Results;
@@ -8807,8 +8827,8 @@ bool Sema::hasCStrMethod(const Expr *E) {
MethodSet Results =
CXXRecordMembersNamed<CXXMethodDecl>("c_str", *this, E->getType());
- for (MethodSet::iterator MI = Results.begin(), ME = Results.end();
- MI != ME; ++MI)
+ for (MethodSet::iterator MI = Results.begin(), ME = Results.end(); MI != ME;
+ ++MI)
if ((*MI)->getMinRequiredArguments() == 0)
return true;
return false;
@@ -8817,15 +8837,15 @@ bool Sema::hasCStrMethod(const Expr *E) {
// Check if a (w)string was passed when a (w)char* was needed, and offer a
// better diagnostic if so. AT is assumed to be valid.
// Returns true when a c_str() conversion method is found.
-bool CheckPrintfHandler::checkForCStrMembers(
- const analyze_printf::ArgType &AT, const Expr *E) {
+bool CheckPrintfHandler::checkForCStrMembers(const analyze_printf::ArgType &AT,
+ const Expr *E) {
using MethodSet = llvm::SmallPtrSet<CXXMethodDecl *, 1>;
MethodSet Results =
CXXRecordMembersNamed<CXXMethodDecl>("c_str", S, E->getType());
- for (MethodSet::iterator MI = Results.begin(), ME = Results.end();
- MI != ME; ++MI) {
+ for (MethodSet::iterator MI = Results.begin(), ME = Results.end(); MI != ME;
+ ++MI) {
const CXXMethodDecl *Method = *MI;
if (Method->getMinRequiredArguments() == 0 &&
AT.matchesType(S.Context, Method->getReturnType())) {
@@ -10039,7 +10059,7 @@ static unsigned getLargerAbsoluteValueFunction(unsigned AbsFunction) {
return 0;
case Builtin::BIcabsf:
- return Builtin::BIcabs;
+ return Builtin::BIcabs;
case Builtin::BIcabs:
return Builtin::BIcabsl;
case Builtin::BIcabsl:
@@ -10089,11 +10109,7 @@ static unsigned getBestAbsFunction(ASTContext &Context, QualType ArgType,
return BestKind;
}
-enum AbsoluteValueKind {
- AVK_Integer,
- AVK_Floating,
- AVK_Complex
-};
+enum AbsoluteValueKind { AVK_Integer, AVK_Floating, AVK_Complex };
static AbsoluteValueKind getAbsoluteValueKind(QualType T) {
if (T->isIntegralOrEnumerationType())
@@ -10283,8 +10299,8 @@ static void emitReplacement(Sema &S, SourceLocation Loc, SourceRange Range,
if (!EmitHeaderHint)
return;
- S.Diag(Loc, diag::note_include_header_or_declare) << HeaderName
- << FunctionName;
+ S.Diag(Loc, diag::note_include_header_or_declare)
+ << HeaderName << FunctionName;
}
template <std::size_t StrLen>
@@ -10439,32 +10455,44 @@ void Sema::CheckAbsoluteValueFunction(const CallExpr *Call,
//===--- CHECK: Warn on use of std::max and unsigned zero. r---------------===//
void Sema::CheckMaxUnsignedZero(const CallExpr *Call,
const FunctionDecl *FDecl) {
- if (!Call || !FDecl) return;
+ if (!Call || !FDecl)
+ return;
// Ignore template specializations and macros.
- if (inTemplateInstantiation()) return;
- if (Call->getExprLoc().isMacroID()) return;
+ if (inTemplateInstantiation())
+ return;
+ if (Call->getExprLoc().isMacroID())
+ return;
// Only care about the one template argument, two function parameter std::max
- if (Call->getNumArgs() != 2) return;
- if (!IsStdFunction(FDecl, "max")) return;
- const auto * ArgList = FDecl->getTemplateSpecializationArgs();
- if (!ArgList) return;
- if (ArgList->size() != 1) return;
+ if (Call->getNumArgs() != 2)
+ return;
+ if (!IsStdFunction(FDecl, "max"))
+ return;
+ const auto *ArgList = FDecl->getTemplateSpecializationArgs();
+ if (!ArgList)
+ return;
+ if (ArgList->size() != 1)
+ return;
// Check that template type argument is unsigned integer.
- const auto& TA = ArgList->get(0);
- if (TA.getKind() != TemplateArgument::Type) return;
+ const auto &TA = ArgList->get(0);
+ if (TA.getKind() != TemplateArgument::Type)
+ return;
QualType ArgType = TA.getAsType();
- if (!ArgType->isUnsignedIntegerType()) return;
+ if (!ArgType->isUnsignedIntegerType())
+ return;
// See if either argument is a literal zero.
- auto IsLiteralZeroArg = [](const Expr* E) -> bool {
+ auto IsLiteralZeroArg = [](const Expr *E) -> bool {
const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E);
- if (!MTE) return false;
+ if (!MTE)
+ return false;
const auto *Num = dyn_cast<IntegerLiteral>(MTE->getSubExpr());
- if (!Num) return false;
- if (Num->getValue() != 0) return false;
+ if (!Num)
+ return false;
+ if (Num->getValue() != 0)
+ return false;
return true;
};
@@ -10474,7 +10502,8 @@ void Sema::CheckMaxUnsignedZero(const CallExpr *Call,
const bool IsSecondArgZero = IsLiteralZeroArg(SecondArg);
// Only warn when exactly one argument is zero.
- if (IsFirstArgZero == IsSecondArgZero) return;
+ if (IsFirstArgZero == IsSecondArgZero)
+ return;
SourceRange FirstRange = FirstArg->getSourceRange();
SourceRange SecondRange = SecondArg->getSourceRange();
@@ -10495,8 +10524,8 @@ void Sema::CheckMaxUnsignedZero(const CallExpr *Call,
}
Diag(Call->getExprLoc(), diag::note_remove_max_call)
- << FixItHint::CreateRemoval(Call->getCallee()->getSourceRange())
- << FixItHint::CreateRemoval(RemovalRange);
+ << FixItHint::CreateRemoval(Call->getCallee()->getSourceRange())
+ << FixItHint::CreateRemoval(RemovalRange);
}
//===--- CHECK: Standard memory functions ---------------------------------===//
@@ -10680,7 +10709,7 @@ struct SearchNonTrivialToCopyField
Sema &S;
};
-}
+} // namespace
/// Detect if \c SizeofExpr is likely to calculate the sizeof an object.
static bool doesExprLikelyComputeSize(const Expr *SizeofExpr) {
@@ -10724,7 +10753,7 @@ static void CheckMemaccessSize(Sema &S, unsigned BId, const CallExpr *Call) {
return;
const Expr *SizeArg =
- Call->getArg(BId == Builtin::BImemset ? 2 : 1)->IgnoreImpCasts();
+ Call->getArg(BId == Builtin::BImemset ? 2 : 1)->IgnoreImpCasts();
auto isLiteralZero = [](const Expr *E) {
return (isa<IntegerLiteral>(E) &&
@@ -10758,8 +10787,7 @@ static void CheckMemaccessSize(Sema &S, unsigned BId, const CallExpr *Call) {
// If the second argument to a memset is a sizeof expression and the third
// isn't, this is also likely an error. This should catch
// 'memset(buf, sizeof(buf), 0xff)'.
- if (BId == Builtin::BImemset &&
- doesExprLikelyComputeSize(Call->getArg(1)) &&
+ if (BId == Builtin::BImemset && doesExprLikelyComputeSize(Call->getArg(1)) &&
!doesExprLikelyComputeSize(Call->getArg(2))) {
SourceLocation DiagLoc = Call->getArg(1)->getExprLoc();
S.Diag(DiagLoc, diag::warn_suspicious_sizeof_memset) << 1;
@@ -10768,8 +10796,7 @@ static void CheckMemaccessSize(Sema &S, unsigned BId, const CallExpr *Call) {
}
}
-void Sema::CheckMemaccessArguments(const CallExpr *Call,
- unsigned BId,
+void Sema::CheckMemaccessArguments(const CallExpr *Call, unsigned BId,
IdentifierInfo *FnName) {
assert(BId != 0);
@@ -10781,7 +10808,9 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
return;
unsigned LastArg = (BId == Builtin::BImemset || BId == Builtin::BIbzero ||
- BId == Builtin::BIstrndup ? 1 : 2);
+ BId == Builtin::BIstrndup
+ ? 1
+ : 2);
unsigned LenArg =
(BId == Builtin::BIbzero || BId == Builtin::BIstrndup ? 1 : 2);
const Expr *LenExpr = Call->getArg(LenArg)->IgnoreParenImpCasts();
@@ -10832,9 +10861,9 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
Context.typesAreCompatible(SizeOfArgTy, DestTy)) {
DiagRuntimeBehavior(LenExpr->getExprLoc(), Dest,
PDiag(diag::warn_sizeof_pointer_type_memaccess)
- << FnName << SizeOfArgTy << ArgIdx
- << PointeeTy << Dest->getSourceRange()
- << LenExpr->getSourceRange());
+ << FnName << SizeOfArgTy << ArgIdx
+ << PointeeTy << Dest->getSourceRange()
+ << LenExpr->getSourceRange());
break;
}
}
@@ -10857,7 +10886,7 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
if (ArgIdx != 0 || IsCmp) {
if (BId == Builtin::BImemcpy)
OperationType = 1;
- else if(BId == Builtin::BImemmove)
+ else if (BId == Builtin::BImemmove)
OperationType = 2;
else if (IsCmp)
OperationType = 3;
@@ -10869,12 +10898,11 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
<< IsContained << ContainedRD << OperationType
<< Call->getCallee()->getSourceRange());
} else if (PointeeTy.hasNonTrivialObjCLifetime() &&
- BId != Builtin::BImemset)
- DiagRuntimeBehavior(
- Dest->getExprLoc(), Dest,
- PDiag(diag::warn_arc_object_memaccess)
- << ArgIdx << FnName << PointeeTy
- << Call->getCallee()->getSourceRange());
+ BId != Builtin::BImemset)
+ DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
+ PDiag(diag::warn_arc_object_memaccess)
+ << ArgIdx << FnName << PointeeTy
+ << Call->getCallee()->getSourceRange());
else if (const auto *RD = PointeeTy->getAsRecordDecl()) {
// FIXME: Do not consider incomplete types even though they may be
@@ -10918,9 +10946,9 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
continue;
DiagRuntimeBehavior(
- Dest->getExprLoc(), Dest,
- PDiag(diag::note_bad_memaccess_silence)
- << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)"));
+ Dest->getExprLoc(), Dest,
+ PDiag(diag::note_bad_memaccess_silence)
+ << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)"));
break;
}
}
@@ -10997,7 +11025,7 @@ static const Expr *ignoreLiteralAdditions(const Expr *Ex, ASTContext &Ctx) {
Ex = Ex->IgnoreParenCasts();
while (true) {
- const BinaryOperator * BO = dyn_cast<BinaryOperator>(Ex);
+ const BinaryOperator *BO = dyn_cast<BinaryOperator>(Ex);
if (!BO || !BO->isAdditiveOp())
break;
@@ -11167,8 +11195,8 @@ void Sema::CheckStrncatArguments(const CallExpr *CE,
// Check if the destination is an array (rather than a pointer to an array).
QualType DstTy = DstArg->getType();
- bool isKnownSizeArray = isConstantSizeArrayWithMoreThanOneElement(DstTy,
- Context);
+ bool isKnownSizeArray =
+ isConstantSizeArrayWithMoreThanOneElement(DstTy, Context);
if (!isKnownSizeArray) {
if (PatternType == 1)
Diag(SL, diag::warn_strncat_wrong_size) << SR;
@@ -11192,7 +11220,7 @@ void Sema::CheckStrncatArguments(const CallExpr *CE,
OS << ") - 1";
Diag(SL, diag::note_strncat_wrong_size)
- << FixItHint::CreateReplacement(SR, OS.str());
+ << FixItHint::CreateReplacement(SR, OS.str());
}
namespace {
@@ -11309,18 +11337,15 @@ void Sema::CheckFreeArguments(const CallExpr *E) {
return CheckFreeArgumentsCast(*this, CalleeName, Cast);
}
-void
-Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType,
- SourceLocation ReturnLoc,
- bool isObjCMethod,
- const AttrVec *Attrs,
- const FunctionDecl *FD) {
+void Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType,
+ SourceLocation ReturnLoc, bool isObjCMethod,
+ const AttrVec *Attrs, const FunctionDecl *FD) {
// Check if the return value is null but should not be.
if (((Attrs && hasSpecificAttr<ReturnsNonNullAttr>(*Attrs)) ||
(!isObjCMethod && isNonNullType(lhsType))) &&
CheckNonNullExpr(*this, RetValExp))
Diag(ReturnLoc, diag::warn_null_ret)
- << (isObjCMethod ? 1 : 0) << RetValExp->getSourceRange();
+ << (isObjCMethod ? 1 : 0) << RetValExp->getSourceRange();
// C++11 [basic.stc.dynamic.allocation]p4:
// If an allocation function declared with a non-throwing
@@ -11330,12 +11355,12 @@ Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType,
if (FD) {
OverloadedOperatorKind Op = FD->getOverloadedOperator();
if (Op == OO_New || Op == OO_Array_New) {
- const FunctionProtoType *Proto
- = FD->getType()->castAs<FunctionProtoType>();
- if (!Proto->isNothrow(/*ResultIfDependent*/true) &&
+ const FunctionProtoType *Proto =
+ FD->getType()->castAs<FunctionProtoType>();
+ if (!Proto->isNothrow(/*ResultIfDependent*/ true) &&
CheckNonNullExpr(*this, RetValExp))
Diag(ReturnLoc, diag::warn_operator_new_returns_null)
- << FD << getLangOpts().CPlusPlus11;
+ << FD << getLangOpts().CPlusPlus11;
}
}
@@ -11417,7 +11442,7 @@ void Sema::CheckFloatComparison(SourceLocation Loc, const Expr *LHS,
// Emit the diagnostic.
Diag(Loc, diag::warn_floatingpoint_eq)
- << LHS->getSourceRange() << RHS->getSourceRange();
+ << LHS->getSourceRange() << RHS->getSourceRange();
}
//===--- CHECK: Integer mixed-sign comparisons (-Wsign-compare) --------===//
@@ -11441,19 +11466,15 @@ struct IntRange {
: Width(Width), NonNegative(NonNegative) {}
/// Number of bits excluding the sign bit.
- unsigned valueBits() const {
- return NonNegative ? Width : Width - 1;
- }
+ unsigned valueBits() const { return NonNegative ? Width : Width - 1; }
/// Returns the range of the bool type.
- static IntRange forBoolType() {
- return IntRange(1, true);
- }
+ static IntRange forBoolType() { return IntRange(1, true); }
/// Returns the range of an opaque value of the given integral type.
static IntRange forValueOfType(ASTContext &C, QualType T) {
return forValueOfCanonicalType(C,
- T->getCanonicalTypeInternal().getTypePtr());
+ T->getCanonicalTypeInternal().getTypePtr());
}
/// Returns the range of an opaque value of a canonical integral type.
@@ -11488,10 +11509,10 @@ struct IntRange {
unsigned NumNegative = Enum->getNumNegativeBits();
if (NumNegative == 0)
- return IntRange(NumPositive, true/*NonNegative*/);
+ return IntRange(NumPositive, true /*NonNegative*/);
else
return IntRange(std::max(NumPositive + 1, NumNegative),
- false/*NonNegative*/);
+ false /*NonNegative*/);
}
if (const auto *EIT = dyn_cast<BitIntType>(T))
@@ -11785,8 +11806,8 @@ static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E,
case BO_Shl:
// ...except that we want to treat '1 << (blah)' as logically
// positive. It's an important idiom.
- if (IntegerLiteral *I
- = dyn_cast<IntegerLiteral>(BO->getLHS()->IgnoreParenCasts())) {
+ if (IntegerLiteral *I =
+ dyn_cast<IntegerLiteral>(BO->getLHS()->IgnoreParenCasts())) {
if (I->getValue() == 1) {
IntRange R = IntRange::forValueOfType(C, GetExprType(E));
return IntRange(R.Width, /*NonNegative*/ true);
@@ -12040,8 +12061,8 @@ static bool IsEnumConstOrFromMacro(Sema &S, const Expr *E) {
if (BeginLoc.isMacroID()) {
StringRef MacroName = Lexer::getImmediateMacroName(
BeginLoc, S.getSourceManager(), S.getLangOpts());
- return MacroName != "YES" && MacroName != "NO" &&
- MacroName != "true" && MacroName != "false";
+ return MacroName != "YES" && MacroName != "NO" && MacroName != "true" &&
+ MacroName != "false";
}
return false;
@@ -12118,21 +12139,30 @@ struct PromotedRange {
Value.isUnsigned() == PromotedMin.isUnsigned());
if (!isContiguous()) {
assert(Value.isUnsigned() && "discontiguous range for signed compare");
- if (Value.isMinValue()) return Min;
- if (Value.isMaxValue()) return Max;
- if (Value >= PromotedMin) return InRange;
- if (Value <= PromotedMax) return InRange;
+ if (Value.isMinValue())
+ return Min;
+ if (Value.isMaxValue())
+ return Max;
+ if (Value >= PromotedMin)
+ return InRange;
+ if (Value <= PromotedMax)
+ return InRange;
return InHole;
}
switch (llvm::APSInt::compareValues(Value, PromotedMin)) {
- case -1: return Less;
- case 0: return PromotedMin == PromotedMax ? OnlyValue : Min;
+ case -1:
+ return Less;
+ case 0:
+ return PromotedMin == PromotedMax ? OnlyValue : Min;
case 1:
switch (llvm::APSInt::compareValues(Value, PromotedMax)) {
- case -1: return InRange;
- case 0: return Max;
- case 1: return Greater;
+ case -1:
+ return InRange;
+ case 0:
+ return Max;
+ case 1:
+ return Greater;
}
}
@@ -12143,11 +12173,15 @@ struct PromotedRange {
constantValue(BinaryOperatorKind Op, ComparisonResult R, bool ConstantOnRHS) {
if (Op == BO_Cmp) {
ComparisonResult LTFlag = LT, GTFlag = GT;
- if (ConstantOnRHS) std::swap(LTFlag, GTFlag);
-
- if (R & EQ) return StringRef("'std::strong_ordering::equal'");
- if (R & LTFlag) return StringRef("'std::strong_ordering::less'");
- if (R & GTFlag) return StringRef("'std::strong_ordering::greater'");
+ if (ConstantOnRHS)
+ std::swap(LTFlag, GTFlag);
+
+ if (R & EQ)
+ return StringRef("'std::strong_ordering::equal'");
+ if (R & LTFlag)
+ return StringRef("'std::strong_ordering::less'");
+ if (R & GTFlag)
+ return StringRef("'std::strong_ordering::greater'");
return std::nullopt;
}
@@ -12176,13 +12210,12 @@ struct PromotedRange {
return std::nullopt;
}
};
-}
+} // namespace
static bool HasEnumType(const Expr *E) {
// Strip off implicit integral promotions.
while (const auto *ICE = dyn_cast<ImplicitCastExpr>(E)) {
- if (ICE->getCastKind() != CK_IntegralCast &&
- ICE->getCastKind() != CK_NoOp)
+ if (ICE->getCastKind() != CK_IntegralCast && ICE->getCastKind() != CK_NoOp)
break;
E = ICE->getSubExpr();
}
@@ -12193,11 +12226,7 @@ static bool HasEnumType(const Expr *E) {
static int classifyConstantValue(Expr *Constant) {
// The values of this enumeration are used in the diagnostics
// diag::warn_out_of_range_compare and diag::warn_tautological_bool_compare.
- enum ConstantValueKind {
- Miscellaneous = 0,
- LiteralTrue,
- LiteralFalse
- };
+ enum ConstantValueKind { Miscellaneous = 0, LiteralTrue, LiteralFalse };
if (auto *BL = dyn_cast<CXXBoolLiteralExpr>(Constant))
return BL->getValue() ? ConstantValueKind::LiteralTrue
: ConstantValueKind::LiteralFalse;
@@ -12307,7 +12336,7 @@ static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E,
if (ED) {
OS << '\'' << *ED << "' (" << Value << ")";
} else if (auto *BL = dyn_cast<ObjCBoolLiteralExpr>(
- Constant->IgnoreParenImpCasts())) {
+ Constant->IgnoreParenImpCasts())) {
OS << (BL->getValue() ? "YES" : "NO");
} else {
OS << Value;
@@ -12346,8 +12375,8 @@ static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E,
(isKnownToHaveUnsignedValue(OriginalOther) && Value == 0)
? (HasEnumType(OriginalOther)
? diag::warn_unsigned_enum_always_true_comparison
- : IsCharTy ? diag::warn_unsigned_char_always_true_comparison
- : diag::warn_unsigned_always_true_comparison)
+ : IsCharTy ? diag::warn_unsigned_char_always_true_comparison
+ : diag::warn_unsigned_always_true_comparison)
: diag::warn_tautological_constant_compare;
S.Diag(E->getOperatorLoc(), Diag)
@@ -12498,7 +12527,7 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
// White-list bool bitfields.
QualType BitfieldType = Bitfield->getType();
if (BitfieldType->isBooleanType())
- return false;
+ return false;
if (auto *BitfieldEnumDecl = BitfieldType->getAsEnumDecl()) {
// If the underlying enum type was not explicitly specified as an unsigned
@@ -12515,8 +12544,7 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
// Ignore value- or type-dependent expressions.
if (Bitfield->getBitWidth()->isValueDependent() ||
- Bitfield->getBitWidth()->isTypeDependent() ||
- Init->isValueDependent() ||
+ Bitfield->getBitWidth()->isTypeDependent() || Init->isValueDependent() ||
Init->isTypeDependent())
return false;
@@ -12695,7 +12723,7 @@ static void DiagnoseImpCast(Sema &S, const Expr *E, QualType SourceType,
return;
}
S.Diag(E->getExprLoc(), diag)
- << SourceType << T << E->getSourceRange() << SourceRange(CContext);
+ << SourceType << T << E->getSourceRange() << SourceRange(CContext);
}
/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion.
@@ -12721,7 +12749,7 @@ static void DiagnoseFloatingImpCast(Sema &S, const Expr *E, QualType T,
llvm::APFloat Value(0.0);
bool IsConstant =
- E->EvaluateAsFloat(Value, S.Context, Expr::SE_AllowSideEffects);
+ E->EvaluateAsFloat(Value, S.Context, Expr::SE_AllowSideEffects);
if (!IsConstant) {
if (S.ObjC().isSignedCharBool(T)) {
return S.ObjC().adornBoolConversionDiagWithTernaryFixit(
@@ -12729,8 +12757,8 @@ static void DiagnoseFloatingImpCast(Sema &S, const Expr *E, QualType T,
<< E->getType());
}
- return DiagnoseImpCast(S, E, T, CContext,
- diag::warn_impcast_float_integer, PruneWarnings);
+ return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer,
+ PruneWarnings);
}
bool isExact = false;
@@ -12757,7 +12785,8 @@ static void DiagnoseFloatingImpCast(Sema &S, const Expr *E, QualType T,
}
if (Result == llvm::APFloat::opOK && isExact) {
- if (IsLiteral) return;
+ if (IsLiteral)
+ return;
return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer,
PruneWarnings);
}
@@ -12776,7 +12805,7 @@ static void DiagnoseFloatingImpCast(Sema &S, const Expr *E, QualType T,
// Warn on floating point literal to integer.
DiagID = diag::warn_impcast_literal_float_to_integer;
} else if (IntegerValue == 0) {
- if (Value.isZero()) { // Skip -0.0 to 0 conversion.
+ if (Value.isZero()) { // Skip -0.0 to 0 conversion.
return DiagnoseImpCast(S, E, T, CContext,
diag::warn_impcast_float_integer, PruneWarnings);
}
@@ -12788,7 +12817,7 @@ static void DiagnoseFloatingImpCast(Sema &S, const Expr *E, QualType T,
return DiagnoseImpCast(S, E, T, CContext,
diag::warn_impcast_float_integer, PruneWarnings);
}
- } else { // IntegerValue.isSigned()
+ } else { // IntegerValue.isSigned()
if (!IntegerValue.isMaxSignedValue() &&
!IntegerValue.isMinSignedValue()) {
return DiagnoseImpCast(S, E, T, CContext,
@@ -12837,7 +12866,8 @@ static void AnalyzeCompoundAssignment(Sema &S, BinaryOperator *E) {
->getAs<BuiltinType>();
// The below checks assume source is floating point.
- if (!ResultBT || !RBT || !RBT->isFloatingPoint()) return;
+ if (!ResultBT || !RBT || !RBT->isFloatingPoint())
+ return;
// If source is floating point but target is an integer.
if (ResultBT->isInteger())
@@ -12858,7 +12888,8 @@ static void AnalyzeCompoundAssignment(Sema &S, BinaryOperator *E) {
static std::string PrettyPrintInRange(const llvm::APSInt &Value,
IntRange Range) {
- if (!Range.Width) return "0";
+ if (!Range.Width)
+ return "0";
llvm::APSInt ValueInRange = Value;
ValueInRange.setIsSigned(!Range.NonNegative);
@@ -12874,7 +12905,7 @@ static bool IsImplicitBoolFloatConversion(Sema &S, const Expr *Ex,
const Expr *InnerE = Ex->IgnoreParenImpCasts();
const Type *Target = S.Context.getCanonicalType(Ex->getType()).getTypePtr();
const Type *Source =
- S.Context.getCanonicalType(InnerE->getType()).getTypePtr();
+ S.Context.getCanonicalType(InnerE->getType()).getTypePtr();
if (Target->isDependentType())
return false;
@@ -12899,8 +12930,7 @@ static void CheckImplicitArgumentConversions(Sema &S, const CallExpr *TheCall,
S, TheCall->getArg(I + 1), false));
if (IsSwapped) {
// Warn on this floating-point to bool conversion.
- DiagnoseImpCast(S, CurrA->IgnoreParenImpCasts(),
- CurrA->getType(), CC,
+ DiagnoseImpCast(S, CurrA->IgnoreParenImpCasts(), CurrA->getType(), CC,
diag::warn_impcast_floating_point_to_bool);
}
}
@@ -13102,12 +13132,15 @@ bool Sema::DiscardingCFIUncheckedCallee(QualType From, QualType To) const {
void Sema::CheckImplicitConversion(Expr *E, QualType T, SourceLocation CC,
bool *ICContext, bool IsListInit) {
- if (E->isTypeDependent() || E->isValueDependent()) return;
+ if (E->isTypeDependent() || E->isValueDependent())
+ return;
const Type *Source = Context.getCanonicalType(E->getType()).getTypePtr();
const Type *Target = Context.getCanonicalType(T).getTypePtr();
- if (Source == Target) return;
- if (Target->isDependentType()) return;
+ if (Source == Target)
+ return;
+ if (Target->isDependentType())
+ return;
// If the conversion context location is invalid don't complain. We also
// don't want to emit a warning if the issue occurs from the expansion of
@@ -13685,7 +13718,8 @@ static void CheckConditionalOperator(Sema &S, AbstractConditionalOperator *E,
// If -Wconversion would have warned about either of the candidates
// for a signedness conversion to the context type...
- if (!Suspicious) return;
+ if (!Suspicious)
+ return;
// ...but it's currently ignored...
if (!S.Diags.isIgnored(diag::warn_impcast_integer_sign_conditional, CC))
@@ -13693,7 +13727,8 @@ static void CheckConditionalOperator(Sema &S, AbstractConditionalOperator *E,
// ...then check whether it would have warned about either of the
// candidates for a signedness conversion to the condition type.
- if (E->getType() == T) return;
+ if (E->getType() == T)
+ return;
Suspicious = false;
S.CheckImplicitConversion(TrueExpr->IgnoreParenImpCasts(), E->getType(), CC,
@@ -13722,7 +13757,7 @@ struct AnalyzeImplicitConversionsWorkItem {
SourceLocation CC;
bool IsListInit;
};
-}
+} // namespace
static void CheckCommaOperand(
Sema &S, Expr *E, QualType T, SourceLocation CC,
@@ -13895,10 +13930,12 @@ static void AnalyzeImplicitConversions(
// we don't really need to recurse into them, because any internal
// expressions should have been analyzed already when they were
// built into statements.
- if (isa<StmtExpr>(E)) return;
+ if (isa<StmtExpr>(E))
+ return;
// Don't descend into unevaluated contexts.
- if (isa<UnaryExprOrTypeTraitExpr>(E)) return;
+ if (isa<UnaryExprOrTypeTraitExpr>(E))
+ return;
// Now just recurse over the expression's children.
CC = E->getExprLoc();
@@ -13949,7 +13986,7 @@ static void AnalyzeImplicitConversions(
/// implicit conversions in the given expression. There are a couple
/// of competing diagnostics here, -Wconversion and -Wsign-compare.
static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC,
- bool IsListInit/*= false*/) {
+ bool IsListInit /*= false*/) {
llvm::SmallVector<AnalyzeImplicitConversionsWorkItem, 16> WorkList;
WorkList.push_back({OrigE, CC, IsListInit});
while (!WorkList.empty())
@@ -14041,8 +14078,8 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
unsigned DiagID = IsCompare
? diag::warn_address_of_reference_null_compare
: diag::warn_address_of_reference_bool_conversion;
- PartialDiagnostic PD = PDiag(DiagID) << E->getSourceRange() << Range
- << IsEqual;
+ PartialDiagnostic PD = PDiag(DiagID)
+ << E->getSourceRange() << Range << IsEqual;
if (CheckForReference(*this, E, PD)) {
return;
}
@@ -14055,8 +14092,8 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
E->printPretty(S, nullptr, getPrintingPolicy());
unsigned DiagID = IsCompare ? diag::warn_nonnull_expr_compare
: diag::warn_cast_nonnull_to_bool;
- Diag(E->getExprLoc(), DiagID) << IsParam << S.str()
- << E->getSourceRange() << Range << IsEqual;
+ Diag(E->getExprLoc(), DiagID)
+ << IsParam << S.str() << E->getSourceRange() << Range << IsEqual;
Diag(NonnullAttr->getLocation(), diag::note_declared_nonnull) << IsParam;
};
@@ -14097,7 +14134,7 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
return;
// Check for parameter decl with nonnull attribute
- if (const auto* PV = dyn_cast<ParmVarDecl>(D)) {
+ if (const auto *PV = dyn_cast<ParmVarDecl>(D)) {
if (getCurFunction() &&
!getCurFunction()->ModifiedNonNullParams.count(PV)) {
if (const Attr *A = PV->getAttr<NonNullAttr>()) {
@@ -14115,8 +14152,8 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
if (!NonNull->args_size()) {
- ComplainAboutNonnullParamOrCall(NonNull);
- return;
+ ComplainAboutNonnullParamOrCall(NonNull);
+ return;
}
for (const ParamIdx &ArgNo : NonNull->args()) {
@@ -14150,11 +14187,7 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
unsigned DiagID = IsCompare ? diag::warn_null_pointer_compare
: diag::warn_impcast_pointer_to_bool;
- enum {
- AddressOf,
- FunctionPointer,
- ArrayPointer
- } DiagType;
+ enum { AddressOf, FunctionPointer, ArrayPointer } DiagType;
if (IsAddressOf)
DiagType = AddressOf;
else if (IsFunction)
@@ -14163,8 +14196,8 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
DiagType = ArrayPointer;
else
llvm_unreachable("Could not determine diagnostic.");
- Diag(E->getExprLoc(), DiagID) << DiagType << S.str() << E->getSourceRange()
- << Range << IsEqual;
+ Diag(E->getExprLoc(), DiagID)
+ << DiagType << S.str() << E->getSourceRange() << Range << IsEqual;
if (!IsFunction)
return;
@@ -14259,7 +14292,7 @@ void Sema::CheckBoolLikeConversion(Expr *E, SourceLocation CC) {
::CheckBoolLikeConversion(*this, E, CC);
}
-void Sema::CheckForIntOverflow (const Expr *E) {
+void Sema::CheckForIntOverflow(const Expr *E) {
// Use a work list to deal with nested struct initializers.
SmallVector<const Expr *, 2> Exprs(1, E);
@@ -14288,8 +14321,7 @@ void Sema::CheckForIntOverflow (const Expr *E) {
Exprs.push_back(Array->getIdx());
else if (const auto *Compound = dyn_cast<CompoundLiteralExpr>(E))
Exprs.push_back(Compound->getInitializer());
- else if (const auto *New = dyn_cast<CXXNewExpr>(E);
- New && New->isArray()) {
+ else if (const auto *New = dyn_cast<CXXNewExpr>(E); New && New->isArray()) {
if (auto ArraySize = New->getArraySize())
Exprs.push_back(*ArraySize);
} else if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(OriginalE))
@@ -14344,9 +14376,7 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
}
/// Merge a sequence of operations into its parent.
- void merge(Seq S) {
- Values[S.Index].Merged = true;
- }
+ void merge(Seq S) { Values[S.Index].Merged = true; }
/// Determine whether two operations are unsequenced. This operation
/// is asymmetric: \p Cur should be the more recent sequence, and \p Old
@@ -14437,7 +14467,7 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
/// UK_ModAsValue.
struct SequencedSubexpression {
SequencedSubexpression(SequenceChecker &Self)
- : Self(Self), OldModAsSideEffect(Self.ModAsSideEffect) {
+ : Self(Self), OldModAsSideEffect(Self.ModAsSideEffect) {
Self.ModAsSideEffect = &ModAsSideEffect;
}
@@ -15189,9 +15219,8 @@ void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc,
}
void Sema::CheckBitFieldInitialization(SourceLocation InitLoc,
- FieldDecl *BitField,
- Expr *Init) {
- (void) AnalyzeBitFieldAssignment(*this, BitField, Init, InitLoc);
+ FieldDecl *BitField, Expr *Init) {
+ (void)AnalyzeBitFieldAssignment(*this, BitField, Init, InitLoc);
}
static void diagnoseArrayStarInParamType(Sema &S, QualType PType,
@@ -15566,39 +15595,44 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) {
// Require that the destination be a pointer type.
const PointerType *DestPtr = T->getAs<PointerType>();
- if (!DestPtr) return;
+ if (!DestPtr)
+ return;
// If the destination has alignment 1, we're done.
QualType DestPointee = DestPtr->getPointeeType();
- if (DestPointee->isIncompleteType()) return;
+ if (DestPointee->isIncompleteType())
+ return;
CharUnits DestAlign = Context.getTypeAlignInChars(DestPointee);
- if (DestAlign.isOne()) return;
+ if (DestAlign.isOne())
+ return;
// Require that the source be a pointer type.
const PointerType *SrcPtr = Op->getType()->getAs<PointerType>();
- if (!SrcPtr) return;
+ if (!SrcPtr)
+ return;
QualType SrcPointee = SrcPtr->getPointeeType();
// Explicitly allow casts from cv void*. We already implicitly
// allowed casts to cv void*, since they have alignment 1.
// Also allow casts involving incomplete types, which implicitly
// includes 'void'.
- if (SrcPointee->isIncompleteType()) return;
+ if (SrcPointee->isIncompleteType())
+ return;
CharUnits SrcAlign = getPresumedAlignmentOfPointer(Op, *this);
- if (SrcAlign >= DestAlign) return;
+ if (SrcAlign >= DestAlign)
+ return;
Diag(TRange.getBegin(), diag::warn_cast_align)
- << Op->getType() << T
- << static_cast<unsigned>(SrcAlign.getQuantity())
- << static_cast<unsigned>(DestAlign.getQuantity())
- << TRange << Op->getSourceRange();
+ << Op->getType() << T << static_cast<unsigned>(SrcAlign.getQuantity())
+ << static_cast<unsigned>(DestAlign.getQuantity()) << TRange
+ << Op->getSourceRange();
}
void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
- const ArraySubscriptExpr *ASE,
- bool AllowOnePastEnd, bool IndexNegated) {
+ const ArraySubscriptExpr *ASE, bool AllowOnePastEnd,
+ bool IndexNegated) {
// Already diagnosed by the constant evaluator.
if (isConstantEvaluatedContext())
return;
@@ -15613,8 +15647,8 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
const ConstantArrayType *ArrayTy =
Context.getAsConstantArrayType(BaseExpr->getType());
- LangOptions::StrictFlexArraysLevelKind
- StrictFlexArraysLevel = getLangOpts().getStrictFlexArraysLevel();
+ LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
+ getLangOpts().getStrictFlexArraysLevel();
const Type *BaseType =
ArrayTy == nullptr ? nullptr : ArrayTy->getElementType().getTypePtr();
@@ -15752,8 +15786,8 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
// ']' location) and the index expression are both from macro expansions
// within a system header.
if (ASE) {
- SourceLocation RBracketLoc = SourceMgr.getSpellingLoc(
- ASE->getRBracketLoc());
+ SourceLocation RBracketLoc =
+ SourceMgr.getSpellingLoc(ASE->getRBracketLoc());
if (SourceMgr.isInSystemHeader(RBracketLoc)) {
SourceLocation IndexLoc =
SourceMgr.getSpellingLoc(IndexExpr->getBeginLoc());
@@ -15775,7 +15809,8 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
unsigned DiagID = diag::warn_array_index_precedes_bounds;
if (!ASE) {
DiagID = diag::warn_ptr_arith_precedes_bounds;
- if (index.isNegative()) index = -index;
+ if (index.isNegative())
+ index = -index;
}
DiagRuntimeBehavior(BaseExpr->getBeginLoc(), BaseExpr,
@@ -15801,68 +15836,67 @@ void Sema::CheckArrayAccess(const Expr *expr) {
while (expr) {
expr = expr->IgnoreParenImpCasts();
switch (expr->getStmtClass()) {
- case Stmt::ArraySubscriptExprClass: {
- const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(expr);
- CheckArrayAccess(ASE->getBase(), ASE->getIdx(), ASE,
- AllowOnePastEnd > 0);
- expr = ASE->getBase();
- break;
- }
- case Stmt::MemberExprClass: {
- expr = cast<MemberExpr>(expr)->getBase();
- break;
- }
- case Stmt::CXXMemberCallExprClass: {
- expr = cast<CXXMemberCallExpr>(expr)->getImplicitObjectArgument();
+ case Stmt::ArraySubscriptExprClass: {
+ const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(expr);
+ CheckArrayAccess(ASE->getBase(), ASE->getIdx(), ASE, AllowOnePastEnd > 0);
+ expr = ASE->getBase();
+ break;
+ }
+ case Stmt::MemberExprClass: {
+ expr = cast<MemberExpr>(expr)->getBase();
+ break;
+ }
+ case Stmt::CXXMemberCallExprClass: {
+ expr = cast<CXXMemberCallExpr>(expr)->getImplicitObjectArgument();
+ break;
+ }
+ case Stmt::ArraySectionExprClass: {
+ const ArraySectionExpr *ASE = cast<ArraySectionExpr>(expr);
+ // FIXME: We should probably be checking all of the elements to the
+ // 'length' here as well.
+ if (ASE->getLowerBound())
+ CheckArrayAccess(ASE->getBase(), ASE->getLowerBound(),
+ /*ASE=*/nullptr, AllowOnePastEnd > 0);
+ return;
+ }
+ case Stmt::UnaryOperatorClass: {
+ // Only unwrap the * and & unary operators
+ const UnaryOperator *UO = cast<UnaryOperator>(expr);
+ expr = UO->getSubExpr();
+ switch (UO->getOpcode()) {
+ case UO_AddrOf:
+ AllowOnePastEnd++;
break;
- }
- case Stmt::ArraySectionExprClass: {
- const ArraySectionExpr *ASE = cast<ArraySectionExpr>(expr);
- // FIXME: We should probably be checking all of the elements to the
- // 'length' here as well.
- if (ASE->getLowerBound())
- CheckArrayAccess(ASE->getBase(), ASE->getLowerBound(),
- /*ASE=*/nullptr, AllowOnePastEnd > 0);
- return;
- }
- case Stmt::UnaryOperatorClass: {
- // Only unwrap the * and & unary operators
- const UnaryOperator *UO = cast<UnaryOperator>(expr);
- expr = UO->getSubExpr();
- switch (UO->getOpcode()) {
- case UO_AddrOf:
- AllowOnePastEnd++;
- break;
- case UO_Deref:
- AllowOnePastEnd--;
- break;
- default:
- return;
- }
+ case UO_Deref:
+ AllowOnePastEnd--;
break;
- }
- case Stmt::ConditionalOperatorClass: {
- const ConditionalOperator *cond = cast<ConditionalOperator>(expr);
- if (const Expr *lhs = cond->getLHS())
- CheckArrayAccess(lhs);
- if (const Expr *rhs = cond->getRHS())
- CheckArrayAccess(rhs);
- return;
- }
- case Stmt::CXXOperatorCallExprClass: {
- const auto *OCE = cast<CXXOperatorCallExpr>(expr);
- for (const auto *Arg : OCE->arguments())
- CheckArrayAccess(Arg);
- return;
- }
default:
return;
+ }
+ break;
+ }
+ case Stmt::ConditionalOperatorClass: {
+ const ConditionalOperator *cond = cast<ConditionalOperator>(expr);
+ if (const Expr *lhs = cond->getLHS())
+ CheckArrayAccess(lhs);
+ if (const Expr *rhs = cond->getRHS())
+ CheckArrayAccess(rhs);
+ return;
+ }
+ case Stmt::CXXOperatorCallExprClass: {
+ const auto *OCE = cast<CXXOperatorCallExpr>(expr);
+ for (const auto *Arg : OCE->arguments())
+ CheckArrayAccess(Arg);
+ return;
+ }
+ default:
+ return;
}
}
}
-static bool checkUnsafeAssignLiteral(Sema &S, SourceLocation Loc,
- Expr *RHS, bool isProperty) {
+static bool checkUnsafeAssignLiteral(Sema &S, SourceLocation Loc, Expr *RHS,
+ bool isProperty) {
// Check if RHS is an Objective-C object literal, which also can get
// immediately zapped in a weak reference. Note that we explicitly
// allow ObjCStringLiterals, since those are designed to never really die.
@@ -15875,23 +15909,20 @@ static bool checkUnsafeAssignLiteral(Sema &S, SourceLocation Loc,
return false;
S.Diag(Loc, diag::warn_arc_literal_assign)
- << (unsigned) Kind
- << (isProperty ? 0 : 1)
- << RHS->getSourceRange();
+ << (unsigned)Kind << (isProperty ? 0 : 1) << RHS->getSourceRange();
return true;
}
static bool checkUnsafeAssignObject(Sema &S, SourceLocation Loc,
- Qualifiers::ObjCLifetime LT,
- Expr *RHS, bool isProperty) {
+ Qualifiers::ObjCLifetime LT, Expr *RHS,
+ bool isProperty) {
// Strip off any implicit cast added to get to the one ARC-specific.
while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
if (cast->getCastKind() == CK_ARCConsumeObject) {
S.Diag(Loc, diag::warn_arc_retained_assign)
- << (LT == Qualifiers::OCL_ExplicitNone)
- << (isProperty ? 0 : 1)
- << RHS->getSourceRange();
+ << (LT == Qualifiers::OCL_ExplicitNone) << (isProperty ? 0 : 1)
+ << RHS->getSourceRange();
return true;
}
RHS = cast->getSubExpr();
@@ -15904,8 +15935,7 @@ static bool checkUnsafeAssignObject(Sema &S, SourceLocation Loc,
return false;
}
-bool Sema::checkUnsafeAssigns(SourceLocation Loc,
- QualType LHS, Expr *RHS) {
+bool Sema::checkUnsafeAssigns(SourceLocation Loc, QualType LHS, Expr *RHS) {
Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime();
if (LT != Qualifiers::OCL_Weak && LT != Qualifiers::OCL_ExplicitNone)
@@ -15917,13 +15947,11 @@ bool Sema::checkUnsafeAssigns(SourceLocation Loc,
return false;
}
-void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
- Expr *LHS, Expr *RHS) {
+void Sema::checkUnsafeExprAssigns(SourceLocation Loc, Expr *LHS, Expr *RHS) {
QualType LHSType;
// PropertyRef on LHS type need be directly obtained from
// its declaration as it has a PseudoType.
- ObjCPropertyRefExpr *PRE
- = dyn_cast<ObjCPropertyRefExpr>(LHS->IgnoreParens());
+ ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(LHS->IgnoreParens());
if (PRE && !PRE->isImplicitProperty()) {
const ObjCPropertyDecl *PD = PRE->getExplicitProperty();
if (PD)
@@ -15967,7 +15995,7 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
if (cast->getCastKind() == CK_ARCConsumeObject) {
Diag(Loc, diag::warn_arc_retained_property_assign)
- << RHS->getSourceRange();
+ << RHS->getSourceRange();
return;
}
RHS = cast->getSubExpr();
@@ -15994,14 +16022,14 @@ static bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr,
// Get line numbers of statement and body.
bool StmtLineInvalid;
- unsigned StmtLine = SourceMgr.getPresumedLineNumber(StmtLoc,
- &StmtLineInvalid);
+ unsigned StmtLine =
+ SourceMgr.getPresumedLineNumber(StmtLoc, &StmtLineInvalid);
if (StmtLineInvalid)
return false;
bool BodyLineInvalid;
- unsigned BodyLine = SourceMgr.getSpellingLineNumber(Body->getSemiLoc(),
- &BodyLineInvalid);
+ unsigned BodyLine =
+ SourceMgr.getSpellingLineNumber(Body->getSemiLoc(), &BodyLineInvalid);
if (BodyLineInvalid)
return false;
@@ -16012,8 +16040,7 @@ static bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr,
return true;
}
-void Sema::DiagnoseEmptyStmtBody(SourceLocation StmtLoc,
- const Stmt *Body,
+void Sema::DiagnoseEmptyStmtBody(SourceLocation StmtLoc, const Stmt *Body,
unsigned DiagID) {
// Since this is a syntactic check, don't emit diagnostic for template
// instantiations, this just adds noise.
@@ -16033,8 +16060,7 @@ void Sema::DiagnoseEmptyStmtBody(SourceLocation StmtLoc,
Diag(NBody->getSemiLoc(), diag::note_empty_body_on_separate_line);
}
-void Sema::DiagnoseEmptyLoopBody(const Stmt *S,
- const Stmt *PossibleBody) {
+void Sema::DiagnoseEmptyLoopBody(const Stmt *S, const Stmt *PossibleBody) {
assert(!CurrentInstantiationScope); // Ensured by caller
SourceLocation StmtLoc;
@@ -16102,7 +16128,7 @@ void Sema::DiagnoseEmptyLoopBody(const Stmt *S,
//===--- CHECK: Warn on self move with std::move. -------------------------===//
void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr,
- SourceLocation OpLoc) {
+ SourceLocation OpLoc) {
if (Diags.isIgnored(diag::warn_sizeof_pointer_expr_memaccess, OpLoc))
return;
@@ -16278,10 +16304,10 @@ static bool isLayoutCompatibleUnion(const ASTContext &C, const RecordDecl *RD1,
auto I = UnmatchedFields.begin();
auto E = UnmatchedFields.end();
- for ( ; I != E; ++I) {
+ for (; I != E; ++I) {
if (isLayoutCompatible(C, Field1, *I, /*IsUnionMember=*/true)) {
bool Result = UnmatchedFields.erase(*I);
- (void) Result;
+ (void)Result;
assert(Result);
break;
}
@@ -16379,7 +16405,7 @@ bool Sema::IsPointerInterconvertibleBaseOf(const TypeSourceInfo *Base,
static bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx,
const ValueDecl **VD, uint64_t *MagicValue,
bool isConstantEvaluated) {
- while(true) {
+ while (true) {
if (!TypeExpr)
return false;
@@ -16491,8 +16517,7 @@ static bool GetMatchingCType(
if (!MagicValues)
return false;
- llvm::DenseMap<Sema::TypeTagMagicValue,
- Sema::TypeTagData>::const_iterator I =
+ llvm::DenseMap<Sema::TypeTagMagicValue, Sema::TypeTagData>::const_iterator I =
MagicValues->find(std::make_pair(ArgumentKind, MagicValue));
if (I == MagicValues->end())
return false;
@@ -16503,8 +16528,7 @@ static bool GetMatchingCType(
void Sema::RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind,
uint64_t MagicValue, QualType Type,
- bool LayoutCompatible,
- bool MustBeNull) {
+ bool LayoutCompatible, bool MustBeNull) {
if (!TypeTagForDatatypeMagicValues)
TypeTagForDatatypeMagicValues.reset(
new llvm::DenseMap<TypeTagMagicValue, TypeTagData>);
@@ -16526,8 +16550,8 @@ static bool IsSameCharType(QualType T1, QualType T2) {
BuiltinType::Kind T1Kind = BT1->getKind();
BuiltinType::Kind T2Kind = BT2->getKind();
- return (T1Kind == BuiltinType::SChar && T2Kind == BuiltinType::Char_S) ||
- (T1Kind == BuiltinType::UChar && T2Kind == BuiltinType::Char_U) ||
+ return (T1Kind == BuiltinType::SChar && T2Kind == BuiltinType::Char_S) ||
+ (T1Kind == BuiltinType::UChar && T2Kind == BuiltinType::Char_U) ||
(T1Kind == BuiltinType::Char_U && T2Kind == BuiltinType::UChar) ||
(T1Kind == BuiltinType::Char_S && T2Kind == BuiltinType::SChar);
}
@@ -16554,7 +16578,7 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
if (FoundWrongKind)
Diag(TypeTagExpr->getExprLoc(),
diag::warn_type_tag_for_datatype_wrong_kind)
- << TypeTagExpr->getSourceRange();
+ << TypeTagExpr->getSourceRange();
return;
}
@@ -16581,12 +16605,11 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
if (TypeInfo.MustBeNull) {
// Type tag with matching void type requires a null pointer.
- if (!ArgumentExpr->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNotNull)) {
+ if (!ArgumentExpr->isNullPointerConstant(
+ Context, Expr::NPC_ValueDependentIsNotNull)) {
Diag(ArgumentExpr->getExprLoc(),
diag::warn_type_safety_null_pointer_required)
- << ArgumentKind->getName()
- << ArgumentExpr->getSourceRange()
+ << ArgumentKind->getName() << ArgumentExpr->getSourceRange()
<< TypeTagExpr->getSourceRange();
}
return;
@@ -16610,19 +16633,16 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
RequiredType->getPointeeType())) ||
(!IsPointerAttr && IsSameCharType(ArgumentType, RequiredType)))
mismatch = false;
- } else
- if (IsPointerAttr)
- mismatch = !isLayoutCompatible(Context,
- ArgumentType->getPointeeType(),
- RequiredType->getPointeeType());
- else
- mismatch = !isLayoutCompatible(Context, ArgumentType, RequiredType);
+ } else if (IsPointerAttr)
+ mismatch = !isLayoutCompatible(Context, ArgumentType->getPointeeType(),
+ RequiredType->getPointeeType());
+ else
+ mismatch = !isLayoutCompatible(Context, ArgumentType, RequiredType);
if (mismatch)
Diag(ArgumentExpr->getExprLoc(), diag::warn_type_safety_type_mismatch)
- << ArgumentType << ArgumentKind
- << TypeInfo.LayoutCompatible << RequiredType
- << ArgumentExpr->getSourceRange()
+ << ArgumentType << ArgumentKind << TypeInfo.LayoutCompatible
+ << RequiredType << ArgumentExpr->getSourceRange()
<< TypeTagExpr->getSourceRange();
}
@@ -16718,7 +16738,7 @@ void Sema::RefersToMemberWithReducedAlignment(
// For now, just disregard these cases. This is left for future
// improvement.
if (!DRE && !isa<CXXThisExpr>(TopBase))
- return;
+ return;
// Alignment expected by the whole expression.
CharUnits ExpectedAlignment = Context.getTypeAlignInChars(E->getType());
@@ -17298,3 +17318,50 @@ void Sema::CheckTCBEnforcement(const SourceLocation CallExprLoc,
}
}
}
+
+bool Sema::BuiltinStartLifetimeAs(CallExpr *Call) {
+ if (checkArgCount(Call, 1))
+ return true;
+
+ // Defer checking if the call is type or value dependent (like inside an
+ // uninstatiated template).
+ if (Call->isTypeDependent() || Call->isValueDependent())
+ return false;
+
+ Expr *PtrArg = Call->getArg(0);
+ QualType PtrType = PtrArg->getType();
+
+ // Ensure that the argument is a standard C/C++ pointer.
+ if (!PtrType->isPointerType()) {
+ Diag(PtrArg->getExprLoc(), diag::err_typecheck_convert_incompatible)
+ << PtrType << "pointer" << 1 << 0 << 0 << PtrArg->getSourceRange();
+ return true;
+ }
+
+ QualType PointeeType = PtrType->getPointeeType();
+
+ // void and function pointers can't gave lifetimes.
+ if (PointeeType->isVoidType() || PointeeType->isFunctionType()) {
+ Diag(PtrArg->getExprLoc(), diag::err_start_lifetime_as_not_implicit)
+ << PointeeType << PtrArg->getSourceRange();
+ return true;
+ }
+
+ // P2679R2: Recursively unwrap array types.
+ QualType BaseElemType = Context.getBaseElementType(PointeeType);
+
+ // We cannot evaluate lifetime properties of an incomplete type
+ if (RequireCompleteType(PtrArg->getExprLoc(), BaseElemType,
+ diag::err_incomplete_type))
+ return true;
+
+ // Enforce C++23 implicit-lifetime constraints.
+ if (!BaseElemType->isImplicitLifetimeType()) {
+ Diag(PtrArg->getExprLoc(), diag::err_start_lifetime_as_not_implicit)
+ << PointeeType << PtrArg->getSourceRange();
+ return true;
+ }
+
+ Call->setType(PtrType);
+ return false;
+}
diff --git a/clang/test/SemaCXX/builtin-start-lifetime-as.cpp b/clang/test/SemaCXX/builtin-start-lifetime-as.cpp
new file mode 100644
index 0000000000000..eb5c1a559d648
--- /dev/null
+++ b/clang/test/SemaCXX/builtin-start-lifetime-as.cpp
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++23 %s
+
+struct Trivial {
+ int x;
+ float y;
+};
+
+struct NonTrivial {
+ int x;
+ ~NonTrivial() {}
+};
+
+struct Incomplete; // expected-note {{forward declaration of 'Incomplete'}}
+
+void test_valid_cases(void* ptr) {
+ // Should complete without any diagnostics.
+ __builtin_start_lifetime_as((int*)ptr);
+ __builtin_start_lifetime_as((Trivial*)ptr);
+
+ // P2679R2 check
+ __builtin_start_lifetime_as((int(*)[5])ptr);
+ __builtin_start_lifetime_as((Trivial(*)[5][10])ptr);
+}
+
+void test_invalid_types(void* ptr) {
+ // expected-error at +1 {{type 'NonTrivial' is not an implicit-lifetime type, cannot start lifetime}}
+ __builtin_start_lifetime_as((NonTrivial*)ptr);
+
+ // expected-error at +1 {{type 'NonTrivial[5]' is not an implicit-lifetime type, cannot start lifetime}}
+ __builtin_start_lifetime_as((NonTrivial(*)[5])ptr);
+
+ // expected-error at +1 {{type 'void' is not an implicit-lifetime type, cannot start lifetime}}
+ __builtin_start_lifetime_as((void*)ptr);
+
+ // expected-error at +1 {{type 'void ()' is not an implicit-lifetime type, cannot start lifetime}}
+ __builtin_start_lifetime_as((void(*)())ptr);
+}
+
+void test_incomplete_types(void* ptr) {
+ // expected-error at +1 {{incomplete type 'Incomplete' where a complete type is required}}
+ __builtin_start_lifetime_as((Incomplete*)ptr);
+}
+
+void test_invalid_arguments() {
+ int x;
+ // expected-error at +1 {{passing 'int' to parameter of incompatible type pointer}}
+ __builtin_start_lifetime_as(x);
+
+ // expected-error at +1 {{too few arguments to function call, expected 1, have 0}}
+ __builtin_start_lifetime_as();
+}
+
+void test_constexpr() {
+ // expected-error at +2 {{constexpr variable 'ptr' must be initialized by a constant expression}}
+ constexpr auto* ptr = (int*)__builtin_start_lifetime_as((int*)nullptr);
+}
\ No newline at end of file
>From 58faeff61395eedd5d99ecebe2e8044967ab57f0 Mon Sep 17 00:00:00 2001
From: Yash Verma <yashverma056 at proton.me>
Date: Thu, 7 May 2026 05:25:56 -0400
Subject: [PATCH 3/4] [Clang][CodeGen] Implement IR emission for
`__builtin_start_lifetime_as`
Implements the CodeGen path for C++23's explicit lifetime management (P2679R2).
Includes a CodeGen test verifying the expected pass-through behavior.
---
clang/lib/CodeGen/CGBuiltin.cpp | 525 +++++++++---------
.../CodeGenCXX/builtin-start-lifetime-as.cpp | 13 +
2 files changed, 277 insertions(+), 261 deletions(-)
create mode 100644 clang/test/CodeGenCXX/builtin-start-lifetime-as.cpp
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 67de2a34f44ea..8135b7c1c000c 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -26,6 +26,7 @@
#include "TargetInfo.h"
#include "clang/AST/OSLog.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/IR/InlineAsm.h"
@@ -244,15 +245,15 @@ llvm::Constant *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD,
}
llvm::FunctionType *Ty =
- cast<llvm::FunctionType>(getTypes().ConvertType(FD->getType()));
+ cast<llvm::FunctionType>(getTypes().ConvertType(FD->getType()));
return GetOrCreateLLVMFunction(Name, Ty, D, /*ForVTable=*/false);
}
/// Emit the conversions required to turn the given value into an
/// integer of the given size.
-Value *EmitToInt(CodeGenFunction &CGF, llvm::Value *V,
- QualType T, llvm::IntegerType *IntType) {
+Value *EmitToInt(CodeGenFunction &CGF, llvm::Value *V, QualType T,
+ llvm::IntegerType *IntType) {
V = CGF.EmitToMemory(V, T);
if (V->getType()->isPointerTy())
@@ -262,8 +263,8 @@ Value *EmitToInt(CodeGenFunction &CGF, llvm::Value *V,
return V;
}
-Value *EmitFromInt(CodeGenFunction &CGF, llvm::Value *V,
- QualType T, llvm::Type *ResultType) {
+Value *EmitFromInt(CodeGenFunction &CGF, llvm::Value *V, QualType T,
+ llvm::Type *ResultType) {
V = CGF.EmitFromMemory(V, T);
if (ResultType->isPointerTy())
@@ -292,14 +293,14 @@ Address CheckAtomicAlignment(CodeGenFunction &CGF, const CallExpr *E) {
/// Utility to insert an atomic instruction based on Intrinsic::ID
/// and the expression node.
-Value *MakeBinaryAtomicValue(
- CodeGenFunction &CGF, llvm::AtomicRMWInst::BinOp Kind, const CallExpr *E,
- AtomicOrdering Ordering) {
+Value *MakeBinaryAtomicValue(CodeGenFunction &CGF,
+ llvm::AtomicRMWInst::BinOp Kind, const CallExpr *E,
+ AtomicOrdering Ordering) {
QualType T = E->getType();
assert(E->getArg(0)->getType()->isPointerType());
- assert(CGF.getContext().hasSameUnqualifiedType(T,
- E->getArg(0)->getType()->getPointeeType()));
+ assert(CGF.getContext().hasSameUnqualifiedType(
+ T, E->getArg(0)->getType()->getPointeeType()));
assert(CGF.getContext().hasSameUnqualifiedType(T, E->getArg(1)->getType()));
Address DestAddr = CheckAtomicAlignment(CGF, E);
@@ -346,13 +347,12 @@ static RValue EmitBinaryAtomic(CodeGenFunction &CGF,
/// operation.
static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF,
llvm::AtomicRMWInst::BinOp Kind,
- const CallExpr *E,
- Instruction::BinaryOps Op,
+ const CallExpr *E, Instruction::BinaryOps Op,
bool Invert = false) {
QualType T = E->getType();
assert(E->getArg(0)->getType()->isPointerType());
- assert(CGF.getContext().hasSameUnqualifiedType(T,
- E->getArg(0)->getType()->getPointeeType()));
+ assert(CGF.getContext().hasSameUnqualifiedType(
+ T, E->getArg(0)->getType()->getPointeeType()));
assert(CGF.getContext().hasSameUnqualifiedType(T, E->getArg(1)->getType()));
Address DestAddr = CheckAtomicAlignment(CGF, E);
@@ -429,8 +429,8 @@ Value *MakeAtomicCmpXchgValue(CodeGenFunction &CGF, const CallExpr *E,
/// function MakeAtomicCmpXchgValue since it expects the arguments to be
/// already swapped.
-static
-Value *EmitAtomicCmpXchgForMSIntrin(CodeGenFunction &CGF, const CallExpr *E,
+static Value *EmitAtomicCmpXchgForMSIntrin(
+ CodeGenFunction &CGF, const CallExpr *E,
AtomicOrdering SuccessOrdering = AtomicOrdering::SequentiallyConsistent) {
assert(E->getArg(0)->getType()->isPointerType());
assert(CGF.getContext().hasSameUnqualifiedType(
@@ -453,9 +453,9 @@ Value *EmitAtomicCmpXchgForMSIntrin(CodeGenFunction &CGF, const CallExpr *E,
}
// For Release ordering, the failure ordering should be Monotonic.
- auto FailureOrdering = SuccessOrdering == AtomicOrdering::Release ?
- AtomicOrdering::Monotonic :
- SuccessOrdering;
+ auto FailureOrdering = SuccessOrdering == AtomicOrdering::Release
+ ? AtomicOrdering::Monotonic
+ : SuccessOrdering;
// The atomic instruction is marked volatile for consistency with MSVC. This
// blocks the few atomics optimizations that LLVM has. If we want to optimize
@@ -538,7 +538,8 @@ static Value *EmitAtomicCmpXchg128ForMSIntrin(CodeGenFunction &CGF,
return CGF.Builder.CreateZExt(Success, CGF.Int8Ty);
}
-static Value *EmitAtomicIncrementValue(CodeGenFunction &CGF, const CallExpr *E,
+static Value *EmitAtomicIncrementValue(
+ CodeGenFunction &CGF, const CallExpr *E,
AtomicOrdering Ordering = AtomicOrdering::SequentiallyConsistent) {
assert(E->getArg(0)->getType()->isPointerType());
@@ -591,14 +592,15 @@ static Value *EmitISOVolatileStore(CodeGenFunction &CGF, const CallExpr *E) {
// matching the argument type. Depending on mode, this may be a constrained
// floating-point intrinsic.
Value *emitUnaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF,
- const CallExpr *E, unsigned IntrinsicID,
- unsigned ConstrainedIntrinsicID) {
+ const CallExpr *E,
+ unsigned IntrinsicID,
+ unsigned ConstrainedIntrinsicID) {
llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0));
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E);
if (CGF.Builder.getIsFPConstrained()) {
Function *F = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, Src0->getType());
- return CGF.Builder.CreateConstrainedFPCall(F, { Src0 });
+ return CGF.Builder.CreateConstrainedFPCall(F, {Src0});
} else {
Function *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType());
return CGF.Builder.CreateCall(F, Src0);
@@ -607,19 +609,20 @@ Value *emitUnaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF,
// Emit an intrinsic that has 2 operands of the same type as its result.
// Depending on mode, this may be a constrained floating-point intrinsic.
-static Value *emitBinaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF,
- const CallExpr *E, unsigned IntrinsicID,
- unsigned ConstrainedIntrinsicID) {
+static Value *
+emitBinaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, const CallExpr *E,
+ unsigned IntrinsicID,
+ unsigned ConstrainedIntrinsicID) {
llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0));
llvm::Value *Src1 = CGF.EmitScalarExpr(E->getArg(1));
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E);
if (CGF.Builder.getIsFPConstrained()) {
Function *F = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, Src0->getType());
- return CGF.Builder.CreateConstrainedFPCall(F, { Src0, Src1 });
+ return CGF.Builder.CreateConstrainedFPCall(F, {Src0, Src1});
} else {
Function *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType());
- return CGF.Builder.CreateCall(F, { Src0, Src1 });
+ return CGF.Builder.CreateCall(F, {Src0, Src1});
}
}
@@ -645,9 +648,10 @@ emitBinaryExpMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, const CallExpr *E,
// Emit an intrinsic that has 3 operands of the same type as its result.
// Depending on mode, this may be a constrained floating-point intrinsic.
-static Value *emitTernaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF,
- const CallExpr *E, unsigned IntrinsicID,
- unsigned ConstrainedIntrinsicID) {
+static Value *
+emitTernaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, const CallExpr *E,
+ unsigned IntrinsicID,
+ unsigned ConstrainedIntrinsicID) {
llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0));
llvm::Value *Src1 = CGF.EmitScalarExpr(E->getArg(1));
llvm::Value *Src2 = CGF.EmitScalarExpr(E->getArg(2));
@@ -655,10 +659,10 @@ static Value *emitTernaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF,
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E);
if (CGF.Builder.getIsFPConstrained()) {
Function *F = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, Src0->getType());
- return CGF.Builder.CreateConstrainedFPCall(F, { Src0, Src1, Src2 });
+ return CGF.Builder.CreateConstrainedFPCall(F, {Src0, Src1, Src2});
} else {
Function *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType());
- return CGF.Builder.CreateCall(F, { Src0, Src1, Src2 });
+ return CGF.Builder.CreateCall(F, {Src0, Src1, Src2});
}
}
@@ -858,11 +862,11 @@ llvm::Value *EmitOverflowIntrinsic(CodeGenFunction &CGF,
}
namespace {
- struct WidthAndSignedness {
- unsigned Width;
- bool Signed;
- };
-}
+struct WidthAndSignedness {
+ unsigned Width;
+ bool Signed;
+};
+} // namespace
static WidthAndSignedness
getIntegerWidthAndSignedness(const clang::ASTContext &context,
@@ -921,11 +925,9 @@ getDefaultBuiltinObjectSizeResult(unsigned Type, llvm::IntegerType *ResType) {
return ConstantInt::get(ResType, (Type & 2) ? 0 : -1, /*isSigned=*/true);
}
-llvm::Value *
-CodeGenFunction::evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type,
- llvm::IntegerType *ResType,
- llvm::Value *EmittedE,
- bool IsDynamic) {
+llvm::Value *CodeGenFunction::evaluateOrEmitBuiltinObjectSize(
+ const Expr *E, unsigned Type, llvm::IntegerType *ResType,
+ llvm::Value *EmittedE, bool IsDynamic) {
if (std::optional<uint64_t> ObjectSize =
E->tryEvaluateObjectSize(getContext(), Type))
return ConstantInt::get(ResType, *ObjectSize, /*isSigned=*/true);
@@ -1505,10 +1507,11 @@ llvm::Value *CodeGenFunction::emitCountedByMemberSize(
/// EmittedE is the result of emitting `E` as a scalar expr. If it's non-null
/// and we wouldn't otherwise try to reference a pass_object_size parameter,
/// we'll call @llvm.objectsize on EmittedE, rather than emitting E.
-llvm::Value *
-CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type,
- llvm::IntegerType *ResType,
- llvm::Value *EmittedE, bool IsDynamic) {
+llvm::Value *CodeGenFunction::emitBuiltinObjectSize(const Expr *E,
+ unsigned Type,
+ llvm::IntegerType *ResType,
+ llvm::Value *EmittedE,
+ bool IsDynamic) {
// We need to reference an argument if the pointer is a parameter with the
// pass_object_size attribute.
if (auto *D = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) {
@@ -1637,16 +1640,19 @@ BitTest BitTest::decodeBitTestBuiltin(unsigned BuiltinID) {
static char bitActionToX86BTCode(BitTest::ActionKind A) {
switch (A) {
- case BitTest::TestOnly: return '\0';
- case BitTest::Complement: return 'c';
- case BitTest::Reset: return 'r';
- case BitTest::Set: return 's';
+ case BitTest::TestOnly:
+ return '\0';
+ case BitTest::Complement:
+ return 'c';
+ case BitTest::Reset:
+ return 'r';
+ case BitTest::Set:
+ return 's';
}
llvm_unreachable("invalid action");
}
-static llvm::Value *EmitX86BitTestIntrinsic(CodeGenFunction &CGF,
- BitTest BT,
+static llvm::Value *EmitX86BitTestIntrinsic(CodeGenFunction &CGF, BitTest BT,
const CallExpr *E, Value *BitBase,
Value *BitPos) {
char Action = bitActionToX86BTCode(BT.Action);
@@ -1683,11 +1689,16 @@ static llvm::Value *EmitX86BitTestIntrinsic(CodeGenFunction &CGF,
static llvm::AtomicOrdering
getBitTestAtomicOrdering(BitTest::InterlockingKind I) {
switch (I) {
- case BitTest::Unlocked: return llvm::AtomicOrdering::NotAtomic;
- case BitTest::Sequential: return llvm::AtomicOrdering::SequentiallyConsistent;
- case BitTest::Acquire: return llvm::AtomicOrdering::Acquire;
- case BitTest::Release: return llvm::AtomicOrdering::Release;
- case BitTest::NoFence: return llvm::AtomicOrdering::Monotonic;
+ case BitTest::Unlocked:
+ return llvm::AtomicOrdering::NotAtomic;
+ case BitTest::Sequential:
+ return llvm::AtomicOrdering::SequentiallyConsistent;
+ case BitTest::Acquire:
+ return llvm::AtomicOrdering::Acquire;
+ case BitTest::Release:
+ return llvm::AtomicOrdering::Release;
+ case BitTest::NoFence:
+ return llvm::AtomicOrdering::Monotonic;
}
llvm_unreachable("invalid interlocking");
}
@@ -1789,11 +1800,7 @@ static llvm::Value *EmitBitTestIntrinsic(CodeGenFunction &CGF,
}
namespace {
-enum class MSVCSetJmpKind {
- _setjmpex,
- _setjmp3,
- _setjmp
-};
+enum class MSVCSetJmpKind { _setjmpex, _setjmp3, _setjmp };
}
/// MSVC handles setjmp a bit differently on different platforms. On every
@@ -2029,7 +2036,7 @@ struct CallObjCArcUse final : EHScopeStack::Cleanup {
CGF.EmitARCIntrinsicUse(object);
}
};
-}
+} // namespace
Value *CodeGenFunction::EmitCheckedArgForBuiltin(const Expr *E,
BuiltinCheckKind Kind) {
@@ -2291,8 +2298,8 @@ RValue CodeGenFunction::emitBuiltinOSLogFormat(const CallExpr &E) {
unsigned ArgValSize =
CGM.getDataLayout().getTypeSizeInBits(ArgVal->getType());
- llvm::IntegerType *IntTy = llvm::Type::getIntNTy(getLLVMContext(),
- ArgValSize);
+ llvm::IntegerType *IntTy =
+ llvm::Type::getIntNTy(getLLVMContext(), ArgValSize);
ArgVal = Builder.CreateBitOrPointerCast(ArgVal, IntTy);
CanQualType ArgTy = getOSLogArgType(Ctx, Size);
// If ArgVal has type x86_fp80, zero-extend ArgVal.
@@ -2427,8 +2434,7 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1,
IsNegative, CGF.Builder.CreateIsNotNull(UnsignedResult));
Overflow = CGF.Builder.CreateOr(UnsignedOverflow, Underflow);
if (ResultInfo.Width < OpWidth) {
- auto IntMax =
- llvm::APInt::getMaxValue(ResultInfo.Width).zext(OpWidth);
+ auto IntMax = llvm::APInt::getMaxValue(ResultInfo.Width).zext(OpWidth);
llvm::Value *TruncOverflow = CGF.Builder.CreateICmpUGT(
UnsignedResult, llvm::ConstantInt::get(OpTy, IntMax));
Overflow = CGF.Builder.CreateOr(Overflow, TruncOverflow);
@@ -2548,69 +2554,69 @@ RValue CodeGenFunction::emitRotate(const CallExpr *E, bool IsRotateRight) {
// Map math builtins for long-double to f128 version.
static unsigned mutateLongDoubleBuiltin(unsigned BuiltinID) {
switch (BuiltinID) {
-#define MUTATE_LDBL(func) \
- case Builtin::BI__builtin_##func##l: \
+#define MUTATE_LDBL(func) \
+ case Builtin::BI__builtin_##func##l: \
return Builtin::BI__builtin_##func##f128;
- MUTATE_LDBL(sqrt)
- MUTATE_LDBL(cbrt)
- MUTATE_LDBL(fabs)
- MUTATE_LDBL(log)
- MUTATE_LDBL(log2)
- MUTATE_LDBL(log10)
- MUTATE_LDBL(log1p)
- MUTATE_LDBL(logb)
- MUTATE_LDBL(exp)
- MUTATE_LDBL(exp2)
- MUTATE_LDBL(expm1)
- MUTATE_LDBL(fdim)
- MUTATE_LDBL(hypot)
- MUTATE_LDBL(ilogb)
- MUTATE_LDBL(pow)
- MUTATE_LDBL(fmin)
- MUTATE_LDBL(fmax)
- MUTATE_LDBL(ceil)
- MUTATE_LDBL(trunc)
- MUTATE_LDBL(rint)
- MUTATE_LDBL(nearbyint)
- MUTATE_LDBL(round)
- MUTATE_LDBL(floor)
- MUTATE_LDBL(lround)
- MUTATE_LDBL(llround)
- MUTATE_LDBL(lrint)
- MUTATE_LDBL(llrint)
- MUTATE_LDBL(fmod)
- MUTATE_LDBL(modf)
- MUTATE_LDBL(nan)
- MUTATE_LDBL(nans)
- MUTATE_LDBL(inf)
- MUTATE_LDBL(fma)
- MUTATE_LDBL(sin)
- MUTATE_LDBL(cos)
- MUTATE_LDBL(tan)
- MUTATE_LDBL(sinh)
- MUTATE_LDBL(cosh)
- MUTATE_LDBL(tanh)
- MUTATE_LDBL(asin)
- MUTATE_LDBL(acos)
- MUTATE_LDBL(atan)
- MUTATE_LDBL(asinh)
- MUTATE_LDBL(acosh)
- MUTATE_LDBL(atanh)
- MUTATE_LDBL(atan2)
- MUTATE_LDBL(erf)
- MUTATE_LDBL(erfc)
- MUTATE_LDBL(ldexp)
- MUTATE_LDBL(frexp)
- MUTATE_LDBL(huge_val)
- MUTATE_LDBL(copysign)
- MUTATE_LDBL(nextafter)
- MUTATE_LDBL(nexttoward)
- MUTATE_LDBL(remainder)
- MUTATE_LDBL(remquo)
- MUTATE_LDBL(scalbln)
- MUTATE_LDBL(scalbn)
- MUTATE_LDBL(tgamma)
- MUTATE_LDBL(lgamma)
+ MUTATE_LDBL(sqrt)
+ MUTATE_LDBL(cbrt)
+ MUTATE_LDBL(fabs)
+ MUTATE_LDBL(log)
+ MUTATE_LDBL(log2)
+ MUTATE_LDBL(log10)
+ MUTATE_LDBL(log1p)
+ MUTATE_LDBL(logb)
+ MUTATE_LDBL(exp)
+ MUTATE_LDBL(exp2)
+ MUTATE_LDBL(expm1)
+ MUTATE_LDBL(fdim)
+ MUTATE_LDBL(hypot)
+ MUTATE_LDBL(ilogb)
+ MUTATE_LDBL(pow)
+ MUTATE_LDBL(fmin)
+ MUTATE_LDBL(fmax)
+ MUTATE_LDBL(ceil)
+ MUTATE_LDBL(trunc)
+ MUTATE_LDBL(rint)
+ MUTATE_LDBL(nearbyint)
+ MUTATE_LDBL(round)
+ MUTATE_LDBL(floor)
+ MUTATE_LDBL(lround)
+ MUTATE_LDBL(llround)
+ MUTATE_LDBL(lrint)
+ MUTATE_LDBL(llrint)
+ MUTATE_LDBL(fmod)
+ MUTATE_LDBL(modf)
+ MUTATE_LDBL(nan)
+ MUTATE_LDBL(nans)
+ MUTATE_LDBL(inf)
+ MUTATE_LDBL(fma)
+ MUTATE_LDBL(sin)
+ MUTATE_LDBL(cos)
+ MUTATE_LDBL(tan)
+ MUTATE_LDBL(sinh)
+ MUTATE_LDBL(cosh)
+ MUTATE_LDBL(tanh)
+ MUTATE_LDBL(asin)
+ MUTATE_LDBL(acos)
+ MUTATE_LDBL(atan)
+ MUTATE_LDBL(asinh)
+ MUTATE_LDBL(acosh)
+ MUTATE_LDBL(atanh)
+ MUTATE_LDBL(atan2)
+ MUTATE_LDBL(erf)
+ MUTATE_LDBL(erfc)
+ MUTATE_LDBL(ldexp)
+ MUTATE_LDBL(frexp)
+ MUTATE_LDBL(huge_val)
+ MUTATE_LDBL(copysign)
+ MUTATE_LDBL(nextafter)
+ MUTATE_LDBL(nexttoward)
+ MUTATE_LDBL(remainder)
+ MUTATE_LDBL(remquo)
+ MUTATE_LDBL(scalbln)
+ MUTATE_LDBL(scalbn)
+ MUTATE_LDBL(tgamma)
+ MUTATE_LDBL(lgamma)
#undef MUTATE_LDBL
default:
return BuiltinID;
@@ -2711,11 +2717,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
if (E->isPRValue() && E->EvaluateAsRValue(Result, CGM.getContext()) &&
!Result.hasSideEffects()) {
if (Result.Val.isInt())
- return RValue::get(llvm::ConstantInt::get(getLLVMContext(),
- Result.Val.getInt()));
+ return RValue::get(
+ llvm::ConstantInt::get(getLLVMContext(), Result.Val.getInt()));
if (Result.Val.isFloat())
- return RValue::get(llvm::ConstantFP::get(getLLVMContext(),
- Result.Val.getFloat()));
+ return RValue::get(
+ llvm::ConstantFP::get(getLLVMContext(), Result.Val.getFloat()));
}
// If current long-double semantics is IEEE 128-bit, replace math builtins
@@ -2813,9 +2819,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_ceill:
case Builtin::BI__builtin_ceilf128:
case Builtin::BI__builtin_elementwise_ceil:
- return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
- Intrinsic::ceil,
- Intrinsic::experimental_constrained_ceil));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(
+ *this, E, Intrinsic::ceil, Intrinsic::experimental_constrained_ceil));
case Builtin::BIcopysign:
case Builtin::BIcopysignf:
@@ -2837,9 +2842,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_cosl:
case Builtin::BI__builtin_cosf128:
case Builtin::BI__builtin_elementwise_cos:
- return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
- Intrinsic::cos,
- Intrinsic::experimental_constrained_cos));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(
+ *this, E, Intrinsic::cos, Intrinsic::experimental_constrained_cos));
case Builtin::BIcosh:
case Builtin::BIcoshf:
@@ -2862,9 +2866,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_expl:
case Builtin::BI__builtin_expf128:
case Builtin::BI__builtin_elementwise_exp:
- return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
- Intrinsic::exp,
- Intrinsic::experimental_constrained_exp));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(
+ *this, E, Intrinsic::exp, Intrinsic::experimental_constrained_exp));
case Builtin::BIexp2:
case Builtin::BIexp2f:
@@ -2875,9 +2878,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_exp2l:
case Builtin::BI__builtin_exp2f128:
case Builtin::BI__builtin_elementwise_exp2:
- return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
- Intrinsic::exp2,
- Intrinsic::experimental_constrained_exp2));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(
+ *this, E, Intrinsic::exp2, Intrinsic::experimental_constrained_exp2));
case Builtin::BI__builtin_exp10:
case Builtin::BI__builtin_exp10f:
case Builtin::BI__builtin_exp10f16:
@@ -2910,9 +2912,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_floorl:
case Builtin::BI__builtin_floorf128:
case Builtin::BI__builtin_elementwise_floor:
- return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
- Intrinsic::floor,
- Intrinsic::experimental_constrained_floor));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(
+ *this, E, Intrinsic::floor,
+ Intrinsic::experimental_constrained_floor));
case Builtin::BIfma:
case Builtin::BIfmaf:
@@ -2923,9 +2925,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_fmal:
case Builtin::BI__builtin_fmaf128:
case Builtin::BI__builtin_elementwise_fma:
- return RValue::get(emitTernaryMaybeConstrainedFPBuiltin(*this, E,
- Intrinsic::fma,
- Intrinsic::experimental_constrained_fma));
+ return RValue::get(emitTernaryMaybeConstrainedFPBuiltin(
+ *this, E, Intrinsic::fma, Intrinsic::experimental_constrained_fma));
case Builtin::BIfmax:
case Builtin::BIfmaxf:
@@ -3011,9 +3012,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_logl:
case Builtin::BI__builtin_logf128:
case Builtin::BI__builtin_elementwise_log:
- return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
- Intrinsic::log,
- Intrinsic::experimental_constrained_log));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(
+ *this, E, Intrinsic::log, Intrinsic::experimental_constrained_log));
case Builtin::BIlog10:
case Builtin::BIlog10f:
@@ -3024,9 +3024,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_log10l:
case Builtin::BI__builtin_log10f128:
case Builtin::BI__builtin_elementwise_log10:
- return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
- Intrinsic::log10,
- Intrinsic::experimental_constrained_log10));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(
+ *this, E, Intrinsic::log10,
+ Intrinsic::experimental_constrained_log10));
case Builtin::BIlog2:
case Builtin::BIlog2f:
@@ -3037,9 +3037,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_log2l:
case Builtin::BI__builtin_log2f128:
case Builtin::BI__builtin_elementwise_log2:
- return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
- Intrinsic::log2,
- Intrinsic::experimental_constrained_log2));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(
+ *this, E, Intrinsic::log2, Intrinsic::experimental_constrained_log2));
case Builtin::BInearbyint:
case Builtin::BInearbyintf:
@@ -3049,9 +3048,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_nearbyintl:
case Builtin::BI__builtin_nearbyintf128:
case Builtin::BI__builtin_elementwise_nearbyint:
- return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
- Intrinsic::nearbyint,
- Intrinsic::experimental_constrained_nearbyint));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(
+ *this, E, Intrinsic::nearbyint,
+ Intrinsic::experimental_constrained_nearbyint));
case Builtin::BIpow:
case Builtin::BIpowf:
@@ -3062,9 +3061,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_powl:
case Builtin::BI__builtin_powf128:
case Builtin::BI__builtin_elementwise_pow:
- return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(*this, E,
- Intrinsic::pow,
- Intrinsic::experimental_constrained_pow));
+ return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(
+ *this, E, Intrinsic::pow, Intrinsic::experimental_constrained_pow));
case Builtin::BIrint:
case Builtin::BIrintf:
@@ -3075,9 +3073,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_rintl:
case Builtin::BI__builtin_rintf128:
case Builtin::BI__builtin_elementwise_rint:
- return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
- Intrinsic::rint,
- Intrinsic::experimental_constrained_rint));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(
+ *this, E, Intrinsic::rint, Intrinsic::experimental_constrained_rint));
case Builtin::BIround:
case Builtin::BIroundf:
@@ -3088,9 +3085,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_roundl:
case Builtin::BI__builtin_roundf128:
case Builtin::BI__builtin_elementwise_round:
- return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
- Intrinsic::round,
- Intrinsic::experimental_constrained_round));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(
+ *this, E, Intrinsic::round,
+ Intrinsic::experimental_constrained_round));
case Builtin::BIroundeven:
case Builtin::BIroundevenf:
@@ -3101,9 +3098,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_roundevenl:
case Builtin::BI__builtin_roundevenf128:
case Builtin::BI__builtin_elementwise_roundeven:
- return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
- Intrinsic::roundeven,
- Intrinsic::experimental_constrained_roundeven));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(
+ *this, E, Intrinsic::roundeven,
+ Intrinsic::experimental_constrained_roundeven));
case Builtin::BIsin:
case Builtin::BIsinf:
@@ -3114,9 +3111,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_sinl:
case Builtin::BI__builtin_sinf128:
case Builtin::BI__builtin_elementwise_sin:
- return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
- Intrinsic::sin,
- Intrinsic::experimental_constrained_sin));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(
+ *this, E, Intrinsic::sin, Intrinsic::experimental_constrained_sin));
case Builtin::BIsinh:
case Builtin::BIsinhf:
@@ -3199,9 +3195,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_truncl:
case Builtin::BI__builtin_truncf128:
case Builtin::BI__builtin_elementwise_trunc:
- return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
- Intrinsic::trunc,
- Intrinsic::experimental_constrained_trunc));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(
+ *this, E, Intrinsic::trunc,
+ Intrinsic::experimental_constrained_trunc));
case Builtin::BIlround:
case Builtin::BIlroundf:
@@ -3282,7 +3278,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
};
switch (BuiltinIDIfNoAsmLabel) {
- default: break;
+ default:
+ break;
case Builtin::BI__builtin___CFStringMakeConstantString:
case Builtin::BI__builtin___NSStringMakeConstantString:
return RValue::get(ConstantEmitter(*this).emitAbstract(E, E->getType()));
@@ -3361,13 +3358,15 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
// is available as debuginfo is needed to preserve user-level
// access pattern.
if (!getDebugInfo()) {
- CGM.Error(E->getExprLoc(), "using builtin_preserve_access_index() without -g");
+ CGM.Error(E->getExprLoc(),
+ "using builtin_preserve_access_index() without -g");
return RValue::get(EmitScalarExpr(E->getArg(0)));
}
// Nested builtin_preserve_access_index() not supported
if (IsInPreservedAIRegion) {
- CGM.Error(E->getExprLoc(), "nested builtin_preserve_access_index() not supported");
+ CGM.Error(E->getExprLoc(),
+ "nested builtin_preserve_access_index() not supported");
return RValue::get(EmitScalarExpr(E->getArg(0)));
}
@@ -3404,8 +3403,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Value *Ctlz = Builder.CreateCall(F, {Tmp, Builder.getFalse()});
Value *Result =
Builder.CreateNUWSub(Ctlz, llvm::ConstantInt::get(ArgType, 1));
- Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
- "cast");
+ Result =
+ Builder.CreateIntCast(Result, ResultType, /*isSigned*/ true, "cast");
return RValue::get(Result);
}
case Builtin::BI__builtin_ctzs:
@@ -3499,8 +3498,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero, "iszero");
Value *Result = Builder.CreateSelect(IsZero, Zero, Tmp, "ffs");
if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
- "cast");
+ Result =
+ Builder.CreateIntCast(Result, ResultType, /*isSigned*/ true, "cast");
return RValue::get(Result);
}
case Builtin::BI__builtin_parity:
@@ -3516,8 +3515,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Value *Tmp = Builder.CreateCall(F, ArgValue);
Value *Result = Builder.CreateAnd(Tmp, llvm::ConstantInt::get(ArgType, 1));
if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
- "cast");
+ Result =
+ Builder.CreateIntCast(Result, ResultType, /*isSigned*/ true, "cast");
return RValue::get(Result);
}
case Builtin::BI__lzcnt16:
@@ -3531,8 +3530,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
llvm::Type *ResultType = ConvertType(E->getType());
Value *Result = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
- "cast");
+ Result =
+ Builder.CreateIntCast(Result, ResultType, /*isSigned*/ true, "cast");
return RValue::get(Result);
}
case Builtin::BI__popcnt16:
@@ -3607,7 +3606,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
const Expr *Ptr = E->getArg(0);
Value *PtrValue = EmitScalarExpr(Ptr);
Value *OffsetValue =
- (E->getNumArgs() > 2) ? EmitScalarExpr(E->getArg(2)) : nullptr;
+ (E->getNumArgs() > 2) ? EmitScalarExpr(E->getArg(2)) : nullptr;
Value *AlignmentValue = EmitScalarExpr(E->getArg(1));
ConstantInt *AlignmentCI = cast<ConstantInt>(AlignmentValue);
@@ -3982,7 +3981,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
CGM.getIntrinsic(Intrinsic::is_constant, ConvertType(ArgType));
Value *Result = Builder.CreateCall(F, ArgValue);
if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/false);
+ Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/ false);
return RValue::get(Result);
}
case Builtin::BI__builtin_dynamic_object_size:
@@ -4029,10 +4028,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_prefetch: {
Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0));
// FIXME: Technically these constants should of type 'int', yes?
- RW = (E->getNumArgs() > 1) ? EmitScalarExpr(E->getArg(1)) :
- llvm::ConstantInt::get(Int32Ty, 0);
- Locality = (E->getNumArgs() > 2) ? EmitScalarExpr(E->getArg(2)) :
- llvm::ConstantInt::get(Int32Ty, 3);
+ RW = (E->getNumArgs() > 1) ? EmitScalarExpr(E->getArg(1))
+ : llvm::ConstantInt::get(Int32Ty, 0);
+ Locality = (E->getNumArgs() > 2) ? EmitScalarExpr(E->getArg(2))
+ : llvm::ConstantInt::get(Int32Ty, 3);
Value *Data = llvm::ConstantInt::get(Int32Ty, 1);
Function *F = CGM.getIntrinsic(Intrinsic::prefetch, Address->getType());
Builder.CreateCall(F, {Address, RW, Locality, Data});
@@ -4091,12 +4090,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E);
Function *F = CGM.getIntrinsic(Intrinsic::experimental_constrained_powi,
Src0->getType());
- return RValue::get(Builder.CreateConstrainedFPCall(F, { Src0, Src1 }));
+ return RValue::get(Builder.CreateConstrainedFPCall(F, {Src0, Src1}));
}
- Function *F = CGM.getIntrinsic(Intrinsic::powi,
- { Src0->getType(), Src1->getType() });
- return RValue::get(Builder.CreateCall(F, { Src0, Src1 }));
+ Function *F =
+ CGM.getIntrinsic(Intrinsic::powi, {Src0->getType(), Src1->getType()});
+ return RValue::get(Builder.CreateCall(F, {Src0, Src1}));
}
case Builtin::BI__builtin_frexpl: {
// Linux PPC will not be adding additional PPCDoubleDouble support.
@@ -4133,7 +4132,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Value *RHS = EmitScalarExpr(E->getArg(1));
switch (BuiltinID) {
- default: llvm_unreachable("Unknown ordered comparison");
+ default:
+ llvm_unreachable("Unknown ordered comparison");
case Builtin::BI__builtin_isgreater:
LHS = Builder.CreateFCmpOGT(LHS, RHS, "cmp");
break;
@@ -4620,8 +4620,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
llvm::Type *ResultType = ConvertType(E->getType());
Value *Result = Builder.CreateCall(F);
if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
- "cast");
+ Result =
+ Builder.CreateIntCast(Result, ResultType, /*isSigned*/ true, "cast");
return RValue::get(Result);
}
@@ -4643,14 +4643,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
BasicBlock *Begin = Builder.GetInsertBlock();
BasicBlock *End = createBasicBlock("fpclassify_end", this->CurFn);
Builder.SetInsertPoint(End);
- PHINode *Result =
- Builder.CreatePHI(ConvertType(E->getArg(0)->getType()), 4,
- "fpclassify_result");
+ PHINode *Result = Builder.CreatePHI(ConvertType(E->getArg(0)->getType()), 4,
+ "fpclassify_result");
// if (V==0) return FP_ZERO
Builder.SetInsertPoint(Begin);
- Value *IsZero = Builder.CreateFCmpOEQ(V, Constant::getNullValue(Ty),
- "iszero");
+ Value *IsZero =
+ Builder.CreateFCmpOEQ(V, Constant::getNullValue(Ty), "iszero");
Value *ZeroLiteral = EmitScalarExpr(E->getArg(4));
BasicBlock *NotZero = createBasicBlock("fpclassify_not_zero", this->CurFn);
Builder.CreateCondBr(IsZero, End, NotZero);
@@ -4667,9 +4666,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
// if (fabs(V) == infinity) return FP_INFINITY
Builder.SetInsertPoint(NotNan);
Value *VAbs = EmitFAbs(*this, V);
- Value *IsInf =
- Builder.CreateFCmpOEQ(VAbs, ConstantFP::getInfinity(V->getType()),
- "isinf");
+ Value *IsInf = Builder.CreateFCmpOEQ(
+ VAbs, ConstantFP::getInfinity(V->getType()), "isinf");
Value *InfLiteral = EmitScalarExpr(E->getArg(1));
BasicBlock *NotInf = createBasicBlock("fpclassify_not_inf", this->CurFn);
Builder.CreateCondBr(IsInf, End, NotInf);
@@ -4679,12 +4677,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Builder.SetInsertPoint(NotInf);
APFloat Smallest = APFloat::getSmallestNormalized(
getContext().getFloatTypeSemantics(E->getArg(5)->getType()));
- Value *IsNormal =
- Builder.CreateFCmpUGE(VAbs, ConstantFP::get(V->getContext(), Smallest),
- "isnormal");
- Value *NormalResult =
- Builder.CreateSelect(IsNormal, EmitScalarExpr(E->getArg(2)),
- EmitScalarExpr(E->getArg(3)));
+ Value *IsNormal = Builder.CreateFCmpUGE(
+ VAbs, ConstantFP::get(V->getContext(), Smallest), "isnormal");
+ Value *NormalResult = Builder.CreateSelect(
+ IsNormal, EmitScalarExpr(E->getArg(2)), EmitScalarExpr(E->getArg(3)));
Builder.CreateBr(End);
Result->addIncoming(NormalResult, NotInf);
@@ -4837,8 +4833,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Address DestAddr = EmitPointerWithAlignment(E->getArg(0));
Address SrcAddr = EmitPointerWithAlignment(E->getArg(1));
Value *SizeVal = EmitScalarExpr(E->getArg(2));
- CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this,
- DestAddr, SrcAddr, SizeVal);
+ CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestAddr, SrcAddr,
+ SizeVal);
return RValue::get(DestAddr, *this);
}
@@ -4883,8 +4879,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BImemset:
case Builtin::BI__builtin_memset: {
Address Dest = EmitPointerWithAlignment(E->getArg(0));
- Value *ByteVal = Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)),
- Builder.getInt8Ty());
+ Value *ByteVal =
+ Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)), Builder.getInt8Ty());
Value *SizeVal = EmitScalarExpr(E->getArg(2));
EmitNonNullArgCheck(Dest, E->getArg(0)->getType(),
E->getArg(0)->getExprLoc(), FD, 0);
@@ -4916,8 +4912,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
if (Size.ugt(DstSize))
break;
Address Dest = EmitPointerWithAlignment(E->getArg(0));
- Value *ByteVal = Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)),
- Builder.getInt8Ty());
+ Value *ByteVal =
+ Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)), Builder.getInt8Ty());
Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size);
auto *I = Builder.CreateMemSet(Dest, ByteVal, SizeVal, false);
addInstToNewSourceAtom(I, nullptr);
@@ -5038,12 +5034,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
int32_t Offset = 0;
Function *F = CGM.getIntrinsic(Intrinsic::eh_dwarf_cfa);
- return RValue::get(Builder.CreateCall(F,
- llvm::ConstantInt::get(Int32Ty, Offset)));
+ return RValue::get(
+ Builder.CreateCall(F, llvm::ConstantInt::get(Int32Ty, Offset)));
}
case Builtin::BI__builtin_return_address: {
- Value *Depth = ConstantEmitter(*this).emitAbstract(E->getArg(0),
- getContext().UnsignedIntTy);
+ Value *Depth = ConstantEmitter(*this).emitAbstract(
+ E->getArg(0), getContext().UnsignedIntTy);
Function *F =
CGM.getIntrinsic(Intrinsic::returnaddress, {CGM.ProgramPtrTy});
return RValue::get(Builder.CreateCall(F, Depth));
@@ -5054,8 +5050,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(Builder.CreateCall(F, Builder.getInt32(0)));
}
case Builtin::BI__builtin_frame_address: {
- Value *Depth = ConstantEmitter(*this).emitAbstract(E->getArg(0),
- getContext().UnsignedIntTy);
+ Value *Depth = ConstantEmitter(*this).emitAbstract(
+ E->getArg(0), getContext().UnsignedIntTy);
Function *F = CGM.getIntrinsic(Intrinsic::frameaddress, AllocaInt8PtrTy);
return RValue::get(Builder.CreateCall(F, Depth));
}
@@ -5074,8 +5070,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(Result);
}
case Builtin::BI__builtin_dwarf_sp_column: {
- llvm::IntegerType *Ty
- = cast<llvm::IntegerType>(ConvertType(E->getType()));
+ llvm::IntegerType *Ty = cast<llvm::IntegerType>(ConvertType(E->getType()));
int Column = getTargetHooks().getDwarfEHStackPointer(CGM);
if (Column == -1) {
CGM.ErrorUnsupported(E, "__builtin_dwarf_sp_column");
@@ -5189,6 +5184,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(Ptr);
}
+ // Sema already validates the target as an implicit-lifetime type hence it doesn't require vptr laundering.
+ case Builtin::BI__builtin_start_lifetime_as: {
+ const Expr *PtrArg = E->getArg(0);
+ llvm::Value *Ptr = EmitScalarExpr(PtrArg);
+
+ return RValue::get(Ptr);
+ }
case Builtin::BI__sync_fetch_and_add:
case Builtin::BI__sync_fetch_and_sub:
case Builtin::BI__sync_fetch_and_or:
@@ -5380,8 +5382,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
CGM.getTypes().arrangeBuiltinFunctionCall(E->getType(), Args);
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FuncInfo);
llvm::FunctionCallee Func = CGM.CreateRuntimeFunction(FTy, LibCallName);
- return EmitCall(FuncInfo, CGCallee::forDirect(Func),
- ReturnValueSlot(), Args);
+ return EmitCall(FuncInfo, CGCallee::forDirect(Func), ReturnValueSlot(),
+ Args);
}
case Builtin::BI__atomic_thread_fence:
@@ -5401,17 +5403,17 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case 0: // memory_order_relaxed
default: // invalid order
break;
- case 1: // memory_order_consume
- case 2: // memory_order_acquire
+ case 1: // memory_order_consume
+ case 2: // memory_order_acquire
Builder.CreateFence(llvm::AtomicOrdering::Acquire, SSID);
break;
- case 3: // memory_order_release
+ case 3: // memory_order_release
Builder.CreateFence(llvm::AtomicOrdering::Release, SSID);
break;
- case 4: // memory_order_acq_rel
+ case 4: // memory_order_acq_rel
Builder.CreateFence(llvm::AtomicOrdering::AcquireRelease, SSID);
break;
- case 5: // memory_order_seq_cst
+ case 5: // memory_order_seq_cst
Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, SSID);
break;
}
@@ -5668,7 +5670,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
// Decide if we are lowering to a uadd.with.overflow or usub.with.overflow.
Intrinsic::ID IntrinsicId;
switch (BuiltinID) {
- default: llvm_unreachable("Unknown multiprecision builtin id.");
+ default:
+ llvm_unreachable("Unknown multiprecision builtin id.");
case Builtin::BI__builtin_addcb:
case Builtin::BI__builtin_addcs:
case Builtin::BI__builtin_addc:
@@ -5687,13 +5690,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
// Construct our resulting LLVM IR expression.
llvm::Value *Carry1;
- llvm::Value *Sum1 = EmitOverflowIntrinsic(*this, IntrinsicId,
- X, Y, Carry1);
+ llvm::Value *Sum1 = EmitOverflowIntrinsic(*this, IntrinsicId, X, Y, Carry1);
llvm::Value *Carry2;
- llvm::Value *Sum2 = EmitOverflowIntrinsic(*this, IntrinsicId,
- Sum1, Carryin, Carry2);
- llvm::Value *CarryOut = Builder.CreateZExt(Builder.CreateOr(Carry1, Carry2),
- X->getType());
+ llvm::Value *Sum2 =
+ EmitOverflowIntrinsic(*this, IntrinsicId, Sum1, Carryin, Carry2);
+ llvm::Value *CarryOut =
+ Builder.CreateZExt(Builder.CreateOr(Carry1, Carry2), X->getType());
Builder.CreateStore(CarryOut, CarryOutPtr);
return RValue::get(Sum2);
}
@@ -5784,7 +5786,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
// Finally, store the result using the pointer.
bool isVolatile =
- ResultArg->getType()->getPointeeType().isVolatileQualified();
+ ResultArg->getType()->getPointeeType().isVolatileQualified();
Builder.CreateStore(EmitToMemory(Result, ResultQTy), ResultPtr, isVolatile);
return RValue::get(Overflow);
@@ -5819,7 +5821,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
// Decide which of the overflow intrinsics we are lowering to:
Intrinsic::ID IntrinsicId;
switch (BuiltinID) {
- default: llvm_unreachable("Unknown overflow builtin id.");
+ default:
+ llvm_unreachable("Unknown overflow builtin id.");
case Builtin::BI__builtin_uadd_overflow:
case Builtin::BI__builtin_uaddl_overflow:
case Builtin::BI__builtin_uaddll_overflow:
@@ -5852,7 +5855,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
break;
}
-
llvm::Value *Carry;
llvm::Value *Sum = EmitOverflowIntrinsic(*this, IntrinsicId, X, Y, Carry);
Builder.CreateStore(Sum, SumOutPtr);
@@ -5887,9 +5889,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_call_with_static_chain: {
const CallExpr *Call = cast<CallExpr>(E->getArg(0));
const Expr *Chain = E->getArg(1);
- return EmitCall(Call->getCallee()->getType(),
- EmitCallee(Call->getCallee()), Call, ReturnValue,
- EmitScalarExpr(Chain));
+ return EmitCall(Call->getCallee()->getType(), EmitCallee(Call->getCallee()),
+ Call, ReturnValue, EmitScalarExpr(Chain));
}
case Builtin::BI_InterlockedExchange8:
case Builtin::BI_InterlockedExchange16:
@@ -6169,8 +6170,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
const char *Name = (BuiltinID == Builtin::BIread_pipe) ? "__read_pipe_4"
: "__write_pipe_4";
- llvm::Type *ArgTys[] = {Arg0->getType(), Arg1->getType(), Int32Ty, I8PTy,
- Int32Ty, Int32Ty};
+ llvm::Type *ArgTys[] = {Arg0->getType(), Arg1->getType(), Int32Ty,
+ I8PTy, Int32Ty, Int32Ty};
Value *Arg2 = EmitScalarExpr(E->getArg(2)),
*Arg3 = EmitScalarExpr(E->getArg(3));
llvm::FunctionType *FTy = llvm::FunctionType::get(Int32Ty, ArgTys, false);
@@ -6307,8 +6308,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
auto NewName = std::string("__") + E->getDirectCallee()->getName().str();
auto NewCall =
EmitRuntimeCall(CGM.CreateRuntimeFunction(FTy, NewName), {NewArg});
- return RValue::get(Builder.CreateBitOrPointerCast(NewCall,
- ConvertType(E->getType())));
+ return RValue::get(
+ Builder.CreateBitOrPointerCast(NewCall, ConvertType(E->getType())));
}
// OpenCL v2.0, s6.13.17 - Enqueue kernel function.
@@ -6731,7 +6732,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
// can move this up to the beginning of the function.
checkTargetFeatures(E, FD);
- if (unsigned VectorWidth = getContext().BuiltinInfo.getRequiredVectorWidth(BuiltinID))
+ if (unsigned VectorWidth =
+ getContext().BuiltinInfo.getRequiredVectorWidth(BuiltinID))
LargestVectorWidth = std::max(LargestVectorWidth, VectorWidth);
// See if we have a target specific intrinsic.
@@ -6752,7 +6754,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
}
if (IntrinsicID != Intrinsic::not_intrinsic) {
- SmallVector<Value*, 16> Args;
+ SmallVector<Value *, 16> Args;
// Find out if any arguments are required to be integer constant
// expressions.
@@ -6802,7 +6804,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
if (RetTy != V->getType()) {
// XXX - vector of pointers?
if (auto *PtrTy = dyn_cast<llvm::PointerType>(RetTy)) {
- if (PtrTy->getAddressSpace() != V->getType()->getPointerAddressSpace()) {
+ if (PtrTy->getAddressSpace() !=
+ V->getType()->getPointerAddressSpace()) {
V = Builder.CreateAddrSpaceCast(
V, llvm::PointerType::get(getLLVMContext(),
PtrTy->getAddressSpace()));
diff --git a/clang/test/CodeGenCXX/builtin-start-lifetime-as.cpp b/clang/test/CodeGenCXX/builtin-start-lifetime-as.cpp
new file mode 100644
index 0000000000000..c3e38e31e89e4
--- /dev/null
+++ b/clang/test/CodeGenCXX/builtin-start-lifetime-as.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -std=c++23 -O2 -emit-llvm %s -o - | FileCheck %s
+
+struct Struct {
+ int x;
+ float y;
+};
+
+// {{.*}} to match for `noundef readnone returned captures(ret: address, provenance)`
+// CHECK-LABEL: define {{.*}} ptr @_Z15test_start_lifePv(ptr {{.*}} %buffer)
+Struct* test_start_life(void* buffer) {
+ // CHECK: ret ptr %buffer
+ return (Struct*)__builtin_start_lifetime_as((Struct*)buffer);
+}
>From fa1c699b3fc6ce9ea54857d9969cd07e452589d6 Mon Sep 17 00:00:00 2001
From: Yash Verma <yashverma056 at proton.me>
Date: Thu, 7 May 2026 06:42:30 -0400
Subject: [PATCH 4/4] [libc++] Implement C++23 std::start_lifetime_as and
std::start_lifetime_as_array
Implements P2590R2 and P2679R2 by exposing the `__builtin_start_lifetime_as` instrinsic through the `<memory>` header.
Key changes:
- Adds `<__memory/start_lifetime_as.h>` providing the scalar and array variants, and exporting them through the public `<memory>` header.
- Adds test suites to validate their behavior.
---
clang/lib/CodeGen/CGBuiltin.cpp | 3 +-
libcxx/include/CMakeLists.txt | 1 +
libcxx/include/__memory/start_lifetime_as.h | 72 ++++++++++++++++++
libcxx/include/memory | 26 +++++++
libcxx/include/module.modulemap.in | 1 +
.../start.lifetime/start_lifetime_as.pass.cpp | 76 +++++++++++++++++++
.../start_lifetime_as.verify.cpp | 35 +++++++++
.../start_lifetime_as_array.pass.cpp | 47 ++++++++++++
8 files changed, 260 insertions(+), 1 deletion(-)
create mode 100644 libcxx/include/__memory/start_lifetime_as.h
create mode 100644 libcxx/test/std/memory/start.lifetime/start_lifetime_as.pass.cpp
create mode 100644 libcxx/test/std/memory/start.lifetime/start_lifetime_as.verify.cpp
create mode 100644 libcxx/test/std/memory/start.lifetime/start_lifetime_as_array.pass.cpp
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 8135b7c1c000c..ac90b4cfbf529 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -5184,7 +5184,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(Ptr);
}
- // Sema already validates the target as an implicit-lifetime type hence it doesn't require vptr laundering.
+ // Sema already validates the target as an implicit-lifetime type hence it
+ // doesn't require vptr laundering.
case Builtin::BI__builtin_start_lifetime_as: {
const Expr *PtrArg = E->getArg(0);
llvm::Value *Ptr = EmitScalarExpr(PtrArg);
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index e27fb7602430f..eb91879b5c965 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -610,6 +610,7 @@ set(files
__memory/raw_storage_iterator.h
__memory/shared_count.h
__memory/shared_ptr.h
+ __memory/start_lifetime_as.h
__memory/swap_allocator.h
__memory/temp_value.h
__memory/temporary_buffer.h
diff --git a/libcxx/include/__memory/start_lifetime_as.h b/libcxx/include/__memory/start_lifetime_as.h
new file mode 100644
index 0000000000000..9ca84dc386dd8
--- /dev/null
+++ b/libcxx/include/__memory/start_lifetime_as.h
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___MEMORY_START_LIFETIME_AS_H
+#define _LIBCPP___MEMORY_START_LIFETIME_AS_H
+
+#include "__configuration/attributes.h"
+#include <__config>
+#include <cstddef>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 23
+
+template <typename _Tp>
+_LIBCPP_HIDE_FROM_ABI _Tp* start_lifetime_as(void* __p) _NOEXCEPT {
+ return __builtin_start_lifetime_as(static_cast<_Tp*>(__p));
+}
+
+template <typename _Tp>
+_LIBCPP_HIDE_FROM_ABI const _Tp* start_lifetime_as(const void* __p) _NOEXCEPT {
+ return __builtin_start_lifetime_as(static_cast<const _Tp*>(__p));
+}
+
+template <typename _Tp>
+_LIBCPP_HIDE_FROM_ABI volatile _Tp* start_lifetime_as(volatile void* __p) _NOEXCEPT {
+ return __builtin_start_lifetime_as(static_cast<volatile _Tp*>(__p));
+}
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI const volatile _Tp* start_lifetime_as(const volatile void* __p) _NOEXCEPT {
+ return __builtin_start_lifetime_as(static_cast<const volatile _Tp*>(__p));
+}
+
+template <typename _Tp>
+_LIBCPP_HIDE_FROM_ABI _Tp* start_lifetime_as_array(void* __p, size_t __n) _NOEXCEPT {
+ static_cast<void>(__n);
+ return __builtin_start_lifetime_as(static_cast<_Tp*>(__p));
+}
+
+template <typename _Tp>
+_LIBCPP_HIDE_FROM_ABI const _Tp* start_lifetime_as_array(const void* __p, size_t __n) _NOEXCEPT {
+ static_cast<void>(__n);
+ return __builtin_start_lifetime_as(static_cast<const _Tp*>(__p));
+}
+
+template <typename _Tp>
+_LIBCPP_HIDE_FROM_ABI volatile _Tp* start_lifetime_as_array(volatile void* __p, size_t __n) _NOEXCEPT {
+ static_cast<void>(__n);
+ return __builtin_start_lifetime_as(static_cast<volatile _Tp*>(__p));
+}
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI const volatile _Tp* start_lifetime_as_array(const volatile void* __p, size_t __n) _NOEXCEPT {
+ static_cast<void>(__n);
+ return __builtin_start_lifetime_as(static_cast<const volatile _Tp*>(__p));
+}
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___MEMORY_START_LIFETIME_AS_H
diff --git a/libcxx/include/memory b/libcxx/include/memory
index ca880c83a544d..4ba8872e093c5 100644
--- a/libcxx/include/memory
+++ b/libcxx/include/memory
@@ -931,6 +931,31 @@ template<class Smart, class Pointer, class... Args>
template<class Pointer = void, class Smart, class... Args>
auto inout_ptr(Smart& s, Args&&... args); // since c++23
+// start_lifetime_as
+template <typename _Tp>
+_Tp* start_lifetime_as(void* __p) noexcept; // since c++23
+
+template <typename _Tp>
+const _Tp* start_lifetime_as(const void* __p) noexcept; // since c++23
+
+template <typename _Tp>
+volatile _Tp* start_lifetime_as(volatile void* __p) noexcept; // since c++23
+
+template <class _Tp>
+const volatile _Tp* start_lifetime_as(const volatile void* __p) noexcept; // since c++23
+
+template <typename _Tp>
+_Tp* start_lifetime_as_array(void* __p, size_t __n) noexcept; // since c++23
+
+template <typename _Tp>
+const _Tp* start_lifetime_as_array(const void* __p, size_t __n) noexcept; // since c++23
+
+template <typename _Tp>
+volatile _Tp* start_lifetime_as_array(volatile void* __p, size_t __n) noexcept; // since c++23
+
+template <class _Tp>
+const volatile _Tp* start_lifetime_as_array(const volatile void* __p, size_t __n) noexcept; // since c++23
+
} // std
*/
@@ -976,6 +1001,7 @@ template<class Pointer = void, class Smart, class... Args>
# if _LIBCPP_STD_VER >= 23
# include <__memory/allocate_at_least.h>
+# include <__memory/start_lifetime_as.h>
# endif
# include <version>
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 44d8e21b2fba3..0882e18a44c36 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1691,6 +1691,7 @@ module std [system] {
header "__memory/shared_ptr.h"
export std.functional.hash
}
+ module start_lifetime_as { header "__memory/start_lifetime_as.h" }
module swap_allocator { header "__memory/swap_allocator.h" }
module temp_value { header "__memory/temp_value.h" }
module temporary_buffer {
diff --git a/libcxx/test/std/memory/start.lifetime/start_lifetime_as.pass.cpp b/libcxx/test/std/memory/start.lifetime/start_lifetime_as.pass.cpp
new file mode 100644
index 0000000000000..c87f0291a8b36
--- /dev/null
+++ b/libcxx/test/std/memory/start.lifetime/start_lifetime_as.pass.cpp
@@ -0,0 +1,76 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <memory>
+// template<class T> T* start_lifetime_as(void* p) noexcept;
+// template<class T> const T* start_lifetime_as(const void* p) noexcept;
+// template<class T> volatile T* start_lifetime_as(volatile void* p) noexcept;
+// template<class T> const volatile T* start_lifetime_as(const volatile void* p) noexcept;
+
+#include <memory>
+#include <cassert>
+#include <type_traits>
+
+struct Trivial {
+ int x;
+ float y;
+};
+
+struct NestedArray {
+ int arr[3][4];
+};
+
+static_assert(noexcept(std::start_lifetime_as<int>(std::declval<void*>())));
+static_assert(noexcept(std::start_lifetime_as<int>(std::declval<const void*>())));
+static_assert(noexcept(std::start_lifetime_as<int>(std::declval<volatile void*>())));
+static_assert(noexcept(std::start_lifetime_as<int>(std::declval<const volatile void*>())));
+
+static_assert(std::is_same_v<decltype(std::start_lifetime_as<int>(std::declval<void*>())), int*>);
+static_assert(std::is_same_v<decltype(std::start_lifetime_as<int>(std::declval<const void*>())), const int*>);
+static_assert(std::is_same_v<decltype(std::start_lifetime_as<int>(std::declval<volatile void*>())), volatile int*>);
+static_assert(
+ std::is_same_v<decltype(std::start_lifetime_as<int>(std::declval<const volatile void*>())), const volatile int*>);
+
+void test_cv_qualifiers() {
+ alignas(Trivial) unsigned char buffer[sizeof(Trivial)];
+ void* p = buffer;
+ const void* cp = buffer;
+ volatile void* vp = buffer;
+ const volatile void* cvp = buffer;
+
+ Trivial* ptr = std::start_lifetime_as<Trivial>(p);
+ const Trivial* cptr = std::start_lifetime_as<Trivial>(cp);
+ volatile Trivial* vptr = std::start_lifetime_as<Trivial>(vp);
+ const volatile Trivial* cvptr = std::start_lifetime_as<Trivial>(cvp);
+
+ assert(static_cast<void*>(ptr) == buffer);
+ assert(static_cast<const void*>(cptr) == buffer);
+ assert(static_cast<volatile void*>(vptr) == buffer);
+ assert(static_cast<const volatile void*>(cvptr) == buffer);
+}
+
+void test_multi_dimensional_arrays() {
+ alignas(NestedArray) unsigned char buffer[sizeof(NestedArray)];
+
+ // P2679R2: The builtin should unwrap NestedArray completely
+ NestedArray* ptr = std::start_lifetime_as<NestedArray>(buffer);
+ assert(static_cast<void*>(ptr) == buffer);
+
+ using Matrix = double[4][4];
+ alignas(double) unsigned char mat_buffer[sizeof(Matrix)];
+ Matrix* mat_ptr = std::start_lifetime_as<Matrix>(mat_buffer);
+ assert(static_cast<void*>(mat_ptr) == mat_buffer);
+}
+
+int main(int, char**) {
+ test_cv_qualifiers();
+ test_multi_dimensional_arrays();
+ return 0;
+}
diff --git a/libcxx/test/std/memory/start.lifetime/start_lifetime_as.verify.cpp b/libcxx/test/std/memory/start.lifetime/start_lifetime_as.verify.cpp
new file mode 100644
index 0000000000000..b29cda44aff07
--- /dev/null
+++ b/libcxx/test/std/memory/start.lifetime/start_lifetime_as.verify.cpp
@@ -0,0 +1,35 @@
+//===----------------------------------------------------------------------===//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+#include <memory>
+
+struct NonTrivial {
+ int x;
+ ~NonTrivial() {}
+};
+
+struct Incomplete; // expected-note {{forward declaration of 'Incomplete'}}
+
+void test_invalid_types(void* p) {
+ // expected-error@*:* {{type 'NonTrivial' is not an implicit-lifetime type, cannot start lifetime}}
+ std::start_lifetime_as<NonTrivial>(p);
+
+ // expected-error@*:* {{incomplete type 'Incomplete' where a complete type is required}}
+ std::start_lifetime_as<Incomplete>(p);
+
+ // expected-error@*:* {{type 'void' is not an implicit-lifetime type, cannot start lifetime}}
+ std::start_lifetime_as<void>(p);
+
+ // expected-error@*:* {{static_cast from 'void *' to 'void (*)()' is not allowed}}
+ std::start_lifetime_as<void()>(p);
+}
+
+void test_constexpr() {
+ // expected-error at +1 {{constexpr variable 'fail' must be initialized by a constant expression}}
+ constexpr auto* fail = std::start_lifetime_as<int>((void*)nullptr);
+}
\ No newline at end of file
diff --git a/libcxx/test/std/memory/start.lifetime/start_lifetime_as_array.pass.cpp b/libcxx/test/std/memory/start.lifetime/start_lifetime_as_array.pass.cpp
new file mode 100644
index 0000000000000..8967e28e18e89
--- /dev/null
+++ b/libcxx/test/std/memory/start.lifetime/start_lifetime_as_array.pass.cpp
@@ -0,0 +1,47 @@
+//===----------------------------------------------------------------------===//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+#include <memory>
+#include <cassert>
+#include <type_traits>
+
+struct Trivial {
+ int id;
+};
+
+static_assert(noexcept(std::start_lifetime_as_array<int>(std::declval<void*>(), 5)));
+static_assert(noexcept(std::start_lifetime_as_array<int>(std::declval<const volatile void*>(), 5)));
+
+static_assert(std::is_same_v<decltype(std::start_lifetime_as_array<int>(std::declval<void*>(), 5)), int*>);
+static_assert(std::is_same_v<decltype(std::start_lifetime_as_array<int>(std::declval<const void*>(), 5)), const int*>);
+static_assert(
+ std::is_same_v<decltype(std::start_lifetime_as_array<int>(std::declval<volatile void*>(), 5)), volatile int*>);
+static_assert(std::is_same_v<decltype(std::start_lifetime_as_array<int>(std::declval<const volatile void*>(), 5)),
+ const volatile int*>);
+
+int main(int, char**) {
+ constexpr std::size_t count = 3;
+ alignas(Trivial) unsigned char buffer[sizeof(Trivial) * count];
+
+ void* p = buffer;
+ const void* cp = buffer;
+ volatile void* vp = buffer;
+ const volatile void* cvp = buffer;
+
+ Trivial* ptr = std::start_lifetime_as_array<Trivial>(p, count);
+ const Trivial* cptr = std::start_lifetime_as_array<Trivial>(cp, count);
+ volatile Trivial* vptr = std::start_lifetime_as_array<Trivial>(vp, count);
+ const volatile Trivial* cvptr = std::start_lifetime_as_array<Trivial>(cvp, count);
+
+ assert(static_cast<void*>(ptr) == buffer);
+ assert(static_cast<const void*>(cptr) == buffer);
+ assert(static_cast<volatile void*>(vptr) == buffer);
+ assert(static_cast<const volatile void*>(cvptr) == buffer);
+
+ return 0;
+}
More information about the libcxx-commits
mailing list